rails 迁移中块中的列定义如何工作?
How does column definition in the blocks in rails migrations work?
通篇Rails有一个习惯用法是通过块变量查询参数。
例如在迁移中。
Rails 中的典型迁移看起来像这样
class CreateUsers < ActiveRecord::Migration[5.0]
def change
create_table :users do |t|
t.string :name
t.integer :parent_id, foreign_key: true
end
end
end
重要的部分是传递给方法的块的变量,例如 create_table
。
我猜 Rails 使用一些 ruby 元编程黑魔法通过块变量 |t|
定义 table 列。
现在问题:此模式的具体最小可重现示例是什么样的?
例如...
例如,方法如何检索块参数的变量?
是否 ActiveRecord::Migration,为了查询带有选项的 table 列覆盖 method_missing
?
你的,冯·斯波茨
create_table
仅在给出块时产生。
def create_table(table_name, **options)
td = create_table_definition(table_name, options)
# ...
yield td if block_given?
# ...
result = execute schema_creation.accept td
# ...
end
create_table_definition
创建 ActiveRecord::ConnectionAdapters::TableDefinition
.
的实例
Represents the schema of an SQL table in an abstract way. This class
provides methods for manipulating the schema representation.
这并不是真正的黑魔法。它是一个 DSL 对象,表示 table 及其列,最后从数据结构创建 SQL 字符串。
然后当您在块内的 table 定义上调用 column
方法(及其委托)时,您实际上是在改变参数中传递给的对象 td通过将 ColumnDefinition 对象添加到其列列表来创建该块。请记住,Ruby 是通过引用传递的。
How for example does a method retrieve the variable(s) of a block parameter?
他们没有。 yield
与 Ruby 中的其他所有内容一样,是一个表达式,return 是块 return 的值。此方法甚至不关心 return 值,因为它全都与副作用有关。
传递到块中的任何参数都是该范围的局部变量,如果局部变量未在块外引用,则在块完成时将被垃圾回收。
Does ActiveRecord::Migration, for the purpose of querying the table
columns with options overwrite method_missing ?
没有。 method_missing
这里没有使用。唯一涉及的元编程是 ColumnMethods 模块,它定义了用于定义列的快捷方法:
module ActiveRecord
module ConnectionAdapters #:nodoc:
# ...
module ColumnMethods
# Appends a primary key definition to the table definition.
# Can be called multiple times, but this is probably not a good idea.
def primary_key(name, type = :primary_key, **options)
column(name, type, options.merge(primary_key: true))
end
# Appends a column or columns of a specified type.
#
# t.string(:goat)
# t.string(:goat, :sheep)
#
# See TableDefinition#column
[
:bigint,
:binary,
:boolean,
:date,
:datetime,
:decimal,
:float,
:integer,
:string,
:text,
:time,
:timestamp,
:virtual,
].each do |column_type|
module_eval <<-CODE, __FILE__, __LINE__ + 1
def #{column_type}(*args, **options)
args.each { |name| column(name, :#{column_type}, options) }
end
CODE
end
alias_method :numeric, :decimal
end
# ...
end
end
实际的数据库驱动程序,如 ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
和 MysqlAdapter
向此列表添加更多类型,如 json。
它实际上也不会查询 table,因为在执行块时它还不存在。
通篇Rails有一个习惯用法是通过块变量查询参数。
例如在迁移中。
Rails 中的典型迁移看起来像这样
class CreateUsers < ActiveRecord::Migration[5.0]
def change
create_table :users do |t|
t.string :name
t.integer :parent_id, foreign_key: true
end
end
end
重要的部分是传递给方法的块的变量,例如 create_table
。
我猜 Rails 使用一些 ruby 元编程黑魔法通过块变量 |t|
定义 table 列。
现在问题:此模式的具体最小可重现示例是什么样的?
例如...
例如,方法如何检索块参数的变量?
是否 ActiveRecord::Migration,为了查询带有选项的 table 列覆盖 method_missing
?
你的,冯·斯波茨
create_table
仅在给出块时产生。
def create_table(table_name, **options)
td = create_table_definition(table_name, options)
# ...
yield td if block_given?
# ...
result = execute schema_creation.accept td
# ...
end
create_table_definition
创建 ActiveRecord::ConnectionAdapters::TableDefinition
.
Represents the schema of an SQL table in an abstract way. This class provides methods for manipulating the schema representation.
这并不是真正的黑魔法。它是一个 DSL 对象,表示 table 及其列,最后从数据结构创建 SQL 字符串。
然后当您在块内的 table 定义上调用 column
方法(及其委托)时,您实际上是在改变参数中传递给的对象 td通过将 ColumnDefinition 对象添加到其列列表来创建该块。请记住,Ruby 是通过引用传递的。
How for example does a method retrieve the variable(s) of a block parameter?
他们没有。 yield
与 Ruby 中的其他所有内容一样,是一个表达式,return 是块 return 的值。此方法甚至不关心 return 值,因为它全都与副作用有关。
传递到块中的任何参数都是该范围的局部变量,如果局部变量未在块外引用,则在块完成时将被垃圾回收。
Does ActiveRecord::Migration, for the purpose of querying the table columns with options overwrite method_missing ?
没有。 method_missing
这里没有使用。唯一涉及的元编程是 ColumnMethods 模块,它定义了用于定义列的快捷方法:
module ActiveRecord
module ConnectionAdapters #:nodoc:
# ...
module ColumnMethods
# Appends a primary key definition to the table definition.
# Can be called multiple times, but this is probably not a good idea.
def primary_key(name, type = :primary_key, **options)
column(name, type, options.merge(primary_key: true))
end
# Appends a column or columns of a specified type.
#
# t.string(:goat)
# t.string(:goat, :sheep)
#
# See TableDefinition#column
[
:bigint,
:binary,
:boolean,
:date,
:datetime,
:decimal,
:float,
:integer,
:string,
:text,
:time,
:timestamp,
:virtual,
].each do |column_type|
module_eval <<-CODE, __FILE__, __LINE__ + 1
def #{column_type}(*args, **options)
args.each { |name| column(name, :#{column_type}, options) }
end
CODE
end
alias_method :numeric, :decimal
end
# ...
end
end
实际的数据库驱动程序,如 ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
和 MysqlAdapter
向此列表添加更多类型,如 json。
它实际上也不会查询 table,因为在执行块时它还不存在。