【问题标题】:Rails 3 - Eager loading with conditionsRails 3 - 有条件的急切加载
【发布时间】:2010-11-16 18:07:45
【问题描述】:

好吧,我完全被这个难住了。我正在尝试构建按类别组织的已发布网页的菜单。

类别.rb:

belongs_to :parent, :class_name => "Category", :foreign_key => "parent_id"
has_many   :children, :class_name => "Category", :foreign_key => "parent_id"
has_many :pages, :documents, :galleries

页面.rb

belongs_to :category

Page 模型也有 :is_published,所以我也在尝试对其进行过滤。我不愿意发布我微弱的查询尝试,但除了乞求更聪明的人之外,没有其他解决方案:

(自己是@current_website)

self.categories.includes(:children, :pages).where('pages.is_published = 1')

这主要返回我需要的内容,但不返回没有发布页面的父类别。例如,如果我有:

Parent Category
- Published Page
- Child Category
-- Published Page

失败的地方是我在父级中没有已发布的页面,如下所示:

Parent Category
- Child Category
-- Published Page
- Child Category
-- Published Page

在此先感谢您提供任何帮助。我正在尝试尽可能多地了解查询,但我在这方面遇到了困难。

更新:实施 KandadaBoggu 的建议产生了更好的结果,已添加到 Category.rb

  has_many :published_pages, :class_name => "Page",
                             :conditions => {:is_published => true}

但是,当使用以下内容时:

self.categories.where(:parent_id => nil).includes({:children => :published_pages},
                                                   :published_pages)

我得到了我需要的结果,但我也得到了空的父类别(没有已发布的页面,没有带有已发布页面的子类别。例如:

- Parent Category
-- Published Page
- Parent Category
-- NOTHING

我的临时解决方法是在查询中附加:

reject{|category| category.pages.empty? && category.children.empty?}

再次感谢您的帮助。

【问题讨论】:

    标签: mysql ruby-on-rails rails-activerecord


    【解决方案1】:

    添加一个名为 published_pages 的新关联(除了您当前的关联)

    class Category
    
      has_many   :children,        :class_name => "Category", 
                   :foreign_key => "parent_id"
      has_many   :published_pages, :class_name => "Page", 
                   :conditions  => { :is_published => true }
    
    end
    

    现在你可以得到所有的分类如下:

    self.categories.includes(:children, :published_pages)
    

    如果您有兴趣了解为什么您的方法不起作用,请阅读 Rails documentation(在 Eager loading of associations 部分之后滚动 10-15 行)。我在下面包含了相关的sn-p:

    例如

    Post.includes([:author, :comments]).where(['comments.approved = ?', true]).all
    

    这将产生一个带有如下连接的 SQL 查询:

    LEFT OUTER JOIN comments ON comments.post_id = posts.id and 
    LEFT OUTER JOIN authors  ON authors.id = posts.author_id. 
    

    请注意,使用这样的条件可能会产生意想不到的后果。 在上面的示例中,不返回带有概念已批准 cmets 的帖子 完全没有,因为条件适用于整个 SQL 语句 而不仅仅是协会。您必须消除列的歧义 发生此后备的参考,例如 :order => "author.name DESC" 会起作用,但 :order => "name DESC" 不会。

    要预先加载关联的过滤行,请使用带条件的关联:

    class Post < ActiveRecord::Base
      has_many :approved_comments, :class_name => 'Comment', 
                 :conditions => ['approved = ?', true]
    end
    
    Post.find(:all, :include => :approved_comments)
    

    【讨论】:

    • 感谢 KandadaBoggu 最出色的文章、链接和解释!这无疑使我走上了正确的道路,我仍然对 self.categories.includes(:children => :published_pa​​ges, :published_pa​​ges) 提供没有页面的父母或带页面的子类别的问题。再次感谢!
    • 更新您的问题并指定您对页面存在/不存在的要求。
    • 当条件为动态时,此解决方案将不起作用。在这种情况下,我使用了一种解决方法,我已经发布了here
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多