如何更简洁地从自引用User模型的好友请求中获取用户名?
优化好友请求的用户名展示方案
你的问题核心是避免在视图里做繁琐的ID查询和嵌套循环,这在Rails里完全可以通过完善Active Record关联来解决,还能顺便解决潜在的N+1查询性能问题,一举两得。
第一步:完善FriendRequest模型的关联
首先在FriendRequest模型里补充针对friend_id的关联,默认情况下belongs_to :friend会去寻找Friend模型,所以需要手动指定关联的目标模型是User:
# app/models/friend_request.rb class FriendRequest < ApplicationRecord belongs_to :user # 你已有的关联,对应发起请求的用户 belongs_to :friend, class_name: "User" # 新增:对应接收请求的用户,指定class_name避免模型匹配错误 end
第二步:控制器预加载关联,避免N+1查询
修改你的控制器,用includes预加载关联的用户数据,这样Rails会一次性把所有需要的用户信息批量查询出来,而不是每循环一个请求就单独查一次数据库:
# app/controllers/friend_requests_controller.rb def index # incoming请求是他人发给当前用户的,关联发起请求的user @incoming = FriendRequest.where(friend: current_user).includes(:user) # outgoing是当前用户发出去的,关联接收请求的friend @outgoing = current_user.friend_requests.includes(:friend) @user = current_user end
第三步:简化视图代码
现在视图里可以直接通过关联对象获取用户名,完全不需要嵌套循环和手动查询了:
展示当前用户发出的请求(查看发给了谁)
<% @outgoing.each do |request| %> <%= request.friend.username %> <% end %>
展示当前用户收到的请求(查看谁发来的)
<% @incoming.each do |request| %> <%= request.user.username %> <% end %>
为什么原来的写法不够好?
你之前的代码不仅繁琐冗余,还会造成N+1查询问题:每循环一个friend_request,就会执行一次User.where(id: user.friend_id),如果有100个请求,就会触发101次数据库查询(1次查请求列表,100次单独查用户)。而用includes预加载后,只会触发2次查询(1次查请求,1次批量查所有关联用户),性能提升非常明显。
内容的提问来源于stack exchange,提问作者tfantina
相关产品推荐
相关产品推荐

