SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

サンプルコードで学ぶRuby on Rails 5実践入門

Rails 5の目玉機能「Action Cable」で双方向通信を実装(2)

サンプルコードで学ぶRuby on Rails 5実践入門 第8回

  • X ポスト
  • このエントリーをはてなブックマークに追加

発言にユーザーIDを保存してユーザー名を表示する

 最後に、発言と併せてユーザーIDもデータベースに保存するようにします。そのためには、クライアント側とサーバー側(チャネル)でコネクションごとにユーザーを識別できるようにする必要があります。また、データベースに発言を保存する処理とブロードキャスト後にクライアント側で発言を表示する処理に、ユーザー名を追加する必要があります。

コネクションの修正

 まず、Action Cableのコネクションを確立する段階でユーザーを識別できるようにするため、リスト10の通りにコネクションを修正します。

リスト10 app/channels/application_cable/connection.rb
module ApplicationCable
  class Connection < ActionCable::Connection::Base
    identified_by :current_user

    def connect
      self.current_user = find_verified_user
      logger.add_tags 'ActionCable', current_user.name
    end

    protected

      def find_verified_user
        if verified_user = User.find_by(id: cookies.signed[:user_id])
          verified_user
        else
          reject_unauthorized_connection
        end
      end
  end
end

 identified_byメソッドは、WebSocketのコネクションを識別するために提供されており、current_userを識別子として指定しています。

 接続するクライアント側のユーザーIDを取得するには、find_verified_userメソッド内のコードの通り、ブラウザのクッキーを用います。ログイン時点で、サーバー側からクッキーをクライアント側に発行した、暗号化されたuser_idcookies.signed[:user_id]として取得して、ユーザーIDがデータベースに登録されている場合は、current_userにセットされ、これを識別子として用います。ユーザーIDがデータベースに登録されていない場合には、reject_unauthorized_connectionメソッドが呼び出されます。

 reject_unauthorized_connectionメソッドは、WebSocket通信を拒否するために提供されているメソッドです。

セッションヘルパーの修正

 セッションヘルパーのlog_inメソッドで、暗号化されたユーザーIDをクッキーとして発行するコードをリスト11の通りに追加しましょう。

リスト11 app/helpers/sessions_helper.rb
module SessionsHelper
…(中略)…
  def log_in(user)
    callback = session[:callback]
    reset_session
    session[:user_id] = user.id
    session[:callback] = callback
    cookies.permanent.signed[:user_id] = user.id
  end
…(中略)…

 コードのpermanentは、発行したクッキーを永続化するためのものです。また、signedを指定することでクッキーに格納されるユーザーIDが暗号化されます。

チャネルの修正

 チャネルのspeakメソッドでモデルを生成する箇所に、ユーザーIDをリスト12の通りに追加します。

リスト12 app/channels/chat_message_channel.rb
class ChatMessageChannel < ApplicationCable::Channel
…(中略)…
  def speak(data)
    ChatMessage.create! user_id: current_user.id, body: data['message']
  end
end

モデルの修正

 ChatMessage、Userモデルの関連とビュー側で使用するuser_nameメソッドを、リスト13、リスト14の通りに追加します。

リスト13 app/models/chat_message.rb
class ChatMessage < ApplicationRecord
…(中略)…
  belongs_to :user

  def user_name
    return '名無しさん' if user_id.blank?
    user.name
  end
end
リスト14 app/models/user.rb
class User < ApplicationRecord
…(中略)…
  has_many :chat_messages
end

 ChatMessageモデルのuser_nameメソッドは、これまでのテストでchat_messagesテーブルのuser_idにNullのデータが入っているための措置で、user_idが空だった場合にはユーザー名を「名無しさん」と表示するようにしています。

ジョブの修正

 ジョブでブロードキャストする処理に、ユーザー名をリスト15の通り追加します。

リスト15 app/jobs/chat_message_broadcast_job.rb
class ChatMessageBroadcastJob < ApplicationJob
…(中略)…
  def perform(chat_message)
    ActionCable.server.broadcast 'chat_message_channel', user_name: chat_message.user_name, message: chat_message.body
  end
end

 ユーザー名の取得には、ChatMessageモデルに定義したuser_nameメソッドを使っています。

CoffeeScriptの修正

 ブロードキャストされた場合、クライアント側で発言を受け取ってhtmlとして表示する箇所を、リスト16の通りに修正します。

リスト16 app/assets/javascripts/channels/chat_message.coffee
…(中略)…
  received: (data) ->
    $('#chat_messages').append '<div>' + data['user_name'] + ': ' + data['message'] + '</div>'

 data['user_name']でブロードキャストされた発言のユーザー名を取得しています。

ビューの修正

 最後にブロードキャストした場合と同様、リスト17の通り発言の表示にユーザー名を加えましょう。

リスト17 app/views/chat_messages/index.html.erb
<div id='chat_messages'>
  <% @chat_messages.each do |chat_message| %>
    <div><%= "#{chat_message.user_name}: #{chat_message.body}" %></div>
  <% end %>
</div>

動作確認

 これで、発言にユーザーIDを保存してユーザー名を表示する修正が完了しました。「http://localhost:3000/chat_messages/index」にアクセスして動作確認をしてみましょう。

 図1は、左側がChromeでtest user1としてログインしたもの、右側がSafariでtest user2としてログインして動作確認した結果です。

図1 ログイン後にチャットする様子
図1 ログイン後にチャットする様子

まとめ

 今回は、前回に引き続きAction Cableのサンプルアプリを拡張して、発言をデータベースに保存できるようにし、会員登録機能と関連付けを行いました。

 連載最終回の次回は、Rails 5のもう1つの目玉機能であるAPIモードで別のRailsアプリケーションを立ち上げ、今回開発したチャットアプリに機能を追加します。

参考文献

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
サンプルコードで学ぶRuby on Rails 5実践入門連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト 竹馬 力(チクバ ツトム)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/10255 2017/07/10 14:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング