Slide 1

Slide 1 text

RAILS 6.0 MAJOR FEATURES RAILS 6.0 MAJOR FEATURES [email protected]

Slide 2

Slide 2 text

この資料について この資料について Rails 6.0のMajor Featuresについて記載したものです 資料は5/20日時点の情報を元に作成しています

Slide 3

Slide 3 text

MAJOR FEATURES? MAJOR FEATURES? リリースアナウンスで大々的にうたわれている機能 https://weblog.rubyonrails.org/2019/1/18/Rails-6-0-Action-Mailbox- Action-Text-Multiple-DBs-Parallel-Testing/

Slide 4

Slide 4 text

MAJOR FEATURES MAJOR FEATURES Action Mailbox Action Text multiple database Parallel Testing Webpacker default Zeitwerk

Slide 5

Slide 5 text

ACTION MAILBOX ACTION MAILBOX メールの受信処理を行う為のライブラリ Ginzarbでは以前取り上げているので詳細は割愛 その時の資料 Rails Guideもあるよ https://gist.github.com/y- yagi/25171f5b6bb24d320ee69517fa7fdebf# le-02_action_mailbox-md https://edgeguides.rubyonrails.org/action_mailbox_basics.html

Slide 6

Slide 6 text

前回からのアップデート 前回からのアップデート Amazon SESのサポートが削除された [Remove the Amazon SES ingress] そもそもバグってて正しく動作してなかった 修正が6.0に間に合わなくて為機能自体が削除された 6.1でサポート予定 https://github.com/rails/rails/pull/35972

Slide 7

Slide 7 text

ACTION TEXT ACTION TEXT リッチテキストの編集・表示を行う為のライブラリ こちらもGinzarbでは以前取り上げているので詳細は割愛 その時の資料 Rails Guideもあるよ https://gist.github.com/y- yagi/25171f5b6bb24d320ee69517fa7fdebf# le-01_action_text-md https://edgeguides.rubyonrails.org/action_text_overview.html

Slide 8

Slide 8 text

