はじめに
Rails 6 に追加された新機能を試す第109段。 今回は、while_preventing_writes 編です。
Rails 6 では、 while_preventing_writes
が追加されました。
multi-db 関連のメソッドで、 while_preventing_writes のブロック内では、 DBへの書き込みができません。
同じDBに対してDBのConnection を別に作成しても書き込みはできないようになっています。
Ruby 2.6.5, Rails 6.0.0 で確認しました。
$ rails --version
Rails 6.0.0
今回は、簡単なスクリプトを作って確認します。
Rails プロジェクトを作成する
$ rails new rails_sandbox
$ cd rails_sandbox
User モデルを作成する
User
モデルを作成します。
$ bin/rails g model User name
User モデルを編集する
User モデルのDBの Connection を ActiveRecord::Base.connection
とは別になるように変更します。
class User < ApplicationRecord
connects_to database: { writing: :primary, reading: :primary }
end
動作確認のスクリプトを作成する
ActiveRecord::Base.connection
と User.connection
が違うことを確認し、 while_preventing_writes
のブロック内では、DBへの書き込みができないことを確認します。
puts User.count
if ActiveRecord::Base.connection.object_id != User.connection.object_id
puts 'ActiveRecord::Base.connection != User.connection'
end
# ActiveRecord::Base.connection.while_preventing_writes do # Rails 6.0.0.rc1
ActiveRecord::Base.connection_handler.while_preventing_writes do # Rails 6.0.0
User.create!(name: 'Taro')
end
puts User.count
マイグレーションを実行する
$ bin/rails db:create db:migrate
スクリプトを実行する
スクリプトを実行します。 Write query attempted while in readonly mode:
のメッセージが出力され、書き込みが失敗することがわかります。
$ bin/rails runner scripts/while_preventing_writes.rb
Running via Spring preloader in process 81
0
ActiveRecord::Base.connection != User.connection
Traceback (most recent call last):
...
/usr/local/bundle/gems/activerecord-6.0.0/lib/active_record/connection_adapters/postgresql_adapter.rb:643:in `execute_and_clear': Write query attempted while in readonly mode: INSERT INTO "users" ("name", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id" (ActiveRecord::ReadOnlyError)
ちなみに
Rails 6.0.0rc1 では、エラーにならず、保存できてしまいます。(6.0.0rc1 では、メソッドの定義場所が異なるため、 ActiveRecord::Base.connection.while_preventing_writes
とする必要があります。)
試したソース
試したソースは以下にあります。
https://github.com/suketa/rails_sandbox/tree/try109_while_preventing_writes