RailsでDM(ダイレクトメッセージ)を送れるようにしよう

#目標

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

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

<img width="640" alt="スクリーンショット 2018-08-07 1.24.51.png" src="https://qiita-image-store.s3.amazonaws.com/0/225909/40ad731a-a963-cda8-5f09-fd491015c977.png">

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

```
$ rails new dm_sample
```

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

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

```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
```

##アソシエーション
１対多の関係が複数発生したのでアソシエーション(モデル同士の結びつけ)を行います。
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
```

##ビューの作成
```erb: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 %>
```

```erb: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 %>
```

```erb: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を全く加えていないのでかなり簡素なものとなっています。