Tricks that Rails didn't tell you.

Tricks that Rails didn't tell you.

Some Rails tricks to help your productivity.

2c41115521424eb593d93c44b92ced0c?s=128

Kassio Borges

October 18, 2014
Tweet

Transcript

  1. TRICKS THAT RAILS DIDN’T TELL YOU

  2. disclaimer

  3. Carlos Antonio RailsConfchicago RubyConfsão paulo

  4. None
  5. None
  6. TRICKS THAT RAILS DIDN’T TELL YOU

  7. TRICKS THAT CARLOS DIDN’T TELL YOU

  8. Who am I?

  9. Kassio Borges kassio! kassioborgesm

  10. ~9 yearsIT

  11. Coffee Boy! Support! Deployment! Trainer! Developer

  12. ~5 yearson Rails

  13. None
  14. Web Development Consultancy! Ruby and Rails! São Paulo

  15. ❤️

  16. plataformatec/devise

  17. plataformatec/simple_form

  18. elixir-lang/elixir elixir-lang.org

  19. TRICKS THAT RAILS DIDN’T TELL YOU

  20. ~5 yearson Rails

  21. I’ve written code

  22. I’ve written good code

  23. I’ve written bad code

  24. I’ve written duplicated code

  25. I’ve rewritten some Rails code

  26. SOME RAILS TRICKS! are not very well know and/or documented

  27. TRICKS THAT RAILS DIDN’T TELL YOU

  28. ActiveRecord! ActiveModel! ActionView! ActionMailer! ActionController! ActiveSupport

  29. ActiveRecord! ActiveModel! ActionView! ActionMailer! ActionController! ActiveSupport

  30. 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
  31. 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
  32. change column null class ChangeNameToNotNullOnAuthors < ActiveRecord::Migration def change change_column_null

    :authors, :name, false end end ! class ChangeNameToNotNullOnAuthors < ActiveRecord::Migration def change change_column :authors, :name, :string, null: false end end # => ActiveRecord::IrreversibleMigration
  33. 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
  34. change column default class ChangeStatusDefaultOnArticles < ActiveRecord::Migration def change change_column_default

    :articles, :status, 'draft' end end
  35. change column default class ChangeStatusDefaultOnArticles < ActiveRecord::Migration def change change_column_default

    :articles, :status, 'draft' end end # => ActiveRecord::IrreversibleMigration ! class ChangeStatusDefaultOnArticles < ActiveRecord::Migration def change change_column :articles, :status, :string, default: 'draft' end end # => ActiveRecord::IrreversibleMigration
  36. 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')
  37. 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')
  38. 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
  39. 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
  40. pluck >> Author.all.map(&:name) SELECT "authors".* FROM "authors" ! => ["Author

    2", "Author 1"]
  41. pluck >> Author.select(:name).map(&:name) SELECT "authors"."name" FROM "authors" ! => ["Author

    2", "Author 1"]
  42. pluck >> Author.pluck(:name) SELECT "authors"."name" FROM "authors" ! => ["Author

    2", "Author 1"]
  43. pluck >> Author.pluck(:name, :active) SELECT "authors"."name", "authors"."active" FROM "authors" !

    => [["Author 2", true], ["Author 1", true]]
  44. benchmark class Article < ActiveRecord::Base def self.expensive_operation sleep 2 'did

    something very expensive' end end ! >> start = Time.now; Article.expensive_operation; Time.now - start => 2.001179
  45. benchmark class Article < ActiveRecord::Base def self.expensive_operation benchmark 'SUPER EXPENSIVE

    OPERATION' do sleep 2 'did something very expensive' end end end ! >> Article.expensive SUPER EXPENSIVE OPERATION (2001.2ms)
  46. ActiveRecord! ActiveModel! ActionView! ActionMailer! ActionController! ActiveSupport

  47. ActiveRecord! ActiveModel! ActionView! ActionMailer! ActionController! ActiveSupport

  48. validates strict class Comment include ActiveModel::Validations ! attr_accessor :message !

    validates :message, presence: true, strict: true end ! >> Comment.new.valid? # ActiveModel::StrictValidationFailed: Message can't be blank
  49. validates strict class Comment include ActiveModel::Validations ! attr_accessor :message validate

    do |comment| if message.blank? errors.add(:base, 'You need a message!') end end end ! >> Comment.new.valid? # false
  50. validates strict class Comment include ActiveModel::Validations ! attr_accessor :message validate

    do |comment| if message.blank? errors.add(:base, 'You need a message!', strict: true) end end end ! > Comment.new.valid? # ActiveModel::StrictValidationFailed: You need a message!
  51. ActiveRecord! ActiveModel! ActionView! ActionMailer! ActionController! ActiveSupport

  52. ActiveRecord! ActiveModel! ActionView! ActionMailer! ActionController! ActiveSupport

  53. menu links <li> <%= link_to 'posts', posts_path, class: active?(posts_path) %>

    </li> <li> <%= link_to 'new post', new_post_path, class: active?(new_post_path) %> </li>
  54. menu links module ApplicationHelper def active?(path) if request.path == path

    'active' end end end
  55. menu links module ApplicationHelper def active?(*page) if current_page?(page) 'active' end

    end end
  56. menu links <li> <%= link_to 'posts', posts_path, class: active?(posts_path) %>

    </li> <li> <%= link_to 'new post', new_post_path, class: active?(new_post_path) %> </li>
  57. menu links <li> <%= link_to_unless current_path?(posts_path), 'posts', posts_path %> </li>

    <li> <%= link_to_unless current_path?(new_post_path), 'new post', new_post_path %> </li>
  58. menu links <li><%= link_to_unless_current 'posts', posts_path %></li> <li><%= link_to_unless_current 'new

    post', new_post_path %></li>
  59. I18n + html <%= link_to t('read_more'), article %> ! <a

    href="/articles/281110143-rails-4-2-0-is"> read more </a> en: read_more: 'read more'
  60. I18n + html <%= link_to t('read_more'), article %> ! <a

    href="/articles/281110143-rails-4-2-0-is"> read &lt;b&gt;more&lt;/b&gt; </a> en: read_more: 'read <b>more</b>'
  61. I18n + html en: read_more: 'read <b>more</b>' <%= link_to raw(t('read_more')),

    article %> ! <a href="/articles/281110143-rails-4-2-0-is"> read <b>more</b> </a>
  62. I18n + html en: read_more_html: 'read <b>more</b>' <%= link_to t('read_more_html'),

    article %> ! <a href="/articles/281110143-rails-4-2-0-is"> read <b>more</b> </a>
  63. benchmark <% start = Time.now %> <%= sleep(2); render 'form'

    %> <% Rails.logger.info("EXPENSIVE VIEW #{Time.now - start}") %> ! ! # logger # Rendered posts/_form.html.erb (2.5ms) # EXPENSIVE VIEW 2.003919
  64. benchmark <% benchmark 'EXPENSIVE VIEW' do %> <%= sleep(2); render

    'form' %> <% end %> ! ! # logger # Rendered posts/_form.html.erb (2.3ms) # EXPENSIVE VIEW (2004.5ms)
  65. ActiveRecord! ActiveModel! ActionView! ActionMailer! ActionController! ActiveSupport

  66. ActiveRecord! ActiveModel! ActionView! ActionMailer! ActionController! ActiveSupport

  67. 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
  68. 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
  69. I18n subject class Notifier < ActionMailer::Base default from: "from@example.com" !

    def new_article @greeting = "Hi" ! mail to: "to@example.org" end end
  70. 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 en: subjects: new_article: 'New article just published.'
  71. I18n subject class Notifier < ActionMailer::Base default from: "from@example.com" !

    def new_article @greeting = "Hi" ! mail to: "to@example.org" end end en: notifier: new_article: subject: 'New article just published.'
  72. I18n subject en: subjects: new_article: 'New article: %{title}.' def new_article

    @greeting = "Hi" ! mail to: "to@example.org", subject: I18n.t('subjects.new_article', title: 'Clarity is king') end
  73. 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 en: notifier: new_article: subject: 'New article: %{title}.'
  74. ActiveRecord! ActiveModel! ActionView! ActionMailer! ActionController! ActiveSupport

  75. ActiveRecord! ActiveModel! ActionView! ActionMailer! ActionController! ActiveSupport

  76. exceptions handling # exceptions handling ! $ ls public/*.html !

    404.html 422.html 500.html
  77. exceptions handling # config/application.rb ! # Use the app's own

    router to display error pages. config.exceptions_app = self.routes
  78. exceptions handling # config/routes.rb ! get "/404", to: "errors#not_found" get

    "/422", to: "errors#unprocessable_entity" get "/500", to: "errors#server_error"
  79. exceptions handling class ErrorsController < ApplicationController layout "error" ! def

    not_found render status: :not_found end ! # ... end
  80. ActiveRecord! ActiveModel! ActionView! ActionMailer! ActionController! ActiveSupport

  81. ActiveRecord! ActiveModel! ActionView! ActionMailer! ActionController! ActiveSupport

  82. index_by /authors /posts [ { "id": 1, "name": "d4rth_v4der" },

    { "id": 2, "name": "luke_skywalk3r" }, { "id": 3, "name": "han_solo" } ] [ { "text": "@luke, I am your father!", "author": 1 }, { "text": "NOOOOOOOOOOOOO!! (╯°□°)╯︵ ┻━┻", "author": 2 }, { "text": "@luke “ ƅϪƅ“)", "author": 3 } ]
  83. index_by @luke, I am your father!! d4rth_v4der! ---! NOOOOOOOOOOOOOOO!! (╯°□°)╯︵

    ┻━┻! luke_skywalk3r! ---! @luke “ ƅϪƅ“)! han_solo! ---
  84. index_by posts.each do |post| author = authors.select do |a| a.id

    == post.author end.first ! puts post.text puts author.name puts '---' end
  85. index_by N*M 10*10 = 100

  86. index_by posts.each do |post| author = indexed_authors[post.author] ! puts post.text

    puts author.name puts '---' end indexed_author = { 1=>#<Author id=1, name="Kassio Borges">, 2=>#<Author id=2, name="Boring">, }
  87. index_by N+M 10+10 = 20

  88. index_by indexed_author = { 1=>#<Author id=1, name="Kassio Borges">, 2=>#<Author id=2,

    name="Boring">, }
  89. index_by indexed_authors = authors.inject({}) do |mem, author| mem[author.id] = author

    mem end
  90. index_by indexed_authors = authors.each_with_object({}) do |author, mem| mem[author.id] = author

    end
  91. index_by indexed_authors = authors.index_by(&:id)

  92. ActiveRecord! ActiveModel! ActionView! ActionMailer! ActionController! ActiveSupport

  93. Finishing

  94. Every single part of Rails! has hidden tricks

  95. Sometimes they are! hard to spot

  96. But they can make you much more productive

  97. So every time you start something new

  98. Before ever considering about pattern X, Y or Z

  99. Ask yourself:
 How Rails can help me?

  100. Search! • API! • Guidelines! • IRC! • Rails Talk

    mailing list! • Stack Overflow
  101. Follow! • Changelogs! • Release notes! • Upgrading guides! •

    Commits (if you can)
  102. And if you find some hidden trick, remember

  103. With a great moustache! cames a great responsibility

  104. Share! • Tweet! • Blog post! • Tell your friends!

    • Talk at RuPy
  105. Contribute back to Rails

  106. And please,! tell me what you found! kassio! kassioborgesm

  107. Thanks! kassio! kassioborgesm