$30 off During Our Annual Pro Sale. View Details »

Os truques que o Rails não te contou @ TDC Floripa 2014

Os truques que o Rails não te contou @ TDC Floripa 2014

Carlos Antonio

May 17, 2014
Tweet

More Decks by Carlos Antonio

Other Decks in Technology

Transcript

  1. Os truques que o Rails
    não te contou

    View Slide

  2. Carlos Antonio
    @cantoniodasilva

    View Slide

  3. ~6 anos
    com Rails

    View Slide

  4. Eu já participei em
    vários projetos com
    contextos diferentes

    View Slide

  5. Eu já vi código

    View Slide

  6. Eu já vi código complexo

    View Slide

  7. Eu já vi código duplicado

    View Slide

  8. Eu já vi código do Rails
    reimplementado em apps

    View Slide

  9. Com que frequência você vê eles?
    Todo o tempo. Eles estão em toda parte.

    View Slide

  10. Você se acostuma com o
    código após algum tempo

    View Slide

  11. E isso é um
    grande problema
    As pessoas têm medo de lidar com esse tipo de código.

    View Slide

  12. Rails tricks / features

    View Slide

  13. Que podem te ajudar a
    refatorar código existente
    ou melhorar sua vida como desenvolvedor um pouquinho

    View Slide

  14. View Slide

  15. View Slide

  16. Consultoria em
    Desenvolvimento Web
    Com foco principal em Ruby e Rails
    São Paulo - Brazil

    View Slide

  17. ❤️

    View Slide

  18. plataformatec/devise

    View Slide

  19. plataformatec/simple_form

    View Slide

  20. elixir-lang/elixir

    View Slide

  21. Rails Core Team
    ! Carlos Antonio

    View Slide

  22. Rails Core Team
    José Valim Carlos Antonio Rafael França

    View Slide

  23. Nós usamos pull requests !
    e code review
    All the f*cking time.

    View Slide

  24. Nós fizemos code review
    de diferentes projetos
    Sempre que o tempo nos permite.

    View Slide

  25. E é comum aprender
    coisas novas no processo
    Estamos sempre aprendendo, certo?

    View Slide

  26. View Slide

  27. View Slide

  28. View Slide

  29. View Slide

  30. View Slide

  31. ಠ_ಠ
    Eu tive que criar este talk depois disso.

    View Slide

  32. Rails tricks / features
    Não usadas por muitos
    Não muito conhecidas e / ou documentadas

    View Slide

  33. O que vamos ver:
    Active Record
    Active Model
    Action Mailer
    Action View
    Action Controller
    Bonus Stuff

    View Slide

  34. Active Record

    View Slide

  35. 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

    View Slide

  36. 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

    View Slide

  37. migrations: change column null
    class ChangeNameToNotNullOnAuthors < ActiveRecord::Migration
    def change
    change_column :authors, :name, :string, null: false
    end
    end
    # => ActiveRecord::IrreversibleMigration
    !
    class ChangeNameToNotNullOnAuthors < ActiveRecord::Migration
    def change
    change_column_null :authors, :name, false
    end
    end

    View Slide

  38. 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

    View Slide

  39. 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

    View Slide

  40. migrations: change column default
    class ChangeStatusDefaultOnArticles < ActiveRecord::Migration
    def change
    change_column :articles, :status, :string, default: 'draft'
    end
    end
    # => ActiveRecord::IrreversibleMigration
    !
    class ChangeStatusDefaultOnArticles < ActiveRecord::Migration
    def change
    change_column_default :articles, :status, 'draft'
    end
    end
    # => ActiveRecord::IrreversibleMigration

    View Slide

  41. Relation#merge
    class Author < ActiveRecord::Base
    has_many :articles
    !
    scope :with_draft_articles, -> {
    uniq.joins(:articles).
    where(articles: { status: 'draft' })
    }
    end

    View Slide

  42. 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'

    View Slide

  43. Relation#merge
    class Author < ActiveRecord::Base
    has_many :articles
    !
    scope :with_draft_articles, -> {
    uniq.joins(:articles).merge(Article.draft)
    }
    end

    View Slide

  44. 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'

    View Slide

  45. group counting
    >> Article.group(:status).count
    !
    SELECT COUNT(*) AS count_all, status AS status
    FROM "articles"
    GROUP BY status
    !
    => {"draft"=>7, "published"=>2}

    View Slide

  46. 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}

    View Slide

  47. first!
    relation = Article.where(title: 'UNKNOWN')
    !
    relation.first or raise(ActiveRecord::RecordNotFound, 'ZOMG not found')
    # => ZOMG Article found (ActiveRecord::RecordNotFound)
    !
    relation.first!
    # => ActiveRecord::RecordNotFound

    View Slide

  48. last!
    relation = Article.where(title: 'UNKNOWN')
    !
    relation.last or raise(ActiveRecord::RecordNotFound, 'ZOMG not found')
    # => ZOMG Article found (ActiveRecord::RecordNotFound)
    !
    relation.last!
    # => ActiveRecord::RecordNotFound

    View Slide

  49. 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')

    View Slide

  50. 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')

    View Slide

  51. estratégias de eager load
    >> Article.includes(:author)
    !
    SELECT "articles".* FROM "articles"
    !
    SELECT "authors".* FROM "authors"
    WHERE "authors"."id" IN (980190962, 298486374)

    View Slide

  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

    View Slide

  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"

    View Slide

  54. estratégias de eager load
    >> Article.preload(:author)
    !
    SELECT "articles".* FROM “articles"
    !
    SELECT "authors".* FROM “authors"
    WHERE "authors"."id" IN (980190962, 298486374)

    View Slide

  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)

    View Slide

  56. 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

    View Slide

  57. 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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  61. pluck: múltiplos atributos
    >> Author.pluck(:name, :active)
    !
    SELECT "authors"."name", "authors"."active"
    FROM "authors"
    !
    => [["Author 2", true], ["Author 1", true]]

    View Slide

  62. pluck: valores distintos
    >> Author.distinct.pluck(:name)
    !
    SELECT DISTINCT "authors"."name" FROM "authors"
    !
    => ["Author 2", "Author 1"]

    View Slide

  63. to_param
    class Article < ActiveRecord::Base
    def to_param
    "#{id}-#{title.parameterize}"
    end
    end
    !
    >> Article.all.map(&:to_param)
    => ["113629430-autoload",
    "281110143-rails-4-2-0-is-going-to-be-more-adequate",
    "298486374-rails-4-1-0-released",
    "980190962-rails-tricks"]

    View Slide

  64. to_param
    class Article < ActiveRecord::Base
    to_param :title
    end
    !
    !
    !
    >> Article.all.map(&:to_param)
    => ["113629430-autoload",
    "281110143-rails-4-2-0-is",
    "298486374-rails-4-1-0-released",
    "980190962-rails-tricks"]

    View Slide

  65. exists?/any? vs present?
    <% if @author.articles.exists? %>
    <%= render @author.articles %>
    <% else %>
    No article found.
    <% end %>

    View Slide

  66. exists?/any? vs present?
    >> author = Author.first
    !
    >> author.articles.exists?
    !
    SELECT 1 AS one FROM "articles"
    WHERE "articles"."author_id" = ? LIMIT 1 [["author_id", 298486374]]
    !
    => true
    !
    >> author.articles.each {}
    !
    SELECT "articles".* FROM "articles"
    WHERE "articles"."author_id" = ? [["author_id", 298486374]]

    View Slide

  67. exists?/any? vs present?
    >> author = Author.first
    !
    >> author.articles.present?
    !
    SELECT "articles".* FROM "articles"
    WHERE "articles"."author_id" = ? [["author_id", 298486374]]
    !
    => true
    !
    >> author.articles.each {}
    !
    # => already loaded, so no query

    View Slide

  68. benchmark
    class Article < ActiveRecord::Base
    def self.expensive_operation
    sleep 2
    'did something very expensive'
    end
    end

    View Slide

  69. 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

    View Slide

  70. benchmark
    >> ActiveRecord::Base.benchmark 'SUPER EXPENSIVE OPERATION' do
    ?> Article.expensive_operation
    >> end
    SUPER EXPENSIVE OPERATION (2000.9ms)
    => "did something very expensive"

    View Slide

  71. benchmark
    class Article < ActiveRecord::Base
    def self.expensive_operation
    benchmark 'SUPER EXPENSIVE OPERATION' do
    sleep 2
    'did something very expensive'
    end
    end
    end

    View Slide

  72. View Slide

  73. http://railsgirlssummerofcode.org/campaign/
    Free hug!

    View Slide

  74. Active Model

    View Slide

  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

    View Slide

  76. ActiveModel::Model
    contact = EmailContact.new
    contact.name = 'Carlos'
    contact.email = '[email protected]'
    contact.message = 'ZOMG'
    contact.deliver

    View Slide

  77. ActiveModel::Model
    <%= form_for @email_contact … %>
    !
    <%= render @email_contact %>

    View Slide

  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

    View Slide

  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

    View Slide

  80. ActiveModel::Model
    contact = EmailContact.new(
    name: 'Carlos',
    email: '[email protected]',
    message: 'ZOMG'
    )
    contact.deliver

    View Slide

  81. ActiveModel::Model
    >> contact = EmailContact.new
    => #
    !
    >> 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"

    View Slide

  82. Action Mailer

    View Slide

  83. Mailer com i18n subject
    class Notifier < ActionMailer::Base
    default from: "[email protected]"
    !
    # 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: "[email protected]"
    end
    end

    View Slide

  84. Mailer com i18n subject
    class Notifier < ActionMailer::Base
    default from: "[email protected]"
    !
    !
    !
    !
    !
    !
    def new_article
    @greeting = "Hi"
    !
    mail to: "[email protected]", subject: I18n.t('subjects.new_article')
    end
    end

    View Slide

  85. Mailer com i18n subject
    en:
    subjects:
    new_article: 'New article just published.'

    View Slide

  86. Mailer com i18n subject
    en:
    notifier:
    new_article:
    subject: 'New article just published.'

    View Slide

  87. Mailer com i18n subject
    class Notifier < ActionMailer::Base
    default from: "[email protected]"
    !
    def new_article
    @greeting = "Hi"
    !
    mail to: "[email protected]"
    end
    end

    View Slide

  88. Mailer com i18n subject
    class Notifier < ActionMailer::Base
    default from: "[email protected]"
    !
    def new_article
    @greeting = "Hi"
    !
    mail to: "[email protected]",
    subject: I18n.t('subjects.new_article', title: 'Clarity is king')
    end
    end

    View Slide

  89. Mailer com i18n subject
    en:
    subjects:
    new_article: 'New article: %{title}.'

    View Slide

  90. Mailer com i18n subject
    en:
    notifier:
    new_article:
    subject: 'New article %{title}.'

    View Slide

  91. Mailer com i18n subject
    class Notifier < ActionMailer::Base
    default from: "[email protected]"
    !
    def new_article
    @greeting = "Hi"
    !
    mail to: "[email protected]",
    subject: default_i18n_subject(title: 'Clarity is king')
    end
    end

    View Slide

  92. Action View

    View Slide

  93. content_tag_for
    <%= content_tag_for :article, @articles do |article| %>
    <%= article.title %>
    <%= simple_format article.body %>
    <% end %>

    View Slide

  94. content_tag_for

    Rails 4.2.0 is going to be more Adequate
    Rails 4.2.0 is going to be made more Adequate by
    Tenderlove and Gorby Puff


    Rails 4.1.0 Released
    Rails 4.1.0 was just released before RailsConf

    View Slide

  95. content_tag_for
    <%= content_tag_for :section, @author do |author| %>
    <%= author.name %>

    <% end %>

    View Slide

  96. content_tag_for

    Author 2


    View Slide

  97. render com coleções vazias
    <% if author.articles.exists? %>
    <%= render author.articles %>
    <% else %>
    No article found.
    <% end %>

    View Slide

  98. render com coleções vazias
    <%= render(author.articles) ||
    content_tag(:p, 'No article found.') %>

    View Slide

  99. partial locals
    <%= render article, full: true %>
    <%= render author.articles, full: false %>
    !
    # article partial
    <%= content_tag_for :article, article do |article| %>
    <%= article.title %>
    !
    <% if full %>
    <%= simple_format article.body %>
    <% else %>
    <%= truncate article.body %>
    <% end %>
    <% end %>

    View Slide

  100. partial locals
    <%= render article, full: true %>
    <%= render author.articles %>
    !
    # article partial
    <%= content_tag_for :article, article do |article| %>
    <%= article.title %>
    !
    <% if local_assigns[:full] %>
    <%= simple_format article.body %>
    <% else %>
    <%= truncate article.body %>
    <% end %>
    <% end %>

    View Slide

  101. truncar textos
    <%= truncate article.body do %>
    <%= link_to 'read more...', article %>
    <% end %>
    !
    !
    Rails 4.2.0 is going to be ...

    read more…

    View Slide

  102. I18n + html
    <%= link_to I18n.t('read_more'), article %>
    !
    !
    en:
    read_more: 'read more…'
    !
    !

    read more…

    View Slide

  103. I18n + html
    <%= link_to I18n.t('read_more'), article %>
    !
    !
    en:
    read_more: 'read more…'
    !
    !

    read <b>more</b>…

    View Slide

  104. I18n + html
    <%= link_to raw(I18n.t('read_more')), article %>
    !
    !
    en:
    read_more: 'read more…'
    !
    !

    read more…

    View Slide

  105. I18n + html
    <%= link_to I18n.t(‘read_more_html'), article %>
    !
    !
    en:
    read_more_html: 'read more…'
    !
    !

    read more…

    View Slide

  106. benchmark
    <% benchmark 'Rendering articles' do %>
    <%= sleep(2); render author.articles %>
    <% end %>
    !
    !
    # logger
    Rendering articles (2005.1ms)

    View Slide

  107. Action Controller

    View Slide

  108. redirects com parâmetros
    get '/articles/:id' => redirect('/articles/%{id}/edit')

    View Slide

  109. tratamento de exceções
    $ ls public/*.html
    !
    404.html 422.html 500.html

    View Slide

  110. tratamento de exceções
    # config/application.rb
    !
    # Use the app's own router to display error pages.
    config.exceptions_app = self.routes

    View Slide

  111. 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"

    View Slide

  112. tratamento de exceções
    class ErrorsController < ApplicationController
    layout "error"
    !
    def not_found
    render status: :not_found
    end
    !
    def server_error
    render status: :server_error
    end
    !
    def unprocessable_entity
    render status: :unprocessable_entity
    end
    end

    View Slide

  113. tratamento de exceções
    app/views/
    errors/
    not_found.html.erb
    server_error.html.erb
    unprocessable_entity.html.erb
    layouts/
    error.html.erb

    View Slide

  114. Bonus Time!

    View Slide

  115. Console

    View Slide

  116. 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

    View Slide

  117. helper
    >> helper.time_ago_in_words 30.days.ago
    => "about 1 month"
    !
    >> helper.hello_rails_conf
    => "Hello RailsConf 2014!"
    !
    >> helper.class
    => ActionView::Base

    View Slide

  118. console helpers da aplicação
    # lib/console_helpers.rb
    module ConsoleHelpers
    def a(id)
    Article.find(id)
    end
    end

    View Slide

  119. console helpers da aplicação
    # config/application.rb
    module RailsConf2014
    class Application < Rails::Application
    console do
    require 'console_helpers'
    Rails::ConsoleMethods.send :include, ConsoleHelpers
    end
    end
    end

    View Slide

  120. console helpers da aplicação
    >> a(113629430)
    Article Load (0.1ms) SELECT "articles".* FROM "articles"
    WHERE "articles"."id" = ? LIMIT 1 [["id", 113629430]]
    !
    => #

    View Slide

  121. console sandbox
    $ rails console
    >> Article.count
    => 4
    !
    $ rails console --sandbox
    >> Article.create! title: 'I will be rolled back'
    => #
    >> Article.count
    => 5
    !
    $ rails console
    >> Article.count
    => 4

    View Slide

  122. console sandbox
    $ rails console --sandbox

    Any modifications you make will be rolled back on exit
    !
    !
    !
    >> exit
    rollback transaction

    View Slide

  123. Annotations

    View Slide

  124. notas
    class Author < ActiveRecord::Base
    # TODO: create inactive scope
    scope :active, -> { where active: true }
    end
    !
    class Article < ActiveRecord::Base
    # FIXME: Fix this
    scope :published, -> { where status: 'published' }
    end
    !
    class AuthorsController < ApplicationController
    # OPTIMIZE: eager load stuff
    def show
    @author = Author.find(params[:id])
    end
    end

    View Slide

  125. notas
    $ rake notes
    !
    app/controllers/authors_controller.rb:
    * [2] [OPTIMIZE] eager load stuff
    !
    app/models/article.rb:
    * [9] [FIXME] Fix this
    !
    app/models/author.rb:
    * [4] [TODO] create inactive scope

    View Slide

  126. notas personalizadas
    class Notifier < ActionMailer::Base
    # ZOMG: Hello!
    def new_article
    end
    end

    View Slide

  127. notas personalizadas
    $ rake notes:custom ANNOTATION=ZOMG
    !
    app/mailers/notifier.rb:
    * [4] Hello!

    View Slide

  128. Atualizando Rails

    View Slide

  129. rails update
    gem 'rails', '4.1.0'
    !
    !
    $ bundle update

    View Slide

  130. 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

    View Slide

  131. rails update
    $ git status
    On branch master
    Changes not staged for commit:
    (use "git add ..." to update what will be committed)
    (use "git checkout -- ..." 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 ..." to include in what will be committed)
    !
    config/initializers/cookies_serializer.rb
    config/secrets.yml

    View Slide

  132. Cada parte do Rails tem
    seus truques escondidos

    View Slide

  133. Eles são às vezes
    difíceis de achar

    View Slide

  134. Mas eles podem te deixar
    muito mais produtivo

    View Slide

  135. Então toda vez que você
    começar algo novo

    View Slide

  136. Antes mesmo de considerar
    usar o pattern X, Y ou Z

    View Slide

  137. Pergunte-se: Como o
    Rails pode me ajudar?

    View Slide

  138. Pesquise
    API
    Guidelines
    Google
    Stack Overflow

    View Slide

  139. Pergunte
    Stack Overflow
    Rails Talk mailing list
    IRC

    View Slide

  140. Siga
    Changelogs
    Release Notes
    Upgrading Guides
    Commits (se puder)

    View Slide

  141. E se você encontrar algum
    truque escondido, lembre-se…

    View Slide

  142. With great moustache!
    !
    !
    !
    comes great responsibility

    View Slide

  143. Compartilhe
    Tweet
    Blog post
    Diga aos seus amigos

    View Slide

  144. Contribua
    De volta para o Rails

    View Slide

  145. E por favor me avise! :)
    !
    @cantoniodasilva

    View Slide

  146. Os truques que o
    Rails não te contou
    Carlos Antonio - @cantoniodasilva

    View Slide