我在ActiveRecord中有以下方法,还有一些简化的类/关联:
class LineItem < ApplicationRecord
has_many :line_item_parts
def media
best = line_item_parts.detect do |part|
part.part.medias.any?
end
best_media = best && best.part.medias.first
best_media || product.medias.first
end
end
class LineItemPart < ApplicationRecord
belongs_to :line_item
belongs_to :part
end
class Part < ApplicationRecord
belongs_to :product
has_many :medias
end
class Media < ApplicationRecord
belongs_to :product
belongs_to :part, optional: true
end
在binding.pry中的服务器上运行时,我会执行以下操作:
> line_item.media #=> nil
> line_item.media #=> <Media: ...>
它有时会在第一次返回nil,但是当我再次运行它时它总是返回正确的对象。我在第一次运行的日志中看到以下行:
Products::Media Exists (1.0ms) SELECT 1 AS one FROM "products_medias" WHERE "products_medias"."part_id" = $1 LIMIT $2 [["part_id", 472], ["LIMIT", 1]]
手动执行查询会按预期返回Media结果。在第二次运行中,它是相同的查询,但使用AR CACHE
,但在第二次运行时,它返回正确的结果(非零媒体对象)。
这怎么可能?这是一个ActiveRecord错误吗?我甚至不知道从哪里开始用谷歌搜索这样的东西。
宝石:
Postgres版本:psql (PostgreSQL) 10.2 (Debian 10.2-1.pgdg90+1)
在Docker for Mac中运行。
答案 0 :(得分:1)
我没有看到错误,但看起来无论如何都会导致多次查询。我可以建议一个替代方案吗?
def media
best_media = Media
.joins(parts: [line_item_parts: :line_items])
.where('line_items.id = ?', id)
.first
best_media || product.medias.first
end
如果您希望直接使用关联,可以尝试在枚举器方法之前添加.to_a
,以便明确地对结果进行操作。
def media
best = line_item_parts.to_a.detect do |lip|
lip.part.medias.any?
end
best_media = best && best.part.medias.first
best_media || product.medias.first
end