[Rails DM] Let's create a notification function when DM is sent!

[Rails DM] Let's make a notification function!

Step

1: Let's implement the DM function

Let's make it with reference to this article!

2: Let's implement the notification function

2-1: Let's create a model

ruby


rails g model Notification visitor_id:integer visited_id:integer room_id:integer message_id:integer action:string checked:boolean

2-2: Link the created notification model with User, Post, and Comment

Association between User model and Notification model

app/models/user.rb


has_many :active_notifications, class_name: 'Notification', foreign_key: 'visitor_id', dependent: :destroy
has_many :passive_notifications, class_name: 'Notification', foreign_key: 'visited_id', dependent: :destroy

Association of Room model and Notification model

app/models/room.rb


has_many :notifications, dependent: :destroy

Association of Message model and Notification model

app/models/message.rb


has_many :notifications, dependent: :destroy

Association of Notification model with User, Room, Message model

app/models/notification.rb


  default_scope -> { order(created_at: :desc) }

  belongs_to :room, optional: true
  belongs_to :message, optional: true

  belongs_to :visitor, class_name: 'User', foreign_key: 'visitor_id', optional: true
  belongs_to :visited, class_name: 'User', foreign_key: 'visited_id', optional: true

2-3: DM notification creation method

messages_controller.rb


class MessagesController < ApplicationController
    def create
        if Entry.where(user_id: current_user.id, room_id: params[:message][:room_id]).present?
          @message = Message.new(message_params)
          #from here
          @[email protected]
          #Add up to here
          if @message.save

            #from here
            @roommembernotme=Entry.where(room_id: @room.id).where.not(user_id: current_user.id)
            @[email protected]_by(room_id: @room.id)
            notification = current_user.active_notifications.new(
                room_id: @room.id,
                message_id: @message.id,
                visited_id: @theid.user_id,
                visitor_id: current_user.id,
                action: 'dm'
            )
            #If it is a comment for your post, it will be notified
            if notification.visitor_id == notification.visited_id
                notification.checked = true
            end
            notification.save if notification.valid?
            #Add up to here

            redirect_to "/rooms/#{@message.room_id}"
          end
        else
          redirect_back(fallback_location: root_path)
        end
    end
  
    private 
      def message_params
          params.require(:message).permit(:user_id, :body, :room_id).merge(user_id: current_user.id)
      end
end

2-4: Creating a notification list screen

terminal


rails g controller notifications index

controller/notifications_controller.rb


class NotificationsController < ApplicationController
  def index
    @notifications = current_user.passive_notifications
  end
end

erb:views/notifications/index.html.erb


<% notifications = @notifications.where.not(visitor_id: current_user.id) %>
<% if notifications.exists? %>
    <%= render notifications %>
<% else %>
    <p>There is no notification</p>
<% end %>

erb:views/notifications/_notificastion.html.erb


<% visitor = notification.visitor %>
<% visited = notification.visited %>
<div>
 <%= link_to user_path(visitor) do %>
     <%= visitor.name %>Is
 <% end %>
 <% if notification.action=='dm' %>
I sent you a DM
 <% end %>
</div>

bonus

Display the message list in an easy-to-understand manner like LINE

スクリーンショット 2020-09-15 18.31.50.png

First, let's imagine how we can implement it!

1: Judge whether it is a message sent by the other party from the message sent by yourself 2: Apply different CSS to the message sent by yourself and the message sent by the other party

It seems that it can be implemented in these 2 steps! The point is step 1.

How do you judge? That's it. There should have been a user_id column in the Message table that makes up the message function. (Pre-existed to determine who posted it) From the value entered there, it seems that you can judge whether it is a message sent by the other party from the message sent by yourself! So let's try it out in the next chapter!

Let's actually implement it!

erb:rooms/show.html.erb


<% @messages.each do |m| %> <%#Please change the instance variables here to your own instance variables!%>
    <% if m.user_id == current_user.id %>
        <div class="current_user">
            <strong class="current_user"><%= m.body %></strong>
            <small class="current_user"><%= m.user.name %>Mr.</small>
        </div>
    <% else %>
        <div class="visited_user">
            <strong class="visited_user"><%= m.body %></strong>
            <small class="visited_user"><%= m.user.name %>Mr.</small>
        </div>
    <% end %>
<% end %>

Do you know what you're doing above? !! If the value of user_id is the id of the logged-in user, put the class current_user in the message box (div). If the value of user_id is the id of the other user (strictly speaking, the id is other than the logged-in user), put the class visited_user in the message box (div). We have given it!

CSS example)

css


