Rails使用Mailboxer gem遇undefined method `receipts_for'错误求助
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

