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

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

【民泊5.1】【MacOSX】メッセージ

コマンド
rails g model Conversation sender_id:bigint recipient_id:bigint


コマンド
rails g model Message context:text user:references conversation:references


コマンド マイグレーション
rails db:migrate


app\models\conversation.rb

class Conversation < ApplicationRecord
  belongs_to :sender, foreign_key: :sender_id, class_name: "User"
  belongs_to :recipient, foreign_key: :recipient_id, class_name: "User"

  has_many :messages, dependent: :destroy
  validates :sender_id, :uniqueness => {:scope => :recipient_id}

  scope :involving, -> (user) {
    where("conversations.sender_id = ? OR conversations.recipient_id = ?", user.id, user.id)
  }

  scope :between, -> (user_A, user_B) {
    where("(conversations.sender_id = ? AND conversations.recipient_id = ?) OR (conversations.sender_id = ? AND conversations.recipient_id = ?)", user_A, user_B, user_B, user_A)
  }
end



app\models\message.rb

class Message < ApplicationRecord
  belongs_to :user
  belongs_to :conversation
  validates_presence_of :context, :conversation_id, :user_id
  def message_time
    self.created_at.strftime('%Y年%-m月%-d日 %-H時%-M分')
  end
end



「app\controllers」フォルダに「conversations_controller.rb」ファイルを新規作成してください。


app\controllers\conversations_controller.rb(新規作成したファイル)

class ConversationsController < ApplicationController
    before_action :authenticate_user!
  
    def index
      @conversations = Conversation.involving(current_user)
    end
  
    def create
      if Conversation.between(params[:sender_id], params[:recipient_id]).present?
        @conversation = Conversation.between(params[:sender_id], params[:recipient_id]).first
      else
        @conversation = Conversation.create(conversation_params)
      end
  
      redirect_to conversation_messages_path(@conversation)
    end
  
    private
  
      def conversation_params
        params.permit(:sender_id, :recipient_id)
      end
  end
  



「app\controllers」フォルダに「messages_controller.rb」ファイルを新規作成してください。


app\controllers\messages_controller.rb(新規作成したファイル)

class MessagesController < ApplicationController
    before_action :authenticate_user!
    before_action :set_conversation
  
    def index
      if current_user == @conversation.sender || current_user == @conversation.recipient
        @other = current_user == @conversation.sender ? @conversation.recipient : @conversation.sender
        @messages = @conversation.messages.order("created_at DESC")
      else
        redirect_to conversations_path, alert: "権限がありません。"
      end
    end
  
    def create
      @message = @conversation.messages.new(message_params)
      @messages = @conversation.messages.order("created_at DESC")
  
      if @message.save
          redirect_to conversation_messages_path(@conversation)
      end
    end
  
    private
  
    def set_conversation
    @conversation = Conversation.find(params[:conversation_id])
    end

    def message_params
    params.require(:message).permit(:context, :user_id)
    end
end



記述追加 config\routes.rb(54行目)

  resources :conversations, only: [:index, :create]  do
    resources :messages, only: [:index, :create]
  end



config\routes.rb

Rails.application.routes.draw do

  #ルートをpages#homeに設定
  root 'pages#home'

  get 'pages/home'
  get '/your_trips' => 'reservations#your_trips'
  get '/your_reservations' => 'reservations#your_reservations'
  get 'search' => 'pages#search'
  get 'dashboard' => 'dashboards#index'
  get '/host_calendar' => "calendars#host"
  get '/payment_method' => "users#payment"
  get '/payout_method' => "users#payout"
  get '/notification_settings' => 'settings#edit'

  post '/add_card' => "users#add_card"
  post '/notification_settings' => 'settings#update'

  resources :users, only: [:show] do
    member do
      post '/verify_phone_number' => 'users#verify_phone_number'
      patch '/update_phone_number' => 'users#update_phone_number'
    end
  end

  resources :rooms, except: [:edit] do
    member do
      get 'listing'
      get 'pricing'
      get 'description'
      get 'photo_upload'
      get 'amenities'
      get 'location'
      get 'preload'
      get 'preview'
    end
    resources :photos, only: [:create, :destroy]
    resources :reservations, only: [:create]
    resources :calendars
  end

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

  resources :revenues, only: [:index]

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

  resources :conversations, only: [:index, :create]  do
    resources :messages, only: [:index, :create]
  end

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



「app\views」フォルダに「conversations」フォルダを新規作成して下さい。
作成した「conversations」フォルダに「index.html.erb」ファイルを新規作成します。



