在 Rails 中组合作用域 ActiveRecord 查询

发布于 2024-10-25 10:18:34 字数 1446 浏览 1 评论 0原文

我正在尝试为用户构建 Facebook 风格的项目提要。该提要将包含用户或用户关注的人最近所做的(关于书籍的)笔记以及其他通知,例如“您关注的用户 x 开始阅读一本新书”。你明白了。

到目前为止,我的 Note 类中有一个作用域,它返回我想要的注释:

class Note < ActiveRecord::Base
  scope :from_users_followed_by, lambda { |user| followed_by user }

  def self.followed_by(user)
    followed_ids = %(SELECT followed_id FROM relationships WHERE follower_id = :user_id)
    where("user_id IN (#{followed_ids}) OR user_id = :user_id", { :user_id => user })
  end
end

而我的 Readings 类中有一个类似的作用域,它返回用户开始阅读一本书时构建的记录:

class Reading < ActiveRecord::Base
  scope :from_users_followed_by, lambda { |user| followed_by(user) }

  def self.followed_by(user)
    # is this not at risk of sql injection??
    followed_ids = %(SELECT followed_id FROM relationships WHERE follower_id = :user_id)
    # return readings where user_id IN (an array of user_ids that the user follows)
    where("reader_id IN (#{followed_ids}) OR reader_id = :user_id", { :user_id => user })
  end
end

现在这工作正常,我可以从这些没有对象的数组中获取对象数组。问题。我正在努力将两个查询合并到一个按创建时间正确排序的提要中。目前我能做的最好的事情就是使用组合提要方法的用户类:

class User < ActiveRecord::Base
  def combined_feed
    feed = Note.from_users_followed_by(self) | Reading.from_users_followed_by(self)

    feed.sort! do |a, b|
      a.created_at <=> b.created_at
    end
    feed.reverse
  end
end

这为我提供了组合提要,但让我觉得效率极其低下。我怎样才能在rails中的数据库级别上做同样的事情?

I'm trying to build a facebook style feed of items for a user. The feed will contain recent notes (on books) made by a user or people the user follows combined with other notifications such as "user x that you follow started reading a new book". You get the idea.

So far I have a scope in my Note class which returns the notes I want:

class Note < ActiveRecord::Base
  scope :from_users_followed_by, lambda { |user| followed_by user }

  def self.followed_by(user)
    followed_ids = %(SELECT followed_id FROM relationships WHERE follower_id = :user_id)
    where("user_id IN (#{followed_ids}) OR user_id = :user_id", { :user_id => user })
  end
end

and a similar scope in my Readings class which returns records built when user starts reading a book:

class Reading < ActiveRecord::Base
  scope :from_users_followed_by, lambda { |user| followed_by(user) }

  def self.followed_by(user)
    # is this not at risk of sql injection??
    followed_ids = %(SELECT followed_id FROM relationships WHERE follower_id = :user_id)
    # return readings where user_id IN (an array of user_ids that the user follows)
    where("reader_id IN (#{followed_ids}) OR reader_id = :user_id", { :user_id => user })
  end
end

Now this works fine and I can get arrays of objects from these no problem. I'm struggling to combine the two queries into a feed which is correctly ordered by creation time. The best I can do at the moment is my user class with a combined feed method:

class User < ActiveRecord::Base
  def combined_feed
    feed = Note.from_users_followed_by(self) | Reading.from_users_followed_by(self)

    feed.sort! do |a, b|
      a.created_at <=> b.created_at
    end
    feed.reverse
  end
end

Which gets me a combined feed but strikes me as being horrendously inefficient. How can I do the equivalent at the database level in rails?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

陈独秀 2024-11-01 10:18:34

我想我可能会创建一个完全独立的模型,称为 FeedItem。然后,当发生某些事件(例如创建新注释)时,您只需创建一个新的 FeedItem 记录。那么您只有一张表可供查询,并且它已经按正确的顺序排列。

I think I would probably create an entirely separate model called FeedItem. Then, when certain events occur (such as the creation of a new note), you just create a new FeedItem record. Then you only have one table to query from and it will already be in the correct order.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文