Ruby on Rails 8.0 を試してみた

2024-11-26 ruby rails /posts/2024/2024-11-09-ruby-on-rails.png

Railsもいよいよバージョン8に!ということでリリース記事から抜き出した、 以下の特徴を実際に検証してみました。

個人的にはSQLiteがproductionでも使っていいよ、となったのが嬉しい部分かも。 なんとなく敷居の高かったActionCableも一段と使いやすくなってるはず?7.2での実装例を参考にしながら、ちょっと試してみます。

[検証1]SQLiteでどこまでいけるのか?

まずは普通にscaffoldとchannelを作ります。

rails new myapp
cd myapp
rails g scaffold message body
rails db:create db:migrate
rails g channel notification

以前はここで、cable.ymlを弄ってadapterの設定をしていましたが、デフォルトのasyncのまま進みます。

app/channels/notification_channel.rb を開いて、stream_fromを以下のように書き換えます。

stream_from "notification_channel"

今回はレコードが作成、更新、削除される度に更新を通知したいと思います。app/controllers/rooms_controller.rbcreate update destroy アクション内に以下の行を追加します。

ActionCable.server.broadcast "notification_channel", {content: @message}

通知を受け取った際に行いたい処理を app/javascript/channels/notification_channel.js の received メソッド内に記述します。 パフォーマンスの観点からは、更新が必要な箇所だけ書き換える方が望ましいですが、ページ全体をリロードしちゃってます。

if (location.pathname == "/messages"){
    location.reload();
}

準備はこれだけです。 一つ目のタブで メッセージの一覧 (/messages) を開いておいて、別のタブで新規作成フォーム(/messages/new)を開いて何か入力してみると、最初のウィンドウに更新内容が(ページをリロードしなくても)表示されるはずです!

new message

list of messages

さて、これを実際にVPSサーバなどに配備して公開するとどうなるんでしょう?プロジェクト一式をサーバに転送して以下の手順で立ち上げてみました。注意点としては、productionのデータベースもstorageフォルダに作成されるので、ここを永続化しておかないと(=例えばcapistranoやherokuみたいなアプリを全部置き換えるようなデプロイ方法を採用してると)バージョンアップの度にデータが全部消えてしまいます。

rm -r storage && ln -s ../storage # ここは環境によって全然違うので参考程度に
export RAILS_ENV=production
bundle install
rails db:setup
rails assets:precompile

小規模なシステムなら、時々 storage にスナップショット(ダンプファイルとか)でも置いておけば一箇所で管理できるので便利そうです(ActiveStorageのリソースもここに置く場合)。

これでバッチリ!かと思いきやRailsとは関係ない制約に引っかかって残念ながら公開できるデモは作れませんでした😅

時間ができたらPumaを単体で動かして公開してみようかなと思います。

[検証2]認証機能を作ってみる

続いて、認証機能の作成支援も試してみます(Devise卒業できるのか?)。

rails g authentication

connection.rbでコンフリクトを起こしますが、上書きして進みます。 データベースのマイグレーションファイル(yymmdd_create_users.rb)を編集して、ユーザに持たせたい情報を追加します。 以下は名前を格納する列を定義する例です。

t.string :name, null: false, default: ''

編集が終わったらテーブルを作成します。

rails db:migrate

サンプルのユーザも作成します。これはrails cで起動したコンソール上で実行してください。

User.create(email_address: "test@lmlab.net", password: "secret")

デフォルトでは認証完了後にトップページ(rootで定義されたパス)にリダイレクトするので、config/routes.rb に以下の設定を追加します。

root "messages#index"

代わりに app/controllers/concertns/authentication.rb の中の after_authentication_url を編集して任意のページに遷移させることも可能です。

sign in dialog

ビューの中では以下のようにログイン状態や現在のユーザ情報などを取得することが可能です(authentication.rbに記述あり)。

<% if authenticated? %>
  <p>Signed in as <%= Current.session.user.email_address %>
    <%= button_to "Sign out", session_path, method: :delete %>
  </p>
<% end %>

認証が必要ないアクションは以下ようにコントローラに宣言することが可能です(skip_before_action :require_authenticationでも多分OK)。

allow_unauthenticated_access only: %i[ index show ]

[検証3]Propshaftとは?

Sprocketsに変わってデフォルトになったらしいpropshaft。誤解をおそれずざっくりまとめると、新しいHTTPプロトコルとかフロント側(JavaScript)の管理ツールが充実してきたので、必要最低限のリソース管理に立ち戻った、という感じでしょうか。

digestの付与がちょっとスッキリしていて良い感じ。

<%= image_tag 'Ruby_logo.png' %>
↓ 
<img src="/assets/Ruby_logo-69c59d4c.png" />

SCSSとか入れなくても、普通のCSS内のリソースもよしなに扱ってくれてる様子です。これは助かる…!

background-image: url("Ruby_logo.png");
↓
background-image: url("/assets/Ruby_logo-69c59d4c.png");

using assets