Os truques que o Rails não te contou @ RubyConf Brasil 2014

Os truques que o Rails não te contou @ RubyConf Brasil 2014

77237b97a465ae5a293ad323b7296837?s=128

Carlos Antonio

August 29, 2014
Tweet

Transcript

  1. 3.
  2. 12.

    E isso é um grande problema As pessoas têm medo

    de lidar com esse tipo de código.
  3. 14.

    Que podem te ajudar a refatorar código existente ou melhorar

    sua vida como desenvolvedor um pouquinho.
  4. 16.
  5. 18.
  6. 19.
  7. 22.
  8. 25.
  9. 26.
  10. 27.
  11. 28.
  12. 29.
  13. 31.

    O que vamos ver: Active Record Active Model Action Mailer

    ! Action View Action Controller Bonus Stuff
  14. 33.

    migrations: revert class DropAuthorsActive < ActiveRecord::Migration def up remove_column :authors,

    :active end ! def down add_column :authors, :active, :boolean, default: true end end
  15. 35.

    migrations: revert class DropAuthorsActive < ActiveRecord::Migration def change revert do

    add_column :authors, :active, :boolean, default: true end end end
  16. 36.

    migrations: change column null class ChangeNameToNotNullOnAuthors < ActiveRecord::Migration def up

    change_column :authors, :name, :string, null: false end ! def down change_column :authors, :name, :string, null: true end end
  17. 37.

    migrations: change column null class ChangeNameToNotNullOnAuthors < ActiveRecord::Migration def up

    change_column_null :authors, :name, false end ! def down change_column_null :authors, :name, true end end
  18. 39.

    migrations: change column default class ChangeStatusDefaultOnArticles < ActiveRecord::Migration def up

    change_column :articles, :status, :string, default: 'draft' end ! def down change_column :articles, :status, :string, default: 'published' end end
  19. 40.

    migrations: change column default class ChangeStatusDefaultOnArticles < ActiveRecord::Migration def up

    change_column_default :articles, :status, 'draft' end ! def down change_column_default :articles, :status, 'published' end end
  20. 41.

    migrations: change column default class ChangeStatusDefaultOnArticles < ActiveRecord::Migration def change

    change_column_default :articles, :status, 'draft' end end # => ActiveRecord::IrreversibleMigration
  21. 42.

    Relation#merge class Author < ActiveRecord::Base has_many :articles ! scope :with_draft_articles,

    -> { uniq.joins(:articles). where(articles: { status: 'draft' }) } end
  22. 43.

    Relation#merge >> Author.with_draft_articles.to_sql ! SELECT DISTINCT "authors".* FROM "authors" INNER

    JOIN "articles" ON "articles"."author_id" = "authors"."id" WHERE "articles"."status" = 'draft'
  23. 45.

    Relation#merge >> Author.with_draft_articles.to_sql ! SELECT DISTINCT "authors".* FROM "authors" INNER

    JOIN "articles" ON "articles"."author_id" = "authors"."id" WHERE "articles"."status" = 'draft'
  24. 46.

    find_by >> Article.where(title: 'ZOMG').first => #<Article id: 113629430 ...> !

    >> Article.find_by(title: 'ZOMG') => #<Article id: 113629430 ...>
  25. 47.

    where.not class Article < ActiveRecord::Base scope :not_draft, -> { where

    'status != ?', 'draft' } end ! >> Article.not_draft.to_sql ! SELECT “articles".* FROM "articles" WHERE (status != 'draft')
  26. 48.

    where.not class Article < ActiveRecord::Base scope :not_draft, -> { where.not

    status: 'draft' } end ! >> Article.not_draft.to_sql ! SELECT “articles".* FROM "articles" WHERE ("articles"."status" != 'draft')
  27. 49.

    order :asc/:desc class Article < ActiveRecord::Base scope :recent, -> {

    order 'created_at DESC' } end ! >> Article.recent ! SELECT "articles".* FROM "articles" ORDER BY created_at DESC
  28. 50.

    order :asc/:desc class Article < ActiveRecord::Base scope :recent, -> {

    order created_at: :desc } end ! >> Article.recent ! SELECT "articles".* FROM "articles" ORDER BY "articles"."created_at" DESC
  29. 51.

    estratégias de eager load >> Article.includes(:author) ! SELECT "articles".* FROM

    "articles" ! SELECT "authors".* FROM "authors" WHERE "authors"."id" IN (980190962, 298486374)
  30. 52.

    estratégias de eager load >> Article.includes(:author).order('authors.name') ! SELECT "articles"."id" AS

    t0_r0 ………… "authors"."updated_at" AS t1_r4 FROM "articles" LEFT OUTER JOIN "authors" ON "authors"."id" = “articles"."author_id" ORDER BY authors.name
  31. 53.

    estratégias de eager load >> Article.eager_load(:author) ! SELECT "articles"."id" AS

    t0_r0 ………… "authors"."updated_at" AS t1_r4 FROM "articles" LEFT OUTER JOIN "authors" ON "authors"."id" = “articles”."author_id"
  32. 54.

    estratégias de eager load >> Article.preload(:author) ! SELECT "articles".* FROM

    “articles" ! SELECT "authors".* FROM “authors" WHERE "authors"."id" IN (980190962, 298486374)
  33. 55.

    estratégias de eager load >> Article.preload(:author). joins(:author).order('authors.name') ! SELECT "articles".*

    FROM "articles" INNER JOIN "authors" ON "authors"."id" = "articles"."author_id" ORDER BY authors.name ! SELECT "authors".* FROM "authors" WHERE "authors"."id" IN (980190962, 298486374)
  34. 56.

    group counting >> Article.group(:status).count ! SELECT COUNT(*) AS count_all, status

    AS status FROM "articles" GROUP BY status ! => {"draft"=>7, “published"=>2}
  35. 57.

    group counting: múltiplos atributos >> Article.group(:status, :category).count ! SELECT COUNT(*)

    AS count_all, status AS status, category AS category FROM "articles" GROUP BY status, category ! => {["draft", nil]=>5, ["draft", "Talks"]=>2, ["published", "News"]=>1, ["published", "Releases"]=>1}
  36. 64.

    exists?/any? vs present? >> author = Author.first ! >> author.articles.exists?

    ! SELECT 1 AS one FROM "articles" WHERE "articles"."author_id" = ? LIMIT 1 [["author_id", 1]] ! => true
  37. 65.

    exists?/any? vs present? >> author.articles.each {} ! SELECT "articles".* FROM

    "articles" WHERE "articles"."author_id" = ? [["author_id", 1]]
  38. 66.

    exists?/any? vs present? >> author = Author.first ! >> author.articles.present?

    ! SELECT "articles".* FROM "articles" WHERE "articles"."author_id" = ? [["author_id", 1]] ! => true
  39. 67.
  40. 68.

    association count vs size >> author = Author.first ! >>

    author.articles.count SELECT COUNT(*) FROM "articles" WHERE "articles"."author_id" = ? [["author_id", 1]] ! >> author.articles.size SELECT COUNT(*) FROM "articles" WHERE "articles"."author_id" = ? [["author_id", 1]]
  41. 69.

    association count vs size >> author = Author.includes(:articles).first ! >>

    author.articles.count SELECT COUNT(*) FROM "articles" WHERE "articles"."author_id" = ? [["author_id", 1]] ! >> author.articles.size ! # => já carregado, não dispara outra query
  42. 71.

    benchmark >> start = Time.now => 2014-04-21 10:48:30 -0500 >>

    Article.expensive_operation => "did something very expensive" >> finish = Time.now => 2014-04-21 10:48:32 -0500 >> finish - start => 2.02356
  43. 72.

    benchmark >> ActiveRecord::Base.benchmark 'SUPER EXPENSIVE OPERATION' do ?> Article.expensive_operation >>

    end SUPER EXPENSIVE OPERATION (2000.9ms) => "did something very expensive"
  44. 73.

    benchmark class Article < ActiveRecord::Base def self.expensive_operation benchmark 'SUPER EXPENSIVE

    OPERATION' do sleep 2 'did something very expensive' end end end
  45. 75.

    ActiveModel::Model class EmailContact attr_accessor :name, :email, :message ! def deliver

    if name.present? && email.present? && message.present? puts 'deliver email' end end end
  46. 78.

    ActiveModel::Model class EmailContact extend ActiveModel::Naming extend ActiveModel::Translation include ActiveModel::Validations include

    ActiveModel::Conversion ! attr_accessor :name, :email, :message validates :name, :email, :message, presence: true ! def deliver if valid? puts 'deliver email' end end ! def persisted? false end end
  47. 79.

    ActiveModel::Model class EmailContact include ActiveModel::Model ! attr_accessor :name, :email, :message

    validates :name, :email, :message, presence: true ! def deliver if valid? puts 'deliver email' end end end
  48. 81.

    ActiveModel::Model >> contact = EmailContact.new => #<EmailContact:0x007fb90e268350> ! >> contact.valid?

    => false ! >> contact.errors.full_messages.to_sentence => "Name can't be blank, Email can't be blank, and Message can't be blank"
  49. 83.

    Mailer com i18n subject class Notifier < ActionMailer::Base default from:

    "from@example.com" ! # Subject can be set in your I18n file at config/locales/en.yml # with the following lookup: # # en.notifier.new_article.subject # def new_article @greeting = "Hi" ! mail to: "to@example.org" end end
  50. 84.

    Mailer com i18n subject class Notifier < ActionMailer::Base default from:

    "from@example.com" ! def new_article @greeting = "Hi" ! mail to: "to@example.org" end end
  51. 85.

    Mailer com i18n subject class Notifier < ActionMailer::Base default from:

    "from@example.com" ! def new_article @greeting = "Hi" ! mail to: "to@example.org", subject: I18n.t('subjects.new_article') end end
  52. 88.

    Mailer com i18n subject class Notifier < ActionMailer::Base default from:

    "from@example.com" ! def new_article @greeting = "Hi" ! mail to: "to@example.org" end end
  53. 89.

    Mailer com i18n subject class Notifier < ActionMailer::Base default from:

    "from@example.com" ! def new_article @greeting = "Hi" ! mail to: "to@example.org", subject: I18n.t('subjects.new_article', title: 'Clarity is king') end end
  54. 92.

    Mailer com i18n subject class Notifier < ActionMailer::Base default from:

    "from@example.com" ! def new_article @greeting = "Hi" ! mail to: "to@example.org", subject: default_i18n_subject(title: 'Clarity is king') end end
  55. 95.

    content_tag_for <article class="article" id="article_281110143"> <h2>Rails 4.2.0 is going to be

    more Adequate</h2> <p>Rails 4.2.0 is going to be made more Adequate by Tenderlove and Gorby Puff</p> </article> <article class="article" id="article_298486374"> <h2>Rails 4.1.0 Released</h2> <p>Rails 4.1.0 was just released before RailsConf</p> </article>
  56. 98.

    render com coleções vazias <% if author.articles.exists? %> <%= render

    author.articles %> <% else %> <p>No article found.</p> <% end %>
  57. 100.

    truncar textos <%= truncate article.body do %> <%= link_to 'read

    more...', article %> <% end %> ! ! Rails 4.2.0 is going to be ... <a href="/articles/281110143-rails-4-2-0-is"> read more… </a>
  58. 101.

    I18n + html <%= link_to t('read_more'), article %> ! en:

    read_more: 'read more…' ! ! <a href="/articles/281110143-rails-4-2-0-is"> read more… </a>
  59. 102.

    I18n + html <%= link_to t('read_more'), article %> ! en:

    read_more: 'read <b>more</b>…' ! ! <a href="/articles/281110143-rails-4-2-0-is"> read &lt;b&gt;more&lt;/b&gt;… </a>
  60. 103.

    I18n + html <%= link_to raw(t('read_more')), article %> ! en:

    read_more: 'read <b>more</b>…' ! ! <a href="/articles/281110143-rails-4-2-0-is"> read <b>more</b>… </a>
  61. 104.

    I18n + html <%= link_to t(‘read_more_html'), article %> ! en:

    read_more_html: 'read <b>more</b>…' ! ! <a href="/articles/281110143-rails-4-2-0-is"> read <b>more</b>… </a>
  62. 105.

    benchmark <% benchmark 'Rendering articles' do %> <%= sleep(2); render

    author.articles %> <% end %> ! ! # logger Rendering articles (2005.1ms)
  63. 109.

    tratamento de exceções # config/application.rb ! # Use the app's

    own router to display error pages. config.exceptions_app = self.routes
  64. 110.

    tratamento de exceções # config/routes.rb ! get "/404", to: "errors#not_found"

    get "/422", to: "errors#unprocessable_entity" get "/500", to: "errors#server_error"
  65. 111.
  66. 113.
  67. 114.

    app >> app.author_path(Author.first) => “/authors/298486374" ! >> app.get _ Started

    GET "/authors/298486374" for 127.0.0.1 at 2014-04-22 19:31:04 -0500 Processing by AuthorsController#show as HTML … Rendered authors/show.html.erb within layouts/application (1.1ms) Completed 200 OK in 9ms (Views: 7.7ms | ActiveRecord: 0.2ms) => 200 ! >> app.class => ActionDispatch::Integration::Session
  68. 115.

    helper >> helper.time_ago_in_words 30.days.ago => "about 1 month" ! >>

    helper.hello_ruby_conf => "Hello RubyConfBR 2014!" ! >> helper.class => ActionView::Base
  69. 117.

    console helpers da aplicação # config/application.rb module RubyConf2014 class Application

    < Rails::Application console do require 'console_helpers' Rails::ConsoleMethods.send :include, ConsoleHelpers end end end
  70. 118.

    console helpers da aplicação >> a(113629430) Article Load (0.1ms) SELECT

    "articles".* FROM "articles" WHERE "articles"."id" = ? LIMIT 1 [["id", 113629430]] ! => #<Article id: 113629430, …>
  71. 119.

    console sandbox $ rails runner 'puts Article.count' 4 ! $

    rails console --sandbox >> Article.create! title: 'I will be rolled back' => #<Article id: 980190968, title: "I will be rolled back", …> >> Article.count => 5 ! $ rails runner 'puts Article.count' 4
  72. 120.

    console sandbox $ rails console --sandbox … Any modifications you

    make will be rolled back on exit ! ! ! >> exit rollback transaction
  73. 123.

    rails update $ rake rails:update identical config/boot.rb exist config conflict

    config/routes.rb ./railsconf2014-404/config/routes.rb? (enter "h" for help) [Ynaqdh] h Y - yes, overwrite n - no, do not overwrite a - all, overwrite this and all others q - quit, abort d - diff, show the differences between the old and the new h - help, show this help ./railsconf2014-404/config/routes.rb? (enter "h" for help) [Ynaqdh] a force config/routes.rb … exist config/initializers identical config/initializers/backtrace_silencers.rb create config/initializers/cookies_serializer.rb identical config/initializers/filter_parameter_logging.rb …
  74. 124.

    rails update $ git status On branch master Changes not

    staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) ! modified: Gemfile modified: Gemfile.lock modified: config/environment.rb modified: config/environments/development.rb modified: config/environments/production.rb modified: config/environments/test.rb modified: config/initializers/mime_types.rb modified: config/initializers/session_store.rb modified: config/routes.rb ! Untracked files: (use "git add <file>..." to include in what will be committed) ! config/initializers/cookies_serializer.rb config/secrets.yml
  75. 135.