重用activerecord范围有很多通过关联

时间:2012-12-04 04:22:06

标签: ruby-on-rails activerecord arel

假设我的rails 3.1项目中有一些activerecord模型,如下所示:

class Component < ActiveRecord::Base
    has_many :bugs
end

class Bug < ActiveRecord::Base
    belongs_to :component
    belongs_to :project

    scope :open, where(:open => true)
    scope :closed, where(:open => false)
end

class Project < ActiveRecord::Base
    has_many :bugs
    has_many :components_with_bugs, :through => :bugs, :conditions => ["bugs.open = ?", true]
end

简而言之:我有一个has_many通过关联(components_with_bugs),我想在其中确定“通过”模型的范围。目前我正在通过复制范围的代码来做到这一点。

有没有办法定义这有很多通过关联(components_with_bugs),这样我可以在直通模型上重用Bug.open范围,同时仍然在单个数据库查询中加载组件? (我想象的是:conditions => Bug.open

5 个答案:

答案 0 :(得分:2)

Rails 4回答

鉴于你有:

class Component < ActiveRecord::Base
  has_many :bugs
end

class Bug < ActiveRecord::Base
  belongs_to :component
  belongs_to :project

  scope :open,   ->{ where( open: true) }
  scope :closed, ->{ where( open: false) }
end

您有两种可能性:

class Project < ActiveRecord::Base
  has_many :bugs

  # you can use an explicitly named scope
  has_many :components_with_bugs, -> { merge( Bug.open ) }, through: :bugs, source: 'component'

  # or you can define an association extension method
  has_many :components, through: :bugs do
    def with_open_bugs
      merge( Bug.open )
    end
  end
end

调用projet.components_with_bugsproject.components.with_open_bugs将触发相同的SQL查询:

SELECT "components".* FROM "components"
INNER JOIN "bugs" ON "components"."id" = "bugs"."component_id"
WHERE "bugs"."project_id" = ? AND "bugs"."open" = 't'  [["project_id", 1]]

哪一个更好用,取决于您的应用程序。但是如果你需要在同一个协会上使用很多范围,我猜association extensions可能会更清楚。

真正的魔术是用merge完成的,正如名称所示,它允许你合并另一个ActiveRecord :: Relation的条件。在这种情况下,它负责在SQL查询中添加AND "bugs"."open" = 't'

答案 1 :(得分:0)

http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html指定

:conditions 指定关联对象必须满足的条件才能包含为WHERE SQL片段,例如authorized = 1。

因此你可以这样做:

class Project < ActiveRecord::Base
  has_many :bugs
  has_many :components_with_bugs, :through => :bugs do
    def open
      where("bugs.open = ?", true)
    end
  end
end

编辑:

你不能指定另一个模型的范围作为条件。在你的情况下,你已经实施的方式是正确的。你可以实现另一种方式

has_many :components_with_bugs, :through => :bugs #in this case, no need to use the relation.

def open_bugs
  self.bugs.openn #openn is the scope in bug. dont use name 'open'. its a private method of Array.
end

答案 2 :(得分:0)

除了您的范围外,请将默认范围写为:
“通过”模型中的 default_scope where(:open => true) 错误

class Bug < ActiveRecord::Base
    belongs_to :component
    belongs_to :project
     default_scope where(:open => true)
    scope :open, where(:open => true)
    scope :closed, where(:open => false)
end

在项目模型中删除:conditions =&gt; [“bugs.open =?”,true]

class Project < ActiveRecord::Base
    has_many :bugs
    has_many :components_with_bugs, :through => :bugs
end

我认为上述内容对您有用。

答案 3 :(得分:0)

尝试使用以下内容。

has_many :components_with_bugs, :through => :bugs do
   Bug.open
end

答案 4 :(得分:0)

你不能用这样的东西吗?

has_many :components_with_bugs, :through => :bugs, :conditions => Bug.open.where_values

我没有测试过,只是提出了一条调查路径