Rails 5.1: upcoming features

Rails 5.1: upcoming features

Presented at RailsConf, April 2017

------------------- BREAKING CHANGES -------------------------

Change Action View ERB handler from Erubis to Erubi
https://github.com/rails/rails/pull/27757

Deprecate String options :if and :unless to set/skip callbacks
https://github.com/rails/rails/commit/0952552

Deprecate :action and :controller path parameters
https://github.com/rails/rails/pull/23980

------------------- ACTIVE RECORD -------------------------

Add ActiveRecord::Base. connection_pool.stat
https://github.com/rails/rails/pull/26988

Change default primary keys to BIGINT
https://github.com/rails/rails/pull/26266

Virtual column support for MySQL and MariaDB
https://github.com/rails/rails/commit/65bf1c6

Adds support for limits in batch processing
https://github.com/rails/rails/commit/451437c

------------------- ACTIVE SUPPORT -------------------------

Update Unicode version to 9.0.0
https://github.com/rails/rails/pull/27822

DateTime#change supports :usec and :nsec options
https://github.com/rails/rails/pull/28242

Add Duration#after and #before as alias for #since and #until
https://github.com/rails/rails/pull/27721

Introduce Module#delegate_missing_to
https://github.com/rails/rails/pull/23930

------------------- ACTION VIEW -------------------------

Add option :check_parameters to current_page?
https://github.com/rails/rails/pull/27549

New syntax for Action View’s tag helpers
https://github.com/rails/rails/pull/25543

Add form_with to unify form_tag and form_for
https://github.com/rails/rails/pull/26976

------------------- RAILTIES -------------------------

Display railtie class name in "rails initializers"
https://github.com/rails/rails/pull/25257

Added a shared section to config/secrets.yml
https://github.com/rails/rails/commit/e530534

Add encrypted secrets in config/secrets.yml.enc
https://github.com/rails/rails/pull/28038

Drop jQuery as a dependency and include rails-ujs
https://github.com/rails/rails/pull/27113

Add Yarn support in new apps using --yarn option
https://github.com/rails/rails/pull/26836

Basic --webpack delegation to new webpacker gem
https://github.com/rails/rails/pull/27288

------------------- ACTION PACK -------------------------

Capybara integration with Rails (AKA System Tests)
https://github.com/rails/rails/pull/26703

Custom URL helpers and polymorphic mapping
https://github.com/rails/rails/pull/23138

------------------- ACTIVE JOB -------------------------

Add retry_on/discard_on for better exception handling
https://github.com/rails/rails/pull/25991

------------------- ACTION MAILER -------------------------

Add parameterized invocation of mailers
https://github.com/rails/rails/pull/27825

0722f1ff8d0a69bce57ebdb93dafc395?s=128

Claudio B.

April 13, 2017
Tweet

