我是Ruby的新手并试图理解这种语法:
create_table :posts do |t|
t.string :title
t.string :content
t.string :likes
t.string :comments
t.timestamps null: false
end
我完全理解这个代码正在做什么,但我不明白 它是如何工作的。更具体地说,我理解create_table
是一种方法,而:posts
是一个参数,但我不了解其余的代码。
答案 0 :(得分:8)
支持它:)
create_table
是一种方法。 :posts
是作为参数传递的符号。括号是可选的,因此它看起来很奇怪,但它是一个简单的方法调用。
do
和end
之间的所有内容都是代码块。这是将代码作为参数传递给方法的众多方法之一。代码块非常适用于常见情况。其他类似(但不同)的方法是使用Proc
或lambda
或->
。
|t|
是由create_table
传递到代码块的参数。 create_table
将执行您的代码块,并将表对象作为单个参数传递给它。您选择命名该对象t
。
现在在您的代码块中,您在对象string
上调用方法t
并将其作为参数传递。你这样做了四次。括号再次是可选的。
您正在同一个对象timestamps
上调用t
方法。在这里你传递一个参数,它是一个值为{ :null => false }
的哈希。
null: false
是{ :null => false }
的快捷语法。 所以上述所有内容都相当于:
create_table(:posts) do |t|
t.string(:title)
t.string(:content)
t.string(:likes)
t.string(:comments)
t.timestamps({:null => false})
end
答案 1 :(得分:4)
让我们首先忘记Active Record并专注于代码结构本身。这是该结构的超简单版本。
class MyBuilder
def initialize
# keys are property names, values are options
@properties = {}
end
def property(name, options={})
@properties[name] = options
end
def build
# For simplicity, just return all properties
@properties
end
end
def create_thing(name)
puts "Begin creating #{name}"
builder = MyBuilder.new
puts "Let user use the builder to define properties"
yield builder
puts "Consume the builder"
properties = builder.build
puts "Persist changes to #{name}..."
# For simplicity just print them out
p properties
puts 'done'
end
create_thing :bar do |builder|
builder.property :counter, color: 'brown'
builder.property :wine_storage, texture: 'wood'
end
请手动输入上面的代码以获得一些感觉。
虽然上面的代码与Active Record无关,但它具有与迁移相同的结构。
当调用create_table
时,它实例化一个构建器(类型为TableDefinition
),并且"推送"该构建器到块(通过yield
)以便让用户定义表列。当用户完成定义列时,构建器稍后将被create_table
使用。
答案 2 :(得分:2)
学习Ruby的一个难点是,像smalltalk等人一样,你可以传递代码和数据。
将代码传递给方法的一种方法是使用代码块。
然后,您可以使用yield
调用方法定义中的代码块,其中“插入此代码块代替yield
”:
def do_it
yield
end
do_it { 2 + 4 }
=> 6
您还可以从方法定义向代码块发送参数。 这就是| t |的地方进来:
def do_it_with_ten
yield 10
end
do_it_with_ten { |t| (2 + 4) * t }
=> 60
请注意,花括号等同于do..end。
我猜这是你在其中找到的代码:
def create_table(name, options = {})
table_definition = TableDefinition.new(self)
table_definition.primary_key(options[:primary_key] || "id") unless options[:id] == false
yield table_definition
if options[:force]
drop_table(name) rescue nil
end
create_sql = "CREATE#{' TEMPORARY' if options[:temporary]} TABLE "
create_sql << "#{name} ("
create_sql << table_definition.to_sql
create_sql << ") #{options[:options]}"
execute create_sql
end
这正是您正在寻找的。这是我们调用的create_table方法的定义。您可以使用参数table_definition
来查看收益率。