MyFirstRails

FireBaseでのリアルタイムチャット

概要

Railsにこれから初めて触れる方を対象にしたチュートリアルです

Rails/Stimulus/FireBaseを使用して、リアルタイムにやり取りができるチャットアプリを作成します

チュートリアル

Railsのひな型を作る

まずは、rails newを実行し、Railsアプリのひな型を作成します

rails new firebase_chat --webpack=stimulus

--webpackはRailsで``Webpackを使いやすくしたWebpackerを使用するためのオプションです

Vue、React、Angular、Elm、Stimulusを使用することができます

今回はStimulusを使用しますので--webpack=stimulusとしています

次に、作成したRailsアプリのディレクトリへと移動します

cd firebase_chat

SQLite3のバージョンを修正

先ほどrails newsqlite3のインストールがエラーになっている場合は、以下のようにバージョンを修正します

gem 'sqlite3', '1.3.13'

bundle installを実行します

bundle install

Foremanを使用する

Webpackerを使用する場合、ruby ./bin/webpack-dev-serverを実行しつつ、rails sでローカルサーバーを起動する必要があります

その為、現状のままではターミナルを複数開いておく必要があり、少々面倒です

そこで、複数のコマンドを並列して実行できるforemanを使用します

まず、Gemfilegem 'foreman'を追記します

gem 'foreman'

その後、bundle installを実行します

foremanで使用するコマンドを記述するProcfile.devを作成します

web: bundle exec rails s
webpacker: ruby ./bin/webpack-dev-server

あとは、foreman start -f Procfile.devを実行するだけです

foreman start -f Procfile.dev

localhost:5000にアクセスできればOKです!(foremanを使用する場合、ポートが5000へと変更されています)

ScaffoldでCRUDを作成

rails g scaffoldコマンドを使い、チャットルームのCRUDを作成します

rails g scaffold room title:string

その後、rails db:migrateでマイグレーションを行います

rails db:migrate

config/routes.rbを修正し、rootへのルーティングを作成します

Rails.application.routes.draw do
  root 'rooms#index'
  resources :rooms
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end

foreman start -f Procfile.devを実行して、localhost:5000にアクセスします

あとは、実際にチャットルームが作成できていればOKです

FireBaseでのリアルタイムチャット

それではFireBaseを使用して、リアルタイムチャットを作成していきます

まず、FireBaseにアクセスし、「コンソール」へ移動をクリックします

「プロジェクトを追加」を選択し、プロジェクト名に「firebase-chat」と入力してプロジェクトを作成します

その後、「次へ」をクリックします

</>というアイコンがありますのでそれをクリックします

apiKeyなどが表示されますのでコピーして保存してください

その後、左メニューのDatabaseを選択し、データベースの作成をクリックします

今回はサンプルですのでテストモードで作成します

データベースの種類をRealtime Databaseを選択し、ルールを下記のように変更します

{
  /* Visit https://firebase.google.com/docs/database/security to learn more about security rules. */
  "rules": {
    ".read": true,
    ".write": true
  }
}

ひとまず、FireBaseでの作業は終了です

次に、.envを作成し以下のように編集します

API_KEY=<FireBaseで取得したapiKey>
AUTH_DOMAIN=<FireBaseで取得したauthDomain>
DB_URL=<FireBaseで取得したdatabaseURL>
PROJECT_ID=<FireBaseで取得したprojectId>
STORAGE_BUCKET=<FireBaseで取得したstorageBucket>
MESSAGEING_SENDER_ID=<FireBaseで取得したmessagingSenderId>

それからGemfileに以下のgemを追加します

gem 'dotenv-rails', '>= 2.1.1'
gem 'gon'

最後に、app/controllers/rooms_controller.rbshowアクションを以下のようにします

  def show
    gon.api_key = ENV['API_KEY']
    gon.auth_domain = ENV['AUTH_DOMAIN']
    gon.database_url = ENV['DB_URL']
    gon.project_id = ENV['PROJECT_ID']
    gon.storage_bucket = ENV['STORAGE_BUCKET']
    gon.message_senderid = ENV['MESSAGEING_SENDER_ID']
  end

yarn add firebaseを実行します

yarn add firebase

あとは、app/javascript/packs/controllers/chat_controller.jsを作成します

import { Controller } from "stimulus"
import FireBase from 'firebase'

const firebase = FireBase.initializeApp({
    apiKey: String(gon.api_key),
    authDomain: String(gon.auth_domain),
    databaseURL: String(gon.database_url),
    projectId: String(gon.project_id),
    storageBucket: String(gon.storage_bucket),
    messagingSenderId: String(gon.message_senderid)
});

const database = firebase.database();

export default class extends Controller {
    static get targets() {
        return ["chats", "content"]
    }

    initialize() {
        this.update();
    }

    update() {
        const data = database.ref(location.pathname);

        data.on("value", (snapshot) => {
            const firebase_chats = Object.entries(snapshot.val());

            this.chatsTarget.innerHTML = "";

            for (let i = 0; i < firebase_chats.length; i++) {
                this.chatsTarget.innerHTML += `<p>${firebase_chats[i][1].content}</p>`
            }
        }, (error) => {
            console.log(error);
        })

    }

    submit() {
        database.ref(location.pathname).push({
            content: this.contentTarget.value
        });
        this.contentTarget.value = "";
    }
}

最後に、app/views/show.html.erbを以下のように変更してチャット機能を使用できるようにします

<p id="notice"><%= notice %></p>

<%= include_gon %>

<p>
  <strong>Title:</strong>
  <%= @room.title %>
</p>

<div data-controller="chat">
  <div data-target="chat.chats"></div>

  <input data-target="chat.content">
  <button data-action="click->chat#submit" data-action="click->chat#update">submit</button>
</div>

<%= javascript_pack_tag 'application' %>

<%= link_to 'Edit', edit_room_path(@room) %> |
<%= link_to 'Back', rooms_path %>

これでRails/Stimulusでのリアルタイムチャットは完成です!