127
121

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(ダイレクトメッセージ)を送れるようにしよう

Last updated at Posted at 2018-08-06

#目標

ユーザー間でDMを送り合えるようになる!!

#イメージ
UserがいろんなUserとDMをできると考えます。
ここでは4つのモデルを通して、DMを実装します!
Userモデル: User情報
Roomモデル: 今回はチャットルームに2人のUserが入るイメージです
Entryモデル: どのUserがどのRoomに所属しているか
Messageモデル: UserがどのRoomでどんなMessageを送ったか

スクリーンショット 2018-08-07 1.24.51.png

#いざ実装
##プロジェクトの作成

$ rails new dm_sample

##Userモデルの作成
今回はdeviseを使用して、ログインできるようにします。

Gemfileに以下を追加してください

gem 'devise'

gemを追加したので以下のコマンドを実行しましょう。

$ bundle install

Railsプロジェクトにdeviseをインストールします

$ rails g devise:install

ここからdeviseを使ってUserモデルを作成していきます。

$ rails g devise:controllers users
$ rails g devise user name:string
$ rails g devise:views
$ rails db:migrate

##他のモデルの作成
次にRoomモデル、 Entryモデル、Messageモデルを作成します。

$ rails g model room name:string
$ rails g model entry user:references room:references
$ rails g model message user:references room:references content:text
$ rails db:migrate

##アソシエーション
1対多の関係が複数発生したのでアソシエーション(モデル同士の結びつけ)を行います。
app/modelsの中の次のファイルを以下のように書き換えてください。

####user.rb

user.rb
class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
  has_many :messages, dependent: :destroy
  has_many :entries, dependent: :destroy
end

####entry.rb

entry.rb
class Entry < ApplicationRecord
  belongs_to :user
  belongs_to :room
end

####room.rb

room.rb
class Room < ApplicationRecord
  has_many :messages, dependent: :destroy
  has_many :entries, dependent: :destroy
end

####message.rb

message.rb
class Message < ApplicationRecord
  belongs_to :user
  belongs_to :room
end

##コントローラーの作成

$ rails g controller users index show
$ rails g controller rooms
$ rails g controller messages
users_controller.rb
class UsersController < ApplicationController
  before_action :authenticate_user!, :only => [:show]
  def index
    @users=User.all
  end

  def show
    @user=User.find(params[:id])
    @currentUserEntry=Entry.where(user_id: current_user.id)
    @userEntry=Entry.where(user_id: @user.id)
    if @user.id == current_user.id
    else
      @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
      if @isRoom
      else
        @room = Room.new
        @entry = Entry.new
      end
    end
  end
end

rooms_controller.rb
class RoomsController < ApplicationController
  before_action :authenticate_user!
  def create
    @room = Room.create
    @entry1 = Entry.create(:room_id => @room.id, :user_id => current_user.id)
    @entry2 = Entry.create(params.require(:entry).permit(:user_id, :room_id).merge(:room_id => @room.id))
    redirect_to "/rooms/#{@room.id}"
  end

  def show
    @room = Room.find(params[:id])
    if Entry.where(:user_id => current_user.id, :room_id => @room.id).present?
      @messages = @room.messages
      @message = Message.new
      @entries = @room.entries
    else
      redirect_back(fallback_location: root_path)
    end
  end
end
messages_controller.rb
class MessagesController < ApplicationController
  before_action :authenticate_user!, :only => [:create]

  def create
    if Entry.where(:user_id => current_user.id, :room_id => params[:message][:room_id]).present?
      @message = Message.create(params.require(:message).permit(:user_id, :content, :room_id).merge(:user_id => current_user.id))
      redirect_to "/rooms/#{@message.room_id}"
    else
      redirect_back(fallback_location: root_path)
    end
  end
end

##ルーティングの作成

route.rb
Rails.application.routes.draw do
  devise_for :users
  resources :users, :only => [:index, :show]
  root "users#index"
  resources :messages, :only => [:create]
  resources :rooms, :only => [:create, :show, :index]
end

##ビューの作成

users/index.html.erb
<h1>DMサンプルアプリ</h1>
<% if user_signed_in? %>
<h2>Hello <%= current_user.email %></h2>
  <% @users.each do |u| %>
  <p><a href="/users/<%= u.id %>"><%= u.email %>さん</a></p>
  <hr>
  <% end %>
  <%= link_to "ログアウト", destroy_user_session_path, :method => :delete %>
<% else %>
  <%= link_to "ユーザーを登録する", new_user_registration_path %>
  <br>
  <%= link_to "ログインする", new_user_session_path %>
<% end %>
users/show.html.erb
<h1>ユーザー詳細</h1>

<h2><%= @user.email %></h2>

<% if @user.id == current_user.id %>

<% else %>
  <% if @isRoom == true %>
    <p><a href="/rooms/<%= @roomId %>">チャットへ</a>
  <% 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 %>

<%= link_to "ユーザー一覧に戻る", users_path %>
rooms/show.html.erb
<h1>DM</h1>

<h4>参加者</h4>
<% @entries.each do |e| %>
  <h5><strong><a href="/users/<%= e.user.id %>"><%= e.user.email%>さん</a></strong></h5>
<% end %>

<hr>
<% if @messages.present? %>
  <% @messages.each do |m| %>
    <strong><%= m.content %></strong>
    <small>by <strong><a href="/users/<%= m.user_id %>"><%= m.user.email %>さん</a></strong></small>
    <hr>
  <% end %>
<% else %>
  <h3 class="text-center">メッセージはまだありません</h3>
<% end %>

<%= form_for @message do |f| %>
  <%= f.text_field :content, :placeholder => "メッセージを入力して下さい" , :size => 70 %>
  <%= f.hidden_field :room_id, :value => @room.id %>
  <br>
  <%= f.submit "投稿する" %>
<% end %>

<%= link_to "ユーザー一覧に戻る", users_path %>

#完成
これでユーザー同士のDM機能が完成しました。viewにcssを全く加えていないのでかなり簡素なものとなっています。

127
121
3

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
127
121

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?