如何重写此行以避免“#<ActiveRecord::Associations::CollectionProxy []”错误?
How do I rewrite this line to avoid the "#<ActiveRecord::Associations::CollectionProxy []" error?
我有这些模型...
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
我想找到一种巧妙的 Rails 方法将上面的内容简化为一行,所以我尝试了这个
@displays = current_user.locations.displays.where(:user => user).includes(:administrator).flatten.uniq
但这会导致错误
undefined method `displays' for #<ActiveRecord::Associations::CollectionProxy []>
有没有办法在一行中重写我的初始块?
您在 locations
而不是 location
呼叫 displays
。
您可能正在寻找类似的东西:
current_user.locations.joins(:displays).where(displays: { user: user }) ...
您可以将 class 方法添加到您的 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
首先执行仅获取位置 ID 的查询,然后使用它们创建新查询。这确实会产生一个额外的查询,但可能会更快,因为查询不那么复杂。
您还可以使用以下范围代替 class 方法:
scope :displays, -> { Display.where(location_id: select(:id)) }
我使用 class 方法的原因是 definition/consistency。让我引用 GNU 版国际英语协作词典中的 definition of "scope":
noun That at which one aims; the thing or end to which the mind directs its view; that which is purposed to be reached or accomplished; hence, ultimate design, aim, or purpose; intention; drift; object.
从上面我们可以得出结论,范围应该在当前范围上添加限制以缩小结果的目标。因此,范围应该只有 return 当前范围的限制版本。由于 displays
return 是一个全新的范围,具有不同的结果记录(Display
的实例而不是 Location
)我选择了 class 方法. (虽然用法相同。)
我有这些模型...
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
我想找到一种巧妙的 Rails 方法将上面的内容简化为一行,所以我尝试了这个
@displays = current_user.locations.displays.where(:user => user).includes(:administrator).flatten.uniq
但这会导致错误
undefined method `displays' for #<ActiveRecord::Associations::CollectionProxy []>
有没有办法在一行中重写我的初始块?
您在 locations
而不是 location
呼叫 displays
。
您可能正在寻找类似的东西:
current_user.locations.joins(:displays).where(displays: { user: user }) ...
您可以将 class 方法添加到您的 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
首先执行仅获取位置 ID 的查询,然后使用它们创建新查询。这确实会产生一个额外的查询,但可能会更快,因为查询不那么复杂。
您还可以使用以下范围代替 class 方法:
scope :displays, -> { Display.where(location_id: select(:id)) }
我使用 class 方法的原因是 definition/consistency。让我引用 GNU 版国际英语协作词典中的 definition of "scope":
noun That at which one aims; the thing or end to which the mind directs its view; that which is purposed to be reached or accomplished; hence, ultimate design, aim, or purpose; intention; drift; object.
从上面我们可以得出结论,范围应该在当前范围上添加限制以缩小结果的目标。因此,范围应该只有 return 当前范围的限制版本。由于 displays
return 是一个全新的范围,具有不同的结果记录(Display
的实例而不是 Location
)我选择了 class 方法. (虽然用法相同。)