.current_user {
    color: red;
    text-align: right;
    background-color: #fff;
    width: fit-content;
    margin: 10px 0 0 auto;
    border-radius: 30px;
    -webkit-border-radius: 30px;
    -moz-border-radius: 30px;
    -ms-border-radius: 30px;
    -o-border-radius: 30px;
    box-sizing: border-box;
    padding: 10px;
}

.visited_user {
    color: #fff;
    margin: 10px;
    background-color: brown;
    text-align: left;
    width: fit-content;
    margin: 10px auto 0 0;
    border-radius:30px;
    -webkit-border-radius:30px;
    -moz-border-radius:30px;
    -ms-border-radius:30px;
    -o-border-radius:30px;
    box-sizing: border-box;
    padding: 10px;
}

Make notifications in the notification list disappear from notifications when they have been read

First, let's imagine how we can implement it!

Assumption: Notification function is implemented in Notification model The columns include id, visitor_id, visited_id, room_id, message_id, action, checked, created_at, updated_at Scheduled to manage read and unread in checked column (boolean type)

1: Show only unread notifications (ie, only show if checked column is false) 2: Initially, unread by default 3: If you press the "Mark as read" link, you can set the checked column to true to make it read.

If you follow the above steps, you can implement it!

Let's actually implement it!

First step 1

erb:_notification.html.erb


<% if notification.checked == false %> <%#← This one line is important%>
    <div>
        <%= link_to room_path(@roomId) do %>
            <%= visitor.name %>Mr.
        <% end %>
        <% if notification.action=='dm' %>
Is you(<%= visited.name %>Mr.)Sent DM to
        <% end %>
        <%= link_to 'Mark as read',notification_path(notification.id),method: :put %>
    </div>
<% end %> <%#← This one line is important%>
Step 2

Since the checked column is set to false in the first place, do not change it!

rb:_notification.html.erb


class NotificationsController < ApplicationController
  def index
    @notifications = current_user.passive_notifications
    #↓ If you have something written below this, especially if you are writing a process that makes check true, delete that description!
  end
end
Step 3

erb:_notification.html.erb


<% if notification.checked == false %>
    <div>
        <%= link_to room_path(@roomId) do %>
            <%= visitor.name %>Mr.
        <% end %>
        <% if notification.action=='dm' %>
Is you(<%= visited.name %>Mr.)Sent DM to
        <% end %>
        <%= link_to 'Mark as read',notification_path(notification.id),method: :put %>
        <%#↑ This one line! !!%>
    </div>
<% end %>

Call the update action of the notification controller when you press "Mark as read". At that time, the id of the Notification table is used as an argument as a parameter.

notification_controller


class NotificationsController < ApplicationController
  #abridgement

  def update
    notification=Notification.find(params[:id]) #...①
    if notification.update(checked: true) #...②
      redirect_to action: :index
    end
  end
end

Then, according to (1), the record with the corresponding id in the Notification table is pulled out below the id passed as the parameter. Finally, by ②, set the value of the checked column of the record to true.

You should now be able to implement it! !! !!

Reference article

[Rails] Explain so that anyone can implement the notification function [Like, comment, follow]

Recommended Posts

[Rails DM] Let's create a notification function when DM is sent!
[Rails withdrawal] Create a simple withdrawal function with rails
[Rails] Let's create a super simple Rails API
[Rails] Notification function
Let's make a search function with Rails (ransack)
Simple notification function in Rails (only when followed)
If there is a state transition, let's create a State class
Rails Tutorial Extension: I created a follower notification function
Create a name input function
Let's create a TODO application in Java 4 Implementation of posting function
Let's create a TODO application in Java 6 Implementation of search function
[Implementation procedure] Create a user authentication function using sorcery in Rails
Let's create a TODO application in Java 8 Implementation of editing function
Remedy for "A server is already running." Error when running rails s
(Ruby on Rails6) Create a function to edit the posted content
Add a search function in Rails.
Preparing to create a Rails application
Create pagination function with Rails Kaminari
Create a new app in Rails
Create a filtering function using acts-as-taggable-on
[Ruby on Rails] DM, chat function
A note of someone who stumbled when trying to create a Rails project
Create a SPA with authentication function with Rails API mode + devise_token_auth + Vue.js 3 (Rails edition)
[Rails] Annotate is not executed when migrating
[Rails] Create an evaluation function using raty.js
[Rails6] Create a new app with Rails [Beginner]
Let's create a Java development environment (updating)
Make a login function with Rails anyway
[rails] How to create a partial template
[Rails] What is a dot (.) Or a colon (:)?
[Rails 5] Create a new app with Rails [Beginner]
[Rails 6] Asynchronous (Ajax) follow function is implemented
Create a login function using Swift's Optional
[Rails / JavaScript / Ajax] I tried to create a like function in two ways.