{"id":21815569,"url":"https://github.com/arbox/rails-style-guide","last_synced_at":"2025-04-09T12:08:32.733Z","repository":{"id":2105081,"uuid":"21326846","full_name":"arbox/rails-style-guide","owner":"arbox","description":":green_book:  Russian Version: A community-driven Rails 3 \u0026 4 \u0026 5 style guide.","archived":false,"fork":false,"pushed_at":"2022-03-12T19:53:39.000Z","size":492,"stargazers_count":200,"open_issues_count":3,"forks_count":40,"subscribers_count":21,"default_branch":"master","last_synced_at":"2025-04-02T10:14:53.165Z","etag":null,"topics":["bbatsov","rails","ruby","style-guide"],"latest_commit_sha":null,"homepage":"https://github.com/arbox/rails-style-guide","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/arbox.png","metadata":{"files":{"readme":"README-enUS.md","changelog":null,"contributing":"CONTRIBUTING-ruRU.md","funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-06-29T16:06:13.000Z","updated_at":"2024-10-03T07:15:04.000Z","dependencies_parsed_at":"2022-07-22T13:33:13.321Z","dependency_job_id":null,"html_url":"https://github.com/arbox/rails-style-guide","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arbox%2Frails-style-guide","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arbox%2Frails-style-guide/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arbox%2Frails-style-guide/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arbox%2Frails-style-guide/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/arbox","download_url":"https://codeload.github.com/arbox/rails-style-guide/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248036067,"owners_count":21037092,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bbatsov","rails","ruby","style-guide"],"created_at":"2024-11-27T15:19:52.590Z","updated_at":"2025-04-09T12:08:32.711Z","avatar_url":"https://github.com/arbox.png","language":"Ruby","funding_links":["https://www.patreon.com/bbatsov"],"categories":[],"sub_categories":[],"readme":"# Prelude\n\n\u003e Role models are important. \u003cbr/\u003e\n\u003e -- Officer Alex J. Murphy / RoboCop\n\nThe goal of this guide is to present a set of best practices and style\nprescriptions for Ruby on Rails 4 development. It's a\ncomplementary guide to the already existing community-driven\n[Ruby coding style guide](https://github.com/rubocop-hq/ruby-style-guide).\n\nSome of the advice here is applicable only to Rails 4.0+.\n\nYou can generate a PDF or an HTML copy of this guide using\n[Pandoc](http://pandoc.org/).\n\nTranslations of the guide are available in the following languages:\n\n  * [Chinese Simplified](https://github.com/JuanitoFatas/rails-style-guide/blob/master/README-zhCN.md)\n  * [Chinese Traditional](https://github.com/JuanitoFatas/rails-style-guide/blob/master/README-zhTW.md)\n  * [Japanese](https://github.com/satour/rails-style-guide/blob/master/README-jaJA.md)\n  * [Russian](https://github.com/arbox/rails-style-guide/blob/master/README-ruRU.md)\n  * [Turkish](https://github.com/tolgaavci/rails-style-guide/blob/master/README-trTR.md)\n  * [Korean](https://github.com/pureugong/rails-style-guide/blob/master/README-koKR.md)\n  * [Vietnamese](https://github.com/CQBinh/rails-style-guide/blob/master/README-viVN.md)\n  * [Portuguese (pt-BR)](https://github.com/abraaomiranda/rails-style-guide/blob/master/README-ptBR.md)\n\n# The Rails Style Guide\n\nThis Rails style guide recommends best practices so that real-world Rails\nprogrammers can write code that can be maintained by other real-world Rails\nprogrammers. A style guide that reflects real-world usage gets used, and a\nstyle guide that holds to an ideal that has been rejected by the people it\nis supposed to help risks not getting used at all \u0026ndash; no matter how good\nit is.\n\nThe guide is separated into several sections of related rules. I've tried to add\nthe rationale behind the rules (if it's omitted I've assumed it's pretty\nobvious).\n\nI didn't come up with all the rules out of nowhere - they are mostly based on my\nextensive career as a professional software engineer, feedback and suggestions\nfrom members of the Rails community and various highly regarded Rails\nprogramming resources.\n\n## Table of Contents\n\n  * [Configuration](#configuration)\n  * [Routing](#routing)\n  * [Controllers](#controllers)\n      * [Rendering](#rendering)\n  * [Models](#models)\n      * [ActiveRecord](#activerecord)\n      * [ActiveRecord Queries](#activerecord-queries)\n  * [Migrations](#migrations)\n  * [Views](#views)\n  * [Internationalization](#internationalization)\n  * [Assets](#assets)\n  * [Mailers](#mailers)\n  * [Active Support Core Extensions](#active-support-core-extensions)\n  * [Time](#time)\n  * [Bundler](#bundler)\n  * [Managing processes](#managing-processes)\n\n## Configuration\n\n  * \u003ca name=\"config-initializers\"\u003e\u003c/a\u003e\n    Put custom initialization code in `config/initializers`. The code in\n    initializers executes on application startup.\n    \u003csup\u003e[[link](#config-initializers)]\u003c/sup\u003e\n\n  * \u003ca name=\"gem-initializers\"\u003e\u003c/a\u003e\n    Keep initialization code for each gem in a separate file with the same name\n    as the gem, for example `carrierwave.rb`, `active_admin.rb`, etc.\n    \u003csup\u003e[[link](#gem-initializers)]\u003c/sup\u003e\n\n  * \u003ca name=\"dev-test-prod-configs\"\u003e\u003c/a\u003e\n    Adjust accordingly the settings for development, test and production\n    environment (in the corresponding files under `config/environments/`)\n    \u003csup\u003e[[link](#dev-test-prod-configs)]\u003c/sup\u003e\n\n      * Mark additional assets for precompilation (if any):\n\n        ```ruby\n        # config/environments/production.rb\n        # Precompile additional assets (application.js, application.css,\n        #and all non-JS/CSS are already added)\n        config.assets.precompile += %w( rails_admin/rails_admin.css rails_admin/rails_admin.js )\n        ```\n\n  * \u003ca name=\"app-config\"\u003e\u003c/a\u003e\n    Keep configuration that's applicable to all environments in the\n    `config/application.rb` file.\n    \u003csup\u003e[[link](#app-config)]\u003c/sup\u003e\n\n  * \u003ca name=\"staging-like-prod\"\u003e\u003c/a\u003e\n    Create an additional `staging` environment that closely resembles the\n    `production` one.\n    \u003csup\u003e[[link](#staging-like-prod)]\u003c/sup\u003e\n\n  * \u003ca name=\"yaml-config\"\u003e\u003c/a\u003e\n    Keep any additional configuration in YAML files under the `config/` directory.\n    \u003csup\u003e[[link](#yaml-config)]\u003c/sup\u003e\n\n    Since Rails 4.2 YAML configuration files can be easily loaded with the new `config_for` method:\n\n    ```ruby\n    Rails::Application.config_for(:yaml_file)\n    ```\n\n## Routing\n\n  * \u003ca name=\"member-collection-routes\"\u003e\u003c/a\u003e\n    When you need to add more actions to a RESTful resource (do you really need\n    them at all?) use `member` and `collection` routes.\n    \u003csup\u003e[[link](#member-collection-routes)]\u003c/sup\u003e\n\n    ```ruby\n    # bad\n    get 'subscriptions/:id/unsubscribe'\n    resources :subscriptions\n\n    # good\n    resources :subscriptions do\n      get 'unsubscribe', on: :member\n    end\n\n    # bad\n    get 'photos/search'\n    resources :photos\n\n    # good\n    resources :photos do\n      get 'search', on: :collection\n    end\n    ```\n\n  * \u003ca name=\"many-member-collection-routes\"\u003e\u003c/a\u003e\n    If you need to define multiple `member/collection` routes use the\n    alternative block syntax.\n    \u003csup\u003e[[link](#many-member-collection-routes)]\u003c/sup\u003e\n\n    ```ruby\n    resources :subscriptions do\n      member do\n        get 'unsubscribe'\n        # more routes\n      end\n    end\n\n    resources :photos do\n      collection do\n        get 'search'\n        # more routes\n      end\n    end\n    ```\n\n  * \u003ca name=\"nested-routes\"\u003e\u003c/a\u003e\n    Use nested routes to express better the relationship between ActiveRecord\n    models.\n    \u003csup\u003e[[link](#nested-routes)]\u003c/sup\u003e\n\n    ```ruby\n    class Post \u003c ActiveRecord::Base\n      has_many :comments\n    end\n\n    class Comment \u003c ActiveRecord::Base\n      belongs_to :post\n    end\n\n    # routes.rb\n    resources :posts do\n      resources :comments\n    end\n    ```\n\n  * \u003ca name=\"namespaced-routes\"\u003e\u003c/a\u003e\n    If you need to nest routes more than 1 level deep then use the `shallow: true` option. This will save user from long urls `posts/1/comments/5/versions/7/edit` and you from long url helpers `edit_post_comment_version`.\n\n    ```ruby\n    resources :posts, shallow: true do\n      resources :comments do\n        resources :versions\n      end\n    end\n    ```\n\n  * \u003ca name=\"namespaced-routes\"\u003e\u003c/a\u003e\n    Use namespaced routes to group related actions.\n    \u003csup\u003e[[link](#namespaced-routes)]\u003c/sup\u003e\n\n    ```ruby\n    namespace :admin do\n      # Directs /admin/products/* to Admin::ProductsController\n      # (app/controllers/admin/products_controller.rb)\n      resources :products\n    end\n    ```\n\n  * \u003ca name=\"no-wild-routes\"\u003e\u003c/a\u003e\n    Never use the legacy wild controller route. This route will make all actions\n    in every controller accessible via GET requests.\n    \u003csup\u003e[[link](#no-wild-routes)]\u003c/sup\u003e\n\n    ```ruby\n    # very bad\n    match ':controller(/:action(/:id(.:format)))'\n    ```\n\n  * \u003ca name=\"no-match-routes\"\u003e\u003c/a\u003e\n    Don't use `match` to define any routes unless there is need to map multiple request types among `[:get, :post, :patch, :put, :delete]` to a single action using `:via` option.\n    \u003csup\u003e[[link](#no-match-routes)]\u003c/sup\u003e\n\n## Controllers\n\n  * \u003ca name=\"skinny-controllers\"\u003e\u003c/a\u003e\n    Keep the controllers skinny - they should only retrieve data for the view\n    layer and shouldn't contain any business logic (all the business logic\n    should naturally reside in the model).\n    \u003csup\u003e[[link](#skinny-controllers)]\u003c/sup\u003e\n\n  * \u003ca name=\"one-method\"\u003e\u003c/a\u003e\n    Each controller action should (ideally) invoke only one method other than an\n    initial find or new.\n    \u003csup\u003e[[link](#one-method)]\u003c/sup\u003e\n\n  * \u003ca name=\"shared-instance-variables\"\u003e\u003c/a\u003e\n    Share no more than two instance variables between a controller and a view.\n    \u003csup\u003e[[link](#shared-instance-variables)]\u003c/sup\u003e\n\n  * \u003ca name=\"lexically-scoped-action-filter\"\u003e\u003c/a\u003e\n    Controller actions specified in the option of Action Filter should be in lexical scope. The ActionFilter specified for an inherited action makes it difficult to understand the scope of its impact on that action.\n    \u003csup\u003e[[link](#lexically-scoped-action-filter)]\u003c/sup\u003e\n\n```ruby\n# bad\nclass UsersController \u003c ApplicationController\n  before_action :require_login, only: :export\nend\n\n# good\nclass UsersController \u003c ApplicationController\n  before_action :require_login, only: :export\n\n  def export\n  end\nend\n```\n\n### Rendering\n\n  * \u003ca name=\"inline-rendering\"\u003e\u003c/a\u003e\n    Prefer using a template over inline rendering.\n    \u003csup\u003e[[link](#inline-rendering)]\u003c/sup\u003e\n\n```ruby\n# very bad\nclass ProductsController \u003c ApplicationController\n  def index\n    render inline: \"\u003c% products.each do |p| %\u003e\u003cp\u003e\u003c%= p.name %\u003e\u003c/p\u003e\u003c% end %\u003e\", type: :erb\n  end\nend\n\n# good\n## app/views/products/index.html.erb\n\u003c%= render partial: 'product', collection: products %\u003e\n\n## app/views/products/_product.html.erb\n\u003cp\u003e\u003c%= product.name %\u003e\u003c/p\u003e\n\u003cp\u003e\u003c%= product.price %\u003e\u003c/p\u003e\n\n## app/controllers/foo_controller.rb\nclass ProductsController \u003c ApplicationController\n  def index\n    render :index\n  end\nend\n```\n\n  * \u003ca name=\"plain-text-rendering\"\u003e\u003c/a\u003e\n    Prefer `render plain:` over `render text:`.\n    \u003csup\u003e[[link](#plain-text-rendering)]\u003c/sup\u003e\n\n```ruby\n# bad - sets MIME type to `text/html`\n...\nrender text: 'Ruby!'\n...\n\n# bad - requires explicit MIME type declaration\n...\nrender text: 'Ruby!', content_type: 'text/plain'\n...\n\n# good - short and precise\n...\nrender plain: 'Ruby!'\n...\n```\n\n  * \u003ca name=\"http-status-code-symbols\"\u003e\u003c/a\u003e\n    Prefer [corresponding symbols](https://gist.github.com/mlanett/a31c340b132ddefa9cca) to numeric HTTP status codes. They are meaningful and do not look like \"magic\" numbers for less known HTTP status codes.\n    \u003csup\u003e[[link](#http-status-code-symbols)]\u003c/sup\u003e\n\n```ruby\n# bad\n...\nrender status: 403\n...\n\n# good\n...\nrender status: :forbidden\n...\n```\n\n## Models\n\n  * \u003ca name=\"model-classes\"\u003e\u003c/a\u003e\n    Introduce non-ActiveRecord model classes freely.\n    \u003csup\u003e[[link](#model-classes)]\u003c/sup\u003e\n\n  * \u003ca name=\"meaningful-model-names\"\u003e\u003c/a\u003e\n    Name the models with meaningful (but short) names without abbreviations.\n    \u003csup\u003e[[link](#meaningful-model-names)]\u003c/sup\u003e\n\n  * \u003ca name=\"activeattr-gem\"\u003e\u003c/a\u003e\n    If you need model objects that support ActiveRecord behavior (like validation)\n    without the ActiveRecord database functionality use the\n    [ActiveAttr](https://github.com/cgriego/active_attr) gem.\n    \u003csup\u003e[[link](#activeattr-gem)]\u003c/sup\u003e\n\n    ```ruby\n    class Message\n      include ActiveAttr::Model\n\n      attribute :name\n      attribute :email\n      attribute :content\n      attribute :priority\n\n      attr_accessible :name, :email, :content\n\n      validates :name, presence: true\n      validates :email, format: { with: /\\A[-a-z0-9_+\\.]+\\@([-a-z0-9]+\\.)+[a-z0-9]{2,4}\\z/i }\n      validates :content, length: { maximum: 500 }\n    end\n    ```\n\n    For a more complete example refer to the\n    [RailsCast on the subject](http://railscasts.com/episodes/326-activeattr).\n\n  * \u003ca name=\"model-business-logic\"\u003e\u003c/a\u003e\n    Unless they have some meaning in the business domain, don't put methods in\n    your model that just format your data (like code generating HTML). These\n    methods are most likely going to be called from the view layer only, so their\n    place is in helpers. Keep your models for business logic and data-persistence\n    only.\n    \u003csup\u003e[[link](#model-business-logic)]\u003c/sup\u003e\n\n### ActiveRecord\n\n  * \u003ca name=\"keep-ar-defaults\"\u003e\u003c/a\u003e\n    Avoid altering ActiveRecord defaults (table names, primary key, etc) unless\n    you have a very good reason (like a database that's not under your control).\n    \u003csup\u003e[[link](#keep-ar-defaults)]\u003c/sup\u003e\n\n    ```ruby\n    # bad - don't do this if you can modify the schema\n    class Transaction \u003c ActiveRecord::Base\n      self.table_name = 'order'\n      ...\n    end\n    ```\n\n  * \u003ca name=\"macro-style-methods\"\u003e\u003c/a\u003e\n    Group macro-style methods (`has_many`, `validates`, etc) in the beginning of\n    the class definition.\n    \u003csup\u003e[[link](#macro-style-methods)]\u003c/sup\u003e\n\n    ```ruby\n    class User \u003c ActiveRecord::Base\n      # keep the default scope first (if any)\n      default_scope { where(active: true) }\n\n      # constants come up next\n      COLORS = %w(red green blue)\n\n      # afterwards we put attr related macros\n      attr_accessor :formatted_date_of_birth\n\n      attr_accessible :login, :first_name, :last_name, :email, :password\n\n      # Rails4+ enums after attr macros, prefer the hash syntax\n      enum gender: { female: 0, male: 1 }\n\n      # followed by association macros\n      belongs_to :country\n\n      has_many :authentications, dependent: :destroy\n\n      # and validation macros\n      validates :email, presence: true\n      validates :username, presence: true\n      validates :username, uniqueness: { case_sensitive: false }\n      validates :username, format: { with: /\\A[A-Za-z][A-Za-z0-9._-]{2,19}\\z/ }\n      validates :password, format: { with: /\\A\\S{8,128}\\z/, allow_nil: true }\n\n      # next we have callbacks\n      before_save :cook\n      before_save :update_username_lower\n\n      # other macros (like devise's) should be placed after the callbacks\n\n      ...\n    end\n    ```\n\n  * \u003ca name=\"has-many-through\"\u003e\u003c/a\u003e\n    Prefer `has_many :through` to `has_and_belongs_to_many`. Using `has_many\n    :through` allows additional attributes and validations on the join model.\n    \u003csup\u003e[[link](#has-many-through)]\u003c/sup\u003e\n\n    ```ruby\n    # not so good - using has_and_belongs_to_many\n    class User \u003c ActiveRecord::Base\n      has_and_belongs_to_many :groups\n    end\n\n    class Group \u003c ActiveRecord::Base\n      has_and_belongs_to_many :users\n    end\n\n    # preferred way - using has_many :through\n    class User \u003c ActiveRecord::Base\n      has_many :memberships\n      has_many :groups, through: :memberships\n    end\n\n    class Membership \u003c ActiveRecord::Base\n      belongs_to :user\n      belongs_to :group\n    end\n\n    class Group \u003c ActiveRecord::Base\n      has_many :memberships\n      has_many :users, through: :memberships\n    end\n    ```\n\n  * \u003ca name=\"read-attribute\"\u003e\u003c/a\u003e\n    Prefer `self[:attribute]` over `read_attribute(:attribute)`.\n    \u003csup\u003e[[link](#read-attribute)]\u003c/sup\u003e\n\n    ```ruby\n    # bad\n    def amount\n      read_attribute(:amount) * 100\n    end\n\n    # good\n    def amount\n      self[:amount] * 100\n    end\n    ```\n\n  * \u003ca name=\"write-attribute\"\u003e\u003c/a\u003e\n    Prefer `self[:attribute] = value` over `write_attribute(:attribute, value)`.\n    \u003csup\u003e[[link](#write-attribute)]\u003c/sup\u003e\n\n    ```ruby\n    # bad\n    def amount\n      write_attribute(:amount, 100)\n    end\n\n    # good\n    def amount\n      self[:amount] = 100\n    end\n    ```\n\n  * \u003ca name=\"sexy-validations\"\u003e\u003c/a\u003e\n    Always use the new [\"sexy\"\n    validations](http://thelucid.com/2010/01/08/sexy-validation-in-edge-rails-rails-3/).\n    \u003csup\u003e[[link](#sexy-validations)]\u003c/sup\u003e\n\n    ```ruby\n    # bad\n    validates_presence_of :email\n    validates_length_of :email, maximum: 100\n\n    # good\n    validates :email, presence: true, length: { maximum: 100 }\n    ```\n\n  * \u003ca name=\"single-attribute-validations\"\u003e\u003c/a\u003e\n    To make validations easy to read, don't list multiple attributes per\n    validation\n    \u003csup\u003e[[link](#single-attribute-validations)]\u003c/sup\u003e\n\n    ```ruby\n    # bad\n    validates :email, :password, presence: true\n    validates :email, length: { maximum: 100 }\n\n    # good\n    validates :email, presence: true, length: { maximum: 100 }\n    validates :password, presence: true\n    ```\n\n  * \u003ca name=\"custom-validator-file\"\u003e\u003c/a\u003e\n    When a custom validation is used more than once or the validation is some\n    regular expression mapping, create a custom validator file.\n    \u003csup\u003e[[link](#custom-validator-file)]\u003c/sup\u003e\n\n    ```ruby\n    # bad\n    class Person\n      validates :email, format: { with: /\\A([^@\\s]+)@((?:[-a-z0-9]+\\.)+[a-z]{2,})\\z/i }\n    end\n\n    # good\n    class EmailValidator \u003c ActiveModel::EachValidator\n      def validate_each(record, attribute, value)\n        record.errors[attribute] \u003c\u003c (options[:message] || 'is not a valid email') unless value =~ /\\A([^@\\s]+)@((?:[-a-z0-9]+\\.)+[a-z]{2,})\\z/i\n      end\n    end\n\n    class Person\n      validates :email, email: true\n    end\n    ```\n\n  * \u003ca name=\"app-validators\"\u003e\u003c/a\u003e\n    Keep custom validators under `app/validators`.\n    \u003csup\u003e[[link](#app-validators)]\u003c/sup\u003e\n\n  * \u003ca name=\"custom-validators-gem\"\u003e\u003c/a\u003e\n    Consider extracting custom validators to a shared gem if you're maintaining\n    several related apps or the validators are generic enough.\n    \u003csup\u003e[[link](#custom-validators-gem)]\u003c/sup\u003e\n\n  * \u003ca name=\"named-scopes\"\u003e\u003c/a\u003e\n    Use named scopes freely.\n    \u003csup\u003e[[link](#named-scopes)]\u003c/sup\u003e\n\n    ```ruby\n    class User \u003c ActiveRecord::Base\n      scope :active, -\u003e { where(active: true) }\n      scope :inactive, -\u003e { where(active: false) }\n\n      scope :with_orders, -\u003e { joins(:orders).select('distinct(users.id)') }\n    end\n    ```\n\n  * \u003ca name=\"named-scope-class\"\u003e\u003c/a\u003e\n    When a named scope defined with a lambda and parameters becomes too\n    complicated, it is preferable to make a class method instead which serves the\n    same purpose of the named scope and returns an `ActiveRecord::Relation`\n    object. Arguably you can define even simpler scopes like this.\n    \u003csup\u003e[[link](#named-scope-class)]\u003c/sup\u003e\n\n    ```ruby\n    class User \u003c ActiveRecord::Base\n      def self.with_orders\n        joins(:orders).select('distinct(users.id)')\n      end\n    end\n    ```\n\n  * \u003ca name=\"callbacks-order\"\u003e\u003c/a\u003e\n    Order callback declarations in the order, in which they will be executed. For\n    referenece, see [Available Callbacks](http://guides.rubyonrails.org/active_record_callbacks.html#available-callbacks)\n    \u003csup\u003e[[link](#callbacks-order)]\u003c/sup\u003e\n\n    ```Ruby\n    #bad\n    class Person\n      after_commit/after_rollback :after_commit_callback\n      after_save :after_save_callback\n      around_save :around_save_callback\n      after_update :after_update_callback\n      before_update :before_update_callback\n      after_validation :after_validation_callback\n      before_validation :before_validation_callback\n      before_save :before_save_callback\n      before_create :before_create_callback\n      after_create :after_create_callback\n      around_create :around_create_callback\n      around_update :around_update_callback\n    end\n\n    #good\n    class Person\n      before_validation :before_validation_callback\n      after_validation :after_validation_callback\n      before_save :before_save_callback\n      around_save :around_save_callback\n      before_create :before_create_callback\n      around_create :around_create_callback\n      after_create :after_create_callback\n      before_update :before_update_callback\n      around_update :around_update_callback\n      after_update :after_update_callback\n      after_save :after_save_callback\n      after_commit/after_rollback :after_commit_callback\n    end\n    ```\n\n  * \u003ca name=\"beware-skip-model-validations\"\u003e\u003c/a\u003e\n    Beware of the behavior of the\n    [following](http://guides.rubyonrails.org/active_record_validations.html#skipping-validations)\n    methods. They do not run the model validations and\n    could easily corrupt the model state.\n    \u003csup\u003e[[link](#beware-skip-model-validations)]\u003c/sup\u003e\n\n    ```ruby\n    # bad\n    Article.first.decrement!(:view_count)\n    DiscussionBoard.decrement_counter(:post_count, 5)\n    Article.first.increment!(:view_count)\n    DiscussionBoard.increment_counter(:post_count, 5)\n    person.toggle :active\n    product.touch\n    Billing.update_all(\"category = 'authorized', author = 'David'\")\n    user.update_attribute(:website, 'example.com')\n    user.update_columns(last_request_at: Time.current)\n    Post.update_counters 5, comment_count: -1, action_count: 1\n\n    # good\n    user.update_attributes(website: 'example.com')\n    ```\n\n  * \u003ca name=\"user-friendly-urls\"\u003e\u003c/a\u003e\n    Use user-friendly URLs. Show some descriptive attribute of the model in the URL\n    rather than its `id`.  There is more than one way to achieve this:\n    \u003csup\u003e[[link](#user-friendly-urls)]\u003c/sup\u003e\n\n      * Override the `to_param` method of the model. This method is used by Rails\n        for constructing a URL to the object.  The default implementation returns\n        the `id` of the record as a String.  It could be overridden to include another\n        human-readable attribute.\n\n        ```ruby\n        class Person\n          def to_param\n            \"#{id} #{name}\".parameterize\n          end\n        end\n        ```\n\n    In order to convert this to a URL-friendly value, `parameterize` should be\n    called on the string. The `id` of the object needs to be at the beginning so\n    that it can be found by the `find` method of ActiveRecord.\n\n      * Use the `friendly_id` gem. It allows creation of human-readable URLs by\n        using some descriptive attribute of the model instead of its `id`.\n\n        ```ruby\n        class Person\n          extend FriendlyId\n          friendly_id :name, use: :slugged\n        end\n        ```\n\n    Check the [gem documentation](https://github.com/norman/friendly_id) for more\n    information about its usage.\n\n  * \u003ca name=\"find-each\"\u003e\u003c/a\u003e\n    Use `find_each` to iterate over a collection of AR objects. Looping through a\n    collection of records from the database (using the `all` method, for example)\n    is very inefficient since it will try to instantiate all the objects at once.\n    In that case, batch processing methods allow you to work with the records in\n    batches, thereby greatly reducing memory consumption.\n    \u003csup\u003e[[link](#find-each)]\u003c/sup\u003e\n\n\n    ```ruby\n    # bad\n    Person.all.each do |person|\n      person.do_awesome_stuff\n    end\n\n    Person.where('age \u003e 21').each do |person|\n      person.party_all_night!\n    end\n\n    # good\n    Person.find_each do |person|\n      person.do_awesome_stuff\n    end\n\n    Person.where('age \u003e 21').find_each do |person|\n      person.party_all_night!\n    end\n    ```\n\n  * \u003ca name=\"before_destroy\"\u003e\u003c/a\u003e\n    Since [Rails creates callbacks for dependent\n    associations](https://github.com/rails/rails/issues/3458), always call\n    `before_destroy` callbacks that perform validation with `prepend: true`.\n    \u003csup\u003e[[link](#before_destroy)]\u003c/sup\u003e\n\n    ```ruby\n    # bad (roles will be deleted automatically even if super_admin? is true)\n    has_many :roles, dependent: :destroy\n\n    before_destroy :ensure_deletable\n\n    def ensure_deletable\n      raise \"Cannot delete super admin.\" if super_admin?\n    end\n\n    # good\n    has_many :roles, dependent: :destroy\n\n    before_destroy :ensure_deletable, prepend: true\n\n    def ensure_deletable\n      raise \"Cannot delete super admin.\" if super_admin?\n    end\n    ```\n\n  * \u003ca name=\"has_many-has_one-dependent-option\"\u003e\u003c/a\u003e\n    Define the `dependent` option to the `has_many` and `has_one` associations.\n    \u003csup\u003e[[link](#has_many-has_one-dependent-option)]\u003c/sup\u003e\n\n    ```ruby\n    # bad\n    class Post \u003c ActiveRecord::Base\n      has_many :comments\n    end\n\n    # good\n    class Post \u003c ActiveRecord::Base\n      has_many :comments, dependent: :destroy\n    end\n    ```\n\n  * \u003ca name=\"save-bang\"\u003e\u003c/a\u003e\n    When persisting AR objects always use the exception raising bang! method or handle the method return value.\n    This applies to `create`, `save`, `update`, `destroy`, `first_or_create` and `find_or_create_by`.\n    \u003csup\u003e[[link](#save-bang)]\u003c/sup\u003e\n\n    ```ruby\n    # bad\n    user.create(name: 'Bruce')\n\n    # bad\n    user.save\n\n    # good\n    user.create!(name: 'Bruce')\n    # or\n    bruce = user.create(name: 'Bruce')\n    if bruce.persisted?\n      ...\n    else\n      ...\n    end\n\n    # good\n    user.save!\n    # or\n    if user.save\n      ...\n    else\n      ...\n    end\n    ```\n\n### ActiveRecord Queries\n\n  * \u003ca name=\"avoid-interpolation\"\u003e\u003c/a\u003e\n    Avoid string interpolation in\n    queries, as it will make your code susceptible to SQL injection\n    attacks.\n    \u003csup\u003e[[link](#avoid-interpolation)]\u003c/sup\u003e\n\n    ```ruby\n    # bad - param will be interpolated unescaped\n    Client.where(\"orders_count = #{params[:orders]}\")\n\n    # good - param will be properly escaped\n    Client.where('orders_count = ?', params[:orders])\n    ```\n\n  * \u003ca name=\"named-placeholder\"\u003e\u003c/a\u003e\n    Consider using named placeholders instead of positional placeholders\n    when you have more than 1 placeholder in your query.\n    \u003csup\u003e[[link](#named-placeholder)]\u003c/sup\u003e\n\n    ```ruby\n    # okish\n    Client.where(\n      'created_at \u003e= ? AND created_at \u003c= ?',\n      params[:start_date], params[:end_date]\n    )\n\n    # good\n    Client.where(\n      'created_at \u003e= :start_date AND created_at \u003c= :end_date',\n      start_date: params[:start_date], end_date: params[:end_date]\n    )\n    ```\n\n  * \u003ca name=\"find\"\u003e\u003c/a\u003e\n    Favor the use of `find` over `where.take!`, `find_by!`, and `find_by_id!`\n    when you need to retrieve a single record by primary key id and raise\n    `ActiveRecord::RecordNotFound` when the record is not found.\n    \u003csup\u003e[[link](#find)]\u003c/sup\u003e\n\n    ```ruby\n    # bad\n    User.where(id: id).take!\n\n    # bad\n    User.find_by_id!(id)\n\n    # bad\n    User.find_by!(id: id)\n\n    # good\n    User.find(id)\n    ```\n\n  * \u003ca name=\"find_by\"\u003e\u003c/a\u003e\n    Favor the use of `find_by` over `where.take` and `find_by_attribute`\n    when you need to retrieve a single record by one or more attributes and return\n    `nil` when the record is not found.\n    \u003csup\u003e[[link](#find_by)]\u003c/sup\u003e\n\n    ```ruby\n    # bad\n    User.where(id: id).take\n    User.where(first_name: 'Bruce', last_name: 'Wayne').take\n\n    # bad\n    User.find_by_id(id)\n    # bad, deprecated in ActiveRecord 4.0, removed in 4.1+\n    User.find_by_first_name_and_last_name('Bruce', 'Wayne')\n\n    # good\n    User.find_by(id: id)\n    User.find_by(first_name: 'Bruce', last_name: 'Wayne')\n    ```\n\n  * \u003ca name=\"where-not\"\u003e\u003c/a\u003e\n    Favor the use of `where.not` over SQL.\n    \u003csup\u003e[[link](#where-not)]\u003c/sup\u003e\n\n    ```ruby\n    # bad\n    User.where(\"id != ?\", id)\n\n    # good\n    User.where.not(id: id)\n    ```\n\n  * \u003ca name =\"order-by-id\"\u003e\u003c/a\u003e\n    Don't use the `id` column for ordering. The sequence of ids is not\n    guaranteed to be in any particular order, despite often (incidentally)\n    being chronological. Use a timestamp column to order chronologically.\n    As a bonus the intent is clearer.\n    \u003csup\u003e[[link](#order-by-id)]\u003c/sup\u003e\n\n    ```ruby\n    # bad\n    scope :chronological, -\u003e { order(id: :asc) }\n\n    # good\n    scope :chronological, -\u003e { order(created_at: :asc) }\n    ```\n\n  * \u003ca name=\"ids\"\u003e\u003c/a\u003e\n    Favor the use of `ids` over `pluck(:id)`.\n    \u003csup\u003e[[link](#ids)]\u003c/sup\u003e\n\n    ```Ruby\n    # bad\n    User.pluck(:id)\n\n    # good\n    User.ids\n    ```\n\n  * \u003ca name=\"squished-heredocs\"\u003e\u003c/a\u003e\n    When specifying an explicit query in a method such as `find_by_sql`, use\n    heredocs with `squish`. This allows you to legibly format the SQL with\n    line breaks and indentations, while supporting syntax highlighting in many\n    tools (including GitHub, Atom, and RubyMine).\n    \u003csup\u003e[[link](#squished-heredocs)]\u003c/sup\u003e\n\n    ```ruby\n    User.find_by_sql(\u003c\u003c-SQL.squish)\n      SELECT\n        users.id, accounts.plan\n      FROM\n        users\n      INNER JOIN\n        accounts\n      ON\n        accounts.user_id = users.id\n      # further complexities...\n    SQL\n    ```\n\n    [`String#squish`](http://apidock.com/rails/String/squish) removes the indentation and newline characters so that your server\n    log shows a fluid string of SQL rather than something like this:\n\n    ```\n    SELECT\\n    users.id, accounts.plan\\n  FROM\\n    users\\n  INNER JOIN\\n    acounts\\n  ON\\n    accounts.user_id = users.id\n    ```\n\n  * \u003ca name=\"size-over-count-or-length\"\u003e\u003c/a\u003e\n    When querying ActiveRecord collections, prefer `size` (selects between count/length behavior based on whether collection is already loaded) or `length` (always loads the whole collection and counts the array elements) over `count` (always does a database query for the count).\n    \u003csup\u003e[[link](#size-over-count-or-length)]\u003c/sup\u003e\n\n    ```ruby\n    # bad\n    User.count\n\n    # good\n    User.all.size\n\n    # good - if you really need to load all users into memory\n    User.all.length\n    ```\n\n## Migrations\n\n  * \u003ca name=\"schema-version\"\u003e\u003c/a\u003e\n    Keep the `schema.rb` (or `structure.sql`) under version control.\n    \u003csup\u003e[[link](#schema-version)]\u003c/sup\u003e\n\n  * \u003ca name=\"db-schema-load\"\u003e\u003c/a\u003e\n    Use `rake db:schema:load` instead of `rake db:migrate` to initialize an empty\n    database.\n    \u003csup\u003e[[link](#db-schema-load)]\u003c/sup\u003e\n\n  * \u003ca name=\"default-migration-values\"\u003e\u003c/a\u003e\n    Enforce default values in the migrations themselves instead of in the\n    application layer.\n    \u003csup\u003e[[link](#default-migration-values)]\u003c/sup\u003e\n\n    ```ruby\n    # bad - application enforced default value\n    class Product \u003c ActiveRecord::Base\n      def amount\n        self[:amount] || 0\n      end\n    end\n\n    # good - database enforced\n    class AddDefaultAmountToProducts \u003c ActiveRecord::Migration\n      def change\n        change_column_default :products, :amount, 0\n      end\n    end\n    ```\n\n    While enforcing table defaults only in Rails is suggested by many\n    Rails developers, it's an extremely brittle approach that\n    leaves your data vulnerable to many application bugs.  And you'll\n    have to consider the fact that most non-trivial apps share a\n    database with other applications, so imposing data integrity from\n    the Rails app is impossible.\n\n  * \u003ca name=\"foreign-key-constraints\"\u003e\u003c/a\u003e\n    Enforce foreign-key constraints. As of Rails 4.2, ActiveRecord\n    supports foreign key constraints natively.\n    \u003csup\u003e[[link](#foreign-key-constraints)]\u003c/sup\u003e\n\n  * \u003ca name=\"change-vs-up-down\"\u003e\u003c/a\u003e\n    When writing constructive migrations (adding tables or columns),\n    use the `change` method instead of `up` and `down` methods.\n    \u003csup\u003e[[link](#change-vs-up-down)]\u003c/sup\u003e\n\n    ```ruby\n    # the old way\n    class AddNameToPeople \u003c ActiveRecord::Migration\n      def up\n        add_column :people, :name, :string\n      end\n\n      def down\n        remove_column :people, :name\n      end\n    end\n\n    # the new preferred way\n    class AddNameToPeople \u003c ActiveRecord::Migration\n      def change\n        add_column :people, :name, :string\n      end\n    end\n    ```\n\n  * \u003ca name=\"define-model-class-migrations\"\u003e\u003c/a\u003e\n    If you have to use models in migrations, make sure you define them\n    so that you don't end up with broken migrations in the future\n    \u003csup\u003e[[link](#define-model-class-migrations)]\u003c/sup\u003e\n\n    ```ruby\n    # db/migrate/\u003cmigration_file_name\u003e.rb\n    # frozen_string_literal: true\n\n    # bad\n    class ModifyDefaultStatusForProducts \u003c ActiveRecord::Migration\n      def change\n        old_status = 'pending_manual_approval'\n        new_status = 'pending_approval'\n\n        reversible do |dir|\n          dir.up do\n            Product.where(status: old_status).update_all(status: new_status)\n            change_column :products, :status, :string, default: new_status\n          end\n\n          dir.down do\n            Product.where(status: new_status).update_all(status: old_status)\n            change_column :products, :status, :string, default: old_status\n          end\n        end\n      end\n    end\n\n    # good\n    # Define `table_name` in a custom named class to make sure that\n    # you run on the same table you had during the creation of the migration.\n    # In future if you override the `Product` class\n    # and change the `table_name`, it won't break\n    # the migration or cause serious data corruption.\n    class MigrationProduct \u003c ActiveRecord::Base\n      self.table_name = :products\n    end\n\n    class ModifyDefaultStatusForProducts \u003c ActiveRecord::Migration\n      def change\n        old_status = 'pending_manual_approval'\n        new_status = 'pending_approval'\n\n        reversible do |dir|\n          dir.up do\n            MigrationProduct.where(status: old_status).update_all(status: new_status)\n            change_column :products, :status, :string, default: new_status\n          end\n\n          dir.down do\n            MigrationProduct.where(status: new_status).update_all(status: old_status)\n            change_column :products, :status, :string, default: old_status\n          end\n        end\n      end\n    end\n    ```\n\n  * \u003ca name=\"meaningful-foreign-key-naming\"\u003e\u003c/a\u003e\n    Name your foreign keys explicitly instead of relying on Rails auto-generated\n    FK names. (http://guides.rubyonrails.org/active_record_migrations.html#foreign-keys)\n    \u003csup\u003e[[link](#meaningful-foreign-key-naming)]\u003c/sup\u003e\n\n    ```ruby\n    # bad\n    class AddFkArticlesToAuthors \u003c ActiveRecord::Migration\n      def change\n        add_foreign_key :articles, :authors\n      end\n    end\n\n    # good\n    class AddFkArticlesToAuthors \u003c ActiveRecord::Migration\n      def change\n        add_foreign_key :articles, :authors, name: :articles_author_id_fk\n      end\n    end\n    ```\n\n  * \u003ca name=\"reversible-migration\"\u003e\u003c/a\u003e\n    Don't use non-reversible migration commands in the `change` method.\n    Reversible migration commands are listed below.\n    [ActiveRecord::Migration::CommandRecorder](http://api.rubyonrails.org/classes/ActiveRecord/Migration/CommandRecorder.html)\n    \u003csup\u003e[[link](#reversible-migration)]\u003c/sup\u003e\n\n    ```ruby\n    # bad\n    class DropUsers \u003c ActiveRecord::Migration\n      def change\n        drop_table :users\n      end\n    end\n\n    # good\n    class DropUsers \u003c ActiveRecord::Migration\n      def up\n        drop_table :users\n      end\n\n      def down\n        create_table :users do |t|\n          t.string :name\n        end\n      end\n    end\n\n    # good\n    # In this case, block will be used by create_table in rollback\n    # http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters.html#method-i-drop_table\n    class DropUsers \u003c ActiveRecord::Migration\n      def change\n        drop_table :users do |t|\n          t.string :name\n        end\n      end\n    end\n    ```\n\n## Views\n\n  * \u003ca name=\"no-direct-model-view\"\u003e\u003c/a\u003e\n    Never call the model layer directly from a view.\n    \u003csup\u003e[[link](#no-direct-model-view)]\u003c/sup\u003e\n\n  * \u003ca name=\"no-complex-view-formatting\"\u003e\u003c/a\u003e\n    Never make complex formatting in the views, export the formatting to a method\n    in the view helper or the model.\n    \u003csup\u003e[[link](#no-complex-view-formatting)]\u003c/sup\u003e\n\n  * \u003ca name=\"partials\"\u003e\u003c/a\u003e\n    Mitigate code duplication by using partial templates and layouts.\n    \u003csup\u003e[[link](#partials)]\u003c/sup\u003e\n\n## Internationalization\n\n  * \u003ca name=\"locale-texts\"\u003e\u003c/a\u003e\n    No strings or other locale specific settings should be used in the views,\n    models and controllers. These texts should be moved to the locale files in the\n    `config/locales` directory.\n    \u003csup\u003e[[link](#locale-texts)]\u003c/sup\u003e\n\n  * \u003ca name=\"translated-labels\"\u003e\u003c/a\u003e\n    When the labels of an ActiveRecord model need to be translated, use the\n    `activerecord` scope:\n    \u003csup\u003e[[link](#translated-labels)]\u003c/sup\u003e\n\n    ```\n    en:\n      activerecord:\n        models:\n          user: Member\n        attributes:\n          user:\n            name: 'Full name'\n    ```\n\n    Then `User.model_name.human` will return \"Member\" and\n    `User.human_attribute_name(\"name\")` will return \"Full name\". These\n    translations of the attributes will be used as labels in the views.\n\n\n  * \u003ca name=\"organize-locale-files\"\u003e\u003c/a\u003e\n    Separate the texts used in the views from translations of ActiveRecord\n    attributes. Place the locale files for the models in a folder `locales/models` and the\n    texts used in the views in folder `locales/views`.\n    \u003csup\u003e[[link](#organize-locale-files)]\u003c/sup\u003e\n\n      * When organization of the locale files is done with additional directories,\n        these directories must be described in the `application.rb` file in order\n        to be loaded.\n\n        ```ruby\n        # config/application.rb\n        config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}')]\n        ```\n\n  * \u003ca name=\"shared-localization\"\u003e\u003c/a\u003e\n    Place the shared localization options, such as date or currency formats, in\n    files under the root of the `locales` directory.\n    \u003csup\u003e[[link](#shared-localization)]\u003c/sup\u003e\n\n  * \u003ca name=\"short-i18n\"\u003e\u003c/a\u003e\n    Use the short form of the I18n methods: `I18n.t` instead of `I18n.translate`\n    and `I18n.l` instead of `I18n.localize`.\n    \u003csup\u003e[[link](#short-i18n)]\u003c/sup\u003e\n\n  * \u003ca name=\"lazy-lookup\"\u003e\u003c/a\u003e\n    Use \"lazy\" lookup for the texts used in views. Let's say we have the following\n    structure:\n    \u003csup\u003e[[link](#lazy-lookup)]\u003c/sup\u003e\n\n    ```\n    en:\n      users:\n        show:\n          title: 'User details page'\n    ```\n\n    The value for `users.show.title` can be looked up in the template\n    `app/views/users/show.html.haml` like this:\n\n    ```ruby\n    = t '.title'\n    ```\n\n  * \u003ca name=\"dot-separated-keys\"\u003e\u003c/a\u003e\n    Use the dot-separated keys in the controllers and models instead of specifying\n    the `:scope` option. The dot-separated call is easier to read and trace the\n    hierarchy.\n    \u003csup\u003e[[link](#dot-separated-keys)]\u003c/sup\u003e\n\n    ```ruby\n    # bad\n    I18n.t :record_invalid, scope: [:activerecord, :errors, :messages]\n\n    # good\n    I18n.t 'activerecord.errors.messages.record_invalid'\n    ```\n\n  * \u003ca name=\"i18n-guides\"\u003e\u003c/a\u003e\n    More detailed information about the Rails I18n can be found in the [Rails\n    Guides](http://guides.rubyonrails.org/i18n.html)\n    \u003csup\u003e[[link](#i18n-guides)]\u003c/sup\u003e\n\n## Assets\n\nUse the [assets pipeline](http://guides.rubyonrails.org/asset_pipeline.html) to leverage organization within\nyour application.\n\n  * \u003ca name=\"reserve-app-assets\"\u003e\u003c/a\u003e\n    Reserve `app/assets` for custom stylesheets, javascripts, or images.\n    \u003csup\u003e[[link](#reserve-app-assets)]\u003c/sup\u003e\n\n  * \u003ca name=\"lib-assets\"\u003e\u003c/a\u003e\n    Use `lib/assets` for your own libraries that don’t really fit into the\n    scope of the application.\n    \u003csup\u003e[[link](#lib-assets)]\u003c/sup\u003e\n\n  * \u003ca name=\"vendor-assets\"\u003e\u003c/a\u003e\n    Third party code such as [jQuery](http://jquery.com/) or\n    [bootstrap](http://twitter.github.com/bootstrap/) should be placed in\n    `vendor/assets`.\n    \u003csup\u003e[[link](#vendor-assets)]\u003c/sup\u003e\n\n  * \u003ca name=\"gem-assets\"\u003e\u003c/a\u003e\n    When possible, use gemified versions of assets (e.g.\n    [jquery-rails](https://github.com/rails/jquery-rails),\n    [jquery-ui-rails](https://github.com/joliss/jquery-ui-rails),\n    [bootstrap-sass](https://github.com/thomas-mcdonald/bootstrap-sass),\n    [zurb-foundation](https://github.com/zurb/foundation)).\n    \u003csup\u003e[[link](#gem-assets)]\u003c/sup\u003e\n\n## Mailers\n\n  * \u003ca name=\"mailer-name\"\u003e\u003c/a\u003e\n    Name the mailers `SomethingMailer`. Without the Mailer suffix it isn't\n    immediately apparent what's a mailer and which views are related to the\n    mailer.\n    \u003csup\u003e[[link](#mailer-name)]\u003c/sup\u003e\n\n  * \u003ca name=\"html-plain-email\"\u003e\u003c/a\u003e\n    Provide both HTML and plain-text view templates.\n    \u003csup\u003e[[link](#html-plain-email)]\u003c/sup\u003e\n\n  * \u003ca name=\"enable-delivery-errors\"\u003e\u003c/a\u003e\n    Enable errors raised on failed mail delivery in your development environment.\n    The errors are disabled by default.\n    \u003csup\u003e[[link](#enable-delivery-errors)]\u003c/sup\u003e\n\n    ```ruby\n    # config/environments/development.rb\n\n    config.action_mailer.raise_delivery_errors = true\n    ```\n\n  * \u003ca name=\"local-smtp\"\u003e\u003c/a\u003e\n    Use a local SMTP server like\n    [Mailcatcher](https://github.com/sj26/mailcatcher) in the development\n    environment.\n    \u003csup\u003e[[link](#local-smtp)]\u003c/sup\u003e\n\n    ```ruby\n    # config/environments/development.rb\n\n    config.action_mailer.smtp_settings = {\n      address: 'localhost',\n      port: 1025,\n      # more settings\n    }\n    ```\n\n  * \u003ca name=\"default-hostname\"\u003e\u003c/a\u003e\n    Provide default settings for the host name.\n    \u003csup\u003e[[link](#default-hostname)]\u003c/sup\u003e\n\n    ```ruby\n    # config/environments/development.rb\n    config.action_mailer.default_url_options = { host: \"#{local_ip}:3000\" }\n\n    # config/environments/production.rb\n    config.action_mailer.default_url_options = { host: 'your_site.com' }\n\n    # in your mailer class\n    default_url_options[:host] = 'your_site.com'\n    ```\n\n  * \u003ca name=\"url-not-path-in-email\"\u003e\u003c/a\u003e\n    If you need to use a link to your site in an email, always use the `_url`, not\n    `_path` methods. The `_url` methods include the host name and the `_path`\n    methods don't.\n    \u003csup\u003e[[link](#url-not-path-in-email)]\u003c/sup\u003e\n\n    ```ruby\n    # bad\n    You can always find more info about this course\n    \u003c%= link_to 'here', course_path(@course) %\u003e\n\n    # good\n    You can always find more info about this course\n    \u003c%= link_to 'here', course_url(@course) %\u003e\n    ```\n\n  * \u003ca name=\"email-addresses\"\u003e\u003c/a\u003e\n    Format the from and to addresses properly. Use the following format:\n    \u003csup\u003e[[link](#email-addresses)]\u003c/sup\u003e\n\n    ```ruby\n    # in your mailer class\n    default from: 'Your Name \u003cinfo@your_site.com\u003e'\n    ```\n\n  * \u003ca name=\"delivery-method-test\"\u003e\u003c/a\u003e\n    Make sure that the e-mail delivery method for your test environment is set to\n    `test`:\n    \u003csup\u003e[[link](#delivery-method-test)]\u003c/sup\u003e\n\n    ```ruby\n    # config/environments/test.rb\n\n    config.action_mailer.delivery_method = :test\n    ```\n\n  * \u003ca name=\"delivery-method-smtp\"\u003e\u003c/a\u003e\n    The delivery method for development and production should be `smtp`:\n    \u003csup\u003e[[link](#delivery-method-smtp)]\u003c/sup\u003e\n\n    ```ruby\n    # config/environments/development.rb, config/environments/production.rb\n\n    config.action_mailer.delivery_method = :smtp\n    ```\n\n  * \u003ca name=\"inline-email-styles\"\u003e\u003c/a\u003e\n    When sending html emails all styles should be inline, as some mail clients\n    have problems with external styles. This however makes them harder to maintain\n    and leads to code duplication. There are two similar gems that transform the\n    styles and put them in the corresponding html tags:\n    [premailer-rails](https://github.com/fphilipe/premailer-rails) and\n    [roadie](https://github.com/Mange/roadie).\n    \u003csup\u003e[[link](#inline-email-styles)]\u003c/sup\u003e\n\n  * \u003ca name=\"background-email\"\u003e\u003c/a\u003e\n    Sending emails while generating page response should be avoided. It causes\n    delays in loading of the page and request can timeout if multiple email are\n    sent. To overcome this emails can be sent in background process with the help\n    of [sidekiq](https://github.com/mperham/sidekiq) gem.\n    \u003csup\u003e[[link](#background-email)]\u003c/sup\u003e\n\n\n## Active Support Core Extensions\n\n  * \u003ca name=\"try-bang\"\u003e\u003c/a\u003e\n    Prefer Ruby 2.3's safe navigation operator `\u0026.` over `ActiveSupport#try!`.\n    \u003csup\u003e[[link](#try-bang)]\u003c/sup\u003e\n\n```ruby\n# bad\nobj.try! :fly\n\n# good\nobj\u0026.fly\n```\n\n  * \u003ca name=\"active_support_aliases\"\u003e\u003c/a\u003e\n    Prefer Ruby's Standard Library methods over `ActiveSupport` aliases.\n    \u003csup\u003e[[link](#active_support_aliases)]\u003c/sup\u003e\n\n```ruby\n# bad\n'the day'.starts_with? 'th'\n'the day'.ends_with? 'ay'\n\n# good\n'the day'.start_with? 'th'\n'the day'.end_with? 'ay'\n```\n\n  * \u003ca name=\"active_support_extensions\"\u003e\u003c/a\u003e\n    Prefer Ruby's Standard Library over uncommon ActiveSupport extensions.\n    \u003csup\u003e[[link](#active_support_extensions)]\u003c/sup\u003e\n\n```ruby\n# bad\n(1..50).to_a.forty_two\n1.in? [1, 2]\n'day'.in? 'the day'\n\n# good\n(1..50).to_a[41]\n[1, 2].include? 1\n'the day'.include? 'day'\n```\n\n  * \u003ca name=\"inquiry\"\u003e\u003c/a\u003e\n    Prefer Ruby's comparison operators over ActiveSupport's `Array#inquiry`, and `String#inquiry`.\n    \u003csup\u003e[[link](#inquiry)]\u003c/sup\u003e\n\n```ruby\n# bad - String#inquiry\nruby = 'two'.inquiry\nruby.two?\n\n# good\nruby = 'two'\nruby == 'two'\n\n# bad - Array#inquiry\npets = %w(cat dog).inquiry\npets.gopher?\n\n# good\npets = %w(cat dog)\npets.include? 'cat'\n```\n\n## Time\n\n  * \u003ca name=\"tz-config\"\u003e\u003c/a\u003e\n    Config your timezone accordingly in `application.rb`.\n    \u003csup\u003e[[link](#tz-config)]\u003c/sup\u003e\n\n    ```ruby\n    config.time_zone = 'Eastern European Time'\n    # optional - note it can be only :utc or :local (default is :utc)\n    config.active_record.default_timezone = :local\n    ```\n\n  * \u003ca name=\"time-parse\"\u003e\u003c/a\u003e\n    Don't use `Time.parse`.\n    \u003csup\u003e[[link](#time-parse)]\u003c/sup\u003e\n\n    ```ruby\n    # bad\n    Time.parse('2015-03-02 19:05:37') # =\u003e Will assume time string given is in the system's time zone.\n\n    # good\n    Time.zone.parse('2015-03-02 19:05:37') # =\u003e Mon, 02 Mar 2015 19:05:37 EET +02:00\n    ```\n\n  * \u003ca name=\"to-time\"\u003e\u003c/a\u003e\n    Don't use [`String#to_time`](https://apidock.com/rails/String/to_time)\n    \u003csup\u003e[[link](#to-time)]\u003c/sup\u003e\n\n    ```ruby\n    # bad - assumes time string given is in the system's time zone.\n    '2015-03-02 19:05:37'.to_time\n\n    # good\n    Time.zone.parse('2015-03-02 19:05:37') # =\u003e Mon, 02 Mar 2015 19:05:37 EET +02:00\n    ```\n\n  * \u003ca name=\"time-now\"\u003e\u003c/a\u003e\n    Don't use `Time.now`.\n    \u003csup\u003e[[link](#time-now)]\u003c/sup\u003e\n\n    ```ruby\n    # bad\n    Time.now # =\u003e Returns system time and ignores your configured time zone.\n\n    # good\n    Time.zone.now # =\u003e Fri, 12 Mar 2014 22:04:47 EET +02:00\n    Time.current # Same thing but shorter.\n    ```\n\n## Bundler\n\n  * \u003ca name=\"dev-test-gems\"\u003e\u003c/a\u003e\n    Put gems used only for development or testing in the appropriate group in the\n    Gemfile.\n    \u003csup\u003e[[link](#dev-test-gems)]\u003c/sup\u003e\n\n  * \u003ca name=\"only-good-gems\"\u003e\u003c/a\u003e\n    Use only established gems in your projects. If you're contemplating on\n    including some little-known gem you should do a careful review of its source\n    code first.\n    \u003csup\u003e[[link](#only-good-gems)]\u003c/sup\u003e\n\n  * \u003ca name=\"os-specific-gemfile-locks\"\u003e\u003c/a\u003e\n    OS-specific gems will by default result in a constantly changing\n    `Gemfile.lock` for projects with multiple developers using different operating\n    systems.  Add all OS X specific gems to a `darwin` group in the Gemfile, and\n    all Linux specific gems to a `linux` group:\n    \u003csup\u003e[[link](#os-specific-gemfile-locks)]\u003c/sup\u003e\n\n    ```ruby\n    # Gemfile\n    group :darwin do\n      gem 'rb-fsevent'\n      gem 'growl'\n    end\n\n    group :linux do\n      gem 'rb-inotify'\n    end\n    ```\n\n    To require the appropriate gems in the right environment, add the\n    following to `config/application.rb`:\n\n    ```ruby\n    platform = RUBY_PLATFORM.match(/(linux|darwin)/)[0].to_sym\n    Bundler.require(platform)\n    ```\n\n  * \u003ca name=\"gemfile-lock\"\u003e\u003c/a\u003e\n    Do not remove the `Gemfile.lock` from version control. This is not some\n    randomly generated file - it makes sure that all of your team members get the\n    same gem versions when they do a `bundle install`.\n    \u003csup\u003e[[link](#gemfile-lock)]\u003c/sup\u003e\n\n## Managing processes\n\n  * \u003ca name=\"foreman\"\u003e\u003c/a\u003e\n    If your projects depends on various external processes use\n    [foreman](https://github.com/ddollar/foreman) to manage them.\n    \u003csup\u003e[[link](#foreman)]\u003c/sup\u003e\n\n# Further Reading\n\nThere are a few excellent resources on Rails style, that you should consider if\nyou have time to spare:\n\n  * [The Rails 4 Way](http://www.amazon.com/The-Rails-Addison-Wesley-Professional-Ruby/dp/0321944275)\n  * [Ruby on Rails Guides](http://guides.rubyonrails.org/)\n  * [The RSpec Book](http://pragprog.com/book/achbd/the-rspec-book)\n  * [The Cucumber Book](http://pragprog.com/book/hwcuc/the-cucumber-book)\n  * [Everyday Rails Testing with RSpec](https://leanpub.com/everydayrailsrspec)\n  * [Rails 4 Test Prescriptions](https://pragprog.com/book/nrtest2/rails-4-test-prescriptions)\n  * [Better Specs for RSpec](http://betterspecs.org)\n\n# Contributing\n\nNothing written in this guide is set in stone. It's my desire to work together\nwith everyone interested in Rails coding style, so that we could ultimately\ncreate a resource that will be beneficial to the entire Ruby community.\n\nFeel free to open tickets or send pull requests with improvements. Thanks in\nadvance for your help!\n\nYou can also support the project (and RuboCop) with financial contributions via\n[Patreon](https://www.patreon.com/bbatsov).\n\n## How to Contribute?\n\nIt's easy, just follow the [contribution guidelines](https://github.com/rubocop-hq/rails-style-guide/blob/master/CONTRIBUTING.md).\n\n# License\n\n![Creative Commons License](http://i.creativecommons.org/l/by/3.0/88x31.png)\nThis work is licensed under a [Creative Commons Attribution 3.0 Unported\nLicense](http://creativecommons.org/licenses/by/3.0/deed.en_US)\n\n# Spread the Word\n\nA community-driven style guide is of little use to a community that doesn't know\nabout its existence. Tweet about the guide, share it with your friends and\ncolleagues. Every comment, suggestion or opinion we get makes the guide just a\nlittle bit better. And we want to have the best possible guide, don't we?\n\nCheers,\u003cbr/\u003e\n[Bozhidar](https://twitter.com/bbatsov)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farbox%2Frails-style-guide","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Farbox%2Frails-style-guide","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farbox%2Frails-style-guide/lists"}