0
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【Rails】リアルタイムDM機能作成

Posted at

開発環境

rails 5.1.7
ruby 2.4.0
devise導入済

作成する

gem 'jquery-rails'
app/assets/javascripts/application.js
...
//
//= require rails-ujs
//= require activestorage
//= require turbolinks
//= require jquery ←追加
//= require jquery_ujs ←追加
//= require_tree .
...
$ bundle

モデル作成

roomモデル、entryモデル、direct_messageモデルを作成

$ rails g model room name:string
$ rails g model entry user:references room:references
$ rails g model DirectMessage user:references  room:references name:string
$ rails db:migrate

モデル編集

app/models/user.rb
...
has_many :entries
has_many :direct_messages
has_many :room, through: :entries
...
app/models/room.rb
...
has_many :entries
has_many :direct_messages
has_many :users, through: :entries
...

コントローラ作成

$ rails g controllers Rooms show

ルーティングの設定

config/routes.rb
root 'users#index'
devise_for :users
resources :users
resources :rooms

これでrails sしてサーバーをたちあげ、http://localhost:3000
へアクセスしてみる。
成功したらおk

Usersコントローラを編集

app/controllers/users_controller.rb
class UsersController < ApplicationController
    before_action :authenticate_user!
  def index
    @users = User.all
  end

  def show
    @user = User.find(params[:id])
    @currentUserEntry = Entry.where(user_id: current_user.id)
    unless @user.id == current_user.id
      @currentUserEntry.each do |cu|
        @userEntry.each do |u|
          if cu.room_id == u.room_id then
            @isRoom = true
            @roomId = cu.room_id
          end
        end
      end
 
      unless @isRoom
        @room  = Room.new
        @entry = Entry.new
      end
     end
    end
   end

users/index/html.erbの作成

app/views/users/index.html.erb
<h3>ユーザー一覧</h3>
<h2><%= @user.name %></h2>

<% unless @user.id == current_user.id %>
  <% if @isRoom == true %>
    <%= link_to "チャットをする", room_path(@roomId) %>
  <% else %>
    <%= form_for @room do |f| %>
      <%= fields_for @entry do |e| %>
        <%= e.hidden_field :user_id, :value => @user.id %>
      <% end %>
      <%= f.submit 'チャットを始める' %>
    <% end %>
  <% end %>
<% end %>

Roomsコントローラ編集

app/controllers/rooms_controller.rb
class RoomsController < ApplicationController
    before_action :authenticate_user!
  def show
    @room = Room.find(params[:id])
    # present?の戻り値はboolean, よってtrueの場合、
    if Entry.where(:user_id => current_user.id, :room_id => @room.id).present?
      @direct_messages = @room.direct_messages
      @entries = @room.entries
    else
      redirect_back(fallback_location: root_path)
    end
  end

  def create
    @room   = Room.create(:name => "DM")
    @entry1 = Entry.create(:room_id => @room.id, :user_id => current_user.id)
    @entry2 = Entry.create(params.require(:entry).permit(:user.id, :room_id).merge
    redirect_to room_path(@room_id) 
  end
end


### rooms/show.html.erbの作成
erb:app/views/rooms/show.html.erb
<h1><%= @room.name %></h1>


<h4>参加者</h4>
<% @entries.each do |e| %>
  <%= link_to e.user.name, user_path(e.user_id) %>
  <br />
<% end %>

<h1>Chat room</h1>
<form>
  <label> Say somethig:</label><br />
  <input type="text" id="chat-input" data-behavior="room_speaker>
</form>

<div id="direct_messages" data-room_id="<%= @room.id %>">
  <%= render @direct_messages %>
</div>

📝memo

<%= render @direct_messages %>とは
<% render partial: 'direct_messages/direct_message', collection: @direct_messages %>の略
この記述をすると、部分テンプレートで繰り返し処理ができる

direct_messageを表示する

app/views/direct_messages/_direct_message.html.erb
<%= direct_message.content %> <br />

### roomチャンネルの作成
speakメソッドを持っているroomチャンネルを作成

```terminal
$ rails g channel room speak
app/assets/javascripts/channels/room.coffee
document.addEventListener 'turbolinks:load', ->
  App.room = App.cable.subscriptions.create {channel: "RoomChannel", room: $('#direct_messages').data('room_id')},
    connected: ->

    disconnected: ->

    received: (data) ->
      $('#direct_messages').append data['direct_message']
    
    speak: (direct_message) ->
      @perform 'speak', direct_message: direct_message
  
  $('#chat-input').on 'keypress',(event) ->
    if event.ketcode is 13 #enter
      App.room.speak event.target.value
      event.target.value = ''
      event.preventDefault()
app/channels/room_channel.rb
class RoomChannel < ApplicationCable::Channel
  def subscribed
    stream_from "room_channel_#{params['room']}"
  end

  def unsubscribed

  end


  def speak(data)
    DirectMessage.create! message: data['direct_message'],user_id: current_user.id, room_id: params['room']
  end
end

jobの作成

$ rails g job DirectMessageBroadcast

job編集

class DirectMessageBroadcastJob < ApplicationJob
queue_as :default

def perform(direct_message)
ActionCable.server.broadcast "room_channel_#{direct_message.room_id}", direct_message: render_direct_message(direct_message)
end

private
def render_direct_message(direct_message)
ApplicationController.renderer.render partial: 'direct_messages/direct_message', locals:{ direct_message: direct_message}
end
end

app/models/direct_message.rb
...
after_create_commit{DirectMessageBroadcastJob.perform_later self}

current_userの情報を取得する

app/channels/application_cable/connection.rb
module ApplicationCable
  class Connection < ActionCable::Connection:Base
    identified_by :current_user
    
    def connect
      self.current_user = find_verified_user
    end
    
    protected
    def find_verified_user
      verified_user = User.find_by(id: env['warden'].user.id)
      return reject_unauthorized_connection unless verified_user
      verified_user
    end
  end
end

###  終わり
誤字間違いありましたらご連絡いただけばと思います
0
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?