从条件关联中获取特定对象

时间:2014-05-31 11:41:58

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

我有下一个用户关联:

has_many :sent_requests, foreign_key: :requester_id, class_name: 'FriendRequest'

这是FriendRequest模型:

class FriendRequest < ActiveRecord::Base

  belongs_to :requester, class_name: 'User'
  belongs_to :target, class_name: 'User'
end

我在查询请求时包含此关联。

我想向特定用户提出请求(如果存在)。下一步方法向DB发起请求:

  def friend_request_sent_to(user)
    self.sent_requests.where(target: user).first
  end

我需要为用户列表调用此方法。如何在不通过每次通话数据库的情况下从自己获取用户请求?

2 个答案:

答案 0 :(得分:1)

ActiveRecord缓存(请注意这一点)

您应该知道ActiveRecord会自动缓存关联。如果您评估self.sent_requests两次,则只会执行一个数据库查询(请注意,有一些警告)。

这意味着您可以多次使用Enumerable方法,并且只会加载一次关联。 E.g。

self.sent_requests.find { |friend_request|  friend_request.target == user }

请注意,如果您向AR查询接口方法添加其他调用(例如sent_requests.where(...)sent_requests.joins(...)),则无法执行此操作。

此外,ActiveRecord caches query results。因此,多次执行self.sent_requests.where(target: user).first可能只会导致单个数据库查询。

记忆化

您也可以按照其他用户的建议使用memoization。关于记忆结果的棘手部分是处理nilfalse个案例。有一个很好的gem可以为你处理这个问题。

一种带有记忆的简单方法,可避免无问题:

class User
  has_many :sent_requests, foreign_key: :requester_id, class_name: 'FriendRequest'

  def friend_request_sent_to(user)
    @sent_requests ||= self.sent_requests.includes(:user).to_a  # Will always result in an Array (no need to worry about nil)
    @sent_requests.find {|sent_request| sent_request.user == user }
  end

此方法还具有允许您使用ActiveRecord不会缓存的更复杂查询的优势。

答案 1 :(得分:0)

您可以将结果缓存在实例变量中:

def friend_request_sent?(user)
  return @friend_request_sent if defined?(@friend_request_sent)
  @friend_request_sent = self.sent_requests.where(target: user).first
end

另请注意,以?结尾的方法返回true或false是一种ruby约定。很可能你更愿意这样做:

def friend_request_sent?(user)
  return @friend_request_sent if defined?(@friend_request_sent)
  @friend_request_sent = self.sent_requests.exists?(target: user)
end