为什么迁移需要表格块参数?

时间:2009-10-05 00:42:22

标签: ruby-on-rails ruby activerecord migration

为什么ruby on rails migration语法如下所示:

create_table :my_table do |t|
     t.integer :col
     t.integer :col2
     t.integer :col3
end

而不是:

create_table :my_table do
     integer :col
     integer :col2
     integer :col3
end

就个人而言,我发现第二个片段更具可读性,是否有任何理由为什么实现使用第一个?

3 个答案:

答案 0 :(得分:3)

这两种方法的基本实施是不同的。 在第一个(实际)案例中,create_table使用yield对象调用TableDefinition。因此,示例块中的t指向TableDefinition。另一种方法是使用instance_eval。这看起来像是:

def create_table(name, &block)
  table_definition = TableDefinition.new
  # Other setup
  table_definition.instance_eval(&block)
  # More work
end

你采用哪种方式部分取决于偏好。然而,有些人不是eval的粉丝所以他们喜欢避免这种情况。此外,使用yield方法可以更清楚地了解您正在使用的对象。

答案 1 :(得分:0)

我的理解是ruby是词法范围的,意味着“整数”必须引用在代码中出现的点定义的东西。你需要动态范围来完成你所要求的。

可能是我错了,并且至少有一个procs,blocks和lambdas是动态范围的,但是你仍然有你的答案 - 范围行为的模糊细节并不是一个好东西,期望程序员知道。

答案 2 :(得分:0)

基本上,界面设计者应该选择这样做,因为这个关于范围的小技巧以及evalinstance_eval的工作方式,请查看此示例:

有两个类FooBoo具有以下定义:

class Foo
  def speak(phrase)
    puts phrase
  end 
  def self.generate(&block)
    f = Foo.new
    f.instance_eval(&block)
  end
end

class Boo
  attr_reader :name
  def initialize(name) ; @name = name ; end
  def express
    Foo.generate { speak name}
  end
end

一般情况下,这应该适用于大多数情况,但是某些情况如下面的语句会发出错误:

Boo.new("someone").express #`express': undefined local variable or method `name' for #<Foo:0xb7f582fc> (NameError)

我们无权访问BooFoo个实例中的实例方法,因为我们使用的是instance_eval ,因此方法{{为name个实例定义的1}}不在Boo个实例的范围内。

为了克服这些问题,最好按以下方式重新定义生成:

Foo

这是一个灵活的界面,您可以根据传递的块参数来评估代码块。现在我们必须在当前需要调用实例方法时将当前foo对象作为参数传递,让我们重新定义class Foo def speak(phrase) puts phrase end def self.generate(&block) f = Foo.new block.arity < 1 ? f.instance_eval(&block) : block.call(f) end end ,检查Booexpress

talk