我无法理解为什么我会得到未定义的方法`email' for nil:NilClass每当我尝试在我的消息类上调用任何方法时。
index.html.erb消息:
<div class="callout">
<div class="messages-box">
<% @messages.each do |message| %>
<% user_status = message.user_id == current_user.id ? "reciever" : "sender" %>
<div class="<%= user_status %> callout">
<p><%= message.body %></p>
<p><%= message.user.email %></p>
</div>
<% end %>
<%= simple_form_for([@conversation, @message]) do |f| %>
<%= f.input :body %>
<%= f.hidden_field :user_id, value: current_user.id %>
<%= f.submit "Add Reply", class: 'button' %>
<% end %>
</div>
</div>
消息控制器:
class MessagesController < ApplicationController
before_action :setup_conversation
def index
@messages = @conversation.messages
@message = @conversation.messages.new
end
def new
@message = @conversation.messages.new
end
def create
@message = @conversation.messages.new(message_params)
redirect_to conversation_messages_path(@conversation) if @message.save
end
private
def setup_conversation
@conversation = Conversation.find(params[:conversation_id])
end
def message_params
params.require(:message).permit(:body, :user_id)
end
end
如果我删除表单,工作正常,或者如果从相应控制器中的索引操作中删除@message实例变量,但我需要它在索引视图中的表单。
答案 0 :(得分:1)
这是一个非常有趣的案例,因为你得到了ActiveRecord集合代理。
在这一行中,您指定@messages
,它是ActiveRecord_Associations_CollectionProxy
的子类的实例,它实际上没有来自数据库的任何记录:
@messages = @conversation.messages
它具有的功能是对Conversation
已分配给@conversation
的{{1}}实例的引用。
在下一行中,您创建了与Message
相关联的新@conversation
实例:
@message = @conversation.messages.new
此时您仍未进行任何SQL查询。然后我们进入渲染,在each
上调用@messages
,触发查询:
@message.each do |message|
...
end
因为CollectionProxy
比简单的AssociationRelation
更复杂,所以它会合并数据库中的数据 - 保存的记录与User
关联 - 与集合中的新数据 - 您的非 - 持有@message
。
结果是在此块的内部,最后message.user
为nil
,尚未设置。这不会在前面的行中爆炸,因为Ruby很乐意呈现message.body
(这是nil)并将nil
与foo@example.com
进行比较。