app\views\conversations\index.html.erb(新規作成したファイル)

<div class="row">
  <div class="col-md-12">
    <div class="panel panel-default">
      <div class="panel-heading">あなたの会話</div>
      <div class="panel-body">
        <div class="container">

          <% @conversations.each do |conversation| %>
              <% other = current_user == conversation.sender ? conversation.recipient : conversation.sender %>
              <%= link_to conversation_messages_path(conversation), data: { turbolinks: false} do %>

                  <div class="row conversation">
                    <% if conversation.messages.any? %>
                        <div class="col-md-2">
                          <%= image_tag avatar_url(other), class: "img-circle avatar-medium" %>
                        </div>
                        <div class="col-md-3" style="white-space: nowrap">
                          <%= other.fullname %><br/>
                          <%= conversation.messages.last.message_time %>
                        </div>
                        <div class="col-md-7">
                          <%= conversation.messages.last.context %>
                        </div>
                    <% end %>
                  </div>

              <% end %>
          <% end %>

        </div>
      </div>
    </div>
  </div>
</div>



「app\views」フォルダに「messages」フォルダを新規作成してください。
作成した「messages」フォルダに「index.html.erb」ファイルを新規作成します。



app\views\messages\index.html.erb(新規作成したファイル)

<div class="row">
  <div class="col-md-3 text-center">
    <%= image_tag avatar_url(@other), class: "img-circle avatar-medium" %>
    <strong><%= @other.fullname %></strong>
    <%= link_to "プロフィールを見る", @other, class: "btn btn-default" %>
  </div>
  <div class="col-md-9">
    <div class="panel panel-default">
      <div class="panel-heading">
         <%= @other.fullname %> さんとの会話内容
        <input id="conversation_id" type="hidden" value="<%= @conversation.id %>">
      </div>
      <div class="panel-body">
        <div class="container text-center">
          <%= form_for [@conversation, @conversation.messages.new], remote: true do |f| %>
              <div class="form-group">
                <%= f.text_field :context, placeholder: "メッセージを入力してください。", class: "form-control" %>
              </div>
              <%= f.hidden_field :user_id, value: current_user.id %>
              <div>
                <%= f.submit "メッセージを送る", class: "btn btn-normal" %>
              </div>
          <% end %>
        </div>
      </div>
    </div>

    <div id="chat">
      <%= render @messages %>
    </div>

  </div>
</div>



「app\views\messages」フォルダに「_message.html.erb」ファイルを新規作成してください。


app\views\messages\_message.html.erb(新規作成したファイル)

<div class="panel">
  <div class="panel-body">
    <%= image_tag message.user.gravatar_url, class: "img-circle avatar-medium" %>
    <strong><%= message.user.fullname %></strong>
    <span class="pull-right"><%= message.message_time %></span>
    <br/>
    <div class="row-space-2">
      <%= message.context %>
    </div>
  </div>
</div>



記述追加 app\views\users\show.html.erb(6行目)

      <% if current_user && current_user != @user %>
          <%= link_to "メッセージを送る", conversations_path(sender_id: current_user.id, recipient_id: @user.id), method: :post, class: "btn btn-default" %>
      <% end %>



app\views\users\show.html.erb

<div class="row">
  <div class="col-md-3">

    <div class="center">
      <%= image_tag @user.gravatar_url, class: "avatar-full" %>
      <% if current_user && current_user != @user %>
        <%= link_to "メッセージを送る", conversations_path(sender_id: current_user.id, recipient_id: @user.id), method: :post, class: "btn btn-default" %>
      <% end %>
    </div>

    <div class="panel panel-default">
      <div class="panel-heading" style="text-align: center;"><%= @user.fullname %></div>
      <br/>
      <div class="center">
        <%= @user.description %>
       </div>
       <hr/>

      <div class="panel-body">
        <ul class="sidebar-list">
          <% if @user.confirmation_token %>
            <li>Emailアドレス<span class="pull-right icon-babu"><i class="fa fa-check-circle-o"></i></span></li>
          <% end %>
          <% if @user.phone_verified %>
            <li>電話番号<span class="pull-right icon-babu"><i class="fa fa-check-circle-o"></i></span></li>
          <% end %>
        </ul>
      </div>

    </div>
  </div>

  <div class="col-md-9">
 
    <br/>
    <h4><%= @user.fullname %>さんが登録しているお部屋(<%= @rooms.length %>)</h4><br/>
    <div class="row">
      <%= render partial: "rooms/rooms_list", locals: {rooms: @rooms} %>
    </div>
    <br/>
    <h4>ゲストからのレビュー (<%= @guest_reviews.count %>)</h4>
    <div class="row">
      <%= render "reviews/guest_list" %>
    </div>
    <br/>
    <h4>ホストからのレビュー (<%= @host_reviews.count %>)</h4>
    <div class="row">
      <%= render "reviews/host_list" %>
    </div>
    <br/>
  </div>
  
