我有三个模型Component
,Version
和User
相互关联,如下所示:
class Component < ActiveRecord::Base
has_many :versions, class_name 'ComponentVersion'
end
class ComponentVersion < ActiveRecord::Base
belongs_to :component
belongs_to :approver, class_name: 'User'
end
class User < ActiveRecord::Base
end
我想在Component
上创建两个范围: approved
和 unapproved
。如果某个组件至少有一个已批准的version
,则该组件已获得“已批准”,并且当其approver_id
不是nil
时,该组件将获得批准。因此Component.approved
应返回所有已批准的组件,Component.unapproved
应返回所有未批准的版本。
不幸的是,我不知道该怎么做。
我可以很容易地在ComponentVersion上定义范围:
class ComponentVersion < ActiveRecord::Base
belongs_to :component
belongs_to :approver, class_name: 'User'
scope :approved, -> { where('approver_id IS NOT NULL') }
scope :unapproved, -> { where('approver_id IS NULL') }
end
然后在控制台Component.joins(:version).merge(ComponentVersion.approved)
给了我一些接近我想要Component.approved
的东西,除了它包含重复项(如果一个组件有多个已批准的版本,它会被多次返回。)
并且Component.joins(:version).merge(ComponentVersion.unapproved)
对于相反的情况并不好,因为当我只想要仅具有未经批准的版本的组件(或根本没有版本)时,它会返回具有未批准和已批准版本的组件)。
我也尝试将SQL查询传递给包含joins
而不是INNER的OUTER JOIN
,但他们没有给我我想要的东西,而且他们对SQL的理解有限。< / p>
如何获得我需要的查询?
(我正在使用Postgres和Rails 3.2.13,如果重要的话。)
答案 0 :(得分:3)
使用查询生成器DSL似乎无法获得您想要的内容。我通常使用相关的子查询。
class Component
scope :approved, lambda{ where('EXISTS (SELECT 1 FROM component_versions WHERE component_versions.component_id = components.id AND component_versions.approver_id IS NOT NULL)') }
end
另一个版本
class Component
scope :approved, lambda { where('id IN (SELECT c.id FROM components c JOIN component_versions cv ON c.id = cv.component_id AND cv.approver_id IS NOT NULL)' }
end
使用Postgres,你可以使用哪一个并不重要,它有一个非常好的查询规划器。