我有下一个用户关联:
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
我需要为用户列表调用此方法。如何在不通过每次通话数据库的情况下从自己获取用户请求?
答案 0 :(得分:1)
您应该知道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。关于记忆结果的棘手部分是处理nil
或false
个案例。有一个很好的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