前回からのアップデート 前回からのアップデート テスト用のヘルパーメソッドが(masterに)追加された [Add ActionDispatch::SystemTestCase# ll_in_rich_text_area] ll_inを使っても入力出来ないので注意してね https://github.com/rails/rails/pull/35885

Slide 9

Slide 9 text

MULTIPLE DB MULTIPLE DB 複数DBサポート 設定ファイルへの複数DBの定義、及び、接続先DBを切り替える為 のAPIを提供 接続先毎にマイグレーションファイルを変える事も出来る シャーディングサポートは(まだ)ない

Slide 10

Slide 10 text

設定ファイル例 設定ファイル例 development: primary: <<: *default database: db/my_primary_db.sqlite3 primary_replica: <<: *default database: db/my_primary_replica_db.sqlite3 replica: true animals: <<: *default database: db/animals.sqlite3 migrations_paths: "db/animals_migrate"

Slide 11

Slide 11 text

MULTIPLE DB MULTIPLE DB connected_toで接続先を指定出来る 未指定の場合は設定ファイルで最初に定義された接続先 User.first # => `primary` DBにアクセス ActiveRecord::Base.connected_to(database: :animals) { Monkey.f # => `animals` DBにアクセス

Slide 12

Slide 12 text

MULTIPLE DB MULTIPLE DB レプリカに対して書き込みを実行するとエラーになる レプリカかどうかは設定ファイルのreplica keyで決まる ActiveRecord::Base.connected_to(database: :primary_replica) { # => ActiveRecord::ReadOnlyError (Write query attempted while

Slide 13

Slide 13 text

READONLY READONLY adapter毎に"READ"とみなすQUERYを定義して、それ以外は全て書 https://github.com/rails/rails/blob/3363a3c2a54ab1796f1a52 https://github.com/rails/rails/blob/3363a3c2a54ab1796f1a52 https://github.com/rails/rails/blob/3363a3c2a54ab1796f1a52

Slide 14

Slide 14 text

MULTIPLE DB MULTIPLE DB モデルで接続先を指定出来る class Monkey < ApplicationRecord connects_to database: { writing: :animals } end Monkey.first # => `animals` DBにアクセス

Slide 15

Slide 15 text

MULTIPLE DB MULTIPLE DB connects_toにはロールとDB名のHashを指定する DB名は設定ファイルで記載した名前 ロールは接続先を識別するための値 任意の値を指定でき、その値をconnected_toに指定出来る connects_to database: { writing: :animals }

Slide 16

Slide 16 text

MULTIPLE DB MULTIPLE DB class Monkey < ApplicationRecord connects_to database: { wr: :animals } end ActiveRecord::Base.connected_to(role: :wr) { Monkey.first }

Slide 17

Slide 17 text

MULTIPLE DB MULTIPLE DB Railsはデフォルトで書き込み用のロールとしてwriting、読み込み 用のロールとしてreadingという名前を使用している ロール名は変更可能 このロール名は後で説明するRackミドルウェアで使用される ActiveRecord::Base.reading_role # => :reading ActiveRecord::Base.writing_role # => :writing ActiveRecord::Base.reading_role = :readonly ActiveRecord::Base.writing_role = :default ActiveRecord::Base.reading_role # => :default ActiveRecord::Base.writing_role # => :readonly

Slide 18

Slide 18 text

MULTIPLE DB MULTIPLE DB connected_toとconnects_toを使えば接続先を切り替えられる しかし処理毎にいちいち接続先を指定するのは面倒だよね?

Slide 19

Slide 19 text

MULTIPLE DB MULTIPLE DB 自動で接続先を切り替えるためのRackミドルウェアが提供されて いる HTTPメソッドがGET、または、HEADの場合に自動でレプリカを、そ れ以外のrequestの場合はプライマリーに接続してくれる GETでdestoryとかしちゃだめですよ レプリカに同期されるまでの時間を考慮し、最後のwrite処理から2 秒未満の場合、GET / HEAD場合もプライマリーが使用される 同期までの時間や接続先の選択するロジックはカスタマイズ可能

Slide 20

Slide 20 text

MULTIPLE DB MULTIPLE DB config.active_record.database_selector = { delay: 2.seconds } config.active_record.database_resolver = ActiveRecord::Middlew config.active_record.database_resolver_context = ActiveRecord:

Slide 21

Slide 21 text

MULTIPLE DB MULTIPLE DB 接続先の指定はロールで行う デフォルトの場合、書き込み処理はwriting、読み込み処理はreadingというロー ルが使用される connects_toでそれぞれのロールで使用するDBを指定する必要がある class ApplicationRecord < ActiveRecord::Base self.abstract_class = true connects_to database: { writing: :primary, reading: :primary end

Slide 22

Slide 22 text

デモ? https://github.com/y-yagi/m_db_p

Slide 23

Slide 23 text

RAKE TASK RAKE TASK 各種DB用のtask(db:create、db:migrate等)は処理を行いたい DB名を末尾に指定出来るようになっている DB名を指定しない場合全てのDBに対してtaskは実行される rails db:create # Creates the databas rails db:create:animals # Create animals data rails db:create:primary # Create primary data rails db:drop # Drops the database rails db:drop:animals # Drop animals databa rails db:drop:primary # Drop primary databa rails db:migrate # Migrate the databas rails db:migrate:animals # Migrate animals dat rails db:migrate:primary # Migrate primary dat

Slide 24

Slide 24 text

MULTIPLE DB対応PR MULTIPLE DB対応PR 関連するPR Part 1 Easy Multi db in Rails: Add basic rake tasks for multi db setup Part 2: Multi-db improvements, Refactor Active Record con gurations Part 3: Multi-db Improvements, identifying replica con gurations Part 4: Multi db improvements, Basic API for connection switching Part 5: Multi db improvements, Fix query cache for multiple connections Part 6: Multi db improvements, Make connection handler per thread instead of per ber Part 7: Multi db improvements, Add ability to block writes to a database Part 8: Multi db improvements, Adds basic automatic database switching to Rails Add ability to change the names of the default handlers For xtures share the connection pool when there are multiple handlers

Slide 25

Slide 25 text

PARALLEL TESTING PARALLEL TESTING 名前の通りテストを並列で実行する為の仕組み 指定した数だけテストを実行するワーカが作成され、そのワーカ毎 にテストが実行される 並列処理用のメソッド(parallelize)を使用するだけでテストが並列 で実行される

Slide 26

Slide 26 text

PARALLEL TESTING PARALLEL TESTING class ActiveSupport::TestCase # Run tests in parallel with specified workers parallelize(workers: :number_of_processors, with: :processes end

Slide 27

Slide 27 text

PARALLEL TESTING PARALLEL TESTING テストを実行するワーカの数はworkers引数で指定する number_of_processorsという値を指定した場合自動でマシンのコア数の値 を指定してくれる ワーカはプロセス / スレッドを選択可能 プロセスの生成にはforkを使用する為、forkが使用出来ない環境ではスレッド を使用する必要がある プロセス間のデータの連携にはdRubyが使用されている

Slide 28

Slide 28 text

プロセス プロセス プロセスを指定した場合とスレッドを指定した場合とでテスト実行 時の挙動が幾つか異なる プロセスの場合、ワーカ作成後そのワーカで使用するDBの作成& セットアップを行い、テストではその作成したDBを使用する そのため、ワーカがそれぞれ違うDBを使う DBはテスト終了後の後処理で削除される

Slide 29

Slide 29 text

スレッド スレッド スレッドでは特に細工は無く同じDBを使用する Rails 6.0.0.rc1の時点で、ワーカにスレッドを指定した場合システム テストが正しく動作しないという制限がある (あと xturesを使用している場合の挙動が怪しい感が)

Slide 30

Slide 30 text

PARALLEL TESTING PARALLEL TESTING Parallel Testingはがっつりminitestに依存している 元々minitestにParallel Testingのための機能がありそれを使用している minitest/hell ワーカにスレッドを使用した場合の実装はminitestの機能そのまま Railsではワーカにプロセスを使用した場合の実装が提供されている そのため、RSpecユーザがそのまま使用出来るような機能ではない Add support for Rails 6 built-in Parallel Testing( ) https://github.com/seattlerb/minitest/blob/master/lib/minitest/hell.rb https://github.com/rspec/rspec- rails/issues/2104

Slide 31

Slide 31 text

WEBPACKER WEBPACKER JavaScriptの管理にデフォルトでWebpackerが使用されるように なった rails newするとwebpacker:installも実行される JSフレームワークは未指定状態

Slide 32

Slide 32 text

WEBPACKER WEBPACKER Rails内のgeneratorが生成するコードがCo eeScriptから JavaScriptを使用したコードに変更 生成されるアプリはCo eeScriptから遂にさよなら (Rails内部のコードにはまだ残っている) rails-ujsやAction Cable等のRails内のJavaScriptライブラリを npmで公開されているライブラリを使用するよう変更

Slide 33

Slide 33 text

WEBPACKER WEBPACKER WebpackerはJavaScriptのビルドにのみ使用されるようになって いる スタイルシートや画像等のJavaScript以外のアセットの管理Sprocketsが使用 されるようになっている DHH的にはWebpackで画像やスタイルシートの管理をするメリッ トはあんま無いのでは、との事 Make Webpacker the default JavaScript compiler for Rails 6 by dhh · Pull Request #33079 · rails/rails

Slide 34

Slide 34 text

WEBPACKER WEBPACKER デフォルトでセットアップが行われるようになっただけで、 Webpacker向けの特別な設定がRails側に入った訳ではない Webpackerを使いたくない場合はrails newに--skip-javascript オプションを指定してね 似たようなオプションに--skip-webpack-installオプションもあるがこれは webpacker:installがスキップされるだけでwebpacker自体は追加される 「こういうオプションがあると助かる」みたいなのがあったらPRください

Slide 35

Slide 35 text

ZEITWERK ZEITWERK 発音がしずらい新たなcode loader Zeitwerk: A new code loader for Ruby eager loadとかautoloadを良い感じにしてくれるやつ https://medium.com/@fxn/zeitwerk-a-new-code-loader-for-ruby- ae7895977e73 https://github.com/fxn/zeitwerk

Slide 36

Slide 36 text

ZEITWERK ZEITWERK 元々のcode loaderはconst_missingを元にした実装になってい た ただ、const_missingだとネスト等の情報が取得出来ず、Rubyの load処理と異なる挙動になっていた ネストしたクラス / モジュールを定義する際に問題になっていた

Slide 37

Slide 37 text

ZEITWERK ZEITWERK vs module Admin class UsersController < ApplicationController def index @users = User.all end end end class Admin::UsersController < ApplicationController def index @users = User.all end end

Slide 38

Slide 38 text

ZEITWERK ZEITWERK 他にもSTIを使っている場合に問題になってたりしていた 既知の問題たち: https://guides.rubyonrails.org/v5.2/autoloading_and_reloading_constan gotchas

Slide 39

Slide 39 text

ZEITWERK ZEITWERK それらの問題を解決する為に作成されたのがZeitwerk const_missingではなくModule#autoloadを元にした実装にな っている TracePoint大活躍 元々ShopifyがModule#autoloadを元にしたgemを実験的に作 っていて、それを元にしている https://github.com/Shopify/autoload_reloader

Slide 40

Slide 40 text

ZEITWERK ZEITWERK 従来のcode loaderと異なり、Zeitwerk自体はRailsに依存してい ない Rails以外のプロジェクトでcode loaderとしてZeitwerkを使う事も可能 Rails側でZeitwerkを使う為の機能を保持している

Slide 41

Slide 41 text

ZEITWERK ZEITWERK Zeitwerkを使用したcode loaderの登場によりcode loaderが2 種類になった デフォルトでは元のcode loader(classic autoloaderと呼ばれて いる) Zeitwerkを使用するにはload_defaultsに6.0を指定する or con g.autoloaderに:zeitwerkを指定する ZeitwerkはJRuby未サポートらしく、JRubyの場合load_defaultsに6.0を指 定してもclassic autoloaderが使用される

Slide 42

Slide 42 text

ZEITWERK ZEITWERK or config.load_defaults 6.0 config.autoloader = :zeitwerk

Slide 43

Slide 43 text

ZEITWERK ZEITWERK 名前解決の挙動が違うので、classic autoloaderとzeitwerk autoloaderは完全に互換性があるわけではない アプリの構造がzeitwerk autoloaderで正しくロード出来るかどう かをチェックする為のタスクが提供されている $ bin/rails zeitwerk:check

Slide 44

Slide 44 text

ZEITWERK ZEITWERK STIのケースは自動では解決出来ない preload用のAPIが提供されているので、それをユーザ側で使用す る必要がある sti_leaves = %w( app/models/leaf1.rb app/models/leaf2.rb app/models/leaf3.rb ) Rails.autoloaders.main.preload(sti_leaves)

Slide 45

Slide 45 text

ZEITWERK ZEITWERK Ruby 2.5でiseq cache + TracePointの挙動があやしい Ruby 2.6では大丈夫 Ruby 2.5でiseq cacheを活用しているライブラリとの相性があや しい ようはbootsnap bootsnapは1.4.4以上だとRuby 2.5でiseq cacheを無効化するよ うにしている Disable iseq cache in Ruby 2.5 https://github.com/Shopify/bootsnap/pull/257

Slide 46

Slide 46 text

ZEITWERK ZEITWERK cache_classes = trueの場合reload処理は動作しない(エラーにな 元々con g/environments/test.rbではache_classes = trueだった だとSpringを使用している場合に問題がおきる Springがコードをreloadするが上記制限によりエラーになる テスト環境でSpringを使用している場合cache_classes = falseを指 要がある generate con g.cache_classes = false if Spring https://github.com/rails/rails/commit/65344f254cde87950c7f176cb7aa0

Slide 47

Slide 47 text

まとめ まとめ 頑張ってRailsのバージョンあげていきましょう