未定义的方法`email' for nil:在索引

时间:2017-01-13 18:39:25

标签: ruby-on-rails

我无法理解为什么我会得到未定义的方法`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实例变量,但我需要它在索引视图中的表单。

1 个答案:

答案 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.usernil,尚未设置。这不会在前面的行中爆炸,因为Ruby很乐意呈现message.body(这是nil)并将nilfoo@example.com进行比较。