0

假设我的 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 through 关联 ( components_with_bugs),我想在其中定义“通过”模型。目前我正在通过复制范围的代码来做到这一点。

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

4

5 回答 5

3

铁轨 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_bugsorproject.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]]

哪个更好用取决于您的应用程序。但是如果您需要在同一个关联上使用多个范围,我想关联扩展可能会更清晰。

真正的魔法是通过合并完成的,正如名字所说,它允许你合并另一个 ActiveRecord::Relation 的条件。在这种情况下,它负责AND "bugs"."open" = 't'在 sql 查询中添加。

于 2014-12-22T21:38:46.150 回答
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. Don't use name 'open'. It's a private method of Array.
end
于 2012-12-04T04:35:07.463 回答
0

尝试使用以下内容。

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

于 2012-12-04T07:14:11.903 回答
0

你不能用这样的东西吗?

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

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

于 2012-12-21T09:10:14.533 回答
0

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

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 => ["bugs.open = ?", true]

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

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

于 2012-12-04T05:25:58.913 回答