Rails API:限制.includes()仅返回最新创建的关联记录
解决方案:加载所有聊天室并关联最新订阅者
这个需求在Rails里其实挺常见的,核心是要预加载每个聊天室的最新订阅者,同时避免讨厌的N+1查询问题。我给你两种常用的实现方式,优先推荐第一种,代码更简洁易维护:
方案一:在模型中定义「最新订阅者」专属关联
直接在Chatroom模型里新增一个has_one关联,通过排序规则只取最新创建的订阅者:
class Chatroom < ApplicationRecord has_many :subscribers # 新增这个关联:按创建时间倒序取第一个(也就是最新的)订阅者 has_one :latest_subscriber, -> { order(created_at: :desc) }, class_name: 'Subscriber' end
然后在控制器的index动作里,只需要预加载这个新关联即可:
def index # 预加载所有聊天室,同时带上每个聊天室的最新订阅者 @chatrooms = Chatroom.includes(:latest_subscriber).all end
视图里的用法
在视图中可以直接调用chatroom.latest_subscriber,而且因为用了includes预加载,不会触发额外的SQL查询:
<% @chatrooms.each do |chatroom| %> <div class="chatroom"> <h2><%= chatroom.title %></h2> <% if chatroom.latest_subscriber %> <p>最新订阅者:<%= chatroom.latest_subscriber.username %></p> <% else %> <p>暂无订阅者</p> <% end %> </div> <% end %>
小提示:如果担心
created_at可能出现重复(比如同一毫秒创建多个订阅者),可以把排序规则改成order(id: :desc),因为数据库ID是自增的,能确保拿到真正最新的那条数据。
方案二:控制器层用子查询过滤
如果不想修改模型,也可以在控制器里通过子查询直接筛选出每个聊天室的最新订阅者,再关联查询:
def index # 先获取每个聊天室最新订阅者的ID(按创建时间倒序取最大ID) latest_subscriber_ids = Subscriber.select('MAX(id)').group(:chatroom_id) # 左连接订阅者表,只保留最新的那条,同时去重避免重复聊天室 @chatrooms = Chatroom.left_joins(:subscribers) .where(subscribers: { id: latest_subscriber_ids }) .distinct end
这种方式不需要修改模型,但代码相对繁琐一些,而且如果聊天室没有订阅者,left_joins也能保证聊天室被正常返回。
内容的提问来源于stack exchange,提问作者mfaorlkzus
相关产品推荐
相关产品推荐

