我有一个故事模型和一个标签模型,彼此有_and_belongs_to_many。标签有一个名为adult的字段,表示任何包含该标签的故事都包含成人内容。 Story有一个名为adult_override的字段,表示即使其标记都不是成人,它也有成人内容。我有以下函数,它使用一个ActiveRecord :: Relation代表一组故事并过滤它只包含成人故事(这是Story类的一个方法):
def self.only_adult(story_set)
story_set.left_outer_joins(:tags)
.distinct
.where("stories.adult_override = true OR tags.adult = true")
end
我还有一个函数应该采用一组给定的故事(一个ActiveRecord :: Relation)并找到该集合中最常见的标签(这是Tag类的一个方法):
def self.most_common(story_set, num = 10)
joins(:stories).merge(story_set)
.select("tags.*, COUNT(*) AS cnt")
.group("tags.name")
.reorder("cnt DESC")
.limit(num)
end
(name是tags表的主键)
这些方法都可以自行运行,但是当我尝试在已经被only_adult过滤的关系上调用most_common时,我收到以下错误:
无法将“标记”加入名为“标记”的关联中;也许你拼错了 它?
即使在要传递的story_set中已经引用了tags表,我如何让most_common工作?
编辑:Tag.joins(故事)生成的SQL是:
SELECT“tags”。* FROM“tags”INNER JOIN“stories_tags”ON “stories_tags”。“name”=“tags”。“name”INNER JOIN“stories”ON “故事”。“id”=“stories_tags”。“story_id”
和only_adult生成的SQL在一个例子中是:
SELECT DISTINCT“故事”。* FROM“故事”LEFT OUTER JOIN “stories_tags”ON“stories_tags”。“story_id”=“故事”。“id”LEFT OUTER JOIN“tags”ON“tags”。“name”=“stories_tags”。“name”WHERE (true)AND(EXISTS(SELECT 1 FROM characters_stories INNER JOIN 字符ON characters_stories.character_id = characters.id WHERE (characters_stories.story_id = stories.id)AND(LOWER(characters.name) 类似'doc%')))AND(stories.adult_override = true OR tags.adult = true)订购“故事”。“作者”ASC
合并这两个关系时会出现问题。
答案 0 :(得分:0)
好的,我想出了如何正常工作,所以我会添加我的解决方案以防其他人遇到类似的问题。我替换了most_common的主体(为了简单起见,编辑了一下):
rflct = reflect_on_association(:stories)
join_table = rflct.join_table
join_sql = "INNER JOIN #{join_table} AS jt ON " +
"jt.#{rflct.foreign_key} = " +
"answer.name}"
processed_set = story_set.where("stories.id = jt.#{rflct.association_foreign_key}")
self.select('answer.*, COUNT(*) as cnt')
.from("tags AS answer")
.joins(join_sql)
.where("EXISTS (#{processed_set.to_sql})")
.group("answer.tags")
.reorder('cnt DESC')
.limit(num)
我对此并不完全满意 - 我觉得这可能是一种更优雅的方式来实现这一目标 - 但它确实有效。