学生向けプログラミング入門 | 無料

学生向けにプログラミングを無料で解説。Java、C++、Ruby、PHP、データベース、Ruby on Rails, Python, Django

Rails6.1 | 民泊予約アプリ作成 | 40 | メッセージ

↓↓クリックして頂けると励みになります。



39 | 予約確認メール】 << 【ホーム】 >> 【41 | 会話表示



ゲストがホストにメッセージを送信できるように実装します。

ジェネレータを使ってメッセージモデルを作成していきます。
次のセクションで解説する会話モデルも一緒に作成しておきます。


まずは会話モデルです。
コマンド
rails g model Conversation sender:references receiver:references


次にメッセージモデルです。
コマンド
rails g model Message content:text user:references conversation:references


「db\migrate\20200728232206_create_conversations.rb」ファイルを編集します。


記述更新 db\migrate\20200728232206_create_conversations.rb
以下のように内容を置き換えて下さい。ユーザーテーブルと関連付けします。

class CreateConversations < ActiveRecord::Migration[6.1]
  def change
    create_table :conversations do |t|
      t.references :sender, foreign_key: { to_table: :users }
      t.references :receiver, foreign_key: { to_table: :users }

      t.timestamps
    end
  end
end



マイグレーションを適用します。
コマンド マイグレーション適用
rails db:migrate


メッセージモデルを編集します。
「app\models\message.rb」ファイルを以下の記述に変更します。


記述追加 app\models\message.rb
5行目に「validates :content, presence: { message: '空白にはできません' }」の記述を追加しています。

class Message < ApplicationRecord
  belongs_to :user
  belongs_to :conversation

  validates :content, presence: { message: '空白にはできません' }
end



次に会話モデルを編集します。
「app\models\conversation.rb」ファイルを以下の記述に変更します。


記述変更 app\models\conversation.rb

class Conversation < ApplicationRecord

  belongs_to :sender, class_name: "User"
  belongs_to :receiver, class_name: "User"

  def last_message
    message = Message.where(conversation_id: self.id).last
    if message.present?
      return message
    else
      return Message.new updated_at: Time.now
    end
  end
  
end



ジェネレーターを使ってメッセージコントローラを作成します。


コマンド
rails g controller messages create


「app\controllers\messages_controller.rb」ファイルを以下のように変更します。


記述変更 app\controllers\messages_controller.rb

class MessagesController < ApplicationController

  def create
    if current_user.id == message_params[:receiver_id]
      redirect_to request.referrer, alert: "自分にメッセージを送ることはできません"
    end
    conversation = Conversation.where("(sender_id = ? AND receiver_id = ?) OR (sender_id = ? AND receiver_id = ?)",
                                      current_user.id, message_params[:receiver_id], 
                                      message_params[:receiver_id], current_user.id
                                    ).first
    if !conversation.present?
      conversation = Conversation.create(sender_id: current_user.id, receiver_id: message_params[:receiver_id])
    end
    @message = Message.new(user_id: current_user.id, 
                           conversation_id: conversation.id,
                           content: message_params[:content]
    )
    if @message.save
      redirect_to request.referrer, notice: "メッセージを送りました。"
    else
      redirect_to request.referrer, alert: "メッセージを送ることができません。"
    end
  end

  private
  def message_params
    params.require(:message).permit(:content, :receiver_id)
  end
  
end



ビューの編集をします。


「app\views\users\show.html.erb」ファイルを以下のように編集します。


記述更新 app\views\users\show.html.erb

