问题
I have a rails app with intern messaging system. User can send message to other user. Example : User 1 send message User 2 can respond viceversa.
All works perfectly. But I want to upgrade this system with notfications functionnality. I want to type of notifications :
1) On navbar 2) By mail
Problem : I dont know how i can do this.
Can you help me ?
Conversations table
class CreateConversations < ActiveRecord::Migration
def change
create_table :conversations do |t|
t.integer :sender_id
t.integer :recipient_id
t.timestamps
end
end
end
Messages table. In this code I have a boolean :read. I think solution can be here. What do you think about this ?
class CreateMessages < ActiveRecord::Migration
def change
create_table :messages do |t|
t.text :body
t.references :conversation, index: true
t.references :user, index: true
t.boolean :read, :default => false
t.timestamps
end
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'
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
def message_time
created_at.strftime("%m/%d/%y at %l:%M %p")
end
end
conversations_controller.rb
class ConversationsController < ApplicationController
before_action :authenticate_user!
# GET /conversations
# GET /conversations.json
def index
@users = User.all
# Restrict to conversations with at least one message and sort by last updated
@conversations = Conversation.joins(:messages).uniq.order('updated_at DESC')
end
# POST /conversations
# POST /conversations.json
def create
if Conversation.between(params[:conversation][:sender_id], params[:conversation][:recipient_id]).present?
@conversation = Conversation.between(params[:conversation][:sender_id], params[:conversation][:recipient_id]).first
else
@conversation = Conversation.create!(conversation_params)
end
redirect_to conversation_messages_path(@conversation)
end
private
# Use callbacks to share common setup or constraints between actions.
def conversation_params
params.require(:conversation).permit(:sender_id, :recipient_id)
end
end
messages_controller.rb
class MessagesController < ApplicationController
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
def new
@message = @conversation.messages.new
end
def create
@message = @conversation.messages.new(message_params)
if @message.save
redirect_to conversation_messages_path(@conversation)
end
end
private
def message_params
params.require(:message).permit(:body, :user_id)
end
end
/conversations/index.html.erb
<div class="ui segment">
<h3>Mailbox</h3>
<div class="ui list">
<div class="item">
<% @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 %>
Conversation avec <%= link_to recipient.prenom, conversation_messages_path(conversation)%>
<% end %>
<% end %>
</div>
</div>
</div>
<div class="ui segment">
<h3>All Users</h3>
<div class="ui list">
<% @users.each do |user| %>
<% if user.id != current_user.id %>
<div class="item">
<%= user.prenom %> <%= button_to 'Message me', conversations_path(conversation: { sender_id: current_user.id, recipient_id: user.id }), class: 'btn btn-primary m-t' %>
</div>
<% end %>
<% end %>
</div>
</div>
messages/index.html.erb
<% if @over_ten %>
<%= link_to 'Show Previous', "?m=all" %>
<% end %>
<div class="ui segment">
<% @messages.each do |message| %>
<% if message.body %>
<% user = User.find(message.user_id) %>
<div class="item">
<div class="content">
<div class="header"><strong><div class="imageavatarmessage"><%= image_tag user.avatar(:thumb), class:"imageavatarmessage" %></div><%= user.prenom %></strong> <%= message.message_time %></div>
<div class="list">
<div class="item">
<i class="right triangle icon"></i>
<%= message.body %>
</div>
</div>
</div>
</div>
<% end %>
<% end %>
</div>
<%= form_for [@conversation, @message], html: {class: "ui reply form"} do |f| %>
<div class=”field”>
<%= f.text_area :body, class: "form-control" %>
</div>
<%= f.text_field :user_id, value: current_user.id, type: "hidden" %>
<div>
<%= f.submit "Add Reply", class: "ui blue labeled submit icon button" %>
</div>
<% end %>
回答1:
I would recommend you to go through this tutorial to build nice notification system https://www.devwalks.com/lets-build-instagram-part-6-notifications/
Basically, you have to create new model, set dependencies with your Message
model and integrate to the controller
For the email notifications, it's even simpler.
Just create new mailer and fire it on create action in messages_controller
def create
@message = @conversation.messages.new(message_params)
if @message.save
SendMessageMailer.new_message(@message).deliver_later
redirect_to conversation_messages_path(@conversation)
end
end
EDIT: To create mailer, you should do something like this:
rails g mailer SendMessage
Go to /app/mailers/send_message_mailer.rb and add action, same type of building as controllers
def new_message(message)
@message = message
mail(to: @message.user.email, subject: 'Hey! Here is what you missed')
end
Also, create an view (email template) and code with erb code
app/views/send_message_mailer/new_message.html.erb
Im not going deep into this, I guess you can figure out how to pass interval (let's say don't send if user is online or have read the message) and differentiate with receiver/sender users
Mailer, once again, is just same type of controller. You can pass as many params as you need and use model nesting inside mailer controller and views
mailer
def new_message(message, sender, receiver)
end
controller
SendMessageMailer.new_message(@message, @message.user, params[:receiver]).deliver_later
来源:https://stackoverflow.com/questions/40431718/add-notification-to-ror-messaging-inbox-system