[45]メッセージと会話 | モデル << [ホームに戻る] >> [47]メッセージと会話 | 会話
メッセージコントローラを作成します。
コマンド
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
27~38行目、266行目からの記述を変更しています。
コードをコピーしてファイルの内容を置き換えて下さい。
<section class="section"> <div class="container"> <div class="columns"> <!-- 左パネル --> <div class="column is-one-third"> <div class="columns is-multiline"> <!-- 上部 --> <div class="column is-full"> <div class="card"> <!-- アバター --> <div class="card-content is-horizontal-center is-flex"> <figure class="image is-256x256"> <%= image_tag avatar_url(@user), class: "is-rounded" %> </figure> </div> <div class="card-content"> <!-- 画像アップロードボタン --> <div class="content has-text-centered"> <p class="title is-5"> <%= @user.full_name %> </p> <% if current_user.id != @user.id %> <a class="button is-black is-outlined is-fullwidth toggle-contact">メッセージを送る</a> <% else %> <%= form_for :user, url: users_edit_url(@user), action: :update, method: :post do |f| %> <div class="file"> <label class="button is-primary is-outlined is-fullwidth"> <%= f.file_field :avatar, class: "file-input", onchange: "this.form.submit();" %> <i class="fas fa-upload"></i> アバター画像アップロード </label> </div> <% end %> <% end %> </div> <hr class="h-10"> <!-- アカウント情報 --> <article class="media"> <div class="media-content">アカウント登録日</div> <div class="media-right"> <strong><%= I18n.l(@user.created_at, format: :full_date) %></strong> </div> </article> <hr class="h-10"> <!-- 出身地 --> <article> <div class="media"> <div class="media-content">出身地</div> <div class="media-right"> <strong><%= @user.from %></strong> <i class="toggle far fa-edit" aria-controls="user-from"></i> </div> </div> <div class="content"> <%= form_for :user, url: users_edit_url(@user), action: :update, method: :post, html: {id: 'user-from', class: 'is-hidden'} do |f| %> <div class="field"> <%= f.text_field :from, autofocus: true, autocomplete: 'form', class: 'input'%> </div> <a class="toggle button is-light" aria-controls="user-from">キャンセル</a> <%= f.submit "保存", class: "button is-danger" %> <% end %> </div> </article> <hr class="h-10"> <!-- オンラインステータス --> <article> <div class="media"> <div class="media-content">ステータス</div> <div class="media-right"> <strong><% if @user.status %> オンライン <% else %> オフライン <% end %></strong> <i class="toggle far fa-edit" aria-controls="user-status"></i> </div> </div> <div class="content"> <%= form_for :user, url: users_edit_url(@user), action: :update, method: :post, html: {id: 'user-status', class: 'is-hidden'} do |f| %> <div class="field"> <%= f.select(:status, options_for_select([["オンライン", true], ["オフライン", false]]), {}, {class: "select is-fullwidth"}) %> </div> <a class="toggle button is-light" aria-controls="user-status">キャンセル</a> <%= f.submit "保存", class: "button is-danger" %> <% end %> </div> </article> </div> </div> </div> <!-- 下部 --> <div class="column is-full"> <div class="card"> <div class="card-content"> <!-- アカウント詳細 --> <article> <div class="media"> <div class="media-content"> <p> <strong>自己紹介</strong> <br> <%= @user.about %> </p> </div> <div class="media-right"> <i class="toggle far fa-edit" aria-controls="user-about"></i> </div> </div> <div class="content"> <%= form_for :user, url: users_edit_url(@user), action: :update, method: :post, html: {id: 'user-about', class: 'is-hidden'} do |f| %> <div class="field"> <%= f.text_area :about, autofocus: true, autocomplete: 'form', class: 'input'%> </div> <a class="toggle button is-light" aria-controls="user-about">キャンセル</a> <%= f.submit "保存", class: "button is-danger" %> <% end %> </div> </article> <hr class="h-10"> <!-- 言語 --> <article> <div class="media"> <div class="media-content"> <p> <strong>言語</strong> <br> <%= @user.language %> </p> </div> <div class="media-right"> <i class="toggle far fa-edit" aria-controls="user-language"></i> </div> </div> <div class="content"> <%= form_for :user, url: users_edit_url(@user), action: :update, method: :post, html: {id: 'user-language', class: 'is-hidden'} do |f| %> <div class="field"> <%= f.text_field :language, autofocus: true, autocomplete: 'form', class: 'input'%> </div> <a class="toggle button is-light" aria-controls="user-language">キャンセル</a> <%= f.submit "保存", class: "button is-danger" %> <% end %> </div> </article> <hr class="h-10"> <!-- アカウント連携 --> <article class="media"> <div class="content"> <p> <strong>アカウント連携</strong><br/> <% if @user.provider %> <span class="has-text-success">Facebookでログイン中</span> <% else %> <span class="has-text-danger">アカウント連携していません。</span> <% end %> </p> </div> </article> </div> </div> </div> </div> </div> <!-- 右側 --> <div class="column"> <div class="columns is-multiline"> <!-- 登録したお仕事 --> <% @user.gigs.each do |gig| %> <div class="column is-one-third"> <div class="card"> <div class="card-image"> <%= link_to edit_gig_path(gig) do %> <figure class="image is-4by3"> <%= image_tag gig_cover(gig) %> </figure> <% end %> </div> <div class="card-content p-t-5 p-b-5"> <p class="subtitle is-6 m-b-5"><%= link_to gig.title, gig_path(gig) %></p> <span class="star-review"><i class="fa fa-star"></i> <%= gig.average_rating %> <span class="has-text-primary">(<%= gig.reviews.count %>)</span> </span> </div> <footer class="card-footer"> <% basic_price = gig.pricings.find{ |p| p.pricing_type == 'basic' } %> <a class="has-text-danger is-block card-footer-item has-text-right"> <% if !basic_price.nil? %> <span class="small-title">最低価格</span> <strong><%= number_to_currency(basic_price.price) %></strong> <% else %> <strong> <span class="small-title has-text-dark">まだ価格がありません</span> </strong> <% end %> </a> </footer> </div> </div> <% end %> </div> <div class="card"> <div class="card-header"> <div class="card-header-title">最新のレビュー</div> </div> <div class="card-content"> <!-- レビュー --> <% @reviews.each do |r| %> <article class="media"> <figure class="media-left"> <p class="image is-64x64"> <%= image_tag avatar_url(r.buyer), class: "is-rounded" %> </p> </figure> <div class="media-content"> <div class="content"> <p> <strong><%= r.buyer.full_name %></strong><br> <%= r.review %> </p> <small><%= time_ago_in_words(r.created_at) %></small> </div> </div> <div class="media-right"> <span class="star-review"><i class="fa fa-star"></i> <%= r.stars %></span> </div> </article> <% end %> </div> </div> </div> </div> </div> </section> <div class="modal" id="contact-form"> <div class="modal-background"></div> <div class="modal-card"> <header class="modal-card-head"> <p class="modal-card-title">メッセージを送る</p> <button class="delete toggle-contact" aria-label="close"></button> </header> <section class="modal-card-body"> <div class="columns"> <div class="column is-one-third"> <div class="card" st> <div class="card-content is-horizontal-center is-flex"> <figure class="image is-128x128"> <%= image_tag avatar_url(@user), class: "is-rounded" %> </figure> </div> <div class="card-content"> <hr> <strong>確認しましょう:</strong> <ul class="is-size-7" style="list-style:initial"> <li>仕事の説明</li> <li>指示</li> <li>関連ファイル</li> <li>予算について</li> </ul> </div> </div> </div> <div class="column"> <%= form_with model: Message.new do |f| %> <%= f.hidden_field :receiver_id, value: @user.id %> <div class="card-content"> <div class="field"> <div class="control"> <%= f.text_area :content, class: "textarea" %> </div> </div> <%= f.submit "メッセージを送る", class: "button is-danger is-pulled-right" %> </div> <% end %> </div> </div> </section> </div> </div> <script> var toggle_modals = $('.toggle-contact'); if (toggle_modals) { toggle_modals.on('click', function(event) { event.stopPropagation(); event.preventDefault(); var form = document.getElementById('contact-form'); form.classList.toggle('is-active'); }); } </script>
「app\views\gigs\show.html.erb」ファイルを以下のように編集します。
記述更新 app\views\gigs\show.html.erb
129~131行目、165行目から220行目の記述を変更しています。
コードをコピーしてファイルの内容を置き換えて下さい。
<% content_for :head do %> <meta name="turbolinks-cache-control" content="no-cache"> <% end %> <%= render 'shared/categories' %> <section class="section"> <div class="container"> <div class="columns"> <!-- 左側 --> <div class="column is-two-thirds"> <div class="columns is-multiline"> <!-- 画像カルーセル表示 --> <div class="column is-full"> <div class="card"> <div class="card-content"> <div class="content"> <p class="title is-4"><%= @gig.title %></p> </div> <hr> <div class="hero-carousel" id="carousel-photo"> <% @gig.photos.each do |photo| %> <div class="carousel-item has-background image is-16by9"> <%= image_tag url_for(photo), class: "is-background", width: "100%" %> </div> <% end %> <% if @gig.video.present? %> <div class="video-container"> <iframe src="https://www.youtube.com/embed/<%= @gig.video %>" allowfullscreen></iframe> </div> <% end %> </div> </div> </div> </div> <!-- お仕事の内容 --> <div class="column"> <div class="card"> <div class="card-content"> <article class="media"> <div class="media-content"> <p><strong>このお仕事について</strong></p> <hr> <%= @gig.description %> </div> </article> </div> </div> </div> </div> </div> <!-- 右側 --> <div class="column"> <div class="columns is-multiline"> <!-- 価格プラン --> <div class="column is-full"> <div class="tabs is-fullwidth" id="tabs"> <ul> <% Pricing.pricing_types.each do |key, value| %> <li class="tab <%= 'is-active' if value == 0 %> " data-tab="<%= key %>" style="<%= 'display: none' if @gig.has_single_pricing && value != 0 %>"> <a> <% if value == 0 %> ベーシック <% elsif value == 1 %> スタンダード <% else %> プレミアム <% end %> </a> </li> <% end %> </ul> </div> <div class="tabs-content"> <% @gig.pricings.each do |p| %> <div class="tab-content" id="tab-<%= p.pricing_type %>" style="<%= 'display: none' if !p.basic? %>"> <div class="card"> <div class="card-content"> <div class="media"> <div class="media-content"> <strong><%= p.title %></strong> </div> <div class="media-right"> <p class="title is-4"><%= number_to_currency(p.price) %></p> </div> </div> <div class="content f-15"> <p class="m-t-30"><%= p.description %></p> <p class="m-t-30"> <strong><i class="far fa-clock"></i> 期日: <%= p.delivery_time %>日</strong> </p> </div> <% if (!user_signed_in? && @gig.active) || (user_signed_in? && @gig.active && @gig.user_id != current_user.id) %> <%= link_to "購入する (#{number_to_currency(p.price)})", checkout_path(id: @gig.id, pricing_type: p.pricing_type), class: "button is-fullwidth is-danger" %> <% else %> <button class="button is-fullwidth is-danger" disabled>購入できません</button> <% end %> </div> </div> </div> <% end %> </div> </div> <!-- プロフィール --> <div class="column"> <div class="card"> <div class="card-content is-horizontal-center is-flex"> <figure class="image is-256x256"> <%= image_tag avatar_url(@gig.user), class: "is-rounded" %> </figure> </div> <div class="card-content f-15"> <div class="content has-text-centered"> <p class="title is-5"><%= @gig.user.full_name %></p> <% if current_user.id != @gig.user.id %> <a class="button is-black is-outlined is-fullwidth toggle-contact">メッセージを送る</a> <% end %> </div> <article class="media"> <div class="media-content"> <i class="fas fa-user m-r-5"></i> アカウント登録日 </div> <div class="media-right"> <%= I18n.l(@gig.user.created_at, format: :full_date) %> </div> </article> <article class="media"> <div class="media-content"> <i class="fas fa-map-marker-alt m-r-5"></i> 出身地 </div> <div class="media-right"> <%= @gig.user.from %> </div> </article> <article class="media"> <div class="media-content"> <%= @gig.user.about %> </div> </article> </div> </div> </div> </div> </div> </div> </div> </section> <div class="modal" id="contact-form"> <div class="modal-background"></div> <div class="modal-card"> <header class="modal-card-head"> <p class="modal-card-title">メッセージを送る</p> <button class="delete toggle-contact" aria-label="close"></button> </header> <section class="modal-card-body"> <div class="columns"> <div class="column is-one-third"> <div class="card" st> <div class="card-content is-horizontal-center is-flex"> <figure class="image is-128x128"> <%= image_tag avatar_url(@gig.user), class: "is-rounded" %> </figure> </div> <div class="card-content"> <hr> <strong>確認しましょう:</strong> <ul class="is-size-7" style="list-style:initial"> <li>仕事の説明</li> <li>指示</li> <li>関連ファイル</li> <li>予算について</li> </ul> </div> </div> </div> <div class="column"> <%= form_with model: Message.new do |f| %> <%= f.hidden_field :receiver_id, value: @gig.user.id %> <div class="card-content"> <div class="field"> <div class="control"> <%= f.text_area :content, class: "textarea" %> </div> </div> <%= f.submit "メッセージを送る", class: "button is-danger is-pulled-right" %> </div> <% end %> </div> </div> </section> </div> </div> <script> var toggle_modals = $('.toggle-contact'); if (toggle_modals) { toggle_modals.on('click', function(event) { event.stopPropagation(); event.preventDefault(); var form = document.getElementById('contact-form'); form.classList.toggle('is-active'); }); } </script> <script> BulmaCarousel.attach('#carousel-photo', { slidesToScroll: 1, slidesToShow: 1 }); $(document).ready(function() { $('#tabs li').on('click', function() { var type = $(this).data('tab'); $('#tabs li').removeClass('is-active'); $(this).addClass('is-active'); $('.tab-content').hide(); $('#tab-' + type).show(); }) }) </script>
「app\views\requests\show.html.erb」ファイルを以下のように編集します。
記述更新 app\views\requests\show.html.erb
63~65行目、141行目から196行目の記述を変更しています。
コードをコピーしてファイルの内容を置き換えて下さい。
<section class="section"> <div class="container"> <div class="columns"> <!-- 左側 --> <div class="column is-two-thirds"> <div class="columns is-multiline"> <!-- タイトル --> <div class="column is-full"> <p class="title is-4"><%= @request.title %></p> <article class="media"> <div class="media-content"> <p> カテゴリー:<%= @request.category.name %> <span class="is-pulled-right">リクエスト日: <%= I18n.l(@request.created_at, format: :full_date) %></span> </p> 期日: <%= @request.delivery %> 日 | 申し込み: <%= @request.offers.count %> | 予算: <%= number_to_currency(@request.budget) %> </div> </article> </div> <!-- 内容 --> <div class="column is-full"> <div class="card"> <div class="card-content"> <strong>内容</strong> <hr> <%= @request.description %> <% if @request.attachment_file.attached? %> <p> <%= link_to url_for(@request.attachment_file), class: "tag small is-warning m-t-20", download: "Attachment_#{@request.attachment_file.id}" do %> <i class="fas fa-paperclip fa-lg p-r-5"></i><%= @request.attachment_file.filename %> <% end %> </p> <% end %> </div> </div> </div> <!-- 買い手について --> <div class="column"> <div class="card"> <div class="card-content"> <strong>買い手について</strong> <hr/> <div class="content"> <div class="columns"> <!-- 買い手のアバター --> <div class="column"> <div class="card-content is-horizontal-center is-flex"> <figure class="image is-256x256"> <%= image_tag avatar_url(@request.user), class: "is-rounded" %> </figure> </div> <div class="content has-text-centered"> <p class="title is-5"><%= @request.user.full_name %></p> <% if current_user.id != @request.user.id %> <a class="button is-black is-outlined is-fullwidth toggle-contact">メッセージを送る</a> <% end %> </div> </div> <!-- 買い手のプロフィール --> <div class="column f-15"> <article class="media"> <div class="media-content"> <i class="fas fa-user m-r-5"></i> アカウント登録日 </div> <div class="media-right"> <%= I18n.l(@request.user.created_at, format: :full_date) %> </div> </article> <article class="media"> <div class="media-content"> <i class="fas fa-map-marker-alt m-r-5"></i> 出身地 </div> <div class="media-right"> <%= @request.user.from %> </div> </article> <article class="media"> <div class="media-content"> <%= @request.user.about %> </div> </article> </div> </div> </div> </div> </div> </div> </div> </div> <!-- 右側 --> <div class="column"> <div class="card"> <%= form_for Offer.new do |f| %> <div class="card-content"> <%= f.hidden_field :request_id, value: @request.id %> <div class="field"> <label for="" class="label">価格 (円)</label> <%= f.text_field :amount, class: "input" %> </div> <div class="field"> <label for="" class="label">期日 (日)</label> <%= f.text_field :days, class: "input" %> </div> <div class="field"> <label for="" class="label">申し込みコメント</label> <%= f.text_area :note, class: "textarea" %> </div> <%= f.submit '申し込みする', class: "button is-primary is-fullwidth" %> </div> <% end %> </div> </div> </div> </div> </section> <div class="modal" id="contact-form"> <div class="modal-background"></div> <div class="modal-card"> <header class="modal-card-head"> <p class="modal-card-title">メッセージを送る</p> <button class="delete toggle-contact" aria-label="close"></button> </header> <section class="modal-card-body"> <div class="columns"> <div class="column is-one-third"> <div class="card" st> <div class="card-content is-horizontal-center is-flex"> <figure class="image is-128x128"> <%= image_tag avatar_url(@request.user), class: "is-rounded" %> </figure> </div> <div class="card-content"> <hr> <strong>確認しましょう:</strong> <ul class="is-size-7" style="list-style:initial"> <li>仕事の説明</li> <li>指示</li> <li>関連ファイル</li> <li>予算について</li> </ul> </div> </div> </div> <div class="column"> <%= form_with model: Message.new do |f| %> <%= f.hidden_field :receiver_id, value: @request.user.id %> <div class="card-content"> <div class="field"> <div class="control"> <%= f.text_area :content, class: "textarea" %> </div> </div> <%= f.submit "メッセージを送る", class: "button is-danger is-pulled-right" %> </div> <% end %> </div> </div> </section> </div> </div> <script> var toggle_modals = $('.toggle-contact'); if (toggle_modals) { toggle_modals.on('click', function(event) { event.stopPropagation(); event.preventDefault(); var form = document.getElementById('contact-form'); form.classList.toggle('is-active'); }); } </script>
ルートの設定をします。
自動で追加された記述は削除して下さい。
記述追加 config\routes.rb
28行目に「post 'messages', to: 'messages#create'」の記述を追加しています。
Rails.application.routes.draw do # ルートを app\views\pages\home.html.erb に設定 root 'pages#home' devise_for :users, path: '', path_names: {sign_up: 'register', sign_in: 'login', edit: 'profile', sign_out: 'logout'}, controllers: {omniauth_callbacks: 'omniauth_callbacks', registrations: 'registrations'} get 'pages/home' get '/dashboard', to: 'users#dashboard' get '/users/:id', to: 'users#show', as: 'users' get '/selling_orders', to: 'orders#selling_orders' get '/buying_orders', to: 'orders#buying_orders' get '/all_requests', to: 'requests#list' get '/request_offers/:id', to: 'requests#offers', as: 'request_offers' get '/my_offers', to: 'requests#my_offers' get '/search', to: 'pages#search' get 'settings/payment', to: 'users#payment', as: 'settings_payment' get 'settings/payout', to: 'users#payout', as: 'settings_payout' get '/gigs/:id/checkout/:pricing_type', to: 'gigs#checkout', as: 'checkout' post '/users/edit', to: 'users#update' post '/offers', to: 'offers#create' post '/reviews', to: 'reviews#create' post '/settings/payment', to: 'users#update_payment', as: "update_payment" post 'messages', to: 'messages#create' put '/orders/:id/complete', to: 'orders#complete', as: 'complete_order' put '/offers/:id/accept', to: 'offers#accept', as: 'accept_offer' put '/offers/:id/reject', to: 'offers#reject', as: 'reject_offer' resources :gigs do member do delete :delete_photo post :upload_photo end resources :orders, only: [:create] end resources :requests # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html end
ブラウザ確認
http://localhost:3000/users/4
自分自身にはメッセージを送ることはできませんので、他のユーザにメッセージを送って確認します。
メッセージを送ります。
メッセージを送ることができました。
↓↓クリックして頂けると励みになります。