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

Rails 5 and its new features by examples

Yoshio Teruia
September 27, 2016

Rails 5 and its new features by examples

Yoshio Teruia

September 27, 2016
Tweet

Other Decks in Technology

Transcript

  1. É uma integração do websocket com o Rails que possibilita

    o desenvolvimento de real-time features. Action Cable
  2. CLI

  3. Agora o `rails` pode ser usado para rodar rake tasks

    na CLI. Comandos do Rails centralizado
  4. A fase de exercise nos testes de integração ficam mais

    explícitas. Kwarg nos métodos de requisição
  5. Rails 4 class UserListTest < ActionDispatch::IntegrationTest test 'returns all users'

    do … get users_url, nil, { 'X-Custom-Header' => 'Header Value', formats: :json } … end end
  6. Rails 4 class UserListTest < ActionDispatch::IntegrationTest test 'returns all users'

    do … get users_url, nil, { 'X-Custom-Header' => 'Header Value’, formats: :json } … end end
  7. Rails 4 class UserListTest < ActionDispatch::IntegrationTest test 'returns all users'

    do … get users_url, nil, { 'X-Custom-Header' => 'Header Value’, formats: :json } … end end
  8. Rails 5 class UserListTest < ActionDispatch::IntegrationTest test 'returns all users'

    do … get users_url, headers: { 'X-Custom-Header' => 'Header Value’ }, as: :json … end end
  9. Rails 5 class UserListTest < ActionDispatch::IntegrationTest test 'returns all users'

    do … get users_url, headers: { 'X-Custom-Header' => 'Header Value’ }, as: :json … end end
  10. Started GET "/users" for ::1 at 2016-09-23 04:14:49 -0300 ActiveRecord::SchemaMigration

    Load (0.7ms) SELECT "schema_migrations".* FROM "schema_migrations" Processing by UsersController#index as HTML Rendering users/index.html.erb within layouts/application User Load (0.5ms) SELECT "users".* FROM "users" Rendered users/index.html.erb within layouts/application (16.8ms) Completed 200 OK in 366ms (Views: 340.1ms | ActiveRecord: 5.0ms) Started GET "/assets/jquery.self-bd7ddd393353a8d2480a622e80342adf488fb6006d667e8b42e4c0073393abee.js? body=1" for ::1 at 2016-09-23 04:14:50 -0300 Started GET "/assets/turbolinks.self-c5acd7a204f5f25ce7a1d8a0e4d92e28d34c9e2df2c7371cd7af88e147e4ad82.js? body=1" for ::1 at 2016-09-23 04:14:50 -0300 Started GET "/assets/application.self- b89234cf2659d7fedea75bca0b8d231ad7dfc2f3f57fcbaf5f44ed9dc384137b.js?body=1" for ::1 at 2016-09-23 04:14:50 -0300 Started GET "/assets/jquery_ujs.self-784a997f6726036b1993eb2217c9cb558e1cbb801c6da88105588c56f13b466a.js? body=1" for ::1 at 2016-09-23 04:14:50 -0300 Started GET "/assets/ action_cable.self-1641ec3e8ea24ed63601e86efcca7f9266e09f390e82199d56aa7e4bd50e1aa9.js?body=1" for ::1 at 2016-09-23 04:14:50 -0300 Started GET "/assets/application.self- e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.css?body=1" for ::1 at 2016-09-23 04:14:50 -0300 Started GET "/assets/cable.self-6e0514260c1aa76eaf252412ce74e63f68819fd19bf740595f592c5ba4c36537.js? body=1" for ::1 at 2016-09-23 04:14:50 -0300
  11. Rails 4 A única forma de desabilitar os logs dos

    assets era instalando uma gem externa.
  12. Rails 5 Existe uma configuração para desabilitar os logs dos

    assets e que vem habilitado por padrão.
  13. Rails.application.configure do config.cache_classes = false # Do not eager load

    code on boot. config.eager_load = false config.assets.debug = true # Suppress logger output for asset requests. config.assets.quiet = true … end
  14. Rails.application.configure do config.cache_classes = false # Do not eager load

    code on boot. config.eager_load = false config.assets.debug = true # Suppress logger output for asset requests. config.assets.quiet = true … end
  15. Started GET "/users" for ::1 at 2016-09-23 04:24:36 -0300 ActiveRecord::SchemaMigration

    Load (0.4ms) SELECT "schema_migrations".* FROM "schema_migrations" Processing by UsersController#index as HTML Rendering users/index.html.erb within layouts/application User Load (0.4ms) SELECT "users".* FROM "users" Rendered users/index.html.erb within layouts/application (12.2ms) Completed 200 OK in 315ms (Views: 293.4ms | ActiveRecord: 3.9ms)
  16. Funciona no Rails 4.2.7‼ Essa funcionalidade foi portada para o

    sprocket-rails 3.1.0, ou seja, essa configuração funciona no Rails 4.2.7 sem a necessidade da gem quiet_assets.
  17. Rails 4 Já havia a possibilidade de utilizar o UUID

    como chave primária mas era um pouco verboso.
  18. rails g model user name:string class CreateUsers < ActiveRecord::Migration def

    change create_table :users do |t| t.string :name t.timestamps null: false end end end
  19. rails g model user name:string class CreateUsers < ActiveRecord::Migration def

    change create_table :users, id: :uuid do |t| t.string :name t.timestamps null: false end end end
  20. class CreateUsers < ActiveRecord::Migration def change create_table :users, id: :uuid

    do |t| t.string :name t.timestamps null: false end end end
  21. Rails 4 Não há uma forma de relacionar os erros

    com as instâncias da associação.
  22. class User < ActiveRecord::Base has_many :addresses validates :name, presence: true

    accepts_nested_attributes_for :addresses end class Address < ActiveRecord::Base belongs_to :user validates :street, :city, presence: true end
  23. u = User.new(name: 'João') u.addresses.new(street: 'Rua joãozinho') u.valid? => false

    u.errors.messages => {:"addresses.city"=>["can't be blank"]} u.addresses.new u.valid? => false u.errors.messages => { :"addresses.city"=>["can't be blank”], :"addresses.street"=>["can't be blank”] }
  24. u = User.new(name: 'João') u.addresses.new(street: 'Rua joãozinho') u.valid? => false

    u.errors.messages => {:"addresses.city"=>["can't be blank"]} u.addresses.new u.valid? => false u.errors.messages => { :"addresses.city"=>["can't be blank”], :"addresses.street"=>["can't be blank”] }
  25. u = User.new(name: 'João') u.addresses.new(street: 'Rua joãozinho') u.valid? => false

    u.errors.messages => {:"addresses.city"=>["can't be blank"]} u.addresses.new u.valid? => false u.errors.messages => { :"addresses.city"=>["can't be blank”], :"addresses.street"=>["can't be blank”] }
  26. u = User.new(name: 'João') u.addresses.new(street: 'Rua joãozinho') u.valid? => false

    u.errors.messages => {:"addresses.city"=>["can't be blank"]} u.addresses.new u.valid? => false u.errors.messages => { :"addresses.city"=>["can't be blank”], :"addresses.street"=>["can't be blank”] }
  27. u = User.new(name: 'João') u.addresses.new(street: 'Rua joãozinho') u.valid? => false

    u.errors.messages => {:"addresses.city"=>["can't be blank"]} u.addresses.new u.valid? => false u.errors.messages => { :"addresses.city"=>["can't be blank”], :"addresses.street"=>["can't be blank”] }
  28. u = User.new(name: 'João') u.addresses.new(street: 'Rua joãozinho') u.valid? => false

    u.errors.messages => {:"addresses.city"=>["can't be blank"]} u.addresses.new u.valid? => false u.errors.messages => { :"addresses.city"=>["can't be blank”], :"addresses.street"=>["can't be blank”] }
  29. u = User.new(name: 'João') u.addresses.new(street: 'Rua joãozinho') u.valid? => false

    u.errors.messages => {:"addresses.city"=>["can't be blank"]} u.addresses.new u.valid? => false u.errors.messages => { :"addresses.city"=>["can't be blank”], :"addresses.street"=>["can't be blank”] }
  30. class Address < ActiveRecord::Base belongs_to :user validates :street, :city, presence:

    true end class User < ActiveRecord::Base has_many :addresses, index_errors: true validates :name, presence: true accepts_nested_attributes_for :addresses end
  31. class Address < ActiveRecord::Base belongs_to :user validates :street, :city, presence:

    true end class User < ActiveRecord::Base has_many :addresses, index_errors: true validates :name, presence: true accepts_nested_attributes_for :addresses end
  32. u = User.new(name: 'João') u.addresses.new(street: 'Rua joãozinho') u.valid? => false

    u.errors.messages => { :"addresses[0].user"=>["must exist”], :"addresses[0].city"=>["can't be blank”] } u.addresses.new u.valid? => false u.errors.messages => { :"addresses[0].user"=>["must exist”], :"addresses[0].city"=>["can't be blank”], :"addresses[1].user"=>["must exist”], :"addresses[1].street"=>["can't be blank”], :"addresses[1].city"=>["can't be blank”] }
  33. u = User.new(name: 'João') u.addresses.new(street: 'Rua joãozinho') u.valid? => false

    u.errors.messages => { :"addresses[0].user"=>["must exist”], :"addresses[0].city"=>["can't be blank”] } u.addresses.new u.valid? => false u.errors.messages => { :"addresses[0].user"=>["must exist”], :"addresses[0].city"=>["can't be blank”], :"addresses[1].user"=>["must exist”], :"addresses[1].street"=>["can't be blank”], :"addresses[1].city"=>["can't be blank”] }
  34. u = User.new(name: 'João') u.addresses.new(street: 'Rua joãozinho') u.valid? => false

    u.errors.messages => { :"addresses[0].user"=>["must exist”], :"addresses[0].city"=>["can't be blank”] } u.addresses.new u.valid? => false u.errors.messages => { :"addresses[0].user"=>["must exist”], :"addresses[0].city"=>["can't be blank”], :"addresses[1].user"=>["must exist”], :"addresses[1].street"=>["can't be blank”], :"addresses[1].city"=>["can't be blank”] }
  35. u = User.new(name: 'João') u.addresses.new(street: 'Rua joãozinho') u.valid? => false

    u.errors.messages => { :"addresses[0].user"=>["must exist”], :"addresses[0].city"=>["can't be blank”] } u.addresses.new u.valid? => false u.errors.messages => { :"addresses[0].user"=>["must exist”], :"addresses[0].city"=>["can't be blank”], :"addresses[1].user"=>["must exist”], :"addresses[1].street"=>["can't be blank”], :"addresses[1].city"=>["can't be blank”] }
  36. u = User.new(name: 'João') u.addresses.new(street: 'Rua joãozinho') u.valid? => false

    u.errors.messages => { :"addresses[0].user"=>["must exist”], :"addresses[0].city"=>["can't be blank”] } u.addresses.new u.valid? => false u.errors.messages => { :"addresses[0].user"=>["must exist”], :"addresses[0].city"=>["can't be blank”], :"addresses[1].user"=>["must exist”], :"addresses[1].street"=>["can't be blank”], :"addresses[1].city"=>["can't be blank”] }
  37. u = User.new(name: 'João') u.addresses.new(street: 'Rua joãozinho') u.valid? => false

    u.errors.messages => { :"addresses[0].user"=>["must exist”], :"addresses[0].city"=>["can't be blank”] } u.addresses.new u.valid? => false u.errors.messages => { :"addresses[0].user"=>["must exist”], :"addresses[0].city"=>["can't be blank”], :"addresses[1].user"=>["must exist”], :"addresses[1].street"=>["can't be blank”], :"addresses[1].city"=>["can't be blank”] }
  38. u = User.new(name: 'João') u.addresses.new(street: 'Rua joãozinho') u.valid? => false

    u.errors.messages => { :"addresses[0].user"=>["must exist”], :"addresses[0].city"=>["can't be blank”] } u.addresses.new u.valid? => false u.errors.messages => { :"addresses[0].user"=>["must exist”], :"addresses[0].city"=>["can't be blank”], :"addresses[1].user"=>["must exist”], :"addresses[1].street"=>["can't be blank”], :"addresses[1].city"=>["can't be blank”] }
  39. u = User.new(name: 'João') u.addresses.new(street: 'Rua joãozinho') u.valid? => false

    u.errors.messages => { :"addresses[0].user"=>["must exist”], :"addresses[0].city"=>["can't be blank”] } u.addresses.new u.valid? => false u.errors.messages => { :"addresses[0].user"=>["must exist”], :"addresses[0].city"=>["can't be blank”], :"addresses[1].user"=>["must exist”], :"addresses[1].street"=>["can't be blank”], :"addresses[1].city"=>["can't be blank”] }
  40. u = User.new(name: 'João') u.addresses.new(street: 'Rua joãozinho') u.valid? => false

    u.errors.messages => { :"addresses[0].user"=>["must exist”], :"addresses[0].city"=>["can't be blank”] } u.addresses.new u.valid? => false u.errors.messages => { :"addresses[0].user"=>["must exist”], :"addresses[0].city"=>["can't be blank”], :"addresses[1].user"=>["must exist”], :"addresses[1].street"=>["can't be blank”], :"addresses[1].city"=>["can't be blank”] }
  41. u = User.new(name: 'João') u.addresses.new(street: 'Rua joãozinho') u.valid? => false

    u.errors.messages => { :"addresses[0].user"=>["must exist”], :"addresses[0].city"=>["can't be blank”] } u.addresses.new u.valid? => false u.errors.messages => { :"addresses[0].user"=>["must exist”], :"addresses[0].city"=>["can't be blank”], :"addresses[1].user"=>["must exist”], :"addresses[1].street"=>["can't be blank”], :"addresses[1].city"=>["can't be blank”] }
  42. u = User.new(name: 'João') u.addresses.new(street: 'Rua joãozinho') u.valid? => false

    u.errors.messages => { :"addresses[0].user"=>["must exist”], :"addresses[0].city"=>["can't be blank”] } u.addresses.new u.valid? => false u.errors.messages => { :"addresses[0].user"=>["must exist”], :"addresses[0].city"=>["can't be blank”], :"addresses[1].user"=>["must exist”], :"addresses[1].street"=>["can't be blank”], :"addresses[1].city"=>["can't be blank”] }
  43. u = User.new(name: 'João') u.addresses.new(street: 'Rua joãozinho') u.valid? => false

    u.errors.messages => { :"addresses[0].user"=>["must exist”], :"addresses[0].city"=>["can't be blank”] } u.addresses.new u.valid? => false u.errors.messages => { :"addresses[0].user"=>["must exist”], :"addresses[0].city"=>["can't be blank”], :"addresses[1].user"=>["must exist”], :"addresses[1].street"=>["can't be blank”], :"addresses[1].city"=>["can't be blank”] }
  44. class Order < ActiveRecord::Base enum status: [:posted, :in_transit, :delivered] scope

    :pending, -> do where( 'status = :posted OR status = :in_transit', { posted: statuses[:posted], in_transit: statuses[:in_transit] } ) end end
  45. class Order < ActiveRecord::Base enum status: [:posted, :in_transit, :delivered] scope

    :pending, -> do where( 'status = :posted OR status = :in_transit', { posted: statuses[:posted], in_transit: statuses[:in_transit] } ) end end
  46. <table> <thead> <th>Nome</th> <th>Idade</th> </thead> <tbody> <% @users.each do |user|

    %> <tr> <td><%= user.name %></td> <td><%= user.age %></td> </tr> <% end %> </tbody> </table>
  47. class UsersController < ApplicationController after_action :print_accessed_fields def index @users =

    User.all end private def print_accessed_fields p @users.first.accessed_fields end end
  48. class UsersController < ApplicationController after_action :print_accessed_fields def index @users =

    User.all end private def print_accessed_fields p @users.first.accessed_fields end end
  49. Started GET "/users" for ::1 at 2016-09-17 23:47:25 -0300 ActiveRecord::SchemaMigration

    Load (0.7ms) SELECT "schema_migrations".* FROM "schema_migrations" Processing by UsersController#index as HTML Rendering users/index.html.erb within layouts/ application User Load (0.4ms) SELECT "users".* FROM "users" Rendered users/index.html.erb within layouts/ application (20.5ms) ["name", "age"] Completed 200 OK in 395ms (Views: 361.8ms | ActiveRecord: 4.2ms)
  50. Started GET "/users" for ::1 at 2016-09-17 23:47:25 -0300 ActiveRecord::SchemaMigration

    Load (0.7ms) SELECT "schema_migrations".* FROM "schema_migrations" Processing by UsersController#index as HTML Rendering users/index.html.erb within layouts/ application User Load (0.4ms) SELECT "users".* FROM "users" Rendered users/index.html.erb within layouts/ application (20.5ms) ["name", "age"] Completed 200 OK in 395ms (Views: 361.8ms | ActiveRecord: 4.2ms)
  51. ⚠Deve ser usado apenas no ambiente de desenvolvimento. ⚠Apenas os

    campos que foram lidos são identificados, então cuidado com os que estão dentro de condicionais.
  52. Rails 4 User Load (2.8ms) SELECT "users"."id", "users"."gender", "users"."name" FROM

    "users" Rails 5 User Load (11.1ms) SELECT "users"."id", "users"."gende "users"."name" FROM "users"
  53. Rails 4 User Load (2.8ms) SELECT "users"."id", "users"."gender", "users"."name" FROM

    "users" Rails 5 User Load (11.1ms) SELECT "users"."id", "users"."gender", "users"."name" FROM "users"
  54. Attributes API Os atributos do banco de dados podem ser

    convertidos para um objeto do Ruby.
  55. irb(main):002:0> User.first.address User Load (0.3ms) SELECT "users".* FROM "users" ORDER

    BY "users"."id" ASC LIMIT $1 [["LIMIT", 1]] => {"city"=>"São Paulo", "street"=>"Rua marília"}
  56. irb(main):002:0> User.first.address User Load (0.3ms) SELECT "users".* FROM "users" ORDER

    BY "users"."id" ASC LIMIT $1 [["LIMIT", 1]] => {"city"=>"São Paulo", "street"=>"Rua marília"}
  57. class AddressType < ActiveRecord::Type::Value def serialize(value) ::ActiveSupport::JSON.encode(value) end def deserialize(value)

    if value address_attrs = JSON.parse(value) ::Address.new( street: address_attrs[‘street'], city: address_attrs[‘city'] ) end end end
  58. User.first.address User Load (0.5ms) SELECT "users".* FROM "users" ORDER BY

    "users"."id" ASC LIMIT $1 [["LIMIT", 1]] => #<Address:0x007fb03a73b738 @street="Rua marília", @city="São Paulo">
  59. User.first.address User Load (0.5ms) SELECT "users".* FROM "users" ORDER BY

    "users"."id" ASC LIMIT $1 [["LIMIT", 1]] => #<Address:0x007fb03a73b738 @street="Rua marília", @city="São Paulo">