Transcript

  1. 2.

    Rails 5.1: awesome features & breaking changes $ git log

    v4.2.0..v5.0.0 # => 18 months # => 962 authors # => 9,998 commits $ git log v5.0.0..v5.1.0.rc2 # => 9 months # => 450 authors # => 4,065 commits 5.0 5.1
  2. 4.

    PR 27757 by Jeremy Evans Change Action View ERB handler

    from Erubis to Erubi Breaking change
  3. 5.

    commit 0952552 by Ryuta Kamizono Deprecate String options :if and

    :unless to set/skip callbacks Breaking change
  4. 6.

    Deprecate String options to set/skip callbacks class Post < ApplicationRecord

    before_save :set_no_title, unless: 'title.present?' skip_callback :save, :before, :set_no_title, if: 'persisted?' private def set_no_title self.title = 'No title' end end 5.0
  5. 7.

    Deprecate String options to set/skip callbacks class Post < ApplicationRecord

    before_save :set_no_title, unless: -> { title.present? } skip_callback :save, :before, :set_no_title, if: :persisted? private def set_no_title self.title = 'No title' end end 5.1
  6. 9.

    Deprecate :action and :controller path parameters # config/routes.rb get ':controller(/:action(/:id))'

    [CVE-2014-0130] Directory traversal vulnerability (4.1.1, 4.0.5) [CVE-2015-7581] Object leak vulnerability (4.2.5, 4.1.13) # config/routes.rb get ':controller(/:action(/:id))' # deprecated get 'photos(/:id)', to: :display # acceptable 5.0 5.1
  7. 13.

    Virtual column support for MySQL and MariaDB class CreateUsers <

    ActiveRecord::Migration[5.1] def change create_table :users do |t| t.string :name t.virtual :upper_name, type: :string, as: "UPPER(name)" t.virtual :name_length, type: :integer, as: "LENGTH(name)", stored: true, index: true end end end 5.1
  8. 15.

    Adds support for limits in batch processing Post.limit(500).find_each.map(&:title) # Scoped

    order and limit are ignored, it's forced to be batch order and batch size. # => Post Load (0.2ms) SELECT "posts".* FROM "posts" ORDER BY "posts"."id" ASC LIMIT ? [["LIMIT", 1000]] Post.limit(500).find_each.map(&:title) # => Post Load (0.1ms) SELECT "posts".* FROM "posts" ORDER BY "posts"."id" ASC LIMIT ? [["LIMIT", 500]] 5.0 5.1
  9. 18.

    Update Unicode version to 9.0.0 ActiveSupport::Multibyte::Unicode::UNICODE_VERSION # => "8.0.0" "

    " ".mb_chars.grapheme_length # => 4 " " ".mb_chars.reverse # => " " ActiveSupport::Multibyte::Unicode::UNICODE_VERSION # => "9.0.0" " " ".mb_chars.grapheme_length # => 1 " " ".mb_chars.reverse # => " " " 5.0 5.1
  10. 19.

    Add Duration#after and #before as alias for #since and #until

    PR 27721 by Nick Johnstone Active Support
  11. 20.

    Add Duration#after and #before as aliases… 2.weeks.since(christmas_day) # => Mon,

    08 Jan 2018 5.days.until(christmas_day) # => Wed, 20 Dec 2017 2.weeks.after(christmas_day) # => Mon, 08 Jan 2018 5.days.before(christmas_day) # => Wed, 20 Dec 2017 5.0 5.1
  12. 22.

    Introduce Module#delegate_missing_to class OrderCompletion delegate :destroy, :update, …more methods…, to:

    :@order def initialize(order) @order = order end def create OrderCompletionNotification.deliver(@order) if @order.save end end 5.0
  13. 23.

    Introduce Module#delegate_missing_to class OrderCompletion delegate_missing_to :@order def initialize(order) @order =

    order end def create OrderCompletionNotification.deliver(@order) if @order.save end end 5.1
  14. 26.

    New syntax for Action View’s tag helpers tag(:br, nil, true)

    <%= content_tag :div, class: "strong" do -%> Hello world! <% end -%> tag.br <%= tag.div class: "strong" do %> Hello world! <% end %> 5.0 5.1
  15. 27.

    PR 26976 by Kasper Timm Hansen Add form_with to unify

    form_tag and form_for Action View
  16. 28.

    Add form_with to unify form_tag and form_for # app/views/posts/show.html.erb <%=

    form_for @post, method: :delete do |f| %> <%= f.submit 'Delete post' %> <% end %> # app/views/posts/show.html.erb <%= form_with model: @post, method: :delete do |f| %> <%= f.submit 'Delete post' %> <% end %> 5.0 5.1
  17. 29.

    Add form_with to unify form_tag and form_for # app/views/posts/index.html.erb <%=

    form_tag '/posts/1', method: :delete do %> <%= submit_tag 'Delete post #1' %> <% end %> # app/views/posts/index.html.erb <%= form_with url: '/posts/1', method: :delete do |f| %> <%= submit_tag 'Delete post #1' %> <% end %> 5.0 5.1
  18. 30.
  19. 32.

    Display railtie class name in `rails initializers` $ rails initializers

    set_load_path set_load_path [124 more…] $ rails initializers ActionView::Railtie.set_load_path ActionCable::Engine.set_load_path [126 more…] 5.0 5.1
  20. 34.

    Added a shared section to config/secrets.yml # config.secrets.yml default: &default

    email_from: noreply@example.com development: <<: *default shared: email_from: noreply@example.com 5.0 5.1
  21. 36.

    Add encrypted secrets in config/secrets.yml.enc # config/secrets.yml # Do not

    keep production secrets in the repository, # instead read values from the environment. production: secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> $ rails console production > Rails.application.secrets # => {:secret_key_base=>nil, :secret_token=>nil} 5.0 5.0
  22. 37.

    Add encrypted secrets in config/secrets.yml.enc $ rails secrets:setup Adding config/secrets.yml.key

    to store the encryption key: 667c… $ more config/secrets.yml.enc # QMdWtttAU5ZJVrsJRFot4j0gCgaqjjsLA0CIFnAhdc+LByI4ILZFwR $ EDITOR=vi rails secrets:edit # See `secrets.yml` for tips on generating suitable keys. production: api_key: "466aac22e6a869134be3d09b9e89232fc2c228" 5.1
  23. 39.

    Drop jQuery as a dependency and include rails-ujs <%= link_to

    'Destroy', post, method: :delete, data: {confirm: 'Are you sure?'} %> <a data-confirm="Are you sure?" data-method="delete" href="/posts/7">Destroy</a>
  24. 40.

    Drop jQuery as a dependency and include rails-ujs <%= link_to

    'Destroy', post, method: :delete, data: {confirm: 'Are you sure?'} %> <a data-confirm="Are you sure?" data-method="delete" href="/posts/7">Destroy</a>
  25. 41.

    Drop jQuery as a dependency and include rails-ujs # Gemfile

    gem 'jquery-rails' # app/assets/javascripts/application.js //= require jquery //= require jquery_ujs # app/assets/javascripts/application.js //= require rails-ujs 5.0 5.1
  26. 42.

    PR 26836 by Liceth Ovalles Rodriguez Add Yarn support in

    new apps using --yarn option Railties
  27. 43.

    Add Yarn support in new apps $ yarn init $

    yarn add bootstrap $ echo ".node_modules/" >> .gitignore # config/initializers/assets.rb config.assets.paths << Rails.root.join('node_modules') # app/assets/stylesheets/application.css *= require bootstrap/dist/css/bootstrap # app/assets/javascripts/application.js //= require bootstrap/dist/js/bootstrap 5.0
  28. 44.

    Add Yarn support in new apps $ bin/yarn init $

    bin/yarn add bootstrap # app/assets/stylesheets/application.css *= require bootstrap/dist/css/bootstrap # app/assets/javascripts/application.js //= require bootstrap/dist/js/bootstrap 5.1
  29. 46.

    Basic --webpack delegation to new webpacker gem $ rails new

    app_name --webpack 5.1 rails webpacker:install Creating javascript app source directory create app/javascript create app/javascript/packs/application.js Copying binstubs create bin/webpack-dev-server create bin/webpack-watcher create bin/webpack Copying webpack core config and loaders create config/webpack/configuration.js create config/webpack/development.js create config/webpack/development.server.js create config/webpack/development.server.yml create config/webpack/paths.yml create config/webpack/production.js create config/webpack/shared.js create config/webpack/loaders create config/webpack/loaders/assets.js create config/webpack/loaders/babel.js create config/webpack/loaders/coffee.js create config/webpack/loaders/erb.js create config/webpack/loaders/sass.js create .postcssrc.yml create .gitignore Installing all JavaScript dependencies run ./bin/yarn add webpack webpack-merge…
  30. 47.

    Basic --webpack delegation to new webpacker gem $ webpack-dev-server #

    app/views/layouts/application.html.erb <%= javascript_pack_tag 'application' %> <%= stylesheet_pack_tag 'application' %> # app/javascript/packs/application.js.erb require('moment') <% helpers = ActionController::Base.helpers %> var railsImagePath = "<%= helpers.image_path('rails.png') %>" 5.1
  31. 51.

    Capybara integration with Rails (AKA System Tests) # Gemfile group

    :development, :test do gem 'capybara' gem 'selenium-webdriver' end # test/test_helper.rb require 'capybara/rails' require 'capybara/minitest' […] 5.0
  32. 52.

    Capybara integration with Rails (AKA System Tests) # test/test_helper.rb class

    ActionDispatch::IntegrationTest include Capybara::DSL include Capybara::Minitest::Assertions Capybara.register_driver :selenium do |app| Capybara::Selenium::Driver.new app, browser: :chrome end Capybara.default_driver = :selenium end 5.0
  33. 53.

    Custom URL helpers and polymorphic mapping $ rails test:integration #

    => 1 runs, 1 assertions, 0 failures # test/integration/posts_test.rb require "test_helper" class PostsTest < ActionDispatch::IntegrationTest test "visiting the 'posts' page" do visit '/posts' assert_selector 'h1', text: 'Posts' end end 5.0
  34. 54.

    Capybara integration with Rails (AKA System Tests) # test/system/posts_test.rb require

    "application_system_test_case" class PostsTest < ApplicationSystemTestCase test "visiting the 'posts' page" do visit posts_url assert_selector 'h1', text: 'Posts' end end $ rails test:system # => 1 runs, 1 assertions, 0 failures 5.1
  35. 57.

    Custom URL helpers and polymorphic mapping <a href="/posts/1#content-2">Comment #2</a> <%=

    link_to "Comment #2", post_path(@comment.post, anchor: 'content-2') %> # config/routes.rb direct(:embedded_content) do |content| url_for [content.post, anchor: "content-#{content.id}"] end <%= link_to "Comment #2", embedded_content_path(@comment) %> 5.0 5.1
  36. 60.

    Custom URL helpers and polymorphic mapping # config/routes.rb resource :profile

    # app/assets/views/profiles/new.html.erb <%= form_for @profile, url: profile_path(@profile) do |f| %> # config/routes.rb resource :profile resolve('Profile') { [:profile] } # app/assets/views/profiles/new.html.erb <%= form_for @profile do |f| %> 5.0 5.1
  37. 62.
  38. 67.

    DateTime#change supports :usec and :nsec options now = DateTime.now now.to_f

    # => 1490028163.625132 now.change(usec: 0).to_f # => 1490028163.625132 now = DateTime.now now.to_f # => 1490028163.625132 now.change(usec: 0).to_f # => 1490028163.0 DateTime.now.end_of_day.nsec # => 999_999_999 5.0 5.1
  39. 69.

    Add :check_parameters option to current_page? # From http://www.example.com/shop/checkout?order=desc&page=1 current_page? 'http://www.example.com/shop/checkout'

    # => true # From http://www.example.com/shop/checkout?order=desc&page=1 current_page? 'http://www.example.com/shop/checkout', check_parameters: true # => false 5.0 5.1
  40. 72.

    Add retry_on/discard_on for exception handling class SiteScraperJob < ActiveJob::Base rescue_from(ApocalypticException)

    rescue_from(ErrorLoadingSite) do retry_job queue: :low_priority end def perform(*args) # raise ErrorLoadingSite if cannot scrape end end 5.0
  41. 73.

    Add retry_on/discard_on for exception handling class SiteScraperJob < ActiveJob::Base discard_on

    ApocalypticException retry_on ErrorLoadingSite # retry_on ErrorLoadingSite, wait: :exponentially_longer # retry_on ErrorLoadingSite, wait: ->(attempts) { attempts * 2 } def perform(*args) # raise ErrorLoadingSite if cannot scrape end end 5.1
  42. 76.

    Add parameterized invocation of mailers class PartyMailer < ApplicationMailer def

    birthday_invite(guest) mail subject: "Come to my birthday!", to: guest.email_address end def wedding_invite(guest) mail subject: "Come to my wedding!", to: guest.email_address end end PartyMailer.birthday_invite(current_user) 5.0
  43. 77.

    Add parameterized invocation of mailers class PartyMailer < ApplicationMailer before_action

    { @guest = params[:guest] } default to: -> { @guest.email_address } def birthday_invite mail subject: "Come to my birthday!" end def wedding_invite; mail subject: "Come to my wedding!"; end end PartyMailer.with(guest: current_user).birthday_invite 5.1