Reputation: 496
I can't seem to figure why I get undefined method `email' for nil:NilClass whenever I try to call any methods on my message class.
index.html.erb messages:
<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>
message controller:
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
works fine if I remove the form or If remove the @message instance variable from the index action in the corresponding controller but I need it for the form in the index view.
Upvotes: 0
Views: 66
Reputation: 80070
This is a pretty interesting case because you're getting bit by ActiveRecord collection proxies.
In this line, you assign @messages
, which is an instance of a subclass of ActiveRecord_Associations_CollectionProxy
, which doesn't actually have any records from the database:
@messages = @conversation.messages
What it does have, however, is a reference to the instance of Conversation
that you've already assigned to @conversation
.
On the next line, you create a new instance of Message
associated with the same @conversation
:
@message = @conversation.messages.new
You still haven't made any SQL queries at this point. Then we get into rendering, where you call each
on @messages
, which triggers the query:
@message.each do |message|
...
end
Because CollectionProxy
is more sophisticated than a simple AssociationRelation
, it coalesces the data from your database — saved records with a User
association — with the new data in the collection — your non-persisted @message
.
The result is that inside of this block, the last message.user
is nil
, having not been set. This doesn't explode on the previous lines because Ruby is happy to render message.body
(which is nil) and compare nil
with [email protected]
.
Upvotes: 1