Search code examples
ruby-on-railsmessagemessaging

Display last body message on messaging system from scratch


I made a messaging system from scractch on my App. All works good but i just want to customize more. So I want to display the last message for each Conversation by user_id inbox in my view . I have 2 models : Conversation and Message.

I can display only this

I m lost. Can you help me ?

messages_controller.rb

class MessagesController < ApplicationController
 before_action :authenticate_user!
  before_action do
   @conversation = Conversation.find(params[:conversation_id])
  end
def index

 @messages = @conversation.messages
  if @messages.length > 10
   @over_ten = true
   @messages = @messages[-10..-1]
  end
  if params[:m]
   @over_ten = false
   @messages = @conversation.messages
  end
 if @messages.last
  if @messages.last.user_id != current_user.id
   @messages.last.read = true;
  end
 end
@message = @conversation.messages.new
 end

private
 def message_params
  params.require(:message).permit(:body, :user_id)
 end
end

Conversations_controller.rb

class ConversationsController < ApplicationController
  before_action :authenticate_user!

  # GET /conversations
  # GET /conversations.json
  def index
    @users = User.all
    @camping = Camping.all

    # Restrict to conversations with at least one message and sort by last updated
    @conversations = Conversation.joins(:messages).distinct


  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def conversation_params
      params.require(:conversation).permit(:sender_id, :recipient_id, :user_id)
    end
end

conversation.rb

class Conversation < ActiveRecord::Base
 belongs_to :sender, :foreign_key => :sender_id, class_name: 'User'
 belongs_to :recipient, :foreign_key => :recipient_id, class_name: 'User'

 belongs_to :user
  has_many :users, through: :messages


has_many :messages, dependent: :destroy



validates_uniqueness_of :sender_id, :scope => :recipient_id
scope :between, -> (sender_id,recipient_id) do
 where("(conversations.sender_id = ? AND conversations.recipient_id =?) OR (conversations.sender_id = ? AND conversations.recipient_id =?)", sender_id,recipient_id, recipient_id, sender_id)
 end


end

message.rb

class Message < ActiveRecord::Base
 belongs_to :conversation
 belongs_to :user

 validates_presence_of :body, :conversation_id, :user_id

/messages/index.html.erb

 <% @messages.each do |message| %>
  <% if message.body %>

   <% user = User.find(message.user_id) %>

<%= image_tag user.avatar(:thumb), class:"imageavatarmessage" %></div>
<%= user.prenom %>
      <%= message.message_time %>
      <div class="list">
         <%= message.body %>
          <% end %>
         <% end %>

<%= form_for [@conversation, @message], html: {class: "ui reply form"} do |f| %>
   <%= f.text_area :body, class: "form-control" %>
 </div>
 <%= f.text_field :user_id, value: current_user.id, type: "hidden" %>
   <%= f.submit "Add Reply", class: "ui blue labeled submit icon button" %>
<% end %>

Probleme is here, i just want to show last message for each conversation. /conversations/index.html.erb

   <% @conversations.each do |conversation| %>
   <% if conversation.sender_id == current_user.id || conversation.recipient_id == current_user.id %>
    <% if conversation.sender_id == current_user.id %>
      <% recipient = User.find(conversation.recipient_id) %>

    <% else %>
      <% recipient = User.find(conversation.sender_id) %>

    <% end %>

    <p>Conversation avec <%= link_to recipient.prenom, conversation_messages_path(conversation)%></p>
    <p><%= image_tag recipient.avatar(:small), class:"imageavatarmessage" %></p>


   <%= @conversations.last %>


    <p>Il y a <%= time_ago_in_words(conversation.updated_at)%></p>


   <% end %>
  <% end %>

I want to display only the last one message for each conversations in my /conversations/index.html.erb I tested this <%= @conversations.last %> but it doesn't work...

Can you help me ?

EDIT

My messages table

:body
:conversation, index: true
:user, index: true
:read, :default => false
t.timestamps

conversations table

   :sender_id
  :recipient_id
   t.timestamps
  end
 end
end

EDIT 2

After some test I can display last message. But this message is the same for all conversation... I can't have last message for each conversation. I don't know why...

Conversation_controller

 @conversa = Conversation.where("? IN (recipient_id, sender_id)", current_user.id)
     @test = Message.where(conversation_id: @conversa).group(:conversation_id).limit(1)

in my /conversations/index.html.erb

<% @test.each do |message| %>

       <%= message.body %>

 <%end%> 

I think that, I m near the solution, can you help me please ?


Solution

  • If your current_user can directly reference the related conversations they are in you can setup your @conversations variable like this

    def index
      ...
      @conversations = current_user.conversations.joins(:messages)
    end
    

    Once that is setup you can iterate over it with each one in your index view

    <% @conversations.each do |conversation| %>
      <div>
        Last Message for Conversation ID:<%= conversation.id %> 
        is <%= conversation.messages.last.body %>
      </div>
    <% end %>