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

Rails 4

Rails 4

Quer saber o que mudou no Rails 4? Nessa palestra eu mostrei grande parte das novidades que esta nova versão trouxe.

Palestra apresentada no TDC 2013

Cb5d9e9095cd41b636764a85e57ade4b?s=128

Nando Vieira

July 14, 2013
Tweet

Transcript

  1. Rails 4 Nando Vieira

  2. Nando Vieira http://simplesideias.com.br @fnando

  3. * * *

  4. O Rails 4 foi lançado em 25 de junho de

    2013. http://fnando.me/i1
  5. Rails 3 Rails 4 Revolução Evolução

  6. Ruby 1.9.3 Ruby 2.0.0 Versão mínima Recomendado

  7. Stron Parameters

  8. # app/models/user.rb class User < ActiveRecord::Base attr_accessible :email, :username end

    # app/controllers/users_controller.rb class UsersController < ApplicationController def create @user = User.create(params[:user]) respond_with(@user) end end Rails 3
  9. # app/controllers/users_controller.rb class UsersController < ApplicationController def create @user =

    User.create(user_params) respond_with(@user) end private def user_params params .require(:user) .permit(:email, :username) end end Rails 4
  10. Lança a exceção ActionController::ParameterMissin caso params[:user] não exista.

  11. Turbolinks

  12. Um plu in JavaScript semelhante ao PJAX (pushState + AJAX)

    e wiselinks.
  13. Turbolinks faz requisições com AJAX e substitui as ta s

    <title> e <body> com o conteúdo retornado pelo servidor.
  14. Firefox 4+ Chrome 5+ IE10+ Safari 6+

  15. Você precisa executar manualmente scripts como Goo le Analytics.

  16. $(document).on("page:change", function(){ if (window._gaq) { _gaq.push(["_trackPageview"]); } else if (window.pageTracker)

    { pageTracker._trackPageview(); } }); http://reed. ithub.io/turbolinks-compatibility/
  17. Post reSQL ActiveRecord

  18. O adapter do Post reSQL recebeu suporte para arrays, hstore

    e novos tipos de dados.
  19. ActiveRecord::Schema.define(version: 0) do create_table :posts do |t| t.text :title t.text

    :tags, array: true end end
  20. post = Post.new post.title = "Array support on ActiveRecord +

    PostgreSQL" post.tags = %w[rails ruby database] post.save p post.tags # ["rails", "ruby", "database"] p Post.where("? = ANY(tags)", "ruby").first # #<Post id: 1, tags: ["rails", "ruby", "database"]>
  21. sudo apt-get install postgresql-contrib

  22. ActiveRecord::Schema.define(version: 0) do execute "CREATE EXTENSION hstore" create_table :users do

    |t| t.string :username t.hstore :profile end end
  23. class User < ActiveRecord::Base store_accessor :profile end

  24. user = User.new user.username = "fnando" user.profile = { github:

    "fnando", twitter: "fnando", instagram: "nandovieira" } user.save p user.profile # {:github=>"fnando"...}
  25. # Find users with github key User.where("profile ? :key", key:

    "github") # Find users without github key User.where("not profile ? :key", key: "github") # Find users with github profile as fnando User.where("profile @> (:key => :value)", key: "github", value: "fnando" ) # Find users with with instagram value like "nan" User.where("profile -> :key LIKE :value", key: "instagram", value: "%nan%" )
  26. Lembre-se de adicionar índices ao seu campo hstore.

  27. execute "CREATE INDEX users_profile ON users USING gin(profile)" execute "DROP

    INDEX users_profile"
  28. Indices GIN Rápidos para buscar. Lentos para indexar. São melhores

    quando existem mais de 100 mil termos únicos. http://fnando.me/j
  29. Indices GiST Mais lentos que GIN. Mais rápidos para indexar.

    São melhores quando o número de termos únicos for abaixo de 100 mil.
  30. Novos tipos de campos.

  31. uuid inet cidr macaddr json ran es Universally Unique Identifier

    Endereço IPv4 Endereço IPv6 MAC Address Serialização com JSON int4ran e, int8ran e, numran e, tsran e, tstzran e, dateran e
  32. Mais ActiveRecord

  33. Nova validação chamada absence.

  34. class User < ActiveRecord::Base attr_accessor :honeypot validates_absence_of :honeypot validates :honeypot,

    absence: true end
  35. user = User.create(honeypot: "SPAM") user.errors.full_messages => ["Honeypot must be blank"]

  36. O ActiveRecord implementa o Null Object Pattern com ActiveRecord::Relation#none e

    ActiveRecord::NullRelation.
  37. class Topic < ActiveRecord::Base def self.filter(filter) case filter when :all

    all when :published where(published: true) when :draft where(published: false) else where("1 = 0") end end end Rails 3
  38. class Topic < ActiveRecord::Base def self.filter(filter) case filter when :all

    all when :published where(published: true) when :draft where(published: false) else none end end end Rails 4
  39. O ActiveRecord implementa um método #not para o operador !=

    nos finders.
  40. User.where("role != ?", "admin") # Rails 3 User.where.not(role: "admin") #

    Rails 4
  41. Novos métodos e semântica para a atualização de re istros.

  42. user = User.find(params[:id]) user.update_attributes(user_params) # Rails 3 user.update(user_params) # Rails

    4
  43. user.update_attribute(:username, "fnando") user.update_attributes(username: "fnando") user.update(username: "fnando") user.update_column(:username, "fnando") user.update_columns(username: "fnando")

  44. Método Validações Callbacks updated_at Dirty update_attributes update update_attribute update_columns update_column

  45. Um novo método ActiveRecord::Base#destroy! lança uma exceção caso o re

    istro não possa ser removido.
  46. class User < ActiveRecord::Base before_destroy :avoid_destruction private def avoid_destruction false

    end end user = User.create!(username: "fnando") user.destroy user.persisted? #=> true user.destroy! #=> exception ActiveRecord::RecordNotDestroyed
  47. O ActiveRecord::Base.all a ora faz lazy loadin em vez de

    retornar um array.
  48. User.all.class #=> ActiveRecord::Relation::ActiveRecord_Relation_User User.all.to_a #=> [] User.scoped DEPRECATION WARNING: Model.scoped

    is deprecated. Please use Model.all instead.
  49. A API do ActiveRecord possui versão com ban para quase

    todos os métodos.
  50. SELECT "users".* FROM "users" WHERE "users"."username" = 'fnando' ORDER BY

    "users"."created_at" DESC scope = User.all scope.where!(username: "fnando") scope.includes!(:articles) scope.order!(created_at: :desc) scope.to_sql SQL RUBY
  51. Novos métodos de busca e inicialização.

  52. User.find_by(username: "fnando") User.find_by!(username: "fnando") User.find_or_initialize_by(username: "fnando") User.find_or_create_by(username: "fnando") User.find_or_create_by!(username: "fnando")

  53. Os escopos precisam ser callable objects.

  54. class User < ActiveRecord::Base scope :recent, -> { order(created_at: :desc)

    } end
  55. Encrypted Cookies

  56. Até o Rails 3 todos os dados salvos na sessão

    podiam ser vistos pelo cliente.
  57. $ curl -i http://localhost:3000/ HTTP/1.1 200 OK Content-Type: text/html; charset=utf-8

    X-Ua-Compatible: IE=Edge Etag: "8b1a9953c4611296a827abf8c47804d7" Cache-Control: max-age=0, private, must-revalidate X-Request-Id: 25af60321d6e9c585c3f04ff8928d824 X-Runtime: 0.014431 Server: WEBrick/1.3.1 (Ruby/2.0.0/2013-06-27) Date: Sat, 13 Jul 2013 20:13:58 GMT Content-Length: 5 Connection: Keep-Alive Set-Cookie: _app_session=BAh7BzoMbWVzc2hh...; path=/; HttpOnly
  58. require "rack" Rack::Session::Cookie::Base64::Marshal.new.decode( "BAh7BzoMbWVzc2FnZUkiDEhhY2tlZ..." ) => { message: "Shhh... Secret!",

    session_id: "e3bc1175000a3b257b4b68d983b9c3e2" } Rails 3
  59. O Rails 4 usa cookies cripto rafados com o hash

    definido em Rails.application.confi .secret_key_base.
  60. O mesmo exemplo anterior retornaria nil no Rails 4.

  61. require "rack" Rack::Session::Cookie::Base64::Marshal.new.decode( "eVlGTkl1cEt1dHJUdVNzdUNkZWNmNDQxSm..." ) nil Rails 4

  62. ActiveModel::Model

  63. Para criar formulários com form_for você precisa implementar a API

    do ActiveModel.
  64. class Contact include ActiveModel::Validations include ActiveModel::Conversion extend ActiveModel::Naming attr_accessor :name,

    :email, :message validates_presence_of :name, :message validates_format_of :email, with: /\A.+@.+\.[a-z]{2,4}\z/ def initialize(attributes = {}) attributes.each do |name, value| public_send("#{name}=", value) end end def persisted? false end end
  65. contact = Contact.new(name: "John") contact.valid? #=> false contact.errors.full_messages #=> ["Message

    can't be blank", "Email is invalid"]
  66. A ora você pode incluir o módulo ActiveModel::Model, que já

    faz tudo isso para você.
  67. class Contact include ActiveModel::Model attr_accessor :name, :email, :message validates_presence_of :name,

    :message validates_format_of :name, with: /\A.+@.+\.[a-z]{2,4}\z/ end
  68. Cachin

  69. Definir ETa s ficou mais simples.

  70. No Rails 3 você precisa definir todas as chaves que

    compõe o ETa , mesmo que elas sejam a mesma em todo o controller.
  71. class ReposController < ApplicationController def show @repo = current_user.repos.find(params[:id]) fresh_when([current_user.id,

    @repo]) end end Rails 3
  72. Você pode definir componentes lobais no controller, complementando com outros

    componentes na action.
  73. class ReposController < ApplicationController etag { current_user.id } def show

    @repo = current_user.repos.find(params[:id]) fresh_when(@repo) end end
  74. O cachin de fra mentos também ficou mais simples com

    a nova estraté ia de russian doll cachin .
  75. No Rails 3 você precisava definir uma versão do fra

    mento e atualizar seu valor caso o markup mudasse.
  76. posts/_post.html.erb posts/index.html.erb posts/_post.html.erb posts/_post.html.erb

  77. <!-- app/views/posts/index.html.erb --> <%= render @posts %> <!-- app/views/posts/_post.html.erb -->

    <% cache ["v1", post] do %> <article class="post"> <%= link_to post.title, post_path(post) %> </article> <% end %>
  78. posts/show.html.erb the posts details comments/_comment.html.erb comments/_comment.html.erb

  79. <!-- app/views/posts/show.html.erb --> <% cache ["v1", @post, "details"] do %>

    <h1><%= @post.title %></h1> <%= simple_format @post.content %> <%= render @post.comments %> <% end %> <!-- app/views/comments/_comment.html.erb --> <% cache ["v1", comment] do %> <article class="comment"> <%= simple_format comment.content %> </article> <% end %>
  80. Esse esquema de cachin iria erar chaves considerando a versão.

  81. views/v1/posts/1-20130714050931 views/v1/posts/2-20130714052742 views/v1/posts/3-20130714052756 views/v1/posts/1-20130714050931/details views/v1/comments/1-20130714050931

  82. Se a partial _comment.html.erb fosse alterada, você precisaria mudar a

    versão de toda a hierarquia.
  83. No Rails 4 você não precisa mais adicionar a versão

    do cache, pois isso é calculado automaticamente.
  84. <!-- app/views/posts/_post.html.erb --> <% cache post do %> <article class="post">

    <%= link_to post.title, post_path(post) %> </article> <% end %> <% cache [@post, "details"] do %> <h1><%= @post.title %></h1> <%= simple_format @post.content %> <%= render @post.comments %> <% end %> <% cache comment do %> <article class="comment"> <%= simple_format comment.content %> </article> <% end %>
  85. Um hash MD5 é calculado à partir do conteúdo do

    bloco do método cache.
  86. views/posts/1-20130714050931154460000/7c2217e636 8… views/posts/2-20130714052742379289000/7c2217e636 8… views/posts/3-20130714052756198046000/7c2217e636 8… views/posts/1-20130714050931154460000/details/369c5d… views/comments/1-20130714050931144537000/7069559c…

  87. O cache di est só é calculado uma vez, mesmo

    em modo de desenvolvimento. Reinicie o memcached ou o app server para recalculá-lo.
  88. Outras mudanças

  89. Foi removido o suporte para plu ins dentro de vendor/plu

    ins.
  90. ActiveRecord session store foi extraída para uma em chamada activerecord-session_store.

  91. Observers e cache sweepers foram extraídos para a em rails-observers.

  92. As funcionalidades de cachin foram extraídas para as ems actionpack-pa

    e_cachin e actionpack-action_cachin .
  93. ActiveResource não é mais incluído nas dependências do Rails por

    padrão.
  94. Al uns finders do ActiveRecord deixaram de existir ou tiveram

    uma nova API.
  95. User.find_all_by_role("admin") # Rails 3 User.where(role: "admin") # Rails 4 User.find_last_by_role("admin")

    # Rails 3 User.where(role: "admin").last # Rails 4 User.find_or_create_by_role("admin") # Rails 3 User.find_or_create_by(role: "admin") # Rails 4 User.find_or_initialize_by_role("admin") # Rails 3 User.find_or_initialize_by(role: "admin") # Rails 4 User.scoped_by_role("admin") # Rails 3 User.where(role: "admin") # Rails 4 User.all(role: "admin") # Rails 3 User.where(role: "admin") # Rails 3
  96. User.find(:first) # Rails 3 User.first # Rails 4 User.find(:last) #

    Rails 3 User.last # Rails 4 User.find(:all) # Rails 3 User.all # Rails 4
  97. Instale a em activerecord-deprecated_finders para trazer a API anti a

    de volta.
  98. O verbo HTTP de atualização de resources foi alterado de

    PUT para PATCH. https:// ithub.com/rails/rails/pull/505
  99. Os filtros de fluxo de requisição foram renomeados de *_filter

    para *_action.
  100. before_filter after_filter around_filter before_action after_action around_action

  101. class TopicsController before_action :require_logged_user, only: %i[ new create ] end

  102. Os diretórios de teste a ora tem nomes mais coerentes.

  103. test user_test.rb repo_test.rb models application_helper_test.rb html_helper_test.rb helpers mailer_test.rb mailers #

    antes era test/units # antes era test/units/helpers # antes era test/functional application_controller_test.rb repos_controller_test.rb controllers # antes era test/functional
  104. Você pode definir headers que serão enviados em todos as

    requisições.
  105. config.action_dispatch.default_headers = { "X-Frame-Options" => "SAMEORIGIN", "X-XSS-Protection" => "1; mode=block",

    "X-Content-Type-Options" => "nosniff" } http://fnando.me/jh
  106. Foram adicionados novos helpers de formulário.

  107. week_field month_field datetime_field datetime_local_field time_field date_field color_field collection_check_boxes collection_radio_buttons

  108. A pá ina de boas-vindas a ora é dinâmica e

    exibida apenas em modo de desenvolvimento quando a rota root não tiver sido definida.
  109. Thread-safe por padrão.

  110. * * *

  111. Existem muito mais novidades. Al umas nem aparecem nos chan

    elo s.
  112. Experimente as novas funcionalidades para saber se vale a pena

    ou não usá-las.
  113. Obri ado!

  114. * * *

  115. http://howtocode.com.br