1日マスクをしているとなぜか頭痛と肩こりがひどい@mikedaです。
最近rubocopのRails/BulkChangeTableを有効にしたのですが、
- 開発環境とCI環境(CircleCI)で挙動が違う
- 有効にしているはずなのにCopが動かない
という問題が発生したので、原因と対応についてまとめておきます。
Rails/BulkChangeTableについて
Railsのmigrationで1つのテーブルについて複数の操作をする時に、このように個別に書くのではなく、
class AddHogeToUsers < ActiveRecord::Migration[6.0] def change add_column :users, :hoge, :string add_column :users, :fuga, :integer end end
change_tableにbulk: true
オプションをつけてまとめましょう、というCopです。
class AddHogeToUsers < ActiveRecord::Migration[6.0] def change change_table :users, bulk: true do |t| t.string :hoge t.integer :fuga end end end
こうすることで個別に実行されていたALTER文が
ALTER TABLE `users` ADD `hoge` varchar(255) ALTER TABLE `users` ADD `fuga` int
まとめて実行されるようになって処理が高速化されます。
ALTER TABLE `users` ADD `hoge` varchar(255), ADD `fuga` int
守れてないとこういうエラーが表示されます。
% bundle exec rubocop db/migrate/20200529235237_add_hoge_to_users.rb Inspecting 1 file C Offenses: db/migrate/20200529235237_add_hoge_to_users.rb:3:5: C: Rails/BulkChangeTable: You can use change_table :users, bulk: true to combine alter queries. add_column :users, :hoge, :string ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 1 file inspected, 1 offense detected
起こった問題
BulkChangeTableは、database.ymlのdevelopmentのadapter設定がmysql2かpostgresqlの時だけ有効になります。
そのため、
- CI用のdatabase.ymlにdevelopment設定がない
- database.ymlがERBファイルになっている
といった場合に、Copが適切に有効化されない問題が起こりました。
詳細な挙動はドキュメント、ソースコードを参照ください。
CI用のdatabase.ymlにdevelopment設定がない
開発環境とCI環境で別のdatabase.ymlを使っていて、CI環境ではtestの定義しか書かれていない場合、database.ymlにdevelopmentの定義がないためCopが有効化されません。
例)
test: adapter: mysql2 database: test username: root password: root host: 127.0.0.1
database.ymlがERBファイルになっている
環境変数によって挙動を切り替える等の理由でdatabase.ymlをERB化している場合、BulkChangeTableはdatabase.ymlを正常に読み込めないためCopが有効化されません。
例)
development: adapter: mysql2 database: development username: root <% if ENV['LOCAL_DB'] %> password: socket: /tmp/mysql.sock <% else %> password: root host: 127.0.0.1 <% end %>
どうすれば良いのか
上記の問題が起こらないようにdatabase.ymlを調整してもいいですが、.rubocop.ymlでdatabaseを明記してあげるのが簡単かつ確実そうです。
Rails/BulkChangeTable: Database: mysql