【问题标题】:Rails: Query to get recent items based on the timestamp of a polymorphic associationRails:根据多态关联的时间戳查询以获取最近的项目
【发布时间】:2010-09-13 16:08:07
【问题描述】:

我对 cme​​ts 有通常的多态关联:

class Book < ActiveRecord::Base
  has_many :comments, :as => :commentable
end

class Article < ActiveRecord::Base
  has_many :comments, :as => :commentable
end

class Comment < ActiveRecord::Base
    belongs_to :commentable, :polymorphic => true
end

我希望能够根据 cmets 上的 created_at 时间戳定义 Book.recently_commented 和 Article.recently_commented。现在我正在查看一个非常丑陋的 find_by_SQL 查询来使用嵌套选择来执行此操作。似乎必须有更好的方法在 Rails 中完成,而无需求助于 SQL。

有什么想法吗?谢谢。

对于它的价值,这里是 SQL:

select * from 
    (select books.*,comments.created_at as comment_date 
    from books inner join comments on books.id = comments.commentable_id 
    where comments.commentable_type='Book' order by comment_date desc) as p 
group by id order by null;

【问题讨论】:

    标签: ruby-on-rails activerecord polymorphic-associations


    【解决方案1】:

    有时最好将字段添加到您正在评论的对象中。就像可能是 datetime 类型的 commented_at 字段。当对对象发表评论时,只需更新该值即可。

    虽然可以使用 SQL 来执行此操作,但 commented_at 方法可能被证明更具可扩展性。

    【讨论】:

    • 是的,这可能是我最终要走的路。代码会更容易理解。
    • 快速更新 - 出于性能原因,将 commented_at 字段添加到对象变得必要。在 'commented' 回调中,我还禁用了 record_timestamps,以便在对象被评论时不会更改 updated_at。
    【解决方案2】:

    不确定您的方法以前是什么样子,但我会从以下开始:

    class Book < ActiveRecord::Base
    
      def self.recently_commented
        self.find(:all, 
                  :include => :comments, 
                  :conditions => ['comments.created_at > ?', 5.minutes.ago])
      end
    end
    

    这应该会找到在过去 5 分钟内对其发表评论的所有书籍。 (您可能还想添加限制)。

    我也很想为此功能创建一个基类以避免重复代码:

    class Commentable < ActiveRecord::Base
      self.abstract_class = true
    
      has_many :comments, :as => :commentable
    
      def self.recently_commented
        self.find(:all, 
                  :include => :comments, 
                  :conditions => ['comments.created_at > ?', Time.now - 5.minutes])
      end
    end
    
    class Book < Commentable
    end
    
    class Article < Commentable
    end
    

    此外,您可能希望考虑使用插件来实现此目的。例如。 acts_as_commentable.

    【讨论】:

    • 你可以重构 Time.now - 5.minutes by 5.minutes.ago :)
    • 谢谢,这让我成功了!我正在使用acts_as_commentable,所以我的下一个任务是将它添加到插件中,这样我就不必为每种类型都重复它了。
    • 没问题。已更新以包含 .ago 改进。
    • 我稍作改动,添加了 :order => 'cmets.created_at desc',所以最近评论的项目最先显示。
    猜你喜欢
    • 1970-01-01
    • 2015-09-10
    • 2020-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多