在关联声明中使用“self”(:has_many,:has_one)

时间:2010-12-30 16:44:05

标签: ruby-on-rails activerecord ruby-on-rails-3

我需要在:has_many声明中引用模型的self。

我有一个课,我们称之为Foo。 Foo:has_many Bar。 Foo有一个名为randomize的布尔属性,用于确定:has_many关系中Bars的顺序。如果randomize为true,则它们按“RAND()”或“RANDOM()”排序,具体取决于DB。如果没有,它们按id排序。我必须在关联上做出这个声明,因为我正在使用急切加载。我很清楚我可以在Foo中定义一个返回我想要的方法,但我需要一次加载所有内容,否则单独运行400-500个查询=坏。

class CreateFoo < ActiveRecord::Migration
  def self.up
    create_table :foos do |t|
      t.string :name
      t.boolean :randomize, :default => false
    end
  end
end

class CreateBar < ActiveRecord::Migration
  def self.up
    create_table :bars do |t|
      t.string :name
      t.references :foo
    end
  end
end

class Bar < ActiveRecord::Base
  belongs_to :foo
end

class Foo < ActiveRecord::Base
  # this is the line that doesn't work
  has_many :bars, :order => self.randomize ? 'RAND()' : 'id'
end

如何在has_many声明中访问 self 的属性?

我尝试过的事情都失败了:

  1. 创建一个返回正确字符串的Foo方法
  2. 创建lambda函数
  3. 哭闹
  4. 这可能吗?

    问题似乎在于:has_many中的“self”不属于Foo类型:

    undefined method `randomize' for #<Class:0x1076fbf78>
    

    是我得到的错误之一。注意它是一般的类,而不是Foo对象......为什么??

3 个答案:

答案 0 :(得分:2)

原来,Ryan Bates在Railscast中触及了类似的主题here。您需要在方法之后定义范围...

答案 1 :(得分:0)

自我在这种背景下是阶级。

要做你需要的事,你可以尝试传递一个lambda。

class Foo < AR::Base
  has_many :bars, :order => lambda { self.randomize? ? 'RAND()' : 'id'  }
end

我没有测试过,但它应该有用。

答案 2 :(得分:-1)

尝试使用默认范围而不是has_many声明

class Bar < ActiveRecord::Base
  default_scope lambda { order(self.randomize ? 'RAND()' : 'id') }

但是直接回答你的问题,你的has_many声明中的self引用了Foo类,而不是Foo的实例。