我有这些模特..。
class Administrator < ApplicationRecord
...
has_many :locations
class Location < ApplicationRecord
...
has_many :displays, :dependent => :destroy我有这样的代码,它的目的是检索所有的显示,但必须符合某些标准.
@displays = []
current_user.locations.each do |location|
@displays = (@displays + location.displays.where(:user => user).includes(:administrator)).uniq
end我想找一种巧妙的铁轨方法把上面的东西简化成一个班轮,所以我试了一下。
@displays = current_user.locations.displays.where(:user => user).includes(:administrator).flatten.uniq但这会导致一个错误
undefined method `displays' for #<ActiveRecord::Associations::CollectionProxy []>有没有一种方法可以用一行重写我的独立块呢?
发布于 2019-11-19 23:53:44
您可以向Location模型中添加一个类方法,以实现您想要的结果。
class Location < ApplicationRecord
has_many :displays, dependent: :destroy
def self.displays
Display.where(location_id: select(:id))
end
end它应该允许您使用:
@displays = current_user.locations.displays.where(user: user).includes(:administrator)如果不想向模型中添加助手,则可以更改记录获取技术。
location_ids = current_user.locations.pluck(:id)
@displays = Display.where(location_id: location_ids, user: user).includes(:administrator)对于一行,您可以简单地将上面的行合并在一起。然而,我会选择多行解决方案,因为这一行将变得相当长。
@displays = Display.where(location_id: current_user.locations.pluck(:id), user: user).includes(:administrator)在这两个场景中,不需要对结果进行flatten或调用uniq。
您可能希望将select(:id)替换为pluck(:id),反之亦然。区别在于select将创建一个子查询。虽然pluck首先只执行查询,但只获取位置ids,然后使用它们创建新的查询。这确实会产生一个额外的查询,但可能会更快,因为查询不那么复杂。
您还可以使用以下作用域而不是类方法:
scope :displays, -> { Display.where(location_id: select(:id)) }我之所以使用类方法是因为定义/一致性的原因。让我引用GNU版的“国际英语合作词典”中的“范围”的定义:
名词,目的;目的是达到或完成的目的;因此,最终的设计、目标或目的;意图;漂泊;目标。
从上面我们可以得出结论,作用域应该增加对当前作用域的限制,以缩小结果的目标。因此,作用域只应返回当前作用域的受限版本。由于displays返回了一个全新的作用域,并且产生了不同的记录( Display而不是Location的实例),所以我选择了一个类方法。(尽管用法相同。)
发布于 2019-11-19 21:52:22
你是在locations上给locations打电话,而不是打location。
你可能在找这样的东西:
current_user.locations.joins(:displays).where(displays: { user: user }) ...
https://stackoverflow.com/questions/58943353
复制相似问题