↓↓クリックして頂けると励みになります。
【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
ゲストからホストにメッセージを送ってみます。
Posticoでメッセージテーブルを確認します。
【39 | 予約確認メール】 << 【ホーム】 >> 【41 | 会話表示】
↓↓クリックして頂けると励みになります。