Railsガイドにきちんと目を通して新しい知識を得る - Rails アプリケーションの設定項目編 -

ドキュメントを読み込むのは大事、ということでRailsガイドを頭から読んでいく取り組みをしています。 各章ごとに、(Railsガイドにちゃんと書いてあるのに)知らなかった機能を雑にまとめていきます。

今回は、Rails アプリケーションの設定項目の章です。

railsguides.jp

rails実行前にコードを実行する

リンクはこちら

require 'rails/all' の上に書くことで、Railsが読み込まれる前にプログラムを実行できるそうです。
あまりユースケースが思いつかないですが、いざという時はありそうなので覚えておきたいです。

Rails全般の設定

リンクはこちら

週初めの設定をconfig.beginning_of_weekで設定する

config.beginning_of_weekで週の初めを何曜日とするかを設定できます。

デフォルト設定の場合、例えばDate.today.beginning_of_weekだと、今日が属する週の月曜日の日付インスタンスを返します。
(日曜かなと思っていたのですが、月曜でした。)

これを、config.beginning_of_weekを設定することで変更できます。

# appllication.rb

config.beginning_of_week = :wednesday
Date.today.beginning_of_week
#=> Wed, 14 Feb 2024

config.colorize_loggingでログの出力に色付けをする

これも設定になっていたとは知りませんでした。
falseにしたら確かにSQLクエリログなどに色がつかなくなりました。

config.disable_sandboxでsandboxの利用をさせない

sandbox環境の制限ができるのも知りませんでした。
データベースサーバーのメモリが枯渇するのを避けるうえで有用とのことです。
一方で、プログラムが問題なく動くか、や間違って更新しても安心なようにsandbox環境を使うことは多いと思うので、なかなか判断が難しいところですね。

これをtrueにしたところ、--sandboxオプションをつけてrailsコンソールを起動するとエラーが表示されるようになりました。

$ rails c --sandbox
Error: Unable to start console in sandbox mode as sandbox mode is disabled (config.disable_sandbox is true).

config.enable_reloadingでクラス等の変更時、リクエストごとに再読み込みするかどうかを決める

開発環境でコードの修正がリロードで反映されるのはconfig.enable_reloadingがtrueになっているからでした。
デフォルト設定では、production環境ではfalseというのも覚えておくべきだなと思いました。

config.sandbox_by_defaultでデフォルトをsandbox環境にする

Rails7.1から入った機能です。
config.sandbox_by_defaultをtrueにすると、railsコンソールがデフォルトでsandbox環境になります。
本番環境での事故防止に良さそうです。

手元の環境で試そうとしたら、trueに設定してもsandbox環境にならず、調べたところ、developmentとtestではこのオプションは無視されるとのことでした。

Note that this option is ignored when rails environment is development or test.

github.com

ActiveRecordを設定する

リンクはこちら

config.active_record.partial_inserts

trueにすると、createをしたときなどに、DBデフォルト値に対してはINSERTで値が送られなくなります。

設定をtrueにして、以下のbooksテーブルで試してみました。

カラム名 デフォルト値
title string 'デフォルトタイトル'
content string (設定なし)
Book.create
#=> INSERT INTO "books" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id"  [["created_at", "2024-02-18 ..."], ["updated_at", "2024-02-18 ..."]]

titleとcontentには確かにINSERTで値が指定されていません。
それぞれ'デフォルトタイトル'という文字列とnilが登録されていました。

こちらはRails7.0でデフォルトがfalseに変更されたそうです。
理由が気になって見てみたら、PRの方で以下の旨が挙げられていました。

  • ignored_columns機能が導入されたことにより、カラムを安全に削除する、より信頼性のある方法が生まれたこと
  • クエリサイズを減らすことの利点はそれほど大きなものではなくなった

github.com

active_record.before_committed_on_all_records

Rails7.1からのオプションです。

トランザクションに登録されているすべてのレコードに対して、before_committed!コールバックを有効にします。

上記の意味が最初よくわからなかったですが、試したらわかりました。

class Book < ApplicationRecord
  before_commit -> { p "title: #{title}" }
end

上記のように適当にbefore_commitを設定し、設定をfalseにします。

ActiveRecord::Base.transaction do
  book = Book.first
  book_2 = Book.first
  book.update(title: 'abc')
  book_2.update(title: 'def')
end

#=> "title: abc"

一方で、trueにした場合、pメソッドで出力される値は"title: def"になります。

これを見ると、falseにした場合、トランザクション内で同じレコードに対して複数回処理をした場合に、before_commitで見るのは最初に更新された方ということがわかりました。

ActionControllerを設定する

リンクはこちら

raise_on_open_redirectsでオープンリダイレクト脆弱性の対策を強化する

うっかりオープンリダイレクト脆弱性が紛れてしまった場合に、リダイレクト先が外部ホストの場合は例外を出してくれます。

例えば適当なコントローラで以下のように設定し、アクセスするとActionController::Redirecting::UnsafeRedirectErrorという例外が発生します。

allow_other_host: trueをつければ外部ホストへのリダイレクトが可能になる、というように回避策も用意されているので、基本はtrueで良さそうに思いました。

def index
  redirect_to 'http://example.com'
end