Railsにこれから初めて触れる方を対象にしたチュートリアルです
Rails/Stimulus/FireBaseを使用して、リアルタイムにやり取りができるチャットアプリを作成します
まずは、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
先ほどrails newでsqlite3のインストールがエラーになっている場合は、以下のようにバージョンを修正します
gem 'sqlite3', '1.3.13'
bundle installを実行します
bundle install
Webpackerを使用する場合、ruby ./bin/webpack-dev-serverを実行しつつ、rails sでローカルサーバーを起動する必要があります
その為、現状のままではターミナルを複数開いておく必要があり、少々面倒です
そこで、複数のコマンドを並列して実行できるforemanを使用します
まず、Gemfileにgem '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へと変更されています)
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-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.rbのshowアクションを以下のようにします
  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でのリアルタイムチャットは完成です!