I managed to install Mailboxer with this tutorial but i have a recurring error :
N+1 Query detected
Mailboxer::Message => [:sender]
Add to your finder: :includes => [:sender]
N+1 Query method call stack
app/views/conversations/_messages.html.erb:12:in `block in _app_views_conversations__messages_html_erb__3829465222244059655_69982701059040'
app/views/conversations/_messages.html.erb:1:in `_app_views_conversations__messages_html_erb__3829465222244059655_69982701059040'
app/views/conversations/show.html.erb:27:in `_app_views_conversations_show_html_erb__1439517360344897040_69982700516580'
app/views/conversations/_messages.html.erb:12:in `block in _app_views_conversations__messages_html_erb__3829465222244059655_69982701059040'
app/views/conversations/_messages.html.erb:1:in `_app_views_conversations__messages_html_erb__3829465222244059655_69982701059040'
app/views/conversations/show.html.erb:27:in `_app_views_conversations_show_html_erb__1439517360344897040_69982700516580'
I had another one for :message but i fixed the problem with includes. If i try to do the same with :sender, i have this error:
Association named 'sender' was not found on Mailboxer::Receipt; perhaps you misspelled it?
Tutorial original code : conversations_controller.rb
class ConversationsController < ApplicationController
before_action :authenticate_user!
def new
end
def create
recipients = User.where(id: conversation_params[:recipients])
conversation = current_user.send_message(recipients, conversation_params[:body], conversation_params[:subject]).conversation
flash[:success] = "Your message was successfully sent!"
redirect_to conversation_path(conversation)
end
def show
@receipts = conversation.receipts_for(current_user)
# mark conversation as read
conversation.mark_as_read(current_user)
end
def reply
current_user.reply_to_conversation(conversation, message_params[:body])
flash[:notice] = "Your reply message was successfully sent!"
redirect_to conversation_path(conversation)
end
def trash
conversation.move_to_trash(current_user)
redirect_to mailbox_inbox_path
end
def untrash
conversation.untrash(current_user)
redirect_to mailbox_inbox_path
end
private
def conversation_params
params.require(:conversation).permit(:subject, :body,recipients:[])
end
def message_params
params.require(:message).permit(:body, :subject)
end
end
Tutorial original code : show.html.erb
<div class="row">
<div class="spacer"></div>
<div class="col-md-6">
<%= link_to "Compose", new_conversation_path, class: "btn btn-success" %>
</div>
<div class="col-md-6 text-right">
<% if conversation.is_trashed?(current_user) %>
<%= link_to 'Untrash', untrash_conversation_path(conversation), class: 'btn btn-info', method: :post %>
<% else %>
<%= link_to 'Move to trash', trash_conversation_path(conversation), class: 'btn btn-danger', method: :post,
data: {confirm: 'Are you sure?'} %>
<% end %>
</div>
</div>
<div class="col-md-4">
<div class="panel panel-default">
<div class="panel-body">
<%= render 'mailbox/folders' %>
</div>
</div>
</div>
<div class="col-md-8">
<div class="panel panel-default">
<div class="panel-body">
<%= render partial: 'messages' %>
</div>
<div class="panel-footer">
<!-- Reply Form -->
<%= form_for :message, url: reply_conversation_path(conversation) do |f| %>
<div class="form-group">
<%= f.text_area :body, placeholder: "Reply Message", rows: 4, class: "form-control" %>
</div>
<%= f.submit "Reply", class: 'btn btn-danger pull-right' %>
<% end %>
<div class="clearfix"></div>
</div>
</div>
</div>
</div>
Tutorial original code : _messages.html.erb
<% @receipts.each do |receipt| %>
<% message = receipt.message %>
<div class="media">
<div class="media-left">
<!-- user avators can go here -->
<a href="#">
<img class="media-object" src="http://placehold.it/64x64" alt="...">
</a>
</div>
<div class="media-body">
<h4 class="media-heading">
<%= message.sender.username %> <br>
<small><b>Subject: </b><%= message.subject %></small><br>
<small><b>Date: </b><%= message.created_at.strftime("%A, %b %d, %Y at %I:%M%p") %></small>
</h4>
<%= message.body %>
</div>
</div>
<% end %>
If i delete <%= message.sender.username %> the problem is solved...
Any ideas ?
Normally, to fix these N+1 query problems we use an
includesand by passing a hash, we canincludesnested associations. So looking at this code, callingreceipt.message.senderis triggering the error, so we have aReceiptmodel, amessageassociation on it and asenderassociated to that. So if we can find where we load theReceiptwe can addincludes(message: :user)like we would for any other model.Digging into the mailboxer gem, the
receipts_formethod in yourshowaction is just a wrapper for a couple of scopes onMailboxer::Receipt. Since this method just runs some scopes for you, we can chain onto the end of it as if it were a normalActiveRecordwherechain.So with all that in mind, we should be able to add on our
includesand avoid the N+1 query problem, ending up with something like