【问题标题】:Rails ActiveRecord: Select Posts WITHOUT commentsRails ActiveRecord:选择没有评论的帖子
【发布时间】:2023-03-04 06:56:01
【问题描述】:

我有一个 Comments 表和一个 Posts 表,其中一个 Post 有许多 cmets,一个评论属于一个帖子(即它在表中有一个 post_id)。

如何有效地选择最后十个没有 cmets 的帖子。 如果不先选择所有帖子并检查每个帖子的评论数为 0,我似乎无法完成此操作。

提前感谢您的帮助。

-内森

【问题讨论】:

    标签: ruby-on-rails activerecord model


    【解决方案1】:

    你可以的

    Post.find(:all, :include => :comments, :conditions => "comments.id is null", :limit => 10, :order => "created_at desc")
    

    【讨论】:

      【解决方案2】:

      您可以将counter cache 添加到Comment 模型,并将几个named scopes 添加到Post 模型。比如:

      class Post < ActiveRecord::Base
        has_many :comments
      
        named_scope :recent, :limit => 10, :order => 'created_at DESC'
        named_scope :uncommented, :conditions => { :comments_count => 0 }
      end
      
      class Comment < ActiveRecord::Base
        belongs_to :post, :counter_cache => true
      end
      

      如果您使用的是 Rails 3,那么命名范围语法会有些不同:

      class Post < ActiveRecord::Base
        has_many :comments
      
        scope :recent, limit(10).order('posts.created_at DESC')
        scope :uncommented, where(:comments_count => 0)
      end
      

      现在您可以通过将命名范围链接在一起来查找没有任何 cmets 的帖子:

      @uncommented = Post.recent.uncommented
      

      如果您想获取所有没有任何 cmets 的帖子(即不仅仅是最近的十个帖子),那么它会是:

      @uncommented = Post.uncommented
      

      ——您可能已经注意到,在 Rails 3 示例中,我将 posts 表名包含在 :recent 范围内。这是一个很好的实践,如果两个表具有相同的列名,您可以避免 SQL 查询中的列名不明确。 This Railscast 解释更多。

      【讨论】:

        【解决方案3】:

        在您的帖子表中添加一个comments_count 列,并让迁移更新计数器。从现在开始,如果您在关联中提供:counter_cache =&gt; true,Rails 将自动更新您的计数器。现在很容易选择最后 10 个帖子:

        Post.find_all_by_comments_count 0, :order => 'created_at DESC', :limit => 10
        

        文档链接:http://rails.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#M001318

        【讨论】:

          【解决方案4】:

          你必须像这样添加一个条件:

          :conditions => '(SELECT count(*) FROM comments WHERE post_id = #{id}) = 0'
          

          我不是 SQL 专家,所以可能有类似 EMPTY 关键字之类的东西。

          【讨论】:

          • 就此而言,您应该使用双引号来替换#{id}
          • 最好不要这样做,因为它可能会打开您的代码以进行 SQL 注入。这样做:conditions => ['(SELECT ... WHERE post_id = ?) = 0', id]
          • @hurikhan77:你是对的。我指的是一个 ActiveRecord 关系,可以按照我写的那样做。
          【解决方案5】:

          你需要的是左外连接:

          Post.all :joins => "left outer join comments on posts.id = comments.post_id", :conditions => "comments.id is null", :limit => 10, :order => 'created at desc'
          

          此链接应该可以帮助您了解不同类型的 SQL 连接:http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html

          【讨论】:

            【解决方案6】:

            Post.includes(:cmets).where("cmets.id is null")

            【讨论】:

              猜你喜欢
              • 2012-04-16
              • 2023-04-10
              • 2015-03-04
              • 1970-01-01
              • 2015-04-17
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-06-17
              相关资源
              最近更新 更多