You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails使用Mailboxer gem遇undefined method `receipts_for'错误求助

解决Mailboxer中undefined method 'receipts_for' for nil:NilClass错误

这个错误的核心原因很明确:你在_conversation.html.erb里调用@conversation.receipts_for(current_user)时,@conversation是nil。咱们一步步拆解问题并修复:

1. 先搞清楚为什么@conversation是nil

你在用户的show.html.erb里渲染了<%= render "conversations/conversation" %>,但你的UsersController#show方法里根本没有初始化@conversation变量!当partial尝试访问这个未定义的变量时,它自然就是nil,调用方法时就会抛出错误。

2. 第一步:在UsersController里初始化对话

首先,我们需要在用户详情页中,获取当前登录用户和目标用户之间的对话(如果没有就初始化一个新的)。修改UsersController的show方法:

def show
  @user = User.find(params[:id])
  @microposts = @user.microposts.paginate(page: params[:page])
  # 新增:获取或初始化当前用户与目标用户的对话(仅在登录状态下执行)
  @conversation = current_user.mailbox.conversations.with(@user).first_or_initialize if logged_in?
end

这里用with(@user)筛选出当前用户和目标用户的对话,first_or_initialize会返回已有对话,或者创建一个未保存的新对话实例。

3. 第二步:修复对话partial的逻辑

现在@conversation有值了,但还需要区分“已有对话”和“新对话”的场景,因为新对话还没有ID,不能直接用conversation_messages_path。修改_conversation.html.erb:

<% if logged_in? %>
  <% if @conversation.persisted? %>
    <!-- 已有对话:显示历史消息 + 发送新消息表单 -->
    <% @conversation.receipts_for(current_user).each do |receipt| %>
      <div class="message">
        <%= receipt.message.body %>
      </div>
    <% end %>

    <%= form_tag conversation_messages_path(@conversation), method: :post do %>
      <div class="form-group">
        <%= text_area_tag :body, nil, class: "form-control", placeholder: "输入消息..." %>
      </div>
      <%= submit_tag "发送", class: "btn btn-primary" %>
    <% end %>
  <% else %>
    <!-- 新对话:显示创建对话的表单 -->
    <%= form_tag conversations_path, method: :post do %>
      <%= hidden_field_tag :user_id, @user.id %>
      <div class="form-group">
        <%= text_area_tag :body, nil, class: "form-control", placeholder: "发送第一条消息..." %>
      </div>
      <%= submit_tag "发送消息", class: "btn btn-primary" %>
    <% end %>
  <% end %>
<% else %>
  <p>请登录后发送消息</p>
<% end %>

4. 第三步:修复MessagesController的小bug

你的MessagesController#create里少了params,直接写body会报错,修改成这样:

def create
  receipt = current_user.send_message(@conversation, params[:body])
  redirect_to receipt.conversation
end

5. 最后确认Mailboxer基础配置

确保你已经完成了Mailboxer的基础配置:

  • 运行过迁移:rails generate mailboxer:install && rails db:migrate
  • User模型中已经包含Mailboxer模块:
    class User < ApplicationRecord
      include Mailboxer::Models::Messageable # 旧版可能是 acts_as_messageable,根据你的gem版本调整
      # ... 其他代码
    end
    
  • 确保控制器中有登录校验的before_action,比如:
    class ConversationsController < ApplicationController
      before_action :logged_in_user
      # ... 其他代码
    end
    

这样处理后,@conversation就不会是nil,receipts_for方法也能正常调用了——这个方法是Mailboxer内置的,不需要你自己定义。

内容的提问来源于stack exchange,提问作者Aly Dabbous

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:46:37