Rails 包含范围

Posted

技术标签:

【中文标题】Rails 包含范围【英文标题】:Rails includes with scope 【发布时间】:2014-11-27 08:47:06 【问题描述】:

我有一个名为 Author 的模型。一个作者有很多文章。 文章有一个名为 .published 的范围,它执行:where(published: true)。

我想加载作者,以及已发表的文章。 我试过了:

Author.includes(:articles.published).find(params[:author_id])

但这会引发错误:未定义的方法“已发布”。 有什么想法吗?

【问题讨论】:

是的,这只是需要用一些不同的术语来搜索。这是“急切加载作用域关联”,请参阅:***.com/questions/7937759/… ...结果是重复的? 【参考方案1】:

我认为最好的解决方案是:

Author.includes(:articles).where(:articles=>published: true).find(params[:author_id])

或者你可以创建范围:

class Author < ActiveRecord::Base 
    scope :with_published_articles, ->  includes(:articles).where(articles:  published: true) 
end

然后:

Author.with_published_articles.find(params[:author_id].to_s)

【讨论】:

【参考方案2】:

我会在 Author 上指定一个名为 with_published_articles 的范围,如下所示:

scope :with_published_articles, ->  joins(:articles).merge(Article.published) 

这将解决您的问题,同时在您的 Author 模型上指定 where(active: true),以防 publishedArticle 的行为将来发生变化。

所以现在你可以调用:

Author.with_published_articles.find(params[:author_id])

【讨论】:

这是最好的答案,因为它没有将作者与文章的“已发布”含义的内部实现结合起来 据我所知joins不会急于加载,所以这仍然会有n+1的问题 这是正确的答案,因为它降低了未来的更改成本(避免代码重复和泄露已发表文章概念的实现细节)。正如 tantrix 所说,它还避免了作者和文章的进一步耦合。【参考方案3】:

试试这个代码:

Author
  .includes(:articles).where(published: true).references(:articles)
  .find(params[:author_id])

您可以在此处找到有关上述示例的更多信息: includes api doc

【讨论】:

【参考方案4】:

使用:

class Articles < ActiveRecord::Base 
    scope :published, ->  where(articles: published: true) 
end

在 Autor 上定义范围

class Author < ActiveRecord::Base 
    scope :with_published_articles, ->  joins(:articles).merge(Articles.published) 
end

或者

Author.joins(:articles).merge(Articles.published).find(params[:author_id])

【讨论】:

以上是关于Rails 包含范围的主要内容,如果未能解决你的问题,请参考以下文章

Mongoid 范围检查数组字段是不是包含值

由关联计数组成的 Rails 查询,最好使用范围

Rails:使范围数据从索引到显示页面保持不变

Rails 3 - 选择包含?

ruby/rails:如何确定是不是包含模块?

Rails 单个包含多个类