アクションケーブルを使ってリアルタイムでメッセージが更新されるようにします。
記述追加 config\routes.rb
6行目に「mount ActionCable.server => '/cable'」の記述追加
Rails.application.routes.draw do #ルートをpages#homeに設定 root 'pages#home' # アクションケーブル mount ActionCable.server => '/cable' 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\assets\javascripts\application.js
25行目に「//= require cable」の記述追加
// This is a manifest file that'll be compiled into application.js, which will include all the files // listed below. // // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path. // // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the // compiled file. JavaScript code in this file should be added after the last require_* statement. // // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details // about supported directives. // //= require jquery //= require bootstrap-sprockets //= require jquery_ujs //= require jquery-ui/datepicker //= require jquery-ui/slider //= require toastr //= require moment //= require fullcalendar //= require gravtastic //= require card //= require Chart.bundle //= require chartkick //= require cable //= require turbolinks //= require_tree .
記述追加 config\environments\development.rb
60行目に「config.action_cable.url = "ws://localhost:3000/cable"」の記述追加
Rails.application.configure do #画像アップロード Paperclip.options[:command_path] = "C:\Program Files\ImageMagick-7.0.10-Q16;C:\Program Files (x86)\GetGnuWin32\bin" # Settings specified here will take precedence over those in config/application.rb. # In the development environment your application's code is reloaded on # every request. This slows down response time but is perfect for development # since you don't have to restart the web server when you make code changes. config.cache_classes = false # Do not eager load code on boot. config.eager_load = false # Show full error reports. config.consider_all_requests_local = true # Enable/disable caching. By default caching is disabled. if Rails.root.join('tmp/caching-dev.txt').exist? config.action_controller.perform_caching = true config.cache_store = :memory_store config.public_file_server.headers = { 'Cache-Control' => 'public, max-age=172800' } else config.action_controller.perform_caching = false config.cache_store = :null_store end # Don't care if the mailer can't send. # trueに変更 config.action_mailer.raise_delivery_errors = true config.action_mailer.perform_caching = false # Print deprecation notices to the Rails logger. config.active_support.deprecation = :log # Raise an error on page load if there are pending migrations. config.active_record.migration_error = :page_load # Debug mode disables concatenation and preprocessing of assets. # This option may cause significant delays in view rendering with a large # number of complex assets. config.assets.debug = true # Suppress logger output for asset requests. config.assets.quiet = true # Raises error for missing translations # config.action_view.raise_on_missing_translations = true # Use an evented file watcher to asynchronously detect changes in source code, # routes, locales, etc. This feature depends on the listen gem. # config.file_watcher = ActiveSupport::EventedFileUpdateChecker #アクションケーブル config.action_cable.url = "ws://localhost:3000/cable" config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } #Gメールの設定 config.action_mailer.delivery_method = :smtp config.action_mailer.smtp_settings = { address: "smtp.gmail.com", port: 587, enable_starttls_auto: true, authentication: "plain", user_name: 'win.rails.learn@gmail.com', password: 'vusopllqzbyvvahk' } #アマゾンS3 config.paperclip_defaults = { storage: :s3, path: ':class/:attachment/:id/:style/:filename', s3_host_name: 's3-ap-northeast-1.amazonaws.com', s3_credentials: { bucket: 'winrailslearn', access_key_id: 'AKIAIU4EZ4WK4HU35G4Q', secret_access_key: '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', s3_region: 'ap-northeast-1' } } end
記述追加 app\views\layouts\application.html.erb
7行目に「<%= action_cable_meta_tag %>」の記述追加
<!DOCTYPE html> <html> <head> <title>Minpaku</title> <%= csrf_meta_tags %> <!-- アクションケーブル --> <%= action_cable_meta_tag %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> <!-- googleフォント --> <link href="https://fonts.googleapis.com/css2?family=Kosugi&display=swap" rel="stylesheet"> <!-- アイコン --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"> <!-- 日付ピッカー デザインsunny--> <link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/sunny/jquery-ui.css"> <!-- 日付ピッカーの日本語化--> <script src="https://rawgit.com/jquery/jquery-ui/master/ui/i18n/datepicker-ja.js"></script> <!-- geocomplete --> <script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBojDcZmScBkIOISjoYREjgid99iZUL2Tk&libraries=places"></script> </head> <body> <!-- _navbar.html.erb をレンダーする --> <%= render 'shared/navbar' %> <%= render 'shared/message' %> <!-- ページをコンテナに格納 --> <div class="container"> <%= yield %> </div> </body> </html>
コマンド
rails g channel messages
書き換え app\channels\messages_channel.rb
class MessagesChannel < ApplicationCable::Channel def subscribed stream_from "conversation_#{params[:id]}" end end
「app\controllers\messages_controller.rb」ファイルを編集します。
1.記述追加 app\controllers\messages_controller.rb(19行目)
ActionCable.server.broadcast "conversation_#{@conversation.id}", message: render_message(@message)
2.21行目の記述をコメントアウトします。
#redirect_to conversation_messages_path(@conversation)
3.記述追加 app\controllers\messages_controller.rb(27行目)
def render_message(message) self.render(partial: 'messages/message', locals: {message: message}) end
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 ActionCable.server.broadcast "conversation_#{@conversation.id}", message: render_message(@message) # 動くがダブルレンダーになるのでリダイレクトを外す #redirect_to conversation_messages_path(@conversation) end end private def render_message(message) self.render(partial: 'messages/message', locals: {message: message}) end def set_conversation @conversation = Conversation.find(params[:conversation_id]) end def message_params params.require(:message).permit(:context, :user_id) end end
書き換え app\assets\javascripts\channels\messages.coffee
$(() -> App.messages = App.cable.subscriptions.create {channel: 'MessagesChannel', id: $('#conversation_id').val() }, received: (data) -> $('#new_message')[0].reset() $('#chat').prepend data.message )
ブラウザ確認
http://localhost:3000/conversations/1/messages
メッセージを送信したと同時に更新され、相手の画面にもメッセージが表示されます。