Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Here Comes a Rails 5.1

y-yagi
March 25, 2017
1.8k

Here Comes a Rails 5.1

y-yagi

March 25, 2017
Tweet

Transcript

  1. MAJOR FEATURES Yarn Support Optional Webpack support jQuery no longer

    a default dependency System tests Encrypted secrets Parameterized mailers Direct & resolved routes Uni cation of form_for and form_tag into form_with
  2. YARN SUPPORT 下記対応が行われている bin/yarn stubの追加 assets path にnode_modulesを追加 assets:precompile task

    実行前にyarn installを実行 するよう対応 bin/yarn stub及び assets pathの追加はrails new時に 追加・設定されるので、既存のアプリを更新する場合は app:update task等により追加作業が必要
  3. YARN SUPPORT bin/yarn の中身はこんな感じ #!/usr/bin/env ruby VENDOR_PATH = File.expand_path('..', __dir__)

    Dir.chdir(VENDOR_PATH) do begin exec "yarnpkg #{ARGV.join(" ")}" rescue Errno::ENOENT puts "Yarn executable was not detected in the system." puts "Download Yarn at https://yarnpkg.com/en/docs/install" end end 一時node_modulesがvendor配下に置かれた時期もあ ったが、最終的にはRails root配下に置かれるようになって いる
  4. OPTIONAL WEBPACK SUPPORT rails newコマンドにwebpackオプションを指定する と、 をGem leに追加、及び、webpackerの install task(webpacker:install)が実行されるようになっ

    ている 引数にwebpackerがサポートしているJSのライブラリを指 定可能 webpacker rails new myapp --webpack=react この場合、上記ライブラリ用のinstall task(e.g. webpacker:install:react)も合わせて実行される
  5. JQUERY NO LONGER A DEFAULT DEPENDENCY 元々Railsはview helper用のJSの実装にjQueryを使って いた( )

    しかしもうjQueryを使う必要は無いだろう、という事で、 jQueryを使わず、素のJSだけで実装するよう変更された 変更後のライブラリ名はrails-ujs これによりデフォルトのスタックにはjQueryは含まれなくな ったので、引き続きjQueryを使いたい場合は明示的に依 存に追加する必要がある 因みにjquery-rails自体は引き続き使用出来る(メンテも まだされる) jquery-rails
  6. JQUERY NO LONGER A DEFAULT DEPENDENCY 因みにrails-ujsは色々議論された結果、Railsリポジトリの 中にソースが含まれた Action Viewの中にいる

    そのため、rails-ujsを使用するのに別途インストール等は 不要 PRの送り先は rails/railsなので注意 は消えるはず。多分。 rails/actionview/app/assets/javascripts · rails/rails rails/rails-ujs
  7. SYSTEM TESTS # test/application_system_test_case.rb require "test_helper" class ApplicationSystemTestCase < ActionDispatch::SystemTestCase

    driven_by :selenium, using: :chrome, screen_size: [1400, 1400] end # test/system/todos_test.rb require "application_system_test_case" class TodosTest < ApplicationSystemTestCase # test "visiting the index" do # visit todos_url # # assert_selector "h1", text: "Todo" # end end
  8. SYSTEM TESTS デフォルトでApplicationSystemTestCase という親クラス が生成されるようになっている driven_by メソッドでテストに使用するdriverを使用出来 る :rack_test、:selenium、:poltergeist selenium

    driverの場合のみbrowser、screen size、及 びその他Capybara::Selenium::Driverに渡すオプション を指定可能 テスト失敗時に自動でスクリーンショットをとってくれるよう になっている
  9. SYSTEM TESTS スクリーンショット取得処理は環境変数 (RAILS_SYSTEM_TESTING_SCREENSHOT)により挙動 が制御出来るようになっている 指定出来る値はinline(デフォルト。iTerm image protocol ( artifact

    format ( ) で表示)の3つ http://iterm2.com/documentation-images.html)で 表示。)、simple(スクリーンショットのファイルのパスだけ表 示)、artifact(terminal http://buildkite.github.io/terminal/inline-images/
  10. SYSTEM TESTS bin/rails test や bin/rake test ではデフォルトではSystem te が実行されないのでちょっと注意が必要

    System testsを行いたい場合は、bin/rails test:system タス や、test runnerにsystemディレクトリを指定する必要がある System testは遅いから通常のテストスイートと別buildにし うがよいから、とのこと https://github.com/rails/rails/pull/28286#issuecomm 284507788
  11. ENCRYPTED SECRETS まず secrets:setup コマンドでセットアップ処理を行う ./bin/rails secrets:setup Adding config/secrets.yml.key to

    store the encryption key: bf55aca3c137840f7 Save this in a password manager your team can access. If you lose the key, no one, including you, can access any encrypted secrets. create config/secrets.yml.key Ignoring config/secrets.yml.key so it won't end up in Git history: append .gitignore Adding config/secrets.yml.enc to store secrets that needs to be encrypted. create config/secrets.yml.enc
  12. ENCRYPTED SECRETS secrets:setup コマンドでは secrets.yml.key と secrets.yml.enc という2つのファイルが生成される secrets.yml.enc が暗号化されたデータが格納されている

    ファイル secrets.yml.key には secrets.yml.enc を暗号 / 復号処 理に使用するkeyが格納されている 当然keyは秘密情報になるので、デフォルトで gitignore にsecrets.yml.keyが追加される
  13. ENCRYPTED SECRETS 秘密情報を編集する為には、 secrets:edit コマンドを使用す る EDITOR="vim" bin/rails secrets:edit 秘密情報はymlで書ける

    # See `secrets.yml` for tips on generating suitable keys. # production: # external_api_key: 1466aac22e6a869134be3d09b9e89232fc2c2289…
  14. ENCRYPTED SECRETS secrets.yml.enc を読み込む為のkeyは secrets.yml.key に定義する以外に、環境変数 (ENV["RAILS_MASTER_KEY"])に設定する事が出来る secrets.yml.encの読み込み処理は con g.read_encrypted_secretsにtrueが設定されてい

    る時しか行われない read_encrypted_secrets は デフォルトはfalseなので、 注意が必要 正確には、新規に作成されたRailsアプリでは production envのみtrueが設定されている
  15. PARAMETERIZED MAILERS Before class InvitationsMailer < ApplicationMailer def account_invitation(inviter, invitee)

    @account = inviter.account @inviter = inviter @invitee = invitee subject = "#{@inviter.name} invited you to their Basecamp (#{@account mail \ subject: subject, to: invitee.email_address, from: common_address(inviter), reply_to: inviter.email_address_with_name end def bulk_project_invitation(projects, inviter, invitee) @account = inviter.account
  16. PARAMETERIZED MAILERS After class InvitationsMailer < ApplicationMailer before_action { @inviter,

    @invitee = params[:inviter], params[:invitee before_action { @account = params[:inviter].account } default to: -> { @invitee.email_address }, from: -> { common_address(@inviter) }, reply_to: -> { @inviter.email_address_with_name } def account_invitation mail subject: "#{@inviter.name} invited you to their Basecamp (#{ end def bulk_project_invitation @projects = params[:projects].sort_by(&:name) mail subject: "#{@inviter.name.familiar} added you to some new stuff in end
  17. DIRECT & RESOLVED ROUTES routing DSLにdirectとresolveというメソッドが追加されて いる directはrouting DSLで custom

    url helpersを定義する為 のメソッド resolveはrouting DSLでcustom polymorphic mappings定義する為のメソッド
  18. DIRECT & RESOLVED ROUTES direct Rails.application.routes.draw do direct :homepage do

    "http://www.rubyonrails.org" end direct :commentable do |model| [ model, anchor: model.id ] end direct :main do { controller: "page", action: "index" } end direct :browse, page: 1, size: 10 do |options| [ :products, options.merge(params.permit(:page, :size).to_h.symbolize_ke end end
  19. DIRECT & RESOLVED ROUTES direct homepage_path # => "http://www.rubyonrails.org" commentable_path(@user)

    # => "/users/2#1" main_path # => "/page/index" browse_path # => "/products?page=1&size=10"
  20. DIRECT & RESOLVED ROUTES resolve Rails.application.routes.draw do resource :basket resolve

    "Basket" do [:basket] end end # actionが`/baskets/:id` ではなく`/basket`になる <%= form_for @basket do |form| %> <!-- basket form --> <% end %>
  21. DIRECT & RESOLVED ROUTES resolve Rails.application.routes.draw do resource :basket #

    オプションも渡せる resolve "Basket", anchor: "items" do |basket, options| [:basket, options] end end # actionが`/basket#items`になる <%= form_for @basket do |form| %> <!-- basket form --> <% end %>
  22. UNIFICATION OF FORM_FOR AND FORM_TAG INTO FORM_WITH form_tag 的な使い方 <%=

    form_with url: posts_path do |form| %> <%= form.text_field :title %> <% end %> # => <form action="/posts" method="post" data-remote="true"> <input type="text" name="title"> </form>
  23. UNIFICATION OF FORM_FOR AND FORM_TAG INTO FORM_WITH form_for 的な使い方 <%=

    form_with model: Post.new do |form| %> <%= form.text_field :title %> <% end %> # => <form action="/posts" method="post" data-remote="true"> <input type="text" name="post[title]"> </form>
  24. UNIFICATION OF FORM_FOR AND FORM_TAG INTO FORM_WITH デフォルトでremote: trueになっている、id属性は出力し ないようになっている、等form_forと微妙にデフォルトの

    挙動が違う箇所があるのでちょっと注意が必要 form_for と form_tag は緩くdeprecateになっていく予 定です
  25. CHANGE THE ERB HANDLER FROM ERUBIS TO ERUBI. ERB Handlerで使用するgemがErubisから

    に変更さ れた 合わせて、Erubis Handlerはdeprecateになった。テンプレ ートエンジンでdeprecateメッセージが出てるとしたらおそ らくこの影響。 ほぼ機能互換はある為、ユーザが気にすることは殆ど無い はず Erubiの方が大分性能的に良いので、何もせずとも早くな る(かも) Erubi
  26. BETTER LOGGING OF CACHED PARTIAL RENDERS before Read fragment views/v1/2914079/v1/2914079/recordings/70182313-20160225015037

    Rendered messages/_message.html.erb in 1.2 ms Write fragment views/v1/2914079/v1/2914079/recordings/70182313-2016022501503 Rendered recordings/threads/_thread.html.erb in 1.5 ms after Rendered messages/_message.html.erb in 1.2 ms [cache hit] Rendered recordings/threads/_thread.html.erb in 1.5 ms [cache miss] 古いフォーマットを使用したい場合は con g.action_controller.enable_fragment_cache_loggin にtrueを設定すればOK
  27. NEW SYNTAX FOR TAG HELPERS before tag(:br, nil, true) content_tag(:div,

    content_tag(:p, "Hello world!"), class: "strong") <%= content_tag :div, class: "strong" do -%> Hello world! <% end -%> after tag.br tag.div tag.p("Hello world!"), class: "strong" <%= tag.div class: "strong" do %> Hello world! <% end %>
  28. ADD :SKIP_PIPELINE OPTION TO SEVERAL ASSET TAG HELPERS 各view用のhelper method(image_tagや

    javascript_include_tag等)に、asset pipelineを使用して いるかどうかを明示的に指定するためのオプション (skip_pipeline)を追加
  29. ADD :SKIP_PIPELINE OPTION TO SEVERAL ASSET TAG HELPERS asset_path("application.js") #

    => "/assets/application-85e543ffb6766161629d4b7a5dd540252230a0f0e5287de6701 asset_path("application.js", skip_pipeline: true) # => "/application.js"
  30. ADD :SKIP_PIPELINE OPTION TO SEVERAL ASSET TAG HELPERS 合わせて、helper methodに存在しないファイルを指定し

    た場合にexceptionをraiseするかどうかの設定 (con g.assets.unknown_asset_fallback)を追加 新規に作成するrailsアプリではfalse(exceptionをraise する)になってる 既存の挙動(exceptionをraiseしない)にしたい場合は、 trueを指定すればOK 参考:Deprecate asset fallback
  31. ADD RETRY_ON/DISCARD_ON FOR BETTER EXCEPTION HANDLING class RemoteServiceJob < ActiveJob::Base

    retry_on CustomAppException # デフォルトでは3秒waitし、5回再実行を行う retry_on AnotherCustomAppException, wait: ->(executions) { executions * retry_on ActiveRecord::StatementInvalid, wait: 5.seconds, attempts: retry_on Net::OpenTimeout, wait: :exponentially_longer, attempts: 10 # `exponentially_longer`を指定するとjobが失敗する毎にwait時間が長くなる(最初は3s, # 計算式は (executions ** 4) + 2) discard_on ActiveJob::DeserializationError def perform(*args) # ... end end
  32. MODULE#DELEGATE_MISSING before class Partition def initialize(first_event) @events = [ first_event

    ] end def people if @events.first.detail.people.any? @events.collect { |e| Array(e.detail.people) }.flatten.uniq else @events.collect(&:creator).uniq end end private def respond_to_missing?(name, include_private = false) @events.respond_to?(name, include_private) end
  33. MODULE#DELEGATE_MISSING after class Partition delegate_missing_to :@events def initialize(first_event) @events =

    [ first_event ] end def people if @events.first.detail.people.any? @events.collect { |e| Array(e.detail.people) }.flatten.uniq else @events.collect(&:creator).uniq end end end
  34. ADDS SUPPORT FOR LIMITS IN BATCH PROCESSING batch処理用のメソッド(# nd_in_batches、in_batches) でlimitが使えるようになった

    Post.limit(10_000).find_each do |post| # ... end batch_sizeオプションも引き続き使用出来る
  35. DEPRECATE THE BEHAVIOR OF AR::DIRTY INSIDE OF AFTER_(CREATE|UPDATE|SAVE) CALLBACKS after

    callbacks(after_create、after_update、 after_save)の中でActiveRecord::Dirtyのメソッド (#previous_changes、#changed?)等を使うのが deprecateになった
  36. DEPRECATE THE BEHAVIOR OF AR::DIRTY INSIDE OF AFTER_(CREATE|UPDATE|SAVE) CALLBACKS class

    User < ApplicationRecord after_save :post_processing def post_processing puts changed? end end User.create! # => DEPRECATION WARNING: The behavior of `changed?` inside of after callbac # => DEPRECATION WARNING: The behavior of `changed_attributes` inside
  37. DEPRECATE THE BEHAVIOR OF AR::DIRTY INSIDE OF AFTER_(CREATE|UPDATE|SAVE) CALLBACKS after

    callbackの中でdirtyメソッドを呼んだ時の挙動がユ ーザが想定している挙動と異なる Model.after_save { puts changed? }; model.save が model.save; puts model.changed? と同じ挙動に なる事を期待している事が多いようだが、実際は違う ユーザの混乱の元になる(この絡みのissueが多い)、という 事でdeprecateにしたとのことです
  38. DEPRECATE THE BEHAVIOR OF AR::DIRTY INSIDE OF AFTER_(CREATE|UPDATE|SAVE) CALLBACKS 現状のAPIとは別に、明示的に変更したattributesや、DB

    に保存されている値を取得するようのAPIが準備されるの で、そちらを使う必要があります 追加されたAPIについて、名前は変えるかもーという話も あったのですが、一旦今の状態で x(のはず) が、これらのAPIをpublic APIにするかどうかはまだ決ま ってなかった https://github.com/rails/rails/pull/28472
  39. POSTGRESQL & MYSQL: USE BIG INTEGER AS PRIMARY KEY TYPE

    FOR NEW TABLES 新規に作成するテーブルのprimary keyに、PostgreSQL は"bigserial"を、MySQLでは"bigint"をそれぞれ使用する ようになった 型を変更した事によるパフォーマンスの影響は無い為との 事 参考: 合わせて読みたい: "Postgres reminder: train yourself to use BIGSERIAL, and never SERIAL…" Restore the behaviour of the compatibility layer for integer-like PKs
  40. INTRODUCE NEW ACTIVERECORD TRANSACTION ERROR CLASSES serialization failureになった場合 ActiveRecord::SerializationFailure が、deadlockになっ

    た場合 ActiveRecord::Deadlocked がraiseされるよう修 正された 上のPRではエラークラス名が DeadlockDetected に なっているが、後から Deadlocked に変更されている The problem isn't the detection but the deadlock itself
  41. VIRTUAL/GENERATED COLUMN SUPPORT FOR MYSQL 5.7.5+ AND MARIADB 5.2.0+. migrationでMySQLのgenerated

    columns、及び、 MariaDBのvirtual columnsを使用出来るよう対応 virtualメソッドで定義出来るようになっている create_table :generated_columns do |t| t.string :name t.virtual :upper_name, type: :string, as: "UPPER(name)" t.virtual :name_length, type: :integer, as: "LENGTH(name)", stored: t.index :name_length # May be indexed, too! end
  42. REMOVE THE SCHEMADUMPER OPTIONS AND CHANGE THE DEFAULT BEHAVIOR create_table

    "address", force: :cascade do |t| t.string "zipcode", limit: 5 t.string "extra_information", limit: 255 end となっていたのが create_table "address", force: :cascade do |t| t.string "zipcode", limit: 5 t.string "extra_information", limit: 255 end となります
  43. DELEGATE TO SCOPE RATHER THAN MERGE! FOR COLLECTION PROXY collection

    proxyを生成する際に必ずassocation.scope の結果をmergeしていたのを、必要に応じて scope`(assocation.scope)にメソッド呼び出しをdelegate するようにして、不要な場合はassocationのscope呼び出 し、及びmerge処理を行わないよう修正 これにより、has_manyが大分高速化(単純なケースだと 170倍速くなっているとのこと)
  44. TRACK THE VERSION-COMPATIBLE CONFIG SETTINGS INSIDE RAILTIES 新規con g、かつ、非互換になる値の設定をrailtiesの中で 行うようになった

    Rails 5.0にあったnew_framework_defaults.rbという ファイルで行っていた内容 rails newで新規に作成したアプリではデフォルトで新しい 値が設定されるようになっている なお、自動で上記値の読み込みは行わない。 load_defaultsメソッドを呼び出す必要がある。 app:updateを実行した場合は、古い値が定義されている con gファイルが生成されるようになっている