<div class="container mt-4 mb-4">
    <div class="row">
        <!-- 左側 -->
        <div class="col-md-4 mb-4">
            <div class="card">
                <div class="card-body">

                    <!-- ステータス -->
                    <div>
                        <% if @user.status %>
                            <span class="badge bg-success"><i class="fa-regular fa-bell"></i>オンライン</span>
                        <% else %>
                            <span class="badge bg-secondary"><i class="fa-regular fa-bell-slash"></i>オフライン</span>
                        <% end %>                                   
                    </div>                
                    <!-- アバター -->
                    <%= image_tag avatar_url(@user), class: "img-fluid img-thumbnail rounded-pill" %>
                    <h4 class="text-center"><%= @user.full_name %></h4>   
                    
                    <!-- 自己紹介 -->
                    <div class="h5 text-center"><%= @user.about %></div>

                    <div class="card">
                        <div class="card-body">
                            <!-- メッセージ送信ボタン -->
                            <% if current_user.id != @user.id %>
                            
                                <!-- モダールトリガー -->
                                <button type="button" class="btn btn-primary w-100" data-bs-toggle="modal" data-bs-target="#exampleModal">
                                    <div class="font2">ホストにメッセージを送る</div>
                                </button>
                                
                                <!-- モダール -->
                                <div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
                                    <div class="modal-dialog">
                                        <div class="modal-content">
                                            <div class="modal-header">
                                                <h1 class="modal-title font2 fs-5" id="exampleModalLabel">メッセージ送信</h1>
                                                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                                            </div>
                                            <%= form_with model: Message.new do |f| %>
                                                <div class="modal-body">
                                                    <div class="container">
                                                        <div class="card">
                                                            <div class="card-body">
                                                                <%= image_tag avatar_url(@user), class: "card-img-top rounded-pill", style: "width: 3rem;" %>
                                                                <span class="font2"><%= @user.full_name %>へのメッセージ</span>
                                                            </div>  
                                                        </div>
                                                        <div class="card mt-2">
                                                            <div class="card-body">
                                                                <h6 class="font2">確認しましょう</h6>
                                                                <ul class="list-group">
                                                                    <li class="list-group-item" style="border: none;">宿泊日時</li>
                                                                    <li class="list-group-item" style="border: none;">宿泊場所</li>
                                                                    <li class="list-group-item" style="border: none;">設備</li>
                                                                    <li class="list-group-item" style="border: none;">キャンセルについて</li>
                                                                </ul>
                                                            </div>
                                                        </div>
                                                        <div class="card mt-2">
                                                            <div class="card-body">                                                                                                
                                                                    <%= f.hidden_field :receiver_id, value: @user.id %>
                                                                    <%= f.text_area :content, class: "w-100", style: "height: 10rem;" %>
                                                            </div>
                                                        </div>                                      

                                                    </div>
                                                </div>
                                                <div class="modal-footer">
                                                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">キャンセル</button>
                                                    <%= f.submit "メッセージを送る", class: "btn btn-outline-primary btn-block" %> 
                                                </div>
                                            <% end %> 
                                        </div>
                                    </div>
                                </div>
                            <% end %>
                        </div>
                    </div>  
                </div>
            </div>       
        </div>
        <!-- 右側 -->
        <div class="col-md-8">

            <!-- 登録している部屋 -->
            <div class="card mb-4">           
                <div class="card-body">
                    <h5 class="card-title"><%= @user.full_name %>さんが登録している部屋</h5>

                    <div class="container mt-4">
                        <div class="row">
                            <% @user.rooms.each do |room| %>
                                <% if room.active? %>
                                    <div class="col-md-4">
                                        <div class="card mb-2">
                                            <div class="card-body">
                                                <span><i class="fa fa-star fa-1x" style="color: gold;"></i><%= pluralize(room.average_rating, "") %></span>
                                                <%= link_to room_path(room), data: { turbolinks: false} do %>
                                                    <%= image_tag room_cover(room), style: "width: 100%;" %>
                                                    <h5 class="card-title">
                                                        <span class="btn btn-light"><%= room.listing_name %></span>
                                                    </h5>
                                                <% end %>
                                                <div class="card-text" style="margin-left: 0.5rem;">
                                                    <p style="font-size: 0.8rem; margin-bottom: -0.3rem;">Address</p>
                                                    <p style="margin-bottom: 2rem;"><%= room.address %></p>
                                
                                                </div>
                                    
                                                <h5 class="badge rounded-pill bg-danger text-light" style="font-size: 1rem;">1泊<%= number_to_currency(room.price) %></h5>
                                            </div>
                                        </div>
                                    </div>
                                <% end %>
                            <% end %>
                        </div>
                    </div>

                </div>
            </div>

            <!-- レビュー -->
            <div class="card">           
                <div class="card-body">
                    <h5 class="card-title"><%= @user.full_name %>さんへのレビュー</h5>
                    <%= render "reviews/guest_list" %>
                    <%= render "reviews/host_list" %>
                </div>
            </div>
        </div>     
    </div>
</div>



ルートの設定をします。
3行目に自動で追加された「get 'messages/create'」の記述は削除して下さい。


記述追加 config\routes.rb
20行目に「post 'messages', to: 'messages#create'」の記述を追加しています。

Rails.application.routes.draw do

  # ルートを app\views\pages\home.html.erb に設定
  root 'pages#home'

  # get
  get '/dashboard', to: 'users#dashboard'
  get 'pages/home'
  get '/users/:id', to: 'users#show', as: 'user'
  get '/your_trips' => 'reservations#your_trips'
  get '/your_reservations' => 'reservations#your_reservations'
  get 'search' => 'pages#search'
  get '/host_calendar' => "calendars#host"
  get 'settings/payment', to: 'users#payment', as: 'settings_payment'
  get 'settings/payout', to: 'users#payout', as: 'settings_payout'

  # post
  post '/users/edit', to: 'users#update'
  post '/settings/payment', to: 'users#update_payment', as: "update_payment"
  post 'messages', to: 'messages#create'

  resources :rooms, except: [:edit] do
    member do
      get 'listing'
      get 'pricing'
      get 'description'
      get 'photo_upload'
      get 'amenities'
      get 'location'
      get 'preload'
      get 'preview'
      delete :delete_photo
      post :upload_photo
    end
    resources :reservations, only: [:create]
  end

  resources :reservations, only: [:approve, :decline] do
    member do
      post '/approve' => "reservations#approve"
    end
  end

  resources :guest_reviews, only: [:create, :destroy]
  resources :host_reviews, only: [:create, :destroy]

  # device
  devise_for :users, 
              path: '', 
              path_names: {sign_up: 'register', sign_in: 'login', edit: 'profile', sign_out: 'logout'},
              controllers: {omniauth_callbacks: 'omniauth_callbacks', registrations: 'registrations'}
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end



ブラウザ確認
http://localhost:3000/users/2


ゲストからホストにメッセージを送ってみます。

PCレイアウト
PCレイアウト


モバイルレイアウト
モバイルレイアウト



Posticoでメッセージテーブルを確認します。

メッセージテーブル
メッセージテーブル



39 | 予約確認メール】 << 【ホーム】 >> 【41 | 会話表示



↓↓クリックして頂けると励みになります。