</div>



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


ユーザプロフィールに「メッセージを送る」ボタンが出ます。

メッセージを送る
メッセージを送る


メッセージを入力します。
メッセージを入力
メッセージを入力


メッセージが表示されます。
メッセージが表示される
メッセージが表示される


ナビゲーションバーのリンクを更新します。


記述追加 app\views\shared\_navbar.html.erb
40行目と65行目にリンクを追加しています。

<!-- ナビゲーションバー -->
<nav class="navbar navbar-default navbar-static-top"  style ="margin: 0;">

  <div class="container">

    <div class="navbar-header">
      <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
        <span class="sr-only">ナビゲーション トグル</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
      <%= link_to "テストサイトMinpaku", root_path, class: "navbar-brand" %>
    </div>

    <div id="navbar" class="navbar-collapse collapse">
      <ul class="nav navbar-nav navbar-right">
        <% if (!user_signed_in?) %>
            <li><%= link_to "ログイン", new_user_session_path %></li>
            <li><%= link_to "新規ユーザ登録", new_user_registration_path %></li>
        <% else %>
            <li class="dropdown">
              <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
                <!-- アバター画像 -->
                <%= image_tag current_user.gravatar_url, class: "img-circle avatar-small" %>&nbsp;
                <!-- 氏名表示に変更 -->
                <%= current_user.fullname %>
                <span class="caret"></span>
              </a>
              <ul class="dropdown-menu">
                <li><%= link_to "ダッシュボード", dashboard_path %></li>
                <li><%= link_to "登録したお部屋の管理", rooms_path %></li>
                <li><%= link_to "お部屋の新規登録", new_room_path %></li>
                <li><%= link_to "受注予約の管理(ホスト用)", your_reservations_path %></li>
                <li><%= link_to "予約履歴(ゲスト用)", your_trips_path %></li>
                <li><%= link_to "ホスト用カレンダー", host_calendar_path %></li>
                <li><%= link_to "収益", revenues_path %></li>
                <li><%= link_to "クレジットカード登録", payment_method_path, data: { turbolinks: false} %></li>
                <li><%= link_to "振り込み口座登録", payout_method_path %></li>
                <li><%= link_to "メッセージを見る", conversations_path %></li>                
                <li role="separator" class="divider"></li>
                <li><%= link_to "ユーザ登録情報修正", edit_user_registration_path %></li>
                <li><%= link_to "予約メール通知設定", notification_settings_path %></li>
                <li><%= link_to "ログアウト", destroy_user_session_path, method: :delete %></li>
              </ul>
            </li>
        <% end %>
      </ul>
    </div>
    
  </div>

</nav>

<% if (user_signed_in?) && !current_page?(root_path) && !current_page?("/rooms/#{params[:id]}") %>
    <nav class="navbar navbar-default" style="background-color: #89dfd7;">
      <div class="container">
        <ul class="nav navbar-nav">
          <li <% if current_page?(dashboard_path) %> class="active" <% end %> > <%= link_to "ダッシュボード", dashboard_path %></li>
          <li <% if current_page?(host_calendar_path) %> class="active" <% end %> ><%= link_to "ホスト用カレンダー", host_calendar_path %></li>
          <li <% if current_page?(revenues_path) %> class="active" <% end %> ><%= link_to "収益", revenues_path %></li>
          <li <% if current_page?(payment_method_path) %> class="active" <% end %> ><%= link_to "クレジットカード登録", payment_method_path, data: { turbolinks: false} %></li>
          <li <% if current_page?(payout_method_path) %> class="active" <% end %> ><%= link_to "振り込み口座登録", payout_method_path %></li>
          <li <% if current_page?(notification_settings_path) %> class="active" <% end %> ><%= link_to "予約メール通知設定", notification_settings_path %></li>
          <li <% if current_page?(conversations_path) %> class="active" <% end %> ><%= link_to "メッセージを見る", conversations_path %></li>
        </ul>
      </div>
    </nav>
<% end %>