我目前面临以下问题。我有以下2种型号:
PageElement
页面
页面has_many :page_elements
,并且在has_many
模型中添加了以下page_element
关系:
#PageElement model
has_many :siblings, ->(pe) { where.not(id: pe.id) }, through: :page, class_name: "PageElement", source: :page_elements
因此,在名为set_position
的方法中,我寻找同级的最高位置,并将其设置为高1个数字。
def set_position
if position.zero? && siblings.present?
new_position = (siblings.order("position ASC").pluck(:position).last + 1 rescue 0)
update(position: new_position) if position != new_position
end
end
但是,当我查看由siblings
方法生成的查询时,由于某种原因,它会根据“当前page_element”自动进行范围调整:
PageElement Load (0.6ms) SELECT "page_elements".* FROM "page_elements" WHERE "page_elements"."page_id" = $1 AND "page_elements"."element_type" = $2 ORDER BY "page_elements"."position" ASC LIMIT $3 [["page_id", 69], ["element_type", 6], ["LIMIT", 1]]
如您所见,这里的重要部分是它对“当前元素类型”(即6)的过滤。但这不是我期望的行为,因为我想获得所有同级兄弟,而没有任何种类过滤。
为什么rails会根据当前元素自动进行作用域设置?我还发现,它会在其他类型的列(例如字符串)中发生,如果我向该元素添加title
,它也会过滤该标题字符串。
我知道一种解决方案是先取消范围的集合,像这样:
has_many :siblings, ->(pe) { unscoped.where.not(id: pe.id) }, through: :page, class_name: "PageElement", source: :page_elements
但是,我想了解为什么首先要对它进行范围调整,以便我理解我没有做错任何事情。
更新:
我发现只有在以after_commit
触发的方法中运行这种关系时,才会发生这种“作用域”。如果使用rails console
我尝试做PageElement.first.siblings
,则会得到正确的SQL查询:
irb(main):002:0> PageElement.last.siblings
PageElement Load (0.7ms) SELECT "page_elements".* FROM "page_elements" ORDER BY "page_elements"."id" DESC LIMIT $1 [["LIMIT", 1]]
PageElement Load (0.8ms) SELECT "page_elements".* FROM "page_elements" INNER JOIN "pages" ON "page_elements"."page_id" = "pages"."id" WHERE "pages"."id" = $1 AND "page_elements"."id" != $2 ORDER BY "page_elements"."position" ASC LIMIT $3 [["id", 79], ["id", 200], ["LIMIT", 11]]
UPDATE2:
经过进一步的挖掘,我发现问题是我正在使用where(element_type: 'something').first_or_create
在种子文件中生成这些实例。通过使用first_or_create,“兄弟姐妹”关系将自动确定范围。我已经找出问题的原因,但没有找到原因的原因。
我们当前正在使用page_instance.page_elements.where(some_condition).first_or_create
,以便我们可以一遍又一遍地运行种子文件而不会造成重复。