diff options
Diffstat (limited to 'guides/source')
50 files changed, 3831 insertions, 1616 deletions
diff --git a/guides/source/2_2_release_notes.md b/guides/source/2_2_release_notes.md index be00087f63..79634d8760 100644 --- a/guides/source/2_2_release_notes.md +++ b/guides/source/2_2_release_notes.md @@ -3,7 +3,7 @@ Ruby on Rails 2.2 Release Notes =============================== -Rails 2.2 delivers a number of new and improved features. This list covers the major upgrades, but doesn't include every little bug fix and change. If you want to see everything, check out the [list of commits](http://github.com/rails/rails/commits/2-2-stable) in the main Rails repository on GitHub. +Rails 2.2 delivers a number of new and improved features. This list covers the major upgrades, but doesn't include every little bug fix and change. If you want to see everything, check out the [list of commits](https://github.com/rails/rails/commits/2-2-stable) in the main Rails repository on GitHub. Along with Rails, 2.2 marks the launch of the [Ruby on Rails Guides](http://guides.rubyonrails.org/), the first results of the ongoing [Rails Guides hackfest](http://hackfest.rubyonrails.org/guide). This site will deliver high-quality documentation of the major features of Rails. @@ -21,8 +21,8 @@ Rails 2.2 supplies an easy system for internationalization (or i18n, for those o * Lead Contributors: Rails i18 Team * More information : * [Official Rails i18 website](http://rails-i18n.org) - * [Finally. Ruby on Rails gets internationalized](http://www.artweb-design.de/2008/7/18/finally-ruby-on-rails-gets-internationalized) - * [Localizing Rails : Demo application](http://github.com/clemens/i18n_demo_app) + * [Finally. Ruby on Rails gets internationalized](https://web.archive.org/web/20140407075019/http://www.artweb-design.de/2008/7/18/finally-ruby-on-rails-gets-internationalized) + * [Localizing Rails : Demo application](https://github.com/clemens/i18n_demo_app) ### Compatibility with Ruby 1.9 and JRuby @@ -59,7 +59,7 @@ rake doc:guides This will put the guides inside `Rails.root/doc/guides` and you may start surfing straight away by opening `Rails.root/doc/guides/index.html` in your favourite browser. * Lead Contributors: [Rails Documentation Team](credits.html) -* Major contributions from [Xavier Noria":http://advogato.org/person/fxn/diary.html and "Hongli Lai](http://izumi.plan99.net/blog/.) +* Major contributions from [Xavier Noria](http://advogato.org/person/fxn/diary.html) and [Hongli Lai](http://izumi.plan99.net/blog/). * More information: * [Rails Guides hackfest](http://hackfest.rubyonrails.org/guide) * [Help improve Rails documentation on Git branch](http://weblog.rubyonrails.org/2008/5/2/help-improve-rails-documentation-on-git-branch) @@ -146,7 +146,7 @@ development: * Lead Contributor: [Nick Sieger](http://blog.nicksieger.com/) * More information: - * [What's New in Edge Rails: Connection Pools](http://ryandaigle.com/articles/2008/9/7/what-s-new-in-edge-rails-connection-pools) + * [What's New in Edge Rails: Connection Pools](http://archives.ryandaigle.com/articles/2008/9/7/what-s-new-in-edge-rails-connection-pools) ### Hashes for Join Table Conditions @@ -166,7 +166,7 @@ Product.all(:joins => :photos, :conditions => { :photos => { :copyright => false ``` * More information: - * [What's New in Edge Rails: Easy Join Table Conditions](http://ryandaigle.com/articles/2008/7/7/what-s-new-in-edge-rails-easy-join-table-conditions) + * [What's New in Edge Rails: Easy Join Table Conditions](http://archives.ryandaigle.com/articles/2008/7/7/what-s-new-in-edge-rails-easy-join-table-conditions) ### New Dynamic Finders @@ -239,7 +239,7 @@ This will enable recognition of (among others) these routes: * Lead Contributor: [S. Brent Faulkner](http://www.unwwwired.net/) * More information: * [Rails Routing from the Outside In](routing.html#nested-resources) - * [What's New in Edge Rails: Shallow Routes](http://ryandaigle.com/articles/2008/9/7/what-s-new-in-edge-rails-shallow-routes) + * [What's New in Edge Rails: Shallow Routes](http://archives.ryandaigle.com/articles/2008/9/7/what-s-new-in-edge-rails-shallow-routes) ### Method Arrays for Member or Collection Routes @@ -287,7 +287,7 @@ Action Mailer Action Mailer now supports mailer layouts. You can make your HTML emails as pretty as your in-browser views by supplying an appropriately-named layout - for example, the `CustomerMailer` class expects to use `layouts/customer_mailer.html.erb`. * More information: - * [What's New in Edge Rails: Mailer Layouts](http://ryandaigle.com/articles/2008/9/7/what-s-new-in-edge-rails-mailer-layouts) + * [What's New in Edge Rails: Mailer Layouts](http://archives.ryandaigle.com/articles/2008/9/7/what-s-new-in-edge-rails-mailer-layouts) Action Mailer now offers built-in support for GMail's SMTP servers, by turning on STARTTLS automatically. This requires Ruby 1.8.7 to be installed. @@ -321,7 +321,7 @@ Other features of memoization include `unmemoize`, `unmemoize_all`, and `memoize * Lead Contributor: [Josh Peek](http://joshpeek.com/) * More information: - * [What's New in Edge Rails: Easy Memoization](http://ryandaigle.com/articles/2008/7/16/what-s-new-in-edge-rails-memoization) + * [What's New in Edge Rails: Easy Memoization](http://archives.ryandaigle.com/articles/2008/7/16/what-s-new-in-edge-rails-memoization) * [Memo-what? A Guide to Memoization](http://www.railway.at/articles/2008/09/20/a-guide-to-memoization) ### each_with_object @@ -389,9 +389,9 @@ To avoid deployment issues and make Rails applications more self-contained, it's You can unpack or install a single gem by specifying `GEM=_gem_name_` on the command line. -* Lead Contributor: [Matt Jones](http://github.com/al2o3cr) +* Lead Contributor: [Matt Jones](https://github.com/al2o3cr) * More information: - * [What's New in Edge Rails: Gem Dependencies](http://ryandaigle.com/articles/2008/4/1/what-s-new-in-edge-rails-gem-dependencies) + * [What's New in Edge Rails: Gem Dependencies](http://archives.ryandaigle.com/articles/2008/4/1/what-s-new-in-edge-rails-gem-dependencies) * [Rails 2.1.2 and 2.2RC1: Update Your RubyGems](http://afreshcup.com/2008/10/25/rails-212-and-22rc1-update-your-rubygems/) * [Detailed discussion on Lighthouse](http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/1128) @@ -411,7 +411,7 @@ Deprecated A few pieces of older code are deprecated in this release: * `Rails::SecretKeyGenerator` has been replaced by `ActiveSupport::SecureRandom` -* `render_component` is deprecated. There's a [render_components plugin](http://github.com/rails/render_component/tree/master) available if you need this functionality. +* `render_component` is deprecated. There's a [render_components plugin](https://github.com/rails/render_component/tree/master) available if you need this functionality. * Implicit local assignments when rendering partials has been deprecated. ```ruby diff --git a/guides/source/2_3_release_notes.md b/guides/source/2_3_release_notes.md index 0a62f34371..06761b67bb 100644 --- a/guides/source/2_3_release_notes.md +++ b/guides/source/2_3_release_notes.md @@ -3,7 +3,7 @@ Ruby on Rails 2.3 Release Notes =============================== -Rails 2.3 delivers a variety of new and improved features, including pervasive Rack integration, refreshed support for Rails Engines, nested transactions for Active Record, dynamic and default scopes, unified rendering, more efficient routing, application templates, and quiet backtraces. This list covers the major upgrades, but doesn't include every little bug fix and change. If you want to see everything, check out the [list of commits](http://github.com/rails/rails/commits/2-3-stable) in the main Rails repository on GitHub or review the `CHANGELOG` files for the individual Rails components. +Rails 2.3 delivers a variety of new and improved features, including pervasive Rack integration, refreshed support for Rails Engines, nested transactions for Active Record, dynamic and default scopes, unified rendering, more efficient routing, application templates, and quiet backtraces. This list covers the major upgrades, but doesn't include every little bug fix and change. If you want to see everything, check out the [list of commits](https://github.com/rails/rails/commits/2-3-stable) in the main Rails repository on GitHub or review the `CHANGELOG` files for the individual Rails components. -------------------------------------------------------------------------------- @@ -125,14 +125,14 @@ Order.scoped_by_customer_id(12).scoped_by_status("open") There's nothing to define to use dynamic scopes: they just work. * Lead Contributor: [Yaroslav Markin](http://evilmartians.com/) -* More Information: [What's New in Edge Rails: Dynamic Scope Methods](http://ryandaigle.com/articles/2008/12/29/what-s-new-in-edge-rails-dynamic-scope-methods.) +* More Information: [What's New in Edge Rails: Dynamic Scope Methods](http://archives.ryandaigle.com/articles/2008/12/29/what-s-new-in-edge-rails-dynamic-scope-methods) ### Default Scopes Rails 2.3 will introduce the notion of _default scopes_ similar to named scopes, but applying to all named scopes or find methods within the model. For example, you can write `default_scope :order => 'name ASC'` and any time you retrieve records from that model they'll come out sorted by name (unless you override the option, of course). * Lead Contributor: Paweł Kondzior -* More Information: [What's New in Edge Rails: Default Scoping](http://ryandaigle.com/articles/2008/11/18/what-s-new-in-edge-rails-default-scoping) +* More Information: [What's New in Edge Rails: Default Scoping](http://archives.ryandaigle.com/articles/2008/11/18/what-s-new-in-edge-rails-default-scoping) ### Batch Processing @@ -158,7 +158,7 @@ Note that you should only use this method for batch processing: for small number * More Information (at that point the convenience method was called just `each`): * [Rails 2.3: Batch Finding](http://afreshcup.com/2009/02/23/rails-23-batch-finding/) - * [What's New in Edge Rails: Batched Find](http://ryandaigle.com/articles/2009/2/23/what-s-new-in-edge-rails-batched-find) + * [What's New in Edge Rails: Batched Find](http://archives.ryandaigle.com/articles/2009/2/23/what-s-new-in-edge-rails-batched-find) ### Multiple Conditions for Callbacks @@ -179,7 +179,7 @@ developers = Developer.find(:all, :group => "salary", :having => "sum(salary) > 10000", :select => "salary") ``` -* Lead Contributor: [Emilio Tagua](http://github.com/miloops) +* Lead Contributor: [Emilio Tagua](https://github.com/miloops) ### Reconnecting MySQL Connections @@ -235,7 +235,7 @@ If you're one of the people who has always been bothered by the special-case nam * More Information: * [The Death of Application.rb](http://afreshcup.com/2008/11/17/rails-2x-the-death-of-applicationrb/) - * [What's New in Edge Rails: Application.rb Duality is no More](http://ryandaigle.com/articles/2008/11/19/what-s-new-in-edge-rails-application-rb-duality-is-no-more) + * [What's New in Edge Rails: Application.rb Duality is no More](http://archives.ryandaigle.com/articles/2008/11/19/what-s-new-in-edge-rails-application-rb-duality-is-no-more) ### HTTP Digest Authentication Support @@ -261,7 +261,7 @@ end ``` * Lead Contributor: [Gregg Kellogg](http://www.kellogg-assoc.com/) -* More Information: [What's New in Edge Rails: HTTP Digest Authentication](http://ryandaigle.com/articles/2009/1/30/what-s-new-in-edge-rails-http-digest-authentication) +* More Information: [What's New in Edge Rails: HTTP Digest Authentication](http://archives.ryandaigle.com/articles/2009/1/30/what-s-new-in-edge-rails-http-digest-authentication) ### More Efficient Routing @@ -377,8 +377,8 @@ You can write this view in Rails 2.3: * Lead Contributor: [Eloy Duran](http://superalloy.nl/) * More Information: * [Nested Model Forms](http://weblog.rubyonrails.org/2009/1/26/nested-model-forms) - * [complex-form-examples](http://github.com/alloy/complex-form-examples) - * [What's New in Edge Rails: Nested Object Forms](http://ryandaigle.com/articles/2009/2/1/what-s-new-in-edge-rails-nested-attributes) + * [complex-form-examples](https://github.com/alloy/complex-form-examples) + * [What's New in Edge Rails: Nested Object Forms](http://archives.ryandaigle.com/articles/2009/2/1/what-s-new-in-edge-rails-nested-attributes) ### Smart Rendering of Partials @@ -394,7 +394,7 @@ render @article render @articles ``` -* More Information: [What's New in Edge Rails: render Stops Being High-Maintenance](http://ryandaigle.com/articles/2008/11/20/what-s-new-in-edge-rails-render-stops-being-high-maintenance) +* More Information: [What's New in Edge Rails: render Stops Being High-Maintenance](http://archives.ryandaigle.com/articles/2008/11/20/what-s-new-in-edge-rails-render-stops-being-high-maintenance) ### Prompts for Date Select Helpers @@ -421,7 +421,7 @@ You're likely familiar with Rails' practice of adding timestamps to static asset Asset hosts get more flexible in edge Rails with the ability to declare an asset host as a specific object that responds to a call. This allows you to implement any complex logic you need in your asset hosting. -* More Information: [asset-hosting-with-minimum-ssl](http://github.com/dhh/asset-hosting-with-minimum-ssl/tree/master) +* More Information: [asset-hosting-with-minimum-ssl](https://github.com/dhh/asset-hosting-with-minimum-ssl/tree/master) ### grouped_options_for_select Helper Method @@ -498,7 +498,7 @@ Active Support has a few interesting changes, including the introduction of `Obj A lot of folks have adopted the notion of using try() to attempt operations on objects. It's especially helpful in views where you can avoid nil-checking by writing code like `<%= @person.try(:name) %>`. Well, now it's baked right into Rails. As implemented in Rails, it raises `NoMethodError` on private methods and always returns `nil` if the object is nil. -* More Information: [try()](http://ozmm.org/posts/try.html.) +* More Information: [try()](http://ozmm.org/posts/try.html) ### Object#tap Backport @@ -533,7 +533,7 @@ If you look up the spec on the "json.org" site, you'll discover that all keys in ### Other Active Support Changes * You can use `Enumerable#none?` to check that none of the elements match the supplied block. -* If you're using Active Support [delegates](http://afreshcup.com/2008/10/19/coming-in-rails-22-delegate-prefixes/,) the new `:allow_nil` option lets you return `nil` instead of raising an exception when the target object is nil. +* If you're using Active Support [delegates](http://afreshcup.com/2008/10/19/coming-in-rails-22-delegate-prefixes/) the new `:allow_nil` option lets you return `nil` instead of raising an exception when the target object is nil. * `ActiveSupport::OrderedHash`: now implements `each_key` and `each_value`. * `ActiveSupport::MessageEncryptor` provides a simple way to encrypt information for storage in an untrusted location (like cookies). * Active Support's `from_xml` no longer depends on XmlSimple. Instead, Rails now includes its own XmlMini implementation, with just the functionality that it requires. This lets Rails dispense with the bundled copy of XmlSimple that it's been carting around. @@ -555,11 +555,11 @@ Rails Metal is a new mechanism that provides superfast endpoints inside of your * [Introducing Rails Metal](http://weblog.rubyonrails.org/2008/12/17/introducing-rails-metal) * [Rails Metal: a micro-framework with the power of Rails](http://soylentfoo.jnewland.com/articles/2008/12/16/rails-metal-a-micro-framework-with-the-power-of-rails-m) * [Metal: Super-fast Endpoints within your Rails Apps](http://www.railsinside.com/deployment/180-metal-super-fast-endpoints-within-your-rails-apps.html) - * [What's New in Edge Rails: Rails Metal](http://ryandaigle.com/articles/2008/12/18/what-s-new-in-edge-rails-rails-metal) + * [What's New in Edge Rails: Rails Metal](http://archives.ryandaigle.com/articles/2008/12/18/what-s-new-in-edge-rails-rails-metal) ### Application Templates -Rails 2.3 incorporates Jeremy McAnally's [rg](http://github.com/jeremymcanally/rg/tree/master) application generator. What this means is that we now have template-based application generation built right into Rails; if you have a set of plugins you include in every application (among many other use cases), you can just set up a template once and use it over and over again when you run the `rails` command. There's also a rake task to apply a template to an existing application: +Rails 2.3 incorporates Jeremy McAnally's [rg](https://github.com/jm/rg) application generator. What this means is that we now have template-based application generation built right into Rails; if you have a set of plugins you include in every application (among many other use cases), you can just set up a template once and use it over and over again when you run the `rails` command. There's also a rake task to apply a template to an existing application: ``` rake rails:template LOCATION=~/template.rb @@ -572,7 +572,7 @@ This will layer the changes from the template on top of whatever code the projec ### Quieter Backtraces -Building on Thoughtbot's [Quiet Backtrace](https://github.com/thoughtbot/quietbacktrace) plugin, which allows you to selectively remove lines from `Test::Unit` backtraces, Rails 2.3 implements `ActiveSupport::BacktraceCleaner` and `Rails::BacktraceCleaner` in core. This supports both filters (to perform regex-based substitutions on backtrace lines) and silencers (to remove backtrace lines entirely). Rails automatically adds silencers to get rid of the most common noise in a new application, and builds a `config/backtrace_silencers.rb` file to hold your own additions. This feature also enables prettier printing from any gem in the backtrace. +Building on thoughtbot's [Quiet Backtrace](https://github.com/thoughtbot/quietbacktrace) plugin, which allows you to selectively remove lines from `Test::Unit` backtraces, Rails 2.3 implements `ActiveSupport::BacktraceCleaner` and `Rails::BacktraceCleaner` in core. This supports both filters (to perform regex-based substitutions on backtrace lines) and silencers (to remove backtrace lines entirely). Rails automatically adds silencers to get rid of the most common noise in a new application, and builds a `config/backtrace_silencers.rb` file to hold your own additions. This feature also enables prettier printing from any gem in the backtrace. ### Faster Boot Time in Development Mode with Lazy Loading/Autoload @@ -605,8 +605,8 @@ Deprecated A few pieces of older code are deprecated in this release: -* If you're one of the (fairly rare) Rails developers who deploys in a fashion that depends on the inspector, reaper, and spawner scripts, you'll need to know that those scripts are no longer included in core Rails. If you need them, you'll be able to pick up copies via the [irs_process_scripts](http://github.com/rails/irs_process_scripts/tree) plugin. -* `render_component` goes from "deprecated" to "nonexistent" in Rails 2.3. If you still need it, you can install the [render_component plugin](http://github.com/rails/render_component/tree/master). +* If you're one of the (fairly rare) Rails developers who deploys in a fashion that depends on the inspector, reaper, and spawner scripts, you'll need to know that those scripts are no longer included in core Rails. If you need them, you'll be able to pick up copies via the [irs_process_scripts](https://github.com/rails/irs_process_scripts/tree) plugin. +* `render_component` goes from "deprecated" to "nonexistent" in Rails 2.3. If you still need it, you can install the [render_component plugin](https://github.com/rails/render_component/tree/master). * Support for Rails components has been removed. * If you were one of the people who got used to running `script/performance/request` to look at performance based on integration tests, you need to learn a new trick: that script has been removed from core Rails now. There's a new request_profiler plugin that you can install to get the exact same functionality back. * `ActionController::Base#session_enabled?` is deprecated because sessions are lazy-loaded now. @@ -614,7 +614,7 @@ A few pieces of older code are deprecated in this release: * Some integration test helpers have been removed. `response.headers["Status"]` and `headers["Status"]` will no longer return anything. Rack does not allow "Status" in its return headers. However you can still use the `status` and `status_message` helpers. `response.headers["cookie"]` and `headers["cookie"]` will no longer return any CGI cookies. You can inspect `headers["Set-Cookie"]` to see the raw cookie header or use the `cookies` helper to get a hash of the cookies sent to the client. * `formatted_polymorphic_url` is deprecated. Use `polymorphic_url` with `:format` instead. * The `:http_only` option in `ActionController::Response#set_cookie` has been renamed to `:httponly`. -* The `:connector` and `:skip_last_comma` options of `to_sentence` have been replaced by `:words_connnector`, `:two_words_connector`, and `:last_word_connector` options. +* The `:connector` and `:skip_last_comma` options of `to_sentence` have been replaced by `:words_connector`, `:two_words_connector`, and `:last_word_connector` options. * Posting a multipart form with an empty `file_field` control used to submit an empty string to the controller. Now it submits a nil, due to differences between Rack's multipart parser and the old Rails one. Credits diff --git a/guides/source/3_0_release_notes.md b/guides/source/3_0_release_notes.md index 696493a3cf..49d37ba489 100644 --- a/guides/source/3_0_release_notes.md +++ b/guides/source/3_0_release_notes.md @@ -17,7 +17,7 @@ Even if you don't give a hoot about any of our internal cleanups, Rails 3.0 is g On top of all that, we've tried our best to deprecate the old APIs with nice warnings. That means that you can move your existing application to Rails 3 without immediately rewriting all your old code to the latest best practices. -These release notes cover the major upgrades, but don't include every little bug fix and change. Rails 3.0 consists of almost 4,000 commits by more than 250 authors! If you want to see everything, check out the [list of commits](http://github.com/rails/rails/commits/3-0-stable) in the main Rails repository on GitHub. +These release notes cover the major upgrades, but don't include every little bug fix and change. Rails 3.0 consists of almost 4,000 commits by more than 250 authors! If you want to see everything, check out the [list of commits](https://github.com/rails/rails/commits/3-0-stable) in the main Rails repository on GitHub. -------------------------------------------------------------------------------- @@ -63,7 +63,7 @@ The `config.gem` method is gone and has been replaced by using `bundler` and a ` ### Upgrade Process -To help with the upgrade process, a plugin named [Rails Upgrade](http://github.com/rails/rails_upgrade) has been created to automate part of it. +To help with the upgrade process, a plugin named [Rails Upgrade](https://github.com/rails/rails_upgrade) has been created to automate part of it. Simply install the plugin, then run `rake rails:upgrade:check` to check your app for pieces that need to be updated (with links to information on how to update them). It also offers a task to generate a `Gemfile` based on your current `config.gem` calls and a task to generate a new routes file from your current one. To get the plugin, simply run the following: @@ -86,7 +86,7 @@ $ cd myapp ### Vendoring Gems -Rails now uses a `Gemfile` in the application root to determine the gems you require for your application to start. This `Gemfile` is processed by the [Bundler](http://github.com/carlhuda/bundler,) which then installs all your dependencies. It can even install all the dependencies locally to your application so that it doesn't depend on the system gems. +Rails now uses a `Gemfile` in the application root to determine the gems you require for your application to start. This `Gemfile` is processed by the [Bundler](https://github.com/bundler/bundler) which then installs all your dependencies. It can even install all the dependencies locally to your application so that it doesn't depend on the system gems. More information: - [bundler homepage](http://bundler.io/) @@ -138,14 +138,14 @@ More Information: - [Rails Edge Architecture](http://yehudakatz.com/2009/06/11/r ### Arel Integration -[Arel](http://github.com/brynary/arel) (or Active Relation) has been taken on as the underpinnings of Active Record and is now required for Rails. Arel provides an SQL abstraction that simplifies out Active Record and provides the underpinnings for the relation functionality in Active Record. +[Arel](https://github.com/brynary/arel) (or Active Relation) has been taken on as the underpinnings of Active Record and is now required for Rails. Arel provides an SQL abstraction that simplifies out Active Record and provides the underpinnings for the relation functionality in Active Record. More information: - [Why I wrote Arel](https://web.archive.org/web/20120718093140/http://magicscalingsprinkles.wordpress.com/2010/01/28/why-i-wrote-arel/) ### Mail Extraction -Action Mailer ever since its beginnings has had monkey patches, pre parsers and even delivery and receiver agents, all in addition to having TMail vendored in the source tree. Version 3 changes that with all email message related functionality abstracted out to the [Mail](http://github.com/mikel/mail) gem. This again reduces code duplication and helps create definable boundaries between Action Mailer and the email parser. +Action Mailer ever since its beginnings has had monkey patches, pre parsers and even delivery and receiver agents, all in addition to having TMail vendored in the source tree. Version 3 changes that with all email message related functionality abstracted out to the [Mail](https://github.com/mikel/mail) gem. This again reduces code duplication and helps create definable boundaries between Action Mailer and the email parser. More information: - [New Action Mailer API in Rails 3](http://lindsaar.net/2010/1/26/new-actionmailer-api-in-rails-3) @@ -161,7 +161,7 @@ More Information: - [Rails Documentation Projects](http://weblog.rubyonrails.org Internationalization -------------------- -A large amount of work has been done with I18n support in Rails 3, including the latest [I18n](http://github.com/svenfuchs/i18n) gem supplying many speed improvements. +A large amount of work has been done with I18n support in Rails 3, including the latest [I18n](https://github.com/svenfuchs/i18n) gem supplying many speed improvements. * I18n for any object - I18n behavior can be added to any object by including `ActiveModel::Translation` and `ActiveModel::Validations`. There is also an `errors.messages` fallback for translations. * Attributes can have default translations. @@ -213,7 +213,6 @@ Railties now deprecates: More information: * [Discovering Rails 3 generators](http://blog.plataformatec.com.br/2010/01/discovering-rails-3-generators) -* [Making Generators for Rails 3 with Thor](http://caffeinedd.com/guides/331-making-generators-for-rails-3-with-thor) * [The Rails Module (in Rails 3)](http://litanyagainstfear.com/blog/2010/02/03/the-rails-module/) Action Pack @@ -250,7 +249,7 @@ Deprecations: More Information: -* [Render Options in Rails 3](http://www.engineyard.com/blog/2010/render-options-in-rails-3/) +* [Render Options in Rails 3](https://blog.engineyard.com/2010/render-options-in-rails-3) * [Three reasons to love ActionController::Responder](http://weblog.rubyonrails.org/2009/8/31/three-reasons-love-responder) @@ -310,7 +309,7 @@ More Information: Major re-write was done in the Action View helpers, implementing Unobtrusive JavaScript (UJS) hooks and removing the old inline AJAX commands. This enables Rails to use any compliant UJS driver to implement the UJS hooks in the helpers. -What this means is that all previous `remote_<method>` helpers have been removed from Rails core and put into the [Prototype Legacy Helper](http://github.com/rails/prototype_legacy_helper). To get UJS hooks into your HTML, you now pass `:remote => true` instead. For example: +What this means is that all previous `remote_<method>` helpers have been removed from Rails core and put into the [Prototype Legacy Helper](https://github.com/rails/prototype_legacy_helper). To get UJS hooks into your HTML, you now pass `:remote => true` instead. For example: ```ruby form_for @post, :remote => true @@ -576,7 +575,7 @@ The following methods have been removed because they are no longer used in the f Action Mailer ------------- -Action Mailer has been given a new API with TMail being replaced out with the new [Mail](http://github.com/mikel/mail) as the email library. Action Mailer itself has been given an almost complete re-write with pretty much every line of code touched. The result is that Action Mailer now simply inherits from Abstract Controller and wraps the Mail gem in a Rails DSL. This reduces the amount of code and duplication of other libraries in Action Mailer considerably. +Action Mailer has been given a new API with TMail being replaced out with the new [Mail](https://github.com/mikel/mail) as the email library. Action Mailer itself has been given an almost complete re-write with pretty much every line of code touched. The result is that Action Mailer now simply inherits from Abstract Controller and wraps the Mail gem in a Rails DSL. This reduces the amount of code and duplication of other libraries in Action Mailer considerably. * All mailers are now in `app/mailers` by default. * Can now send email using new API with three methods: `attachments`, `headers` and `mail`. diff --git a/guides/source/3_1_release_notes.md b/guides/source/3_1_release_notes.md index 327495704a..feee0f9920 100644 --- a/guides/source/3_1_release_notes.md +++ b/guides/source/3_1_release_notes.md @@ -558,4 +558,4 @@ Credits See the [full list of contributors to Rails](http://contributors.rubyonrails.org/) for the many people who spent many hours making Rails, the stable and robust framework it is. Kudos to all of them. -Rails 3.1 Release Notes were compiled by [Vijay Dev](https://github.com/vijaydev.) +Rails 3.1 Release Notes were compiled by [Vijay Dev](https://github.com/vijaydev) diff --git a/guides/source/4_0_release_notes.md b/guides/source/4_0_release_notes.md index b9444510ea..4615cf18e6 100644 --- a/guides/source/4_0_release_notes.md +++ b/guides/source/4_0_release_notes.md @@ -108,7 +108,7 @@ In Rails 4.0, several features have been extracted into gems. You can simply add * Mass assignment protection in Active Record models ([GitHub](https://github.com/rails/protected_attributes), [Pull Request](https://github.com/rails/rails/pull/7251)) * ActiveRecord::SessionStore ([GitHub](https://github.com/rails/activerecord-session_store), [Pull Request](https://github.com/rails/rails/pull/7436)) * Active Record Observers ([GitHub](https://github.com/rails/rails-observers), [Commit](https://github.com/rails/rails/commit/39e85b3b90c58449164673909a6f1893cba290b2)) -* Active Resource ([GitHub](https://github.com/rails/activeresource), [Pull Request](https://github.com/rails/rails/pull/572), [Blog](http://yetimedia.tumblr.com/post/35233051627/activeresource-is-dead-long-live-activeresource)) +* Active Resource ([GitHub](https://github.com/rails/activeresource), [Pull Request](https://github.com/rails/rails/pull/572), [Blog](http://yetimedia-blog-blog.tumblr.com/post/35233051627/activeresource-is-dead-long-live-activeresource)) * Action Caching ([GitHub](https://github.com/rails/actionpack-action_caching), [Pull Request](https://github.com/rails/rails/pull/7833)) * Page Caching ([GitHub](https://github.com/rails/actionpack-page_caching), [Pull Request](https://github.com/rails/rails/pull/7833)) * Sprockets ([GitHub](https://github.com/rails/sprockets-rails)) diff --git a/guides/source/4_2_release_notes.md b/guides/source/4_2_release_notes.md index 8a59007420..73e6c2c05b 100644 --- a/guides/source/4_2_release_notes.md +++ b/guides/source/4_2_release_notes.md @@ -405,7 +405,7 @@ Please refer to the [Changelog][railties] for detailed changes. url: http://localhost:3001 namespace: my_app_development - # config/production.rb + # config/environments/production.rb Rails.application.configure do config.middleware.use ExceptionNotifier, config_for(:exception_notification) end diff --git a/guides/source/5_0_release_notes.md b/guides/source/5_0_release_notes.md new file mode 100644 index 0000000000..638547565c --- /dev/null +++ b/guides/source/5_0_release_notes.md @@ -0,0 +1,938 @@ +**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** + +Ruby on Rails 5.0 Release Notes +=============================== + +Highlights in Rails 5.0: + +* Action Cable +* Rails API +* Active Record Attributes API +* Test Runner +* Exclusive use of `rails` CLI over Rake +* Sprockets 3 +* Turbolinks 5 +* Ruby 2.2.2+ required + +These release notes cover only the major changes. To learn about various bug +fixes and changes, please refer to the change logs or check out the [list of +commits](https://github.com/rails/rails/commits/5-0-stable) in the main Rails +repository on GitHub. + +-------------------------------------------------------------------------------- + +Upgrading to Rails 5.0 +---------------------- + +If you're upgrading an existing application, it's a great idea to have good test +coverage before going in. You should also first upgrade to Rails 4.2 in case you +haven't and make sure your application still runs as expected before attempting +an update to Rails 5.0. A list of things to watch out for when upgrading is +available in the +[Upgrading Ruby on Rails](upgrading_ruby_on_rails.html#upgrading-from-rails-4-2-to-rails-5-0) +guide. + + +Major Features +-------------- + +### Action Cable +[Pull Request](https://github.com/rails/rails/pull/22586) + +ToDo... + +### Rails API +[Pull Request](https://github.com/rails/rails/pull/19832) + +ToDo... + +### Active Record attributes API + +Defines an attribute with a type on a model. It will override the type of existing attributes if needed. +This allows control over how values are converted to and from SQL when assigned to a model. +It also changes the behavior of values passed to ActiveRecord::Base.where, which lets use our domain objects across much of Active Record, +without having to rely on implementation details or monkey patching. + +Some things that you can achieve with this: +* The type detected by Active Record can be overridden. +* A default can also be provided. +* Attributes do not need to be backed by a database column. + +```ruby + +# db/schema.rb +create_table :store_listings, force: true do |t| + t.decimal :price_in_cents + t.string :my_string, default: "original default" +end + +# app/models/store_listing.rb +class StoreListing < ActiveRecord::Base +end + +store_listing = StoreListing.new(price_in_cents: '10.1') + +# before +store_listing.price_in_cents # => BigDecimal.new(10.1) +StoreListing.new.my_string # => "original default" + +class StoreListing < ActiveRecord::Base + attribute :price_in_cents, :integer # custom type + attribute :my_string, :string, default: "new default" # default value + attribute :my_default_proc, :datetime, default: -> { Time.now } # default value + attribute :field_without_db_column, :integer, array: true +end + +# after +store_listing.price_in_cents # => 10 +StoreListing.new.my_string # => "new default" +StoreListing.new.my_default_proc # => 2015-05-30 11:04:48 -0600 +model = StoreListing.new(field_without_db_column: ["1", "2", "3"]) +model.attributes #=> {field_without_db_column: [1, 2, 3]} +``` + +**Creating Custom Types:** + +You can define your own custom types, as long as they respond +to the methods defined on the value type. The method +deserialize+ or ++cast+ will be called on your type object, with raw input from the +database or from your controllers. This is useful, for example, when doing custom conversion, +like Money data. + +**Querying:** + +When `ActiveRecord::Base.where` is called, it will +use the type defined by the model class to convert the value to SQL, +calling +serialize+ on your type object. + +This gives the objects ability to specify, how to convert values when performing SQL queries. + +**Dirty Tracking:** + +The type of an attribute is given the opportunity to change how dirty +tracking is performed. + +See its +[documentation](http://api.rubyonrails.org/classes/ActiveRecord/Attributes/ClassMethods.html) +for a detailed write up. + + +### Test Runner +[Pull Request](https://github.com/rails/rails/pull/19216) + +ToDo... + + +Railties +-------- + +Please refer to the [Changelog][railties] for detailed changes. + +### Removals + +* Removed debugger support, use byebug instead. `debugger` is not supported by + Ruby + 2.2. ([commit](https://github.com/rails/rails/commit/93559da4826546d07014f8cfa399b64b4a143127)) + +* Removed deprecated `test:all` and `test:all:db` tasks. + ([commit](https://github.com/rails/rails/commit/f663132eef0e5d96bf2a58cec9f7c856db20be7c)) + +* Removed deprecated `Rails::Rack::LogTailer`. + ([commit](https://github.com/rails/rails/commit/c564dcb75c191ab3d21cc6f920998b0d6fbca623)) + +* Removed deprecated `RAILS_CACHE` constant. + ([commit](https://github.com/rails/rails/commit/b7f856ce488ef8f6bf4c12bb549f462cb7671c08)) + +* Removed deprecated `serve_static_assets` configuration. + ([commit](https://github.com/rails/rails/commit/463b5d7581ee16bfaddf34ca349b7d1b5878097c)) + +* Removed the documentation tasks `doc:app`, `doc:rails`, and `doc:guides`. + ([commit](https://github.com/rails/rails/commit/cd7cc5254b090ccbb84dcee4408a5acede25ef2a)) + +* Removed `Rack::ContentLength` middleware from the default + stack. ([Commit](https://github.com/rails/rails/commit/56903585a099ab67a7acfaaef0a02db8fe80c450)) + +### Deprecations + +* Deprecated `config.static_cache_control` in favor of + `config.public_file_server.headers`. + ([Pull Request](https://github.com/rails/rails/pull/22173)) + +* Deprecated `config.serve_static_files` in favor of `config.public_file_server.enabled`. + ([Pull Request](https://github.com/rails/rails/pull/22173)) + +* Deprecated the tasks in the `rails` task namespace in favor of the `app` namespace. + (e.g. `rails:update` and `rails:template` tasks is renamed to `app:update` and `app:template`.) + ([Pull Request](https://github.com/rails/rails/pull/23439)) + +### Notable changes + +* Added Rails test runner `bin/rails test`. + ([Pull Request](https://github.com/rails/rails/pull/19216)) + +* Newly generated applications and plugins get a `README.md` in Markdown. + ([commit](https://github.com/rails/rails/commit/89a12c931b1f00b90e74afffcdc2fc21f14ca663), + [Pull Request](https://github.com/rails/rails/pull/22068)) + +* Added `bin/rails restart` task to restart your Rails app by touching `tmp/restart.txt`. + ([Pull Request](https://github.com/rails/rails/pull/18965)) + +* Added `bin/rails initializers` task to print out all defined initializers in + the order they are invoked by Rails. + ([Pull Request](https://github.com/rails/rails/pull/19323)) + +* Added `bin/rails dev:cache` to enable or disable caching in development mode. + ([Pull Request](https://github.com/rails/rails/pull/20961)) + +* Added `bin/update` script to update the development environment automatically. + ([Pull Request](https://github.com/rails/rails/pull/20972)) + +* Proxy Rake tasks through `bin/rails`. + ([Pull Request](https://github.com/rails/rails/pull/22457), + [Pull Request](https://github.com/rails/rails/pull/22288)) + +* New applications are generated with the evented file system monitor enabled + on Linux and Mac OS X. The feature can be opted out by passing + `--skip-listen` to the generator. + ([commit](https://github.com/rails/rails/commit/de6ad5665d2679944a9ee9407826ba88395a1003), + [commit](https://github.com/rails/rails/commit/94dbc48887bf39c241ee2ce1741ee680d773f202)) + +* Generate applications with an option to log to STDOUT in production + using the environment variable `RAILS_LOG_TO_STDOUT`. + ([Pull Request](https://github.com/rails/rails/pull/23734)) + +* Enable HSTS with IncludeSudomains header for new applications. + ([Pull Request](https://github.com/rails/rails/pull/23852)) + +* The application generator writes a new file `config/spring.rb`, which tells + Spring to watch additional common files. + ([commit](https://github.com/rails/rails/commit/b04d07337fd7bc17e88500e9d6bcd361885a45f8)) + + +Action Pack +----------- + +Please refer to the [Changelog][action-pack] for detailed changes. + +### Removals + +* Removed `ActionDispatch::Request::Utils.deep_munge`. + ([commit](https://github.com/rails/rails/commit/52cf1a71b393486435fab4386a8663b146608996)) + +* Removed `ActionController::HideActions`. + ([Pull Request](https://github.com/rails/rails/pull/18371)) + +* Removed `respond_to` and `respond_with` placeholder methods, this functionality + has been extracted to the + [responders](https://github.com/plataformatec/responders) gem. + ([commit](https://github.com/rails/rails/commit/afd5e9a7ff0072e482b0b0e8e238d21b070b6280)) + +* Removed deprecated assertion files. + ([commit](https://github.com/rails/rails/commit/92e27d30d8112962ee068f7b14aa7b10daf0c976)) + +* Removed deprecated usage of string keys in URL helpers. + ([commit](https://github.com/rails/rails/commit/34e380764edede47f7ebe0c7671d6f9c9dc7e809)) + +* Removed deprecated `only_path` option on `*_path` helpers. + ([commit](https://github.com/rails/rails/commit/e4e1fd7ade47771067177254cb133564a3422b8a)) + +* Removed deprecated `NamedRouteCollection#helpers`. + ([commit](https://github.com/rails/rails/commit/2cc91c37bc2e32b7a04b2d782fb8f4a69a14503f)) + +* Removed deprecated support to define routes with `:to` option that doesn't contain `#`. + ([commit](https://github.com/rails/rails/commit/1f3b0a8609c00278b9a10076040ac9c90a9cc4a6)) + +* Removed deprecated `ActionDispatch::Response#to_ary`. + ([commit](https://github.com/rails/rails/commit/4b19d5b7bcdf4f11bd1e2e9ed2149a958e338c01)) + +* Removed deprecated `ActionDispatch::Request#deep_munge`. + ([commit](https://github.com/rails/rails/commit/7676659633057dacd97b8da66e0d9119809b343e)) + +* Removed deprecated + `ActionDispatch::Http::Parameters#symbolized_path_parameters`. + ([commit](https://github.com/rails/rails/commit/7fe7973cd8bd119b724d72c5f617cf94c18edf9e)) + +* Removed deprecated option `use_route` in controller tests. + ([commit](https://github.com/rails/rails/commit/e4cfd353a47369dd32198b0e67b8cbb2f9a1c548)) + +* Removed `assigns` and `assert_template`. Both methods have been extracted + into the + [rails-controller-testing](https://github.com/rails/rails-controller-testing) + gem. + ([Pull Request](https://github.com/rails/rails/pull/20138)) + +### Deprecations + +* Deprecated all `*_filter` callbacks in favor of `*_action` callbacks. + ([Pull Request](https://github.com/rails/rails/pull/18410)) + +* Deprecated `*_via_redirect` integration test methods. Use `follow_redirect!` + manually after the request call for the same behavior. + ([Pull Request](https://github.com/rails/rails/pull/18693)) + +* Deprecated `AbstractController#skip_action_callback` in favor of individual + skip_callback methods. + ([Pull Request](https://github.com/rails/rails/pull/19060)) + +* Deprecated `:nothing` option for `render` method. + ([Pull Request](https://github.com/rails/rails/pull/20336)) + +* Deprecated passing first parameter as `Hash` and default status code for + `head` method. + ([Pull Request](https://github.com/rails/rails/pull/20407)) + +* Deprecated using strings or symbols for middleware class names. Use class + names instead. + ([commit](https://github.com/rails/rails/commit/83b767ce)) + +* Deprecated accessing mime types via constants (eg. `Mime::HTML`). Use the + subscript operator with a symbol instead (eg. `Mime[:html]`). + ([Pull Request](https://github.com/rails/rails/pull/21869)) + +* Deprecated `redirect_to :back` in favor of `redirect_back`, which accepts a + required `fallback_location` argument, thus eliminating the possibility of a + `RedirectBackError`. + ([Pull Request](https://github.com/rails/rails/pull/22506)) + +* `ActionDispatch::IntegrationTest` and `ActionController::TestCase` deprecate positional arguments in favor of + keyword arguments. ([Pull Request](https://github.com/rails/rails/pull/18323)) + +* Deprecated `:controller` and `:action` path parameters. + ([Pull Request](https://github.com/rails/rails/pull/23980)) + +### Notable changes + +* Added `ActionController::Renderer` to render arbitrary templates + outside controller actions. + ([Pull Request](https://github.com/rails/rails/pull/18546)) + +* Migrating to keyword arguments syntax in `ActionController::TestCase` and + `ActionDispatch::Integration` HTTP request methods. + ([Pull Request](https://github.com/rails/rails/pull/18323)) + +* Added `http_cache_forever` to Action Controller, so we can cache a response + that never gets expired. + ([Pull Request](https://github.com/rails/rails/pull/18394)) + +* Provide friendlier access to request variants. + ([Pull Request](https://github.com/rails/rails/pull/18939)) + +* For actions with no corresponding templates, render `head :no_content` + instead of raising an error. + ([Pull Request](https://github.com/rails/rails/pull/19377)) + +* Added the ability to override default form builder for a controller. + ([Pull Request](https://github.com/rails/rails/pull/19736)) + +* Added support for API only apps. + `ActionController::API` is added as a replacement of + `ActionController::Base` for this kind of applications. + ([Pull Request](https://github.com/rails/rails/pull/19832)) + +* Make `ActionController::Parameters` no longer inherits from + `HashWithIndifferentAccess`. + ([Pull Request](https://github.com/rails/rails/pull/20868)) + +* Make it easier to opt in to `config.force_ssl` and `config.ssl_options` by + making them less dangerous to try and easier to disable. + ([Pull Request](https://github.com/rails/rails/pull/21520)) + +* Added the ability of returning arbitrary headers to `ActionDispatch::Static`. + ([Pull Request](https://github.com/rails/rails/pull/19135)) + +* Changed the `protect_from_forgery` prepend default to `false`. + ([commit](https://github.com/rails/rails/commit/39794037817703575c35a75f1961b01b83791191)) + +* `ActionController::TestCase` will be moved to its own gem in Rails 5.1. Use + `ActionDispatch::IntegrationTest` instead. + ([commit](https://github.com/rails/rails/commit/4414c5d1795e815b102571425974a8b1d46d932d)) + +* Rails will only generate "weak", instead of strong ETags. + ([Pull Request](https://github.com/rails/rails/pull/17573)) + +* Controller actions without an explicit `render` call and with no + corresponding templates will render `head :no_content` implicitly + instead of raising an error. + (Pull Request [1](https://github.com/rails/rails/pull/19377), + [2](https://github.com/rails/rails/pull/23827)) + +* Added an option for per-form CSRF tokens. + ([Pull Request](https://github.com/rails/rails/pull/22275)) + +* Added request encoding and response parsing to integration tests. + ([Pull Request](https://github.com/rails/rails/pull/21671)) + +* Update default rendering policies when the controller action did + not explicitly indicate a response. + ([Pull Request](https://github.com/rails/rails/pull/23827)) + + +* Add `ActionController#helpers` to get access to the view context + at the controller level. + ([Pull Request](https://github.com/rails/rails/pull/24866)) + +Action View +------------- + +Please refer to the [Changelog][action-view] for detailed changes. + +### Removals + +* Removed deprecated `AbstractController::Base::parent_prefixes`. + ([commit](https://github.com/rails/rails/commit/34bcbcf35701ca44be559ff391535c0dd865c333)) + +* Removed `ActionView::Helpers::RecordTagHelper`, this functionality + has been extracted to the + [record_tag_helper](https://github.com/rails/record_tag_helper) gem. + ([Pull Request](https://github.com/rails/rails/pull/18411)) + +* Removed `:rescue_format` option for `translate` helper since it's no longer + supported by I18n. + ([Pull Request](https://github.com/rails/rails/pull/20019)) + +### Deprecations + +* Deprecated `datetime_field` and `datetime_field_tag` helpers. + Datetime input type was removed from HTML specification. + One can use `datetime_local_field` and `datetime_local_field_tag` instead. + ([Pull Request](https://github.com/rails/rails/pull/24385)) + +### Notable Changes + +* Changed the default template handler from `ERB` to `Raw`. + ([commit](https://github.com/rails/rails/commit/4be859f0fdf7b3059a28d03c279f03f5938efc80)) + +* Collection rendering can cache and fetches multiple partials at once. + ([Pull Request](https://github.com/rails/rails/pull/18948), + [commit](https://github.com/rails/rails/commit/e93f0f0f133717f9b06b1eaefd3442bd0ff43985)) + +* Added wildcard matching to explicit dependencies. + ([Pull Request](https://github.com/rails/rails/pull/20904)) + +* Make `disable_with` the default behavior for submit tags. Disables the + button on submit to prevent double submits. + ([Pull Request](https://github.com/rails/rails/pull/21135)) + +Action Mailer +------------- + +Please refer to the [Changelog][action-mailer] for detailed changes. + +### Removals + +* Removed deprecated `*_path` helpers in email views. + ([commit](https://github.com/rails/rails/commit/d282125a18c1697a9b5bb775628a2db239142ac7)) + +* Removed deprecated `deliver` and `deliver!` methods. + ([commit](https://github.com/rails/rails/commit/755dcd0691f74079c24196135f89b917062b0715)) + +### Notable changes + +* Template lookup now respects default locale and I18n fallbacks. + ([commit](https://github.com/rails/rails/commit/ecb1981b)) + +* Added `_mailer` suffix to mailers created via generator, following the same + naming convention used in controllers and jobs. + ([Pull Request](https://github.com/rails/rails/pull/18074)) + +* Added `assert_enqueued_emails` and `assert_no_enqueued_emails`. + ([Pull Request](https://github.com/rails/rails/pull/18403)) + +* Added `config.action_mailer.deliver_later_queue_name` configuration to set + the mailer queue name. + ([Pull Request](https://github.com/rails/rails/pull/18587)) + +* Added support for fragment caching in Action Mailer views. + Added new config option `config.action_mailer.perform_caching` to determine + whether your templates should perform caching or not. + ([Pull Request](https://github.com/rails/rails/pull/22825)) + + +Active Record +------------- + +Please refer to the [Changelog][active-record] for detailed changes. + +### Removals + +* Removed deprecated behavior allowing nested arrays to be passed as query + values. ([Pull Request](https://github.com/rails/rails/pull/17919)) + +* Removed deprecated `ActiveRecord::Tasks::DatabaseTasks#load_schema`. This + method was replaced by `ActiveRecord::Tasks::DatabaseTasks#load_schema_for`. + ([commit](https://github.com/rails/rails/commit/ad783136d747f73329350b9bb5a5e17c8f8800da)) + +* Removed deprecated `serialized_attributes`. + ([commit](https://github.com/rails/rails/commit/82043ab53cb186d59b1b3be06122861758f814b2)) + +* Removed deprecated automatic counter caches on `has_many :through`. + ([commit](https://github.com/rails/rails/commit/87c8ce340c6c83342df988df247e9035393ed7a0)) + +* Removed deprecated `sanitize_sql_hash_for_conditions`. + ([commit](https://github.com/rails/rails/commit/3a59dd212315ebb9bae8338b98af259ac00bbef3)) + +* Removed deprecated `Reflection#source_macro`. + ([commit](https://github.com/rails/rails/commit/ede8c199a85cfbb6457d5630ec1e285e5ec49313)) + +* Removed deprecated `symbolized_base_class` and `symbolized_sti_name`. + ([commit](https://github.com/rails/rails/commit/9013e28e52eba3a6ffcede26f85df48d264b8951)) + +* Removed deprecated `ActiveRecord::Base.disable_implicit_join_references=`. + ([commit](https://github.com/rails/rails/commit/0fbd1fc888ffb8cbe1191193bf86933110693dfc)) + +* Removed deprecated access to connection specification using a string accessor. + ([commit](https://github.com/rails/rails/commit/efdc20f36ccc37afbb2705eb9acca76dd8aabd4f)) + +* Removed deprecated support to preload instance-dependent associations. + ([commit](https://github.com/rails/rails/commit/4ed97979d14c5e92eb212b1a629da0a214084078)) + +* Removed deprecated support for PostgreSQL ranges with exclusive lower bounds. + ([commit](https://github.com/rails/rails/commit/a076256d63f64d194b8f634890527a5ed2651115)) + +* Removed deprecation when modifying a relation with cached Arel. + This raises an `ImmutableRelation` error instead. + ([commit](https://github.com/rails/rails/commit/3ae98181433dda1b5e19910e107494762512a86c)) + +* Removed `ActiveRecord::Serialization::XmlSerializer` from core. This feature + has been extracted into the + [activemodel-serializers-xml](https://github.com/rails/activemodel-serializers-xml) + gem. ([Pull Request](https://github.com/rails/rails/pull/21161)) + +* Removed support for the legacy `mysql` database adapter from core. It will + live on in a separate gem for now, but most users should just use `mysql2`. + +* Removed support for the `protected_attributes` gem. + ([commit](https://github.com/rails/rails/commit/f4fbc0301021f13ae05c8e941c8efc4ae351fdf9)) + +* Removed support for PostgreSQL versions below 9.1. + ([Pull Request](https://github.com/rails/rails/pull/23434)) + +### Deprecations + +* Deprecated passing a class as a value in a query. Users should pass strings + instead. ([Pull Request](https://github.com/rails/rails/pull/17916)) + +* Deprecated returning `false` as a way to halt Active Record callback + chains. The recommended way is to + `throw(:abort)`. ([Pull Request](https://github.com/rails/rails/pull/17227)) + +* Deprecated `ActiveRecord::Base.errors_in_transactional_callbacks=`. + ([commit](https://github.com/rails/rails/commit/07d3d402341e81ada0214f2cb2be1da69eadfe72)) + +* Deprecated `Relation#uniq` use `Relation#distinct` instead. + ([commit](https://github.com/rails/rails/commit/adfab2dcf4003ca564d78d4425566dd2d9cd8b4f)) + +* Deprecated the PostgreSQL `:point` type in favor of a new one which will return + `Point` objects instead of an `Array` + ([Pull Request](https://github.com/rails/rails/pull/20448)) + +* Deprecated force association reload by passing a truthy argument to + association method. + ([Pull Request](https://github.com/rails/rails/pull/20888)) + +* Deprecated the keys for association `restrict_dependent_destroy` errors in favor + of new key names. + ([Pull Request](https://github.com/rails/rails/pull/20668)) + +* Synchronize behavior of `#tables`. + ([Pull Request](https://github.com/rails/rails/pull/21601)) + +* Deprecated `SchemaCache#tables`, `SchemaCache#table_exists?` and + `SchemaCache#clear_table_cache!` in favor of their new data source + counterparts. + ([Pull Request](https://github.com/rails/rails/pull/21715)) + +* Deprecated `connection.tables` on the SQLite3 and MySQL adapters. + ([Pull Request](https://github.com/rails/rails/pull/21601)) + +* Deprecated passing arguments to `#tables` - the `#tables` method of some + adapters (mysql2, sqlite3) would return both tables and views while others + (postgresql) just return tables. To make their behavior consistent, + `#tables` will return only tables in the future. + ([Pull Request](https://github.com/rails/rails/pull/21601)) + +* Deprecated `table_exists?` - The `#table_exists?` method would check both + tables and views. To make their behavior consistent with `#tables`, + `#table_exists?` will check only tables in the future. + ([Pull Request](https://github.com/rails/rails/pull/21601)) + +* Deprecate sending the `offset` argument to `find_nth`. Please use the + `offset` method on relation instead. + ([Pull Request](https://github.com/rails/rails/pull/22053)) + +* Deprecated `{insert|update|delete}_sql` in `DatabaseStatements`. + Use the `{insert|update|delete}` public methods instead. + ([Pull Request](https://github.com/rails/rails/pull/23086)) + +* Deprecated `use_transactional_fixtures` in favor of + `use_transactional_tests` for more clarity. + ([Pull Request](https://github.com/rails/rails/pull/19282)) + +### Notable changes + +* Added a `foreign_key` option to `references` while creating the table. + ([commit](https://github.com/rails/rails/commit/99a6f9e60ea55924b44f894a16f8de0162cf2702)) + +* New attributes + API. ([commit](https://github.com/rails/rails/commit/8c752c7ac739d5a86d4136ab1e9d0142c4041e58)) + +* Added `:_prefix`/`:_suffix` option to `enum` definition. + ([Pull Request](https://github.com/rails/rails/pull/19813), + [Pull Request](https://github.com/rails/rails/pull/20999)) + +* Added `#cache_key` to `ActiveRecord::Relation`. + ([Pull Request](https://github.com/rails/rails/pull/20884)) + +* Changed the default `null` value for `timestamps` to `false`. + ([commit](https://github.com/rails/rails/commit/a939506f297b667291480f26fa32a373a18ae06a)) + +* Added `ActiveRecord::SecureToken` in order to encapsulate generation of + unique tokens for attributes in a model using `SecureRandom`. + ([Pull Request](https://github.com/rails/rails/pull/18217)) + +* Added `:if_exists` option for `drop_table`. + ([Pull Request](https://github.com/rails/rails/pull/18597)) + +* Added `ActiveRecord::Base#accessed_fields`, which can be used to quickly + discover which fields were read from a model when you are looking to only + select the data you need from the database. + ([commit](https://github.com/rails/rails/commit/be9b68038e83a617eb38c26147659162e4ac3d2c)) + +* Added the `#or` method on `ActiveRecord::Relation`, allowing use of the OR + operator to combine WHERE or HAVING clauses. + ([commit](https://github.com/rails/rails/commit/b0b37942d729b6bdcd2e3178eda7fa1de203b3d0)) + +* Added `:time` option added for `#touch`. + ([Pull Request](https://github.com/rails/rails/pull/18956)) + +* Added `ActiveRecord::Base.suppress` to prevent the receiver from being saved + during the given block. + ([Pull Request](https://github.com/rails/rails/pull/18910)) + +* `belongs_to` will now trigger a validation error by default if the + association is not present. You can turn this off on a per-association basis + with `optional: true`. Also deprecate `required` option in favor of `optional` + for `belongs_to`. + ([Pull Request](https://github.com/rails/rails/pull/18937)) + +* Added `config.active_record.dump_schemas` to configure the behavior of + `db:structure:dump`. + ([Pull Request](https://github.com/rails/rails/pull/19347)) + +* Added `config.active_record.warn_on_records_fetched_greater_than` option. + ([Pull Request](https://github.com/rails/rails/pull/18846)) + +* Added a native JSON data type support in MySQL. + ([Pull Request](https://github.com/rails/rails/pull/21110)) + +* Added support for dropping indexes concurrently in PostgreSQL. + ([Pull Request](https://github.com/rails/rails/pull/21317)) + +* Added `#views` and `#view_exists?` methods on connection adapters. + ([Pull Request](https://github.com/rails/rails/pull/21609)) + +* Added `ActiveRecord::Base.ignored_columns` to make some columns + invisible from Active Record. + ([Pull Request](https://github.com/rails/rails/pull/21720)) + +* Added `connection.data_sources` and `connection.data_source_exists?`. + These methods determine what relations can be used to back Active Record + models (usually tables and views). + ([Pull Request](https://github.com/rails/rails/pull/21715)) + +* Allow fixtures files to set the model class in the YAML file itself. + ([Pull Request](https://github.com/rails/rails/pull/20574)) + +* Added ability to default to `uuid` as primary key when generating database + migrations. ([Pull Request](https://github.com/rails/rails/pull/21762)) + +* Added `ActiveRecord::Relation#left_joins` and + `ActiveRecord::Relation#left_outer_joins`. + ([Pull Request](https://github.com/rails/rails/pull/12071)) + +* Added `after_{create,update,delete}_commit` callbacks. + ([Pull Request](https://github.com/rails/rails/pull/22516)) + +* Version the API presented to migration classes, so we can change parameter + defaults without breaking existing migrations, or forcing them to be + rewritten through a deprecation cycle. + ([Pull Request](https://github.com/rails/rails/pull/21538)) + +* `ApplicationRecord` is a new superclass for all app models, analogous to app + controllers subclassing `ApplicationController` instead of + `ActionController::Base`. This gives apps a single spot to configure app-wide + model behavior. + ([Pull Request](https://github.com/rails/rails/pull/22567)) + +* Added ActiveRecord `#second_to_last` and `#third_to_last` methods. + ([Pull Request](https://github.com/rails/rails/pull/23583)) + +* Added ability to annotate database objects (tables, columns, indexes) + with comments stored in database metadata for PostgreSQL & MySQL. + ([Pull Request](https://github.com/rails/rails/pull/22911)) + +* Added prepared statements support to `mysql2` adapter, for mysql2 0.4.4+, + Previously this was only supported on the deprecated `mysql` legacy adapter. + To enable, set `prepared_statements: true` in config/database.yml. + ([Pull Request](https://github.com/rails/rails/pull/23461)) + +Active Model +------------ + +Please refer to the [Changelog][active-model] for detailed changes. + +### Removals + +* Removed deprecated `ActiveModel::Dirty#reset_#{attribute}` and + `ActiveModel::Dirty#reset_changes`. + ([Pull Request](https://github.com/rails/rails/commit/37175a24bd508e2983247ec5d011d57df836c743)) + +* Removed XML serialization. This feature has been extracted into the + [activemodel-serializers-xml](https://github.com/rails/activemodel-serializers-xml) gem. + ([Pull Request](https://github.com/rails/rails/pull/21161)) + +### Deprecations + +* Deprecated returning `false` as a way to halt Active Model and + `ActiveModel::Validations` callback chains. The recommended way is to + `throw(:abort)`. ([Pull Request](https://github.com/rails/rails/pull/17227)) + +* Deprecated `ActiveModel::Errors#get`, `ActiveModel::Errors#set` and + `ActiveModel::Errors#[]=` methods that have inconsistent behavior. + ([Pull Request](https://github.com/rails/rails/pull/18634)) + +* Deprecated the `:tokenizer` option for `validates_length_of`, in favor of + plain Ruby. + ([Pull Request](https://github.com/rails/rails/pull/19585)) + +* Deprecated `ActiveModel::Errors#add_on_empty` and `ActiveModel::Errors#add_on_blank` + with no replacement. + ([Pull Request](https://github.com/rails/rails/pull/18996)) + +### Notable changes + +* Added `ActiveModel::Errors#details` to determine what validator has failed. + ([Pull Request](https://github.com/rails/rails/pull/18322)) + +* Extracted `ActiveRecord::AttributeAssignment` to `ActiveModel::AttributeAssignment` + allowing to use it for any object as an includable module. + ([Pull Request](https://github.com/rails/rails/pull/10776)) + +* Added `ActiveModel::Dirty#[attr_name]_previously_changed?` and + `ActiveModel::Dirty#[attr_name]_previous_change` to improve access + to recorded changes after the model has been saved. + ([Pull Request](https://github.com/rails/rails/pull/19847)) + +* Validate multiple contexts on `valid?` and `invalid?` at once. + ([Pull Request](https://github.com/rails/rails/pull/21069)) + + +Active Job +----------- + +Please refer to the [Changelog][active-job] for detailed changes. + +### Notable changes + +* `ActiveJob::Base.deserialize` delegates to the job class. This allows jobs + to attach arbitrary metadata when they get serialized and read it back when + they get performed. + ([Pull Request](https://github.com/rails/rails/pull/18260)) + +* Add ability to configure the queue adapter on a per job basis without + affecting each other. + ([Pull Request](https://github.com/rails/rails/pull/16992)) + +* A generated job now inherits from `app/jobs/application_job.rb` by default. + ([Pull Request](https://github.com/rails/rails/pull/19034)) + +* Allow `DelayedJob`, `Sidekiq`, `qu`, `que`, and `queue_classic` to report + the job id back to `ActiveJob::Base` as `provider_job_id`. + ([Pull Request](https://github.com/rails/rails/pull/20064), + [Pull Request](https://github.com/rails/rails/pull/20056), + [commit](https://github.com/rails/rails/commit/68e3279163d06e6b04e043f91c9470e9259bbbe0)) + +* Implement a simple `AsyncJob` processor and associated `AsyncAdapter` that + queue jobs to a `concurrent-ruby` thread pool. + ([Pull Request](https://github.com/rails/rails/pull/21257)) + +* Change the default adapter from inline to async. It's a better default as + tests will then not mistakenly come to rely on behavior happening + synchronously. + ([commit](https://github.com/rails/rails/commit/625baa69d14881ac49ba2e5c7d9cac4b222d7022)) + +Active Support +-------------- + +Please refer to the [Changelog][active-support] for detailed changes. + +### Removals + +* Removed deprecated `ActiveSupport::JSON::Encoding::CircularReferenceError`. + ([commit](https://github.com/rails/rails/commit/d6e06ea8275cdc3f126f926ed9b5349fde374b10)) + +* Removed deprecated methods `ActiveSupport::JSON::Encoding.encode_big_decimal_as_string=` + and `ActiveSupport::JSON::Encoding.encode_big_decimal_as_string`. + ([commit](https://github.com/rails/rails/commit/c8019c0611791b2716c6bed48ef8dcb177b7869c)) + +* Removed deprecated `ActiveSupport::SafeBuffer#prepend`. + ([commit](https://github.com/rails/rails/commit/e1c8b9f688c56aaedac9466a4343df955b4a67ec)) + +* Removed deprecated methods from `Kernel`. `silence_stderr`, `silence_stream`, + `capture` and `quietly`. + ([commit](https://github.com/rails/rails/commit/481e49c64f790e46f4aff3ed539ed227d2eb46cb)) + +* Removed deprecated `active_support/core_ext/big_decimal/yaml_conversions` + file. + ([commit](https://github.com/rails/rails/commit/98ea19925d6db642731741c3b91bd085fac92241)) + +* Removed deprecated methods `ActiveSupport::Cache::Store.instrument` and + `ActiveSupport::Cache::Store.instrument=`. + ([commit](https://github.com/rails/rails/commit/a3ce6ca30ed0e77496c63781af596b149687b6d7)) + +* Removed deprecated `Class#superclass_delegating_accessor`. + Use `Class#class_attribute` instead. + ([Pull Request](https://github.com/rails/rails/pull/16938)) + +* Removed deprecated `ThreadSafe::Cache`. Use `Concurrent::Map` instead. + ([Pull Request](https://github.com/rails/rails/pull/21679)) + +### Deprecations + +* Deprecated `MissingSourceFile` in favor of `LoadError`. + ([commit](https://github.com/rails/rails/commit/734d97d2)) + +* Deprecated `alias_method_chain` in favour of `Module#prepend` introduced in + Ruby 2.0. + ([Pull Request](https://github.com/rails/rails/pull/19434)) + +* Deprecated `ActiveSupport::Concurrency::Latch` in favor of + `Concurrent::CountDownLatch` from concurrent-ruby. + ([Pull Request](https://github.com/rails/rails/pull/20866)) + +* Deprecated `:prefix` option of `number_to_human_size` with no replacement. + ([Pull Request](https://github.com/rails/rails/pull/21191)) + +* Deprecated `Module#qualified_const_` in favour of the builtin + `Module#const_` methods. + ([Pull Request](https://github.com/rails/rails/pull/17845)) + +* Deprecated passing string to define callback. + ([Pull Request](https://github.com/rails/rails/pull/22598)) + +* Deprecated `ActiveSupport::Cache::Store#namespaced_key`, + `ActiveSupport::Cache::MemCachedStore#escape_key`, and + `ActiveSupport::Cache::FileStore#key_file_path`. + Use `normalize_key` instead. + + Deprecated `ActiveSupport::Cache::LocaleCache#set_cache_value` in favor of `write_cache_value`. + ([Pull Request](https://github.com/rails/rails/pull/22215)) + +* Deprecated passing arguments to `assert_nothing_raised`. + ([Pull Request](https://github.com/rails/rails/pull/23789)) + +* Deprecated `Module.local_constants` in favor of `Module.constants(false)`. + ([Pull Request](https://github.com/rails/rails/pull/23936)) + + +### Notable changes + +* Added `#verified` and `#valid_message?` methods to + `ActiveSupport::MessageVerifier`. + ([Pull Request](https://github.com/rails/rails/pull/17727)) + +* Changed the way in which callback chains can be halted. The preferred method + to halt a callback chain from now on is to explicitly `throw(:abort)`. + ([Pull Request](https://github.com/rails/rails/pull/17227)) + +* New config option + `config.active_support.halt_callback_chains_on_return_false` to specify + whether ActiveRecord, ActiveModel and ActiveModel::Validations callback + chains can be halted by returning `false` in a 'before' callback. + ([Pull Request](https://github.com/rails/rails/pull/17227)) + +* Changed the default test order from `:sorted` to `:random`. + ([commit](https://github.com/rails/rails/commit/5f777e4b5ee2e3e8e6fd0e2a208ec2a4d25a960d)) + +* Added `#on_weekend?`, `#on_weekday?`, `#next_weekday`, `#prev_weekday` methods to `Date`, + `Time`, and `DateTime`. + ([Pull Request](https://github.com/rails/rails/pull/18335)) + +* Added `same_time` option to `#next_week` and `#prev_week` for `Date`, `Time`, + and `DateTime`. + ([Pull Request](https://github.com/rails/rails/pull/18335)) + +* Added `#prev_day` and `#next_day` counterparts to `#yesterday` and + `#tomorrow` for `Date`, `Time`, and `DateTime`. + ([Pull Request](httpshttps://github.com/rails/rails/pull/18335)) + +* Added `SecureRandom.base58` for generation of random base58 strings. + ([commit](https://github.com/rails/rails/commit/b1093977110f18ae0cafe56c3d99fc22a7d54d1b)) + +* Added `file_fixture` to `ActiveSupport::TestCase`. + It provides a simple mechanism to access sample files in your test cases. + ([Pull Request](https://github.com/rails/rails/pull/18658)) + +* Added `#without` on `Enumerable` and `Array` to return a copy of an + enumerable without the specified elements. + ([Pull Request](https://github.com/rails/rails/pull/19157)) + +* Added `ActiveSupport::ArrayInquirer` and `Array#inquiry`. + ([Pull Request](https://github.com/rails/rails/pull/18939)) + +* Added `ActiveSupport::TimeZone#strptime` to allow parsing times as if + from a given timezone. + ([commit](https://github.com/rails/rails/commit/a5e507fa0b8180c3d97458a9b86c195e9857d8f6)) + +* Added `Integer#positive?` and `Integer#negative?` query methods + in the vein of `Integer#zero?`. + ([commit](https://github.com/rails/rails/commit/e54277a45da3c86fecdfa930663d7692fd083daa)) + +* Added a bang version to `ActiveSupport::OrderedOptions` get methods which will raise + an `KeyError` if the value is `.blank?`. + ([Pull Request](https://github.com/rails/rails/pull/20208)) + +* Added `Time.days_in_year` to return the number of days in the given year, or the + current year if no argument is provided. + ([commit](https://github.com/rails/rails/commit/2f4f4d2cf1e4c5a442459fc250daf66186d110fa)) + +* Added an evented file watcher to asynchronously detect changes in the + application source code, routes, locales, etc. + ([Pull Request](https://github.com/rails/rails/pull/22254)) + +* Added thread_m/cattr_accessor/reader/writer suite of methods for declaring + class and module variables that live per-thread. + ([Pull Request](https://github.com/rails/rails/pull/22630)) + +* Added `Array#second_to_last` and `Array#third_to_last` methods. + ([Pull Request](https://github.com/rails/rails/pull/23583)) + +* Added `#on_weekday?` method to `Date`, `Time`, and `DateTime`. + ([Pull Request](https://github.com/rails/rails/pull/23687)) + +* Publish `ActiveSupport::Executor` and `ActiveSupport::Reloader` APIs to allow + components and libraries to manage, and participate in, the execution of + application code, and the application reloading process. + ([Pull Request](https://github.com/rails/rails/pull/23807)) + +* `ActiveSupport::Duration` now supports ISO8601 formatting and parsing. + ([Pull Request](https://github.com/rails/rails/pull/16917)) + + +Credits +------- + +See the +[full list of contributors to Rails](http://contributors.rubyonrails.org/) for +the many people who spent many hours making Rails, the stable and robust +framework it is. Kudos to all of them. + +[railties]: https://github.com/rails/rails/blob/5-0-stable/railties/CHANGELOG.md +[action-pack]: https://github.com/rails/rails/blob/5-0-stable/actionpack/CHANGELOG.md +[action-view]: https://github.com/rails/rails/blob/5-0-stable/actionview/CHANGELOG.md +[action-mailer]: https://github.com/rails/rails/blob/5-0-stable/actionmailer/CHANGELOG.md +[action-cable]: https://github.com/rails/rails/blob/5-0-stable/actioncable/CHANGELOG.md +[active-record]: https://github.com/rails/rails/blob/5-0-stable/activerecord/CHANGELOG.md +[active-model]: https://github.com/rails/rails/blob/5-0-stable/activemodel/CHANGELOG.md +[active-support]: https://github.com/rails/rails/blob/5-0-stable/activesupport/CHANGELOG.md +[active-job]: https://github.com/rails/rails/blob/5-0-stable/activejob/CHANGELOG.md diff --git a/guides/source/action_cable_overview.md b/guides/source/action_cable_overview.md new file mode 100644 index 0000000000..c7770c16ea --- /dev/null +++ b/guides/source/action_cable_overview.md @@ -0,0 +1,665 @@ +Action Cable Overview +===================== + +In this guide you will learn how Action Cable works and how to use WebSockets to +incorporate real-time features into your Rails application. + +After reading this guide, you will know: + +* How to setup Action Cable +* How to setup channels + +Introduction +------------ + +Action Cable seamlessly integrates +[WebSockets](https://en.wikipedia.org/wiki/WebSocket) with the rest of your +Rails application. It allows for real-time features to be written in Ruby in the +same style and form as the rest of your Rails application, while still being +performant and scalable. It's a full-stack offering that provides both a +client-side JavaScript framework and a server-side Ruby framework. You have +access to your full domain model written with Active Record or your ORM of +choice. + +What is Pub/Sub +--------------- + +[Pub/Sub](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern), or +Publish-Subscribe, refers to a message queue paradigm whereby senders of +information (publishers), send data to an abstract class of recipients +(subscribers), without specifying individual recipients. Action Cable uses this +approach to communicate between the server and many clients. + +## Server-Side Components + +### Connections + +*Connections* form the foundation of the client-server relationship. For every +WebSocket accepted by the server, a connection object is instantiated. This +object becomes the parent of all the *channel subscriptions* that are created +from there on. The connection itself does not deal with any specific application +logic beyond authentication and authorization. The client of a WebSocket +connection is called the connection *consumer*. An individual user will create +one consumer-connection pair per browser tab, window, or device they have open. + +Connections are instances of `ApplicationCable::Connection`. In this class, you +authorize the incoming connection, and proceed to establish it if the user can +be identified. + +#### Connection Setup + +```ruby +# app/channels/application_cable/connection.rb +module ApplicationCable + class Connection < ActionCable::Connection::Base + identified_by :current_user + + def connect + self.current_user = find_verified_user + end + + protected + def find_verified_user + if current_user = User.find_by(id: cookies.signed[:user_id]) + current_user + else + reject_unauthorized_connection + end + end + end +end +``` + +Here `identified_by` is a connection identifier that can be used to find the +specific connection later. Note that anything marked as an identifier will automatically +create a delegate by the same name on any channel instances created off the connection. + +This example relies on the fact that you will already have handled authentication of the user +somewhere else in your application, and that a successful authentication sets a signed +cookie with the user ID. + +The cookie is then automatically sent to the connection instance when a new connection +is attempted, and you use that to set the `current_user`. By identifying the connection +by this same current user, you're also ensuring that you can later retrieve all open +connections by a given user (and potentially disconnect them all if the user is deleted +or deauthorized). + +### Channels + +A *channel* encapsulates a logical unit of work, similar to what a controller does in a +regular MVC setup. By default, Rails creates a parent `ApplicationCable::Channel` class +for encapsulating shared logic between your channels. + +#### Parent Channel Setup + +```ruby +# app/channels/application_cable/channel.rb +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end +``` + +Then you would create your own channel classes. For example, you could have a +`ChatChannel` and an `AppearanceChannel`: + +```ruby +# app/channels/chat_channel.rb +class ChatChannel < ApplicationCable::Channel +end + +# app/channels/appearance_channel.rb +class AppearanceChannel < ApplicationCable::Channel +end +``` + +A consumer could then be subscribed to either or both of these channels. + +#### Subscriptions + +Consumers subscribe to channels, acting as *subscribers*. Their connection is +called a *subscription*. Produced messages are then routed to these channel +subscriptions based on an identifier sent by the cable consumer. + +```ruby +# app/channels/chat_channel.rb +class ChatChannel < ApplicationCable::Channel + # Called when the consumer has successfully + # become a subscriber of this channel. + def subscribed + end +end +``` + +## Client-Side Components + +### Connections + +Consumers require an instance of the connection on their side. This can be +established using the following JavaScript, which is generated by default by Rails: + +#### Connect Consumer + +```js +// app/assets/javascripts/cable.js +//= require action_cable +//= require_self +//= require_tree ./channels + +(function() { + this.App || (this.App = {}); + + App.cable = ActionCable.createConsumer(); +}).call(this); +``` + +This will ready a consumer that'll connect against `/cable` on your server by default. +The connection won't be established until you've also specified at least one subscription +you're interested in having. + +#### Subscriber + +A consumer becomes a subscriber by creating a subscription to a given channel: + +```coffeescript +# app/assets/javascripts/cable/subscriptions/chat.coffee +App.cable.subscriptions.create { channel: "ChatChannel", room: "Best Room" } + +# app/assets/javascripts/cable/subscriptions/appearance.coffee +App.cable.subscriptions.create { channel: "AppearanceChannel" } +``` + +While this creates the subscription, the functionality needed to respond to +received data will be described later on. + +A consumer can act as a subscriber to a given channel any number of times. For +example, a consumer could subscribe to multiple chat rooms at the same time: + +```coffeescript +App.cable.subscriptions.create { channel: "ChatChannel", room: "1st Room" } +App.cable.subscriptions.create { channel: "ChatChannel", room: "2nd Room" } +``` + +## Client-Server Interactions + +### Streams + +*Streams* provide the mechanism by which channels route published content +(broadcasts) to their subscribers. + +```ruby +# app/channels/chat_channel.rb +class ChatChannel < ApplicationCable::Channel + def subscribed + stream_from "chat_#{params[:room]}" + end +end +``` + +If you have a stream that is related to a model, then the broadcasting used +can be generated from the model and channel. The following example would +subscribe to a broadcasting like `comments:Z2lkOi8vVGVzdEFwcC9Qb3N0LzE` + +```ruby +class CommentsChannel < ApplicationCable::Channel + def subscribed + post = Post.find(params[:id]) + stream_for post + end +end +``` + +You can then broadcast to this channel like this: + +```ruby +CommentsChannel.broadcast_to(@post, @comment) +``` + +### Broadcasting + +A *broadcasting* is a pub/sub link where anything transmitted by a publisher +is routed directly to the channel subscribers who are streaming that named +broadcasting. Each channel can be streaming zero or more broadcastings. + +Broadcastings are purely an online queue and time dependent. If a consumer is +not streaming (subscribed to a given channel), they'll not get the broadcast +should they connect later. + +Broadcasts are called elsewhere in your Rails application: + +```ruby +WebNotificationsChannel.broadcast_to( + current_user, + title: 'New things!', + body: 'All the news fit to print' +) +``` + +The `WebNotificationsChannel.broadcast_to` call places a message in the current +subscription adapter (Redis by default)'s pubsub queue under a separate +broadcasting name for each user. For a user with an ID of 1, the broadcasting +name would be `web_notifications_1`. + +The channel has been instructed to stream everything that arrives at +`web_notifications_1` directly to the client by invoking the `received` +callback. + +### Subscriptions + +When a consumer is subscribed to a channel, they act as a subscriber. This +connection is called a subscription. Incoming messages are then routed to +these channel subscriptions based on an identifier sent by the cable consumer. + +```coffeescript +# app/assets/javascripts/cable/subscriptions/chat.coffee +# Assumes you've already requested the right to send web notifications +App.cable.subscriptions.create { channel: "ChatChannel", room: "Best Room" }, + received: (data) -> + @appendLine(data) + + appendLine: (data) -> + html = @createLine(data) + $("[data-chat-room='Best Room']").append(html) + + createLine: (data) -> + """ + <article class="chat-line"> + <span class="speaker">#{data["sent_by"]}</span> + <span class="body">#{data["body"]}</span> + </article> + """ +``` + +### Passing Parameters to Channels + +You can pass parameters from the client side to the server side when creating a +subscription. For example: + +```ruby +# app/channels/chat_channel.rb +class ChatChannel < ApplicationCable::Channel + def subscribed + stream_from "chat_#{params[:room]}" + end +end +``` + +An object passed as the first argument to `subscriptions.create` becomes the +params hash in the cable channel. The keyword `channel` is required: + +```coffeescript +# app/assets/javascripts/cable/subscriptions/chat.coffee +App.cable.subscriptions.create { channel: "ChatChannel", room: "Best Room" }, + received: (data) -> + @appendLine(data) + + appendLine: (data) -> + html = @createLine(data) + $("[data-chat-room='Best Room']").append(html) + + createLine: (data) -> + """ + <article class="chat-line"> + <span class="speaker">#{data["sent_by"]}</span> + <span class="body">#{data["body"]}</span> + </article> + """ +``` + +```ruby +# Somewhere in your app this is called, perhaps +# from a NewCommentJob. +ChatChannel.broadcast_to( + "chat_#{room}", + sent_by: 'Paul', + body: 'This is a cool chat app.' +) +``` + +### Rebroadcasting a Message + +A common use case is to *rebroadcast* a message sent by one client to any +other connected clients. + +```ruby +# app/channels/chat_channel.rb +class ChatChannel < ApplicationCable::Channel + def subscribed + stream_from "chat_#{params[:room]}" + end + + def receive(data) + ChatChannel.broadcast_to("chat_#{params[:room]}", data) + end +end +``` + +```coffeescript +# app/assets/javascripts/cable/subscriptions/chat.coffee +App.chatChannel = App.cable.subscriptions.create { channel: "ChatChannel", room: "Best Room" }, + received: (data) -> + # data => { sent_by: "Paul", body: "This is a cool chat app." } + +App.chatChannel.send({ sent_by: "Paul", body: "This is a cool chat app." }) +``` + +The rebroadcast will be received by all connected clients, _including_ the +client that sent the message. Note that params are the same as they were when +you subscribed to the channel. + +## Full-Stack Examples + +The following setup steps are common to both examples: + + 1. [Setup your connection](#connection-setup). + 2. [Setup your parent channel](#parent-channel-setup). + 3. [Connect your consumer](#connect-consumer). + +### Example 1: User Appearances + +Here's a simple example of a channel that tracks whether a user is online or not +and what page they're on. (This is useful for creating presence features like showing +a green dot next to a user name if they're online). + +Create the server-side appearance channel: + +```ruby +# app/channels/appearance_channel.rb +class AppearanceChannel < ApplicationCable::Channel + def subscribed + current_user.appear + end + + def unsubscribed + current_user.disappear + end + + def appear(data) + current_user.appear(on: data['appearing_on']) + end + + def away + current_user.away + end +end +``` + +When a subscription is initiated the `subscribed` callback gets fired and we +take that opportunity to say "the current user has indeed appeared". That +appear/disappear API could be backed by Redis, a database, or whatever else. + +Create the client-side appearance channel subscription: + +```coffeescript +# app/assets/javascripts/cable/subscriptions/appearance.coffee +App.cable.subscriptions.create "AppearanceChannel", + # Called when the subscription is ready for use on the server. + connected: -> + @install() + @appear() + + # Called when the WebSocket connection is closed. + disconnected: -> + @uninstall() + + # Called when the subscription is rejected by the server. + rejected: -> + @uninstall() + + appear: -> + # Calls `AppearanceChannel#appear(data)` on the server. + @perform("appear", appearing_on: $("main").data("appearing-on")) + + away: -> + # Calls `AppearanceChannel#away` on the server. + @perform("away") + + + buttonSelector = "[data-behavior~=appear_away]" + + install: -> + $(document).on "page:change.appearance", => + @appear() + + $(document).on "click.appearance", buttonSelector, => + @away() + false + + $(buttonSelector).show() + + uninstall: -> + $(document).off(".appearance") + $(buttonSelector).hide() +``` + +##### Client-Server Interaction + +1. **Client** connects to the **Server** via `App.cable = +ActionCable.createConsumer("ws://cable.example.com")`. (`cable.js`). The +**Server** identifies this connection by `current_user`. + +2. **Client** subscribes to the appearance channel via +`App.cable.subscriptions.create(channel: "AppearanceChannel")`. (`appearance.coffee`) + +3. **Server** recognizes a new subscription has been initiated for the +appearance channel and runs its `subscribed` callback, calling the `appear` +method on `current_user`. (`appearance_channel.rb`) + +4. **Client** recognizes that a subscription has been established and calls +`connected` (`appearance.coffee`) which in turn calls `@install` and `@appear`. +`@appear` calls `AppearanceChannel#appear(data)` on the server, and supplies a +data hash of `{ appearing_on: $("main").data("appearing-on") }`. This is +possible because the server-side channel instance automatically exposes all +public methods declared on the class (minus the callbacks), so that these can be +reached as remote procedure calls via a subscription's `perform` method. + +5. **Server** receives the request for the `appear` action on the appearance +channel for the connection identified by `current_user` +(`appearance_channel.rb`). **Server** retrieves the data with the +`:appearing_on` key from the data hash and sets it as the value for the `:on` +key being passed to `current_user.appear`. + +### Example 2: Receiving New Web Notifications + +The appearance example was all about exposing server functionality to +client-side invocation over the WebSocket connection. But the great thing +about WebSockets is that it's a two-way street. So now let's show an example +where the server invokes an action on the client. + +This is a web notification channel that allows you to trigger client-side +web notifications when you broadcast to the right streams: + +Create the server-side web notifications channel: + +```ruby +# app/channels/web_notifications_channel.rb +class WebNotificationsChannel < ApplicationCable::Channel + def subscribed + stream_for current_user + end +end +``` + +Create the client-side web notifications channel subscription: + +```coffeescript +# app/assets/javascripts/cable/subscriptions/web_notifications.coffee +# Client-side which assumes you've already requested +# the right to send web notifications. +App.cable.subscriptions.create "WebNotificationsChannel", + received: (data) -> + new Notification data["title"], body: data["body"] +``` + +Broadcast content to a web notification channel instance from elsewhere in your +application: + +```ruby +# Somewhere in your app this is called, perhaps from a NewCommentJob +WebNotificationsChannel.broadcast_to( + current_user, + title: 'New things!', + body: 'All the news fit to print' +) +``` + +The `WebNotificationsChannel.broadcast_to` call places a message in the current +subscription adapter's pubsub queue under a separate broadcasting name for each +user. For a user with an ID of 1, the broadcasting name would be +"web_notifications_1". + +The channel has been instructed to stream everything that arrives at +"web_notifications_1" directly to the client by invoking the `received` +callback. The data passed as argument is the hash sent as the second parameter +to the server-side broadcast call, JSON encoded for the trip across the wire, +and unpacked for the data argument arriving to `received`. + +### More Complete Examples + +See the [rails/actioncable-examples](https://github.com/rails/actioncable-examples) +repository for a full example of how to setup Action Cable in a Rails app and adding channels. + +## Configuration + +Action Cable has two required configurations: a subscription adapter and allowed request origins. + +### Subscription Adapter + +By default, Action Cable looks for a configuration file in `config/cable.yml`. +The file must specify an adapter and a URL for each Rails environment. See the +[Dependencies](#dependencies) section for additional information on adapters. + +```yaml +development: + adapter: async + +test: + adapter: async + +production: + adapter: redis + url: redis://10.10.3.153:6381 +``` + +### Allowed Request Origins + +Action Cable will only accept requests from specified origins, which are +passed to the server config as an array. The origins can be instances of +strings or regular expressions, against which a check for match will be performed. + +```ruby +config.action_cable.allowed_request_origins = ['http://rubyonrails.com', %r{http://ruby.*}] +``` + +To disable and allow requests from any origin: + +```ruby +config.action_cable.disable_request_forgery_protection = true +``` + +By default, Action Cable allows all requests from localhost:3000 when running +in the development environment. + +### Consumer Configuration + +To configure the URL, add a call to `action_cable_meta_tag` in your HTML layout +HEAD. This uses a URL or path typically set via `config.action_cable.url` in the +environment configuration files. + +### Other Configurations + +The other common option to configure is the log tags applied to the +per-connection logger. Here's close to what we're using in Basecamp: + +```ruby +config.action_cable.log_tags = [ + -> request { request.env['bc.account_id'] || "no-account" }, + :action_cable, + -> request { request.uuid } +] +``` + +For a full list of all configuration options, see the +`ActionCable::Server::Configuration` class. + +Also note that your server must provide at least the same number of database +connections as you have workers. The default worker pool size is set to 4, so +that means you have to make at least that available. You can change that in +`config/database.yml` through the `pool` attribute. + +## Running Standalone Cable Servers + +### In App + +Action Cable can run alongside your Rails application. For example, to +listen for WebSocket requests on `/websocket`, specify that path to +`config.action_cable.mount_path`: + +```ruby +# config/application.rb +class Application < Rails::Application + config.action_cable.mount_path = '/websocket' +end +``` + +You can use `App.cable = ActionCable.createConsumer()` to connect to the cable +server if `action_cable_meta_tag` is invoked in the layout. A custom path is +specified as first argument to `createConsumer` (e.g. `App.cable = +ActionCable.createConsumer("/websocket")`). + +For every instance of your server you create and for every worker your server +spawns, you will also have a new instance of Action Cable, but the use of Redis +keeps messages synced across connections. + +### Standalone + +The cable servers can be separated from your normal application server. It's +still a Rack application, but it is its own Rack application. The recommended +basic setup is as follows: + +```ruby +# cable/config.ru +require_relative '../config/environment' +Rails.application.eager_load! + +run ActionCable.server +``` + +Then you start the server using a binstub in `bin/cable` ala: + +``` +#!/bin/bash +bundle exec puma -p 28080 cable/config.ru +``` + +The above will start a cable server on port 28080. + +### Notes + +The WebSocket server doesn't have access to the session, but it has +access to the cookies. This can be used when you need to handle +authentication. You can see one way of doing that with Devise in this [article](http://www.rubytutorial.io/actioncable-devise-authentication). + +## Dependencies + +Action Cable provides a subscription adapter interface to process its +pubsub internals. By default, asynchronous, inline, PostgreSQL, evented +Redis, and non-evented Redis adapters are included. The default adapter +in new Rails applications is the asynchronous (`async`) adapter. + +The Ruby side of things is built on top of [websocket-driver](https://github.com/faye/websocket-driver-ruby), +[nio4r](https://github.com/celluloid/nio4r), and [concurrent-ruby](https://github.com/ruby-concurrency/concurrent-ruby). + +## Deployment + +Action Cable is powered by a combination of WebSockets and threads. Both the +framework plumbing and user-specified channel work are handled internally by +utilizing Ruby's native thread support. This means you can use all your regular +Rails models with no problem, as long as you haven't committed any thread-safety sins. + +The Action Cable server implements the Rack socket hijacking API, +thereby allowing the use of a multithreaded pattern for managing connections +internally, irrespective of whether the application server is multi-threaded or not. + +Accordingly, Action Cable works with popular servers like Unicorn, Puma, and +Passenger. diff --git a/guides/source/action_controller_overview.md b/guides/source/action_controller_overview.md index 7e43ba375a..a906f64633 100644 --- a/guides/source/action_controller_overview.md +++ b/guides/source/action_controller_overview.md @@ -203,7 +203,7 @@ predefined raise/rescue flow to end up as a 400 Bad Request. ```ruby class PeopleController < ActionController::Base - # This will raise an ActiveModel::ForbiddenAttributes exception + # This will raise an ActiveModel::ForbiddenAttributesError exception # because it's using mass assignment without an explicit permit # step. def create @@ -394,7 +394,7 @@ Rails sets up (for the CookieStore) a secret key used for signing the session da # Make sure the secret is at least 30 characters and all random, # no regular words or you'll be exposed to dictionary attacks. -# You can use `rake secret` to generate a secure secret key. +# You can use `rails secret` to generate a secure secret key. # Make sure the secrets in this file are kept private # if you're sharing your code publicly. @@ -700,7 +700,7 @@ class LoginsController < ApplicationController end ``` -Now, the `LoginsController`'s `new` and `create` actions will work as before without requiring the user to be logged in. The `:only` option is used to only skip this filter for these actions, and there is also an `:except` option which works the other way. These options can be used when adding filters too, so you can add a filter which only runs for selected actions in the first place. +Now, the `LoginsController`'s `new` and `create` actions will work as before without requiring the user to be logged in. The `:only` option is used to skip this filter only for these actions, and there is also an `:except` option which works the other way. These options can be used when adding filters too, so you can add a filter which only runs for selected actions in the first place. ### After Filters and Around Filters @@ -995,10 +995,6 @@ you would like in a response object. The `ActionController::Live` module allows you to create a persistent connection with a browser. Using this module, you will be able to send arbitrary data to the browser at specific points in time. -NOTE: The default Rails server (WEBrick) is a buffering web server and does not -support streaming. In order to use this feature, you'll need to use a non buffering -server like [Puma](http://puma.io), [Rainbows](http://rainbows.bogomips.org) -or [Passenger](https://www.phusionpassenger.com). #### Incorporating Live Streaming @@ -1092,6 +1088,8 @@ You can filter out sensitive request parameters from your log files by appending config.filter_parameters << :password ``` +NOTE: Provided parameters will be filtered out by partial matching regular expression. Rails adds default `:password` in the appropriate initializer (`initializers/filter_parameter_logging.rb`) and cares about typical application parameters `password` and `password_confirmation`. + ### Redirects Filtering Sometimes it's desirable to filter out from log files some sensitive locations your application is redirecting to. @@ -1118,7 +1116,7 @@ Rails default exception handling displays a "500 Server Error" message for all e ### The Default 500 and 404 Templates -By default a production application will render either a 404 or a 500 error message. These messages are contained in static HTML files in the `public` folder, in `404.html` and `500.html` respectively. You can customize these files to add some extra information and style, but remember that they are static HTML; i.e. you can't use ERB, SCSS, CoffeeScript, or layouts for them. +By default a production application will render either a 404 or a 500 error message, in the development environment all unhandled exceptions are raised. These messages are contained in static HTML files in the `public` folder, in `404.html` and `500.html` respectively. You can customize these files to add some extra information and style, but remember that they are static HTML; i.e. you can't use ERB, SCSS, CoffeeScript, or layouts for them. ### `rescue_from` @@ -1150,7 +1148,7 @@ class ApplicationController < ActionController::Base def user_not_authorized flash[:error] = "You don't have access to this section." - redirect_to :back + redirect_back(fallback_location: root_path) end end @@ -1174,7 +1172,11 @@ end WARNING: You shouldn't do `rescue_from Exception` or `rescue_from StandardError` unless you have a particular reason as it will cause serious side-effects (e.g. you won't be able to see exception details and tracebacks during development). -NOTE: Certain exceptions are only rescuable from the `ApplicationController` class, as they are raised before the controller gets initialized and the action gets executed. +NOTE: When running in the production environment, all +`ActiveRecord::RecordNotFound` errors render the 404 error page. Unless you need +a custom behavior you don't need to handle this. + +NOTE: Certain exceptions are only rescuable from the `ApplicationController` class, as they are raised before the controller gets initialized and the action gets executed. Force HTTPS protocol -------------------- diff --git a/guides/source/action_mailer_basics.md b/guides/source/action_mailer_basics.md index 4800cece82..5346b7c32b 100644 --- a/guides/source/action_mailer_basics.md +++ b/guides/source/action_mailer_basics.md @@ -170,7 +170,7 @@ First, let's create a simple `User` scaffold: ```bash $ bin/rails generate scaffold user name email login -$ bin/rake db:migrate +$ bin/rails db:migrate ``` Now that we have a user model to play with, we will just edit the @@ -204,10 +204,14 @@ class UsersController < ApplicationController end ``` -NOTE: Active Job's default behavior is to execute jobs ':inline'. So, you can use -`deliver_later` now to send emails, and when you later decide to start sending -them from a background job, you'll only need to set up Active Job to use a queueing -backend (Sidekiq, Resque, etc). +NOTE: Active Job's default behavior is to execute jobs via the `:async` adapter. So, you can use +`deliver_later` now to send emails asynchronously. +Active Job's default adapter runs jobs with an in-process thread pool. +It's well-suited for the development/test environments, since it doesn't require +any external infrastructure, but it's a poor fit for production since it drops +pending jobs on restart. +If you need a persistent backend, you will need to use an Active Job adapter +that has a persistent backend (Sidekiq, Resque, etc). If you want to send emails right away (from a cronjob for example) just call `deliver_now`: @@ -222,7 +226,7 @@ class SendWeeklySummary end ``` -The method `welcome_email` returns a `ActionMailer::MessageDelivery` object which +The method `welcome_email` returns an `ActionMailer::MessageDelivery` object which can then just be told `deliver_now` or `deliver_later` to send itself out. The `ActionMailer::MessageDelivery` object is just a wrapper around a `Mail::Message`. If you want to inspect, alter or do anything else with the `Mail::Message` object you can @@ -278,7 +282,7 @@ different, encode your content and pass in the encoded content and encoding in a ```ruby encoded_content = SpecialEncode(File.read('/path/to/filename.jpg')) attachments['filename.jpg'] = { - mime_type: 'application/x-gzip', + mime_type: 'application/gzip', encoding: 'SpecialEncoding', content: encoded_content } @@ -407,6 +411,22 @@ use the rendered text for the text part. The render command is the same one used inside of Action Controller, so you can use all the same options, such as `:text`, `:inline` etc. +#### Caching mailer view + +You can do cache in mailer views like in application views using `cache` method. + +``` +<% cache do %> + <%= @company.name %> +<% end %> +``` + +And in order to use this feature, you need to configure your application with this: + +``` + config.action_mailer.perform_caching = true +``` + ### Action Mailer Layouts Just like controller views, you can also have mailer layouts. The layout name diff --git a/guides/source/action_view_overview.md b/guides/source/action_view_overview.md index 4b0e9bff7c..0e6bb76101 100644 --- a/guides/source/action_view_overview.md +++ b/guides/source/action_view_overview.md @@ -173,11 +173,11 @@ would produce: ```json { "name": "Alex", - "email: "alex@example.com" + "email": "alex@example.com" } ``` -See the [Jbuilder documention](https://github.com/rails/jbuilder#jbuilder) for +See the [Jbuilder documentation](https://github.com/rails/jbuilder#jbuilder) for more examples and information. #### Template Caching @@ -260,7 +260,7 @@ With the `as` option we can specify a different name for the local variable. For <%= render partial: "product", as: "item" %> ``` -The `object` option can be used to directly specify which object is rendered into the partial; useful when the template's object is elsewhere (eg. in a different instance variable or in a local variable). +The `object` option can be used to directly specify which object is rendered into the partial; useful when the template's object is elsewhere (e.g. in a different instance variable or in a local variable). For example, instead of: @@ -442,7 +442,7 @@ image_path("edit.png") # => /assets/edit-2d1a2db63fc738690021fedb5a65b68e.png #### image_url -Computes the url to an image asset in the `app/assets/images` directory. This will call `image_path` internally and merge with your current host or your asset host. +Computes the URL to an image asset in the `app/assets/images` directory. This will call `image_path` internally and merge with your current host or your asset host. ```ruby image_url("edit.png") # => http://www.example.com/assets/edit.png @@ -493,7 +493,7 @@ javascript_path "common" # => /assets/common.js #### javascript_url -Computes the url to a JavaScript asset in the `app/assets/javascripts` directory. This will call `javascript_path` internally and merge with your current host or your asset host. +Computes the URL to a JavaScript asset in the `app/assets/javascripts` directory. This will call `javascript_path` internally and merge with your current host or your asset host. ```ruby javascript_url "common" # => http://www.example.com/assets/common.js @@ -530,7 +530,7 @@ stylesheet_path "application" # => /assets/application.css #### stylesheet_url -Computes the url to a stylesheet asset in the `app/assets/stylesheets` directory. This will call `stylesheet_path` internally and merge with your current host or your asset host. +Computes the URL to a stylesheet asset in the `app/assets/stylesheets` directory. This will call `stylesheet_path` internally and merge with your current host or your asset host. ```ruby stylesheet_url "application" # => http://www.example.com/assets/application.css @@ -599,7 +599,7 @@ This would add something like "Process data files (0.34523)" to the log, which y #### cache -A method for caching fragments of a view rather than an entire action or page. This technique is useful caching pieces like menus, lists of news topics, static HTML fragments, and so on. This method takes a block that contains the content you wish to cache. See `ActionController::Caching::Fragments` for more information. +A method for caching fragments of a view rather than an entire action or page. This technique is useful for caching pieces like menus, lists of news topics, static HTML fragments, and so on. This method takes a block that contains the content you wish to cache. See `AbstractController::Caching::Fragments` for more information. ```erb <% cache do %> @@ -990,11 +990,11 @@ Returns `select` and `option` tags for the collection of existing return values Example object structure for use with this method: ```ruby -class Article < ActiveRecord::Base +class Article < ApplicationRecord belongs_to :author end -class Author < ActiveRecord::Base +class Author < ApplicationRecord has_many :articles def name_with_initial "#{first_name.first}. #{last_name}" @@ -1026,11 +1026,11 @@ Returns `radio_button` tags for the collection of existing return values of `met Example object structure for use with this method: ```ruby -class Article < ActiveRecord::Base +class Article < ApplicationRecord belongs_to :author end -class Author < ActiveRecord::Base +class Author < ApplicationRecord has_many :articles def name_with_initial "#{first_name.first}. #{last_name}" @@ -1062,11 +1062,11 @@ Returns `check_box` tags for the collection of existing return values of `method Example object structure for use with this method: ```ruby -class Article < ActiveRecord::Base +class Article < ApplicationRecord has_and_belongs_to_many :authors end -class Author < ActiveRecord::Base +class Author < ApplicationRecord has_and_belongs_to_many :articles def name_with_initial "#{first_name.first}. #{last_name}" @@ -1099,12 +1099,12 @@ Returns a string of `option` tags, like `options_from_collection_for_select`, bu Example object structure for use with this method: ```ruby -class Continent < ActiveRecord::Base +class Continent < ApplicationRecord has_many :countries # attribs: id, name end -class Country < ActiveRecord::Base +class Country < ApplicationRecord belongs_to :continent # attribs: id, name, continent_id end @@ -1247,7 +1247,7 @@ file_field_tag 'attachment' #### form_tag -Starts a form tag that points the action to a url configured with `url_for_options` just like `ActionController::Base#url_for`. +Starts a form tag that points the action to a URL configured with `url_for_options` just like `ActionController::Base#url_for`. ```html+erb <%= form_tag '/articles' do %> @@ -1419,7 +1419,7 @@ number_to_percentage(100, precision: 0) # => 100% #### number_to_phone -Formats a number into a US phone number. +Formats a number into a phone number (US by default). ```ruby number_to_phone(1235551234) # => 123-555-1234 @@ -1524,7 +1524,7 @@ Localized Views Action View has the ability to render different templates depending on the current locale. -For example, suppose you have a `ArticlesController` with a show action. By default, calling this action will render `app/views/articles/show.html.erb`. But if you set `I18n.locale = :de`, then `app/views/articles/show.de.html.erb` will be rendered instead. If the localized template isn't present, the undecorated version will be used. This means you're not required to provide localized views for all cases, but they will be preferred and used if available. +For example, suppose you have an `ArticlesController` with a show action. By default, calling this action will render `app/views/articles/show.html.erb`. But if you set `I18n.locale = :de`, then `app/views/articles/show.de.html.erb` will be rendered instead. If the localized template isn't present, the undecorated version will be used. This means you're not required to provide localized views for all cases, but they will be preferred and used if available. You can use the same technique to localize the rescue files in your public directory. For example, setting `I18n.locale = :de` and creating `public/500.de.html` and `public/404.de.html` would allow you to have localized rescue pages. diff --git a/guides/source/active_job_basics.md b/guides/source/active_job_basics.md index a114686f0f..d6de92ace6 100644 --- a/guides/source/active_job_basics.md +++ b/guides/source/active_job_basics.md @@ -83,7 +83,7 @@ Note that you can define `perform` with as many arguments as you want. Enqueue a job like so: ```ruby -# Enqueue a job to be performed as soon the queuing system is +# Enqueue a job to be performed as soon as the queuing system is # free. GuestsCleanupJob.perform_later guest ``` @@ -109,10 +109,12 @@ That's it! Job Execution ------------- -For enqueuing and executing jobs you need to set up a queuing backend, that is to -say you need to decide for a 3rd-party queuing library that Rails should use. -Rails itself does not provide a sophisticated queuing system and just executes the -job immediately if no adapter is set. +For enqueuing and executing jobs in production you need to set up a queuing backend, +that is to say you need to decide for a 3rd-party queuing library that Rails should use. +Rails itself only provides an in-process queuing system, which only keeps the jobs in RAM. +If the process crashes or the machine is reset, then all outstanding jobs are lost with the +default async back-end. This may be fine for smaller apps or non-critical jobs, but most +production apps will need to pick a persistent backend. ### Backends @@ -136,6 +138,18 @@ module YourApp end ``` +You can also configure your backend on a per job basis. + +```ruby +class GuestsCleanupJob < ActiveJob::Base + self.queue_adapter = :resque + #.... +end + +# Now your job will use `resque` as it's backend queue adapter overriding what +# was configured in `config.active_job.queue_adapter`. +``` + ### Starting the Backend Since jobs run in parallel to your Rails application, most queuing libraries @@ -174,7 +188,7 @@ module YourApp end end -# app/jobs/guests_cleanup.rb +# app/jobs/guests_cleanup_job.rb class GuestsCleanupJob < ActiveJob::Base queue_as :low_priority #.... @@ -197,7 +211,7 @@ module YourApp end end -# app/jobs/guests_cleanup.rb +# app/jobs/guests_cleanup_job.rb class GuestsCleanupJob < ActiveJob::Base queue_as :low_priority #.... diff --git a/guides/source/active_model_basics.md b/guides/source/active_model_basics.md index 8f8256c983..e834aeadb1 100644 --- a/guides/source/active_model_basics.md +++ b/guides/source/active_model_basics.md @@ -13,7 +13,7 @@ After reading this guide, you will know: * How an Active Record model behaves. * How Callbacks and validations work. * How serializers work. -* The Rails internationalization (i18n) framework. +* How Active Model integrates with the Rails internationalization (i18n) framework. -------------------------------------------------------------------------------- @@ -319,7 +319,7 @@ person.serializable_hash # => {"name"=>"Bob"} #### ActiveModel::Serializers -Rails provides a `ActiveModel::Serializers::JSON` serializer. +Rails provides an `ActiveModel::Serializers::JSON` serializer. This module automatically include the `ActiveModel::Serialization`. ##### ActiveModel::Serializers::JSON @@ -435,7 +435,7 @@ the Active Model API. ``` ```bash -$ rake test +$ rails test Run options: --seed 14596 diff --git a/guides/source/active_record_basics.md b/guides/source/active_record_basics.md index dafbe17bbd..d9e9466a33 100644 --- a/guides/source/active_record_basics.md +++ b/guides/source/active_record_basics.md @@ -132,10 +132,10 @@ Creating Active Record Models ----------------------------- It is very easy to create Active Record models. All you have to do is to -subclass the `ActiveRecord::Base` class and you're good to go: +subclass the `ApplicationRecord` class and you're good to go: ```ruby -class Product < ActiveRecord::Base +class Product < ApplicationRecord end ``` @@ -168,11 +168,12 @@ What if you need to follow a different naming convention or need to use your Rails application with a legacy database? No problem, you can easily override the default conventions. -You can use the `ActiveRecord::Base.table_name=` method to specify the table -name that should be used: +`ApplicationRecord` inherits from `ActiveRecord::Base`, which defines a +number of helpful methods. You can use the `ActiveRecord::Base.table_name=` +method to specify the table name that should be used: ```ruby -class Product < ActiveRecord::Base +class Product < ApplicationRecord self.table_name = "my_products" end ``` @@ -193,7 +194,7 @@ It's also possible to override the column that should be used as the table's primary key using the `ActiveRecord::Base.primary_key=` method: ```ruby -class Product < ActiveRecord::Base +class Product < ApplicationRecord self.primary_key = "product_id" end ``` @@ -320,7 +321,7 @@ they raise the exception `ActiveRecord::RecordInvalid` if validation fails. A quick example to illustrate: ```ruby -class User < ActiveRecord::Base +class User < ApplicationRecord validates :name, presence: true end @@ -350,7 +351,7 @@ database that Active Record supports using `rake`. Here's a migration that creates a table: ```ruby -class CreatePublications < ActiveRecord::Migration +class CreatePublications < ActiveRecord::Migration[5.0] def change create_table :publications do |t| t.string :title @@ -360,7 +361,7 @@ class CreatePublications < ActiveRecord::Migration t.string :publisher_type t.boolean :single_issue - t.timestamps null: false + t.timestamps end add_index :publications, :publication_type_id end @@ -368,8 +369,8 @@ end ``` Rails keeps track of which files have been committed to the database and -provides rollback features. To actually create the table, you'd run `rake db:migrate` -and to roll it back, `rake db:rollback`. +provides rollback features. To actually create the table, you'd run `rails db:migrate` +and to roll it back, `rails db:rollback`. Note that the above code is database-agnostic: it will run in MySQL, PostgreSQL, Oracle and others. You can learn more about migrations in the diff --git a/guides/source/active_record_callbacks.md b/guides/source/active_record_callbacks.md index 13989a3b33..fb5d2065d3 100644 --- a/guides/source/active_record_callbacks.md +++ b/guides/source/active_record_callbacks.md @@ -31,7 +31,7 @@ Callbacks are methods that get called at certain moments of an object's life cyc In order to use the available callbacks, you need to register them. You can implement the callbacks as ordinary methods and use a macro-style class method to register them as callbacks: ```ruby -class User < ActiveRecord::Base +class User < ApplicationRecord validates :login, :email, presence: true before_validation :ensure_login_has_a_value @@ -48,7 +48,7 @@ end The macro-style class methods can also receive a block. Consider using this style if the code inside your block is so short that it fits in a single line: ```ruby -class User < ActiveRecord::Base +class User < ApplicationRecord validates :login, :email, presence: true before_create do @@ -60,7 +60,7 @@ end Callbacks can also be registered to only fire on certain life cycle events: ```ruby -class User < ActiveRecord::Base +class User < ApplicationRecord before_validation :normalize_name, on: :create # :on takes an array as well @@ -126,7 +126,7 @@ The `after_find` callback will be called whenever Active Record loads a record f The `after_initialize` and `after_find` callbacks have no `before_*` counterparts, but they can be registered just like the other Active Record callbacks. ```ruby -class User < ActiveRecord::Base +class User < ApplicationRecord after_initialize do |user| puts "You have initialized an object!" end @@ -151,7 +151,7 @@ You have initialized an object! The `after_touch` callback will be called whenever an Active Record object is touched. ```ruby -class User < ActiveRecord::Base +class User < ApplicationRecord after_touch do |user| puts "You have touched an object" end @@ -168,14 +168,14 @@ You have touched an object It can be used along with `belongs_to`: ```ruby -class Employee < ActiveRecord::Base +class Employee < ApplicationRecord belongs_to :company, touch: true after_touch do puts 'An Employee was touched' end end -class Company < ActiveRecord::Base +class Company < ApplicationRecord has_many :employees after_touch :log_when_employees_or_company_touched @@ -258,7 +258,7 @@ As you start registering new callbacks for your models, they will be queued for The whole callback chain is wrapped in a transaction. If any _before_ callback method returns exactly `false` or raises an exception, the execution chain gets halted and a ROLLBACK is issued; _after_ callbacks can only accomplish that by raising an exception. -WARNING. Any exception that is not `ActiveRecord::Rollback` will be re-raised by Rails after the callback chain is halted. Raising an exception other than `ActiveRecord::Rollback` may break code that does not expect methods like `save` and `update_attributes` (which normally try to return `true` or `false`) to raise an exception. +WARNING. Any exception that is not `ActiveRecord::Rollback` or `ActiveRecord::RecordInvalid` will be re-raised by Rails after the callback chain is halted. Raising an exception other than `ActiveRecord::Rollback` or `ActiveRecord::RecordInvalid` may break code that does not expect methods like `save` and `update_attributes` (which normally try to return `true` or `false`) to raise an exception. Relational Callbacks -------------------- @@ -266,11 +266,11 @@ Relational Callbacks Callbacks work through model relationships, and can even be defined by them. Suppose an example where a user has many articles. A user's articles should be destroyed if the user is destroyed. Let's add an `after_destroy` callback to the `User` model by way of its relationship to the `Article` model: ```ruby -class User < ActiveRecord::Base +class User < ApplicationRecord has_many :articles, dependent: :destroy end -class Article < ActiveRecord::Base +class Article < ApplicationRecord after_destroy :log_destroy_action def log_destroy_action @@ -297,7 +297,7 @@ As with validations, we can also make the calling of a callback method condition You can associate the `:if` and `:unless` options with a symbol corresponding to the name of a predicate method that will get called right before the callback. When using the `:if` option, the callback won't be executed if the predicate method returns false; when using the `:unless` option, the callback won't be executed if the predicate method returns true. This is the most common option. Using this form of registration it is also possible to register several different predicates that should be called to check if the callback should be executed. ```ruby -class Order < ActiveRecord::Base +class Order < ApplicationRecord before_save :normalize_card_number, if: :paid_with_card? end ``` @@ -307,7 +307,7 @@ end You can also use a string that will be evaluated using `eval` and hence needs to contain valid Ruby code. You should use this option only when the string represents a really short condition: ```ruby -class Order < ActiveRecord::Base +class Order < ApplicationRecord before_save :normalize_card_number, if: "paid_with_card?" end ``` @@ -317,7 +317,7 @@ end Finally, it is possible to associate `:if` and `:unless` with a `Proc` object. This option is best suited when writing short validation methods, usually one-liners: ```ruby -class Order < ActiveRecord::Base +class Order < ApplicationRecord before_save :normalize_card_number, if: Proc.new { |order| order.paid_with_card? } end @@ -328,7 +328,7 @@ end When writing conditional callbacks, it is possible to mix both `:if` and `:unless` in the same callback declaration: ```ruby -class Comment < ActiveRecord::Base +class Comment < ApplicationRecord after_create :send_email_to_author, if: :author_wants_emails?, unless: Proc.new { |comment| comment.article.ignore_comments? } end @@ -354,7 +354,7 @@ end When declared inside a class, as above, the callback methods will receive the model object as a parameter. We can now use the callback class in the model: ```ruby -class PictureFile < ActiveRecord::Base +class PictureFile < ApplicationRecord after_destroy PictureFileCallbacks.new end ``` @@ -374,7 +374,7 @@ end If the callback method is declared this way, it won't be necessary to instantiate a `PictureFileCallbacks` object. ```ruby -class PictureFile < ActiveRecord::Base +class PictureFile < ApplicationRecord after_destroy PictureFileCallbacks end ``` @@ -398,7 +398,7 @@ end By using the `after_commit` callback we can account for this case. ```ruby -class PictureFile < ActiveRecord::Base +class PictureFile < ApplicationRecord after_commit :delete_picture_file_from_disk, on: [:destroy] def delete_picture_file_from_disk @@ -412,4 +412,23 @@ end NOTE: the `:on` option specifies when a callback will be fired. If you don't supply the `:on` option the callback will fire for every action. +Since using `after_commit` callback only on create, update or delete is +common, there are aliases for those operations: + +* `after_create_commit` +* `after_update_commit` +* `after_destroy_commit` + +```ruby +class PictureFile < ApplicationRecord + after_destroy_commit :delete_picture_file_from_disk + + def delete_picture_file_from_disk + if File.exist?(filepath) + File.delete(filepath) + end + end +end +``` + WARNING. The `after_commit` and `after_rollback` callbacks are guaranteed to be called for all models created, updated, or destroyed within a transaction block. If any exceptions are raised within one of these callbacks, they will be ignored so that they don't interfere with the other callbacks. As such, if your callback code could raise an exception, you'll need to rescue it and handle it appropriately within the callback. diff --git a/guides/source/active_record_migrations.md b/guides/source/active_record_migrations.md index 5aa5dc4f60..f914122242 100644 --- a/guides/source/active_record_migrations.md +++ b/guides/source/active_record_migrations.md @@ -12,7 +12,7 @@ After reading this guide, you will know: * The generators you can use to create them. * The methods Active Record provides to manipulate your database. -* The Rake tasks that manipulate migrations and your schema. +* The bin/rails tasks that manipulate migrations and your schema. * How migrations relate to `schema.rb`. -------------------------------------------------------------------------------- @@ -35,13 +35,13 @@ history to the latest version. Active Record will also update your Here's an example of a migration: ```ruby -class CreateProducts < ActiveRecord::Migration +class CreateProducts < ActiveRecord::Migration[5.0] def change create_table :products do |t| t.string :name t.text :description - t.timestamps null: false + t.timestamps end end end @@ -72,7 +72,7 @@ If you wish for a migration to do something that Active Record doesn't know how to reverse, you can use `reversible`: ```ruby -class ChangeProductsPrice < ActiveRecord::Migration +class ChangeProductsPrice < ActiveRecord::Migration[5.0] def change reversible do |dir| change_table :products do |t| @@ -87,7 +87,7 @@ end Alternatively, you can use `up` and `down` instead of `change`: ```ruby -class ChangeProductsPrice < ActiveRecord::Migration +class ChangeProductsPrice < ActiveRecord::Migration[5.0] def up change_table :products do |t| t.change :price, :string @@ -129,7 +129,7 @@ $ bin/rails generate migration AddPartNumberToProducts This will create an empty but appropriately named migration: ```ruby -class AddPartNumberToProducts < ActiveRecord::Migration +class AddPartNumberToProducts < ActiveRecord::Migration[5.0] def change end end @@ -146,7 +146,7 @@ $ bin/rails generate migration AddPartNumberToProducts part_number:string will generate ```ruby -class AddPartNumberToProducts < ActiveRecord::Migration +class AddPartNumberToProducts < ActiveRecord::Migration[5.0] def change add_column :products, :part_number, :string end @@ -162,7 +162,7 @@ $ bin/rails generate migration AddPartNumberToProducts part_number:string:index will generate ```ruby -class AddPartNumberToProducts < ActiveRecord::Migration +class AddPartNumberToProducts < ActiveRecord::Migration[5.0] def change add_column :products, :part_number, :string add_index :products, :part_number @@ -180,7 +180,7 @@ $ bin/rails generate migration RemovePartNumberFromProducts part_number:string generates ```ruby -class RemovePartNumberFromProducts < ActiveRecord::Migration +class RemovePartNumberFromProducts < ActiveRecord::Migration[5.0] def change remove_column :products, :part_number, :string end @@ -196,7 +196,7 @@ $ bin/rails generate migration AddDetailsToProducts part_number:string price:dec generates ```ruby -class AddDetailsToProducts < ActiveRecord::Migration +class AddDetailsToProducts < ActiveRecord::Migration[5.0] def change add_column :products, :part_number, :string add_column :products, :price, :decimal @@ -215,7 +215,7 @@ $ bin/rails generate migration CreateProducts name:string part_number:string generates ```ruby -class CreateProducts < ActiveRecord::Migration +class CreateProducts < ActiveRecord::Migration[5.0] def change create_table :products do |t| t.string :name @@ -239,7 +239,7 @@ $ bin/rails generate migration AddUserRefToProducts user:references generates ```ruby -class AddUserRefToProducts < ActiveRecord::Migration +class AddUserRefToProducts < ActiveRecord::Migration[5.0] def change add_reference :products, :user, index: true, foreign_key: true end @@ -247,6 +247,7 @@ end ``` This migration will create a `user_id` column and appropriate index. +For more `add_reference` options, visit the [API documentation](http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_reference). There is also a generator which will produce join tables if `JoinTable` is part of the name: @@ -257,7 +258,7 @@ $ bin/rails g migration CreateJoinTableCustomerProduct customer product will produce the following migration: ```ruby -class CreateJoinTableCustomerProduct < ActiveRecord::Migration +class CreateJoinTableCustomerProduct < ActiveRecord::Migration[5.0] def change create_join_table :customers, :products do |t| # t.index [:customer_id, :product_id] @@ -281,13 +282,13 @@ $ bin/rails generate model Product name:string description:text will create a migration that looks like this ```ruby -class CreateProducts < ActiveRecord::Migration +class CreateProducts < ActiveRecord::Migration[5.0] def change create_table :products do |t| t.string :name t.text :description - t.timestamps null: false + t.timestamps end end end @@ -309,7 +310,7 @@ $ bin/rails generate migration AddDetailsToProducts 'price:decimal{5,2}' supplie will produce a migration that looks like this ```ruby -class AddDetailsToProducts < ActiveRecord::Migration +class AddDetailsToProducts < ActiveRecord::Migration[5.0] def change add_column :products, :price, :decimal, precision: 5, scale: 2 add_reference :products, :supplier, polymorphic: true, index: true @@ -353,7 +354,14 @@ end ``` will append `ENGINE=BLACKHOLE` to the SQL statement used to create the table -(when using MySQL, the default is `ENGINE=InnoDB`). +(when using MySQL or MariaDB, the default is `ENGINE=InnoDB`). + +Also you can pass the `:comment` option with any description for the table +that will be stored in database itself and can be viewed with database administration +tools, such as MySQL Workbench or PgAdmin III. It's highly recommended to specify +comments in migrations for applications with large databases as it helps people +to understand data model and generate documentation. +Currently only the MySQL and PostgreSQL adapters support comments. ### Creating a Join Table @@ -454,6 +462,7 @@ number of digits after the decimal point. are using a dynamic value (such as a date), the default will only be calculated the first time (i.e. on the date the migration is applied). * `index` Adds an index for the column. +* `comment` Adds a comment for the column. Some adapters may support additional options; see the adapter specific API docs for further information. @@ -563,7 +572,7 @@ to reverse. You can use `reversible` to specify what to do when running a migration and what else to do when reverting it. For example: ```ruby -class ExampleMigration < ActiveRecord::Migration +class ExampleMigration < ActiveRecord::Migration[5.0] def change create_table :distributors do |t| t.string :zipcode @@ -616,7 +625,7 @@ is wise to perform the transformations in precisely the reverse order they were made in the `up` method. The example in the `reversible` section is equivalent to: ```ruby -class ExampleMigration < ActiveRecord::Migration +class ExampleMigration < ActiveRecord::Migration[5.0] def up create_table :distributors do |t| t.string :zipcode @@ -659,7 +668,7 @@ You can use Active Record's ability to rollback migrations using the `revert` me ```ruby require_relative '20121212123456_example_migration' -class FixupExampleMigration < ActiveRecord::Migration +class FixupExampleMigration < ActiveRecord::Migration[5.0] def change revert ExampleMigration @@ -677,7 +686,7 @@ is later decided it would be best to use Active Record validations, in place of the `CHECK` constraint, to verify the zipcode. ```ruby -class DontUseConstraintForZipcodeValidationMigration < ActiveRecord::Migration +class DontUseConstraintForZipcodeValidationMigration < ActiveRecord::Migration[5.0] def change revert do # copy-pasted code from ExampleMigration @@ -717,10 +726,10 @@ you will have to use `structure.sql` as dump method. See Running Migrations ------------------ -Rails provides a set of Rake tasks to run certain sets of migrations. +Rails provides a set of bin/rails tasks to run certain sets of migrations. -The very first migration related Rake task you will use will probably be -`rake db:migrate`. In its most basic form it just runs the `change` or `up` +The very first migration related bin/rails task you will use will probably be +`rails db:migrate`. In its most basic form it just runs the `change` or `up` method for all the migrations that have not yet been run. If there are no such migrations, it exits. It will run these migrations in order based on the date of the migration. @@ -734,7 +743,7 @@ is the numerical prefix on the migration's filename. For example, to migrate to version 20080906120000 run: ```bash -$ bin/rake db:migrate VERSION=20080906120000 +$ bin/rails db:migrate VERSION=20080906120000 ``` If version 20080906120000 is greater than the current version (i.e., it is @@ -751,7 +760,7 @@ mistake in it and wish to correct it. Rather than tracking down the version number associated with the previous migration you can run: ```bash -$ bin/rake db:rollback +$ bin/rails db:rollback ``` This will rollback the latest migration, either by reverting the `change` @@ -759,7 +768,7 @@ method or by running the `down` method. If you need to undo several migrations you can provide a `STEP` parameter: ```bash -$ bin/rake db:rollback STEP=3 +$ bin/rails db:rollback STEP=3 ``` will revert the last 3 migrations. @@ -769,26 +778,26 @@ back up again. As with the `db:rollback` task, you can use the `STEP` parameter if you need to go more than one version back, for example: ```bash -$ bin/rake db:migrate:redo STEP=3 +$ bin/rails db:migrate:redo STEP=3 ``` -Neither of these Rake tasks do anything you could not do with `db:migrate`. They +Neither of these bin/rails tasks do anything you could not do with `db:migrate`. They are simply more convenient, since you do not need to explicitly specify the version to migrate to. ### Setup the Database -The `rake db:setup` task will create the database, load the schema and initialize +The `rails db:setup` task will create the database, load the schema and initialize it with the seed data. ### Resetting the Database -The `rake db:reset` task will drop the database and set it up again. This is -functionally equivalent to `rake db:drop db:setup`. +The `rails db:reset` task will drop the database and set it up again. This is +functionally equivalent to `rails db:drop db:setup`. NOTE: This is not the same as running all the migrations. It will only use the contents of the current `db/schema.rb` or `db/structure.sql` file. If a migration can't be rolled back, -`rake db:reset` may not help you. To find out more about dumping the schema see +`rails db:reset` may not help you. To find out more about dumping the schema see [Schema Dumping and You](#schema-dumping-and-you) section. ### Running Specific Migrations @@ -799,7 +808,7 @@ the corresponding migration will have its `change`, `up` or `down` method invoked, for example: ```bash -$ bin/rake db:migrate:up VERSION=20080906120000 +$ bin/rails db:migrate:up VERSION=20080906120000 ``` will run the 20080906120000 migration by running the `change` method (or the @@ -809,13 +818,13 @@ Active Record believes that it has already been run. ### Running Migrations in Different Environments -By default running `rake db:migrate` will run in the `development` environment. +By default running `bin/rails db:migrate` will run in the `development` environment. To run migrations against another environment you can specify it using the `RAILS_ENV` environment variable while running the command. For example to run migrations against the `test` environment you could run: ```bash -$ bin/rake db:migrate RAILS_ENV=test +$ bin/rails db:migrate RAILS_ENV=test ``` ### Changing the Output of Running Migrations @@ -841,13 +850,13 @@ Several methods are provided in migrations that allow you to control all this: For example, this migration: ```ruby -class CreateProducts < ActiveRecord::Migration +class CreateProducts < ActiveRecord::Migration[5.0] def change suppress_messages do create_table :products do |t| t.string :name t.text :description - t.timestamps null: false + t.timestamps end end @@ -876,18 +885,18 @@ generates the following output == CreateProducts: migrated (10.0054s) ======================================= ``` -If you want Active Record to not output anything, then running `rake db:migrate +If you want Active Record to not output anything, then running `rails db:migrate VERBOSE=false` will suppress all output. Changing Existing Migrations ---------------------------- Occasionally you will make a mistake when writing a migration. If you have -already run the migration then you cannot just edit the migration and run the +already run the migration, then you cannot just edit the migration and run the migration again: Rails thinks it has already run the migration and so will do -nothing when you run `rake db:migrate`. You must rollback the migration (for -example with `rake db:rollback`), edit your migration and then run -`rake db:migrate` to run the corrected version. +nothing when you run `rails db:migrate`. You must rollback the migration (for +example with `bin/rails db:rollback`), edit your migration and then run +`rails db:migrate` to run the corrected version. In general, editing existing migrations is not a good idea. You will be creating extra work for yourself and your co-workers and cause major headaches @@ -933,7 +942,7 @@ There are two ways to dump the schema. This is set in `config/application.rb` by the `config.active_record.schema_format` setting, which may be either `:sql` or `:ruby`. -If `:ruby` is selected then the schema is stored in `db/schema.rb`. If you look +If `:ruby` is selected, then the schema is stored in `db/schema.rb`. If you look at this file you'll find that it looks an awful lot like one very big migration: @@ -969,8 +978,8 @@ this, then you should set the schema format to `:sql`. Instead of using Active Record's schema dumper, the database's structure will be dumped using a tool specific to the database (via the `db:structure:dump` -Rake task) into `db/structure.sql`. For example, for PostgreSQL, the `pg_dump` -utility is used. For MySQL, this file will contain the output of +rails task) into `db/structure.sql`. For example, for PostgreSQL, the `pg_dump` +utility is used. For MySQL and MariaDB, this file will contain the output of `SHOW CREATE TABLE` for the various tables. Loading these schemas is simply a question of executing the SQL statements they @@ -1015,7 +1024,7 @@ to add or modify data. This is useful in an existing database that can't be dest and recreated, such as a production database. ```ruby -class AddInitialProducts < ActiveRecord::Migration +class AddInitialProducts < ActiveRecord::Migration[5.0] def up 5.times do |i| Product.create(name: "Product ##{i}", description: "A product.") @@ -1032,7 +1041,7 @@ To add initial data after a database is created, Rails has a built-in 'seeds' feature that makes the process quick and easy. This is especially useful when reloading the database frequently in development and test environments. It's easy to get started with this feature: just fill up `db/seeds.rb` with some -Ruby code, and run `rake db:seed`: +Ruby code, and run `rails db:seed`: ```ruby 5.times do |i| diff --git a/guides/source/active_record_postgresql.md b/guides/source/active_record_postgresql.md index 742db7be32..dee64e6439 100644 --- a/guides/source/active_record_postgresql.md +++ b/guides/source/active_record_postgresql.md @@ -14,7 +14,7 @@ After reading this guide, you will know: -------------------------------------------------------------------------------- -In order to use the PostgreSQL adapter you need to have at least version 8.2 +In order to use the PostgreSQL adapter you need to have at least version 9.1 installed. Older versions are not supported. To get started with PostgreSQL have a look at the @@ -39,7 +39,7 @@ create_table :documents do |t| end # app/models/document.rb -class Document < ActiveRecord::Base +class Document < ApplicationRecord end # Usage @@ -63,7 +63,7 @@ add_index :books, :tags, using: 'gin' add_index :books, :ratings, using: 'gin' # app/models/book.rb -class Book < ActiveRecord::Base +class Book < ApplicationRecord end # Usage @@ -84,6 +84,7 @@ Book.where("array_length(ratings, 1) >= 3") ### Hstore * [type definition](http://www.postgresql.org/docs/current/static/hstore.html) +* [functions and operators](http://www.postgresql.org/docs/current/static/hstore.html#AEN167712) NOTE: You need to enable the `hstore` extension to use hstore. @@ -97,7 +98,7 @@ ActiveRecord::Schema.define do end # app/models/profile.rb -class Profile < ActiveRecord::Base +class Profile < ApplicationRecord end # Usage @@ -108,6 +109,9 @@ profile.settings # => {"color"=>"blue", "resolution"=>"800x600"} profile.settings = {"color" => "yellow", "resolution" => "1280x1024"} profile.save! + +Profile.where("settings->'color' = ?", "yellow") +#=> #<ActiveRecord::Relation [#<Profile id: 1, settings: {"color"=>"yellow", "resolution"=>"1280x1024"}>]> ``` ### JSON @@ -122,7 +126,7 @@ create_table :events do |t| end # app/models/event.rb -class Event < ActiveRecord::Base +class Event < ApplicationRecord end # Usage @@ -150,7 +154,7 @@ create_table :events do |t| end # app/models/event.rb -class Event < ActiveRecord::Base +class Event < ApplicationRecord end # Usage @@ -200,7 +204,7 @@ create_table :contacts do |t| end # app/models/contact.rb -class Contact < ActiveRecord::Base +class Contact < ApplicationRecord end # Usage @@ -239,7 +243,7 @@ def down end # app/models/article.rb -class Article < ActiveRecord::Base +class Article < ApplicationRecord end # Usage @@ -294,7 +298,7 @@ create_table :revisions do |t| end # app/models/revision.rb -class Revision < ActiveRecord::Base +class Revision < ApplicationRecord end # Usage @@ -317,12 +321,12 @@ create_table :comments, id: :uuid, default: 'gen_random_uuid()' do |t| end # app/models/post.rb -class Post < ActiveRecord::Base +class Post < ApplicationRecord has_many :comments end # app/models/comment.rb -class Comment < ActiveRecord::Base +class Comment < ApplicationRecord belongs_to :post end ``` @@ -341,7 +345,7 @@ create_table :users, force: true do |t| end # app/models/device.rb -class User < ActiveRecord::Base +class User < ApplicationRecord end # Usage @@ -370,7 +374,7 @@ create_table(:devices, force: true) do |t| end # app/models/device.rb -class Device < ActiveRecord::Base +class Device < ApplicationRecord end # Usage @@ -410,7 +414,7 @@ create_table :devices, id: :uuid, default: 'gen_random_uuid()' do |t| end # app/models/device.rb -class Device < ActiveRecord::Base +class Device < ApplicationRecord end # Usage @@ -431,10 +435,10 @@ create_table :documents do |t| t.string 'body' end -execute "CREATE INDEX documents_idx ON documents USING gin(to_tsvector('english', title || ' ' || body));" +add_index :documents, "to_tsvector('english', title || ' ' || body)", using: :gin, name: 'documents_idx' # app/models/document.rb -class Document < ActiveRecord::Base +class Document < ApplicationRecord end # Usage @@ -484,7 +488,7 @@ CREATE VIEW articles AS SQL # app/models/article.rb -class Article < ActiveRecord::Base +class Article < ApplicationRecord self.primary_key = "id" def archive! update_attribute :archived, true diff --git a/guides/source/active_record_querying.md b/guides/source/active_record_querying.md index ec31fa9d67..928ab43b3b 100644 --- a/guides/source/active_record_querying.md +++ b/guides/source/active_record_querying.md @@ -11,7 +11,7 @@ After reading this guide, you will know: * How to specify the order, retrieved attributes, grouping, and other properties of the found records. * How to use eager loading to reduce the number of database queries needed for data retrieval. * How to use dynamic finder methods. -* How to use method chaining to use multiple ActiveRecord methods together. +* How to use method chaining to use multiple Active Record methods together. * How to check for the existence of particular records. * How to perform various calculations on Active Record models. * How to run EXPLAIN on relations. @@ -25,7 +25,7 @@ Code examples throughout this guide will refer to one or more of the following m TIP: All of the following models use `id` as the primary key, unless specified otherwise. ```ruby -class Client < ActiveRecord::Base +class Client < ApplicationRecord has_one :address has_many :orders has_and_belongs_to_many :roles @@ -33,24 +33,24 @@ end ``` ```ruby -class Address < ActiveRecord::Base +class Address < ApplicationRecord belongs_to :client end ``` ```ruby -class Order < ActiveRecord::Base +class Order < ApplicationRecord belongs_to :client, counter_cache: true end ``` ```ruby -class Role < ActiveRecord::Base +class Role < ApplicationRecord has_and_belongs_to_many :clients end ``` -Active Record will perform queries on the database for you and is compatible with most database systems (MySQL, PostgreSQL and SQLite to name a few). Regardless of which database system you're using, the Active Record method format will always be the same. +Active Record will perform queries on the database for you and is compatible with most database systems, including MySQL, MariaDB, PostgreSQL and SQLite. Regardless of which database system you're using, the Active Record method format will always be the same. Retrieving Objects from the Database ------------------------------------ @@ -59,7 +59,7 @@ To retrieve objects from the database, Active Record provides several finder met The methods are: -* `bind` +* `find` * `create_with` * `distinct` * `eager_load` @@ -153,9 +153,9 @@ You can pass in a numerical argument to the `take` method to return up to that n ```ruby client = Client.take(2) # => [ - #<Client id: 1, first_name: "Lifo">, - #<Client id: 220, first_name: "Sara"> -] +# #<Client id: 1, first_name: "Lifo">, +# #<Client id: 220, first_name: "Sara"> +# ] ``` The SQL equivalent of the above is: @@ -170,7 +170,7 @@ TIP: The retrieved record may vary depending on the database engine. #### `first` -The `first` method finds the first record ordered by the primary key. For example: +The `first` method finds the first record ordered by primary key (default). For example: ```ruby client = Client.first @@ -192,10 +192,10 @@ You can pass in a numerical argument to the `first` method to return up to that ```ruby client = Client.first(3) # => [ - #<Client id: 1, first_name: "Lifo">, - #<Client id: 2, first_name: "Fifo">, - #<Client id: 3, first_name: "Filo"> -] +# #<Client id: 1, first_name: "Lifo">, +# #<Client id: 2, first_name: "Fifo">, +# #<Client id: 3, first_name: "Filo"> +# ] ``` The SQL equivalent of the above is: @@ -204,11 +204,24 @@ The SQL equivalent of the above is: SELECT * FROM clients ORDER BY clients.id ASC LIMIT 3 ``` +On a collection that is ordered using `order`, `first` will return the first record ordered by the specified attribute for `order`. + +```ruby +client = Client.order(:first_name).first +# => #<Client id: 2, first_name: "Fifo"> +``` + +The SQL equivalent of the above is: + +```sql +SELECT * FROM clients ORDER BY clients.first_name ASC LIMIT 1 +``` + The `first!` method behaves exactly like `first`, except that it will raise `ActiveRecord::RecordNotFound` if no matching record is found. #### `last` -The `last` method finds the last record ordered by the primary key. For example: +The `last` method finds the last record ordered by primary key (default). For example: ```ruby client = Client.last @@ -230,10 +243,10 @@ You can pass in a numerical argument to the `last` method to return up to that n ```ruby client = Client.last(3) # => [ - #<Client id: 219, first_name: "James">, - #<Client id: 220, first_name: "Sara">, - #<Client id: 221, first_name: "Russel"> -] +# #<Client id: 219, first_name: "James">, +# #<Client id: 220, first_name: "Sara">, +# #<Client id: 221, first_name: "Russel"> +# ] ``` The SQL equivalent of the above is: @@ -242,6 +255,19 @@ The SQL equivalent of the above is: SELECT * FROM clients ORDER BY clients.id DESC LIMIT 3 ``` +On a collection that is ordered using `order`, `last` will return the last record ordered by the specified attribute for `order`. + +```ruby +client = Client.order(:first_name).last +# => #<Client id: 220, first_name: "Sara"> +``` + +The SQL equivalent of the above is: + +```sql +SELECT * FROM clients ORDER BY clients.first_name DESC LIMIT 1 +``` + The `last!` method behaves exactly like `last`, except that it will raise `ActiveRecord::RecordNotFound` if no matching record is found. #### `find_by` @@ -322,7 +348,7 @@ end The `find_each` method accepts most of the options allowed by the regular `find` method, except for `:order` and `:limit`, which are reserved for internal use by `find_each`. -Three additional options, `:batch_size`, `:begin_at` and `:end_at`, are available as well. +Three additional options, `:batch_size`, `:start` and `:finish`, are available as well. **`:batch_size`** @@ -334,34 +360,34 @@ User.find_each(batch_size: 5000) do |user| end ``` -**`:begin_at`** +**`:start`** -By default, records are fetched in ascending order of the primary key, which must be an integer. The `:begin_at` option allows you to configure the first ID of the sequence whenever the lowest ID is not the one you need. This would be useful, for example, if you wanted to resume an interrupted batch process, provided you saved the last processed ID as a checkpoint. +By default, records are fetched in ascending order of the primary key, which must be an integer. The `:start` option allows you to configure the first ID of the sequence whenever the lowest ID is not the one you need. This would be useful, for example, if you wanted to resume an interrupted batch process, provided you saved the last processed ID as a checkpoint. For example, to send newsletters only to users with the primary key starting from 2000, and to retrieve them in batches of 5000: ```ruby -User.find_each(begin_at: 2000, batch_size: 5000) do |user| +User.find_each(start: 2000, batch_size: 5000) do |user| NewsMailer.weekly(user).deliver_now end ``` -**`:end_at`** +**`:finish`** -Similar to the `:begin_at` option, `:end_at` allows you to configure the last ID of the sequence whenever the highest ID is not the one you need. -This would be useful, for example, if you wanted to run a batch process, using a subset of records based on `:begin_at` and `:end_at` +Similar to the `:start` option, `:finish` allows you to configure the last ID of the sequence whenever the highest ID is not the one you need. +This would be useful, for example, if you wanted to run a batch process, using a subset of records based on `:start` and `:finish` For example, to send newsletters only to users with the primary key starting from 2000 up to 10000 and to retrieve them in batches of 5000: ```ruby -User.find_each(begin_at: 2000, end_at: 10000, batch_size: 5000) do |user| +User.find_each(start: 2000, finish: 10000, batch_size: 5000) do |user| NewsMailer.weekly(user).deliver_now end ``` Another example would be if you wanted multiple workers handling the same processing queue. You could have each worker handle 10000 records by setting the -appropriate `:begin_at` and `:end_at` options on each worker. +appropriate `:start` and `:finish` options on each worker. #### `find_in_batches` @@ -376,7 +402,7 @@ end ##### Options for `find_in_batches` -The `find_in_batches` method accepts the same `:batch_size`, `:begin_at` and `:end_at` options as `find_each`. +The `find_in_batches` method accepts the same `:batch_size`, `:start` and `:finish` options as `find_each`. Conditions ---------- @@ -446,6 +472,12 @@ NOTE: Only equality, range and subset checking are possible with Hash conditions Client.where(locked: true) ``` +This will generate SQL like this: + +```sql +SELECT * FROM clients WHERE (clients.locked = 1) +``` + The field name can also be a string: ```ruby @@ -491,13 +523,17 @@ SELECT * FROM clients WHERE (clients.orders_count IN (1,3,5)) ### NOT Conditions -`NOT` SQL queries can be built by `where.not`. +`NOT` SQL queries can be built by `where.not`: ```ruby -Article.where.not(author: author) +Client.where.not(locked: true) ``` -In other words, this query can be generated by calling `where` with no argument, then immediately chain with `not` passing `where` conditions. +In other words, this query can be generated by calling `where` with no argument, then immediately chain with `not` passing `where` conditions. This will generate SQL like this: + +```sql +SELECT * FROM clients WHERE (clients.locked != 1) +``` Ordering -------- @@ -740,7 +776,7 @@ SELECT "articles".* FROM "articles" WHERE (id > 10) ORDER BY id desc LIMIT 20 The `reorder` method overrides the default scope order. For example: ```ruby -class Article < ActiveRecord::Base +class Article < ApplicationRecord has_many :comments, -> { order('posted_at DESC') } end @@ -889,7 +925,7 @@ This behavior can be turned off by setting `ActiveRecord::Base.lock_optimistical To override the name of the `lock_version` column, `ActiveRecord::Base` provides a class attribute called `locking_column`: ```ruby -class Client < ActiveRecord::Base +class Client < ApplicationRecord self.locking_column = :lock_client_column end ``` @@ -970,26 +1006,26 @@ Active Record lets you use the names of the [associations](association_basics.ht For example, consider the following `Category`, `Article`, `Comment`, `Guest` and `Tag` models: ```ruby -class Category < ActiveRecord::Base +class Category < ApplicationRecord has_many :articles end -class Article < ActiveRecord::Base +class Article < ApplicationRecord belongs_to :category has_many :comments has_many :tags end -class Comment < ActiveRecord::Base +class Comment < ApplicationRecord belongs_to :article has_one :guest end -class Guest < ActiveRecord::Base +class Guest < ApplicationRecord belongs_to :comment end -class Tag < ActiveRecord::Base +class Tag < ApplicationRecord belongs_to :article end ``` @@ -1059,6 +1095,8 @@ SELECT categories.* FROM categories INNER JOIN tags ON tags.article_id = articles.id ``` +Or, in English: "return all categories that have articles, where those articles have a comment made by a guest, and where those articles also have a tag." + #### Specifying Conditions on the Joined Tables You can specify conditions on the joined tables using the regular [Array](#array-conditions) and [String](#pure-string-conditions) conditions. [Hash conditions](#hash-conditions) provide a special syntax for specifying conditions for the joined tables: @@ -1083,7 +1121,7 @@ If you want to select a set of records whether or not they have associated records you can use the `left_outer_joins` method. ```ruby -Author.left_outer_joins(:posts).uniq.select('authors.*, COUNT(posts.*) AS posts_count').group('authors.id') +Author.left_outer_joins(:posts).distinct.select('authors.*, COUNT(posts.*) AS posts_count').group('authors.id') ``` Which produces: @@ -1199,7 +1237,7 @@ Scoping allows you to specify commonly-used queries which can be referenced as m To define a simple scope, we use the `scope` method inside the class, passing the query that we'd like to run when this scope is called: ```ruby -class Article < ActiveRecord::Base +class Article < ApplicationRecord scope :published, -> { where(published: true) } end ``` @@ -1207,7 +1245,7 @@ end This is exactly the same as defining a class method, and which you use is a matter of personal preference: ```ruby -class Article < ActiveRecord::Base +class Article < ApplicationRecord def self.published where(published: true) end @@ -1217,7 +1255,7 @@ end Scopes are also chainable within scopes: ```ruby -class Article < ActiveRecord::Base +class Article < ApplicationRecord scope :published, -> { where(published: true) } scope :published_and_commented, -> { published.where("comments_count > 0") } end @@ -1241,7 +1279,7 @@ category.articles.published # => [published articles belonging to this category] Your scope can take arguments: ```ruby -class Article < ActiveRecord::Base +class Article < ApplicationRecord scope :created_before, ->(time) { where("created_at < ?", time) } end ``` @@ -1255,7 +1293,7 @@ Article.created_before(Time.zone.now) However, this is just duplicating the functionality that would be provided to you by a class method. ```ruby -class Article < ActiveRecord::Base +class Article < ApplicationRecord def self.created_before(time) where("created_at < ?", time) end @@ -1268,13 +1306,35 @@ Using a class method is the preferred way to accept arguments for scopes. These category.articles.created_before(time) ``` +### Using conditionals + +Your scope can utilize conditionals: + +```ruby +class Article < ApplicationRecord + scope :created_before, ->(time) { where("created_at < ?", time) if time.present? } +end +``` + +Like the other examples, this will behave similarly to a class method. + +```ruby +class Article < ApplicationRecord + def self.created_before(time) + where("created_at < ?", time) if time.present? + end +end +``` + +However, there is one important caveat: A scope will always return an `ActiveRecord::Relation` object, even if the conditional evaluates to `false`, whereas a class method, will return `nil`. This can cause `NoMethodError` when chaining class methods with conditionals, if any of the conditionals return `false`. + ### Applying a default scope If we wish for a scope to be applied across all queries to the model we can use the `default_scope` method within the model itself. ```ruby -class Client < ActiveRecord::Base +class Client < ApplicationRecord default_scope { where("removed_at IS NULL") } end ``` @@ -1290,7 +1350,7 @@ If you need to do more complex things with a default scope, you can alternativel define it as a class method: ```ruby -class Client < ActiveRecord::Base +class Client < ApplicationRecord def self.default_scope # Should return an ActiveRecord::Relation. end @@ -1301,7 +1361,7 @@ NOTE: The `default_scope` is also applied while creating/building a record. It is not applied while updating a record. E.g.: ```ruby -class Client < ActiveRecord::Base +class Client < ApplicationRecord default_scope { where(active: true) } end @@ -1314,7 +1374,7 @@ Client.unscoped.new # => #<Client id: nil, active: nil> Just like `where` clauses scopes are merged using `AND` conditions. ```ruby -class User < ActiveRecord::Base +class User < ApplicationRecord scope :active, -> { where state: 'active' } scope :inactive, -> { where state: 'inactive' } end @@ -1343,7 +1403,7 @@ One important caveat is that `default_scope` will be prepended in `scope` and `where` conditions. ```ruby -class User < ActiveRecord::Base +class User < ApplicationRecord default_scope { where state: 'pending' } scope :active, -> { where state: 'active' } scope :inactive, -> { where state: 'inactive' } @@ -1374,8 +1434,15 @@ Client.unscoped.load This method removes all scoping and will do a normal query on the table. -Note that chaining `unscoped` with a `scope` does not work. In these cases, it is -recommended that you use the block form of `unscoped`: +```ruby +Client.unscoped.all +# SELECT "clients".* FROM "clients" + +Client.where(published: false).unscoped.all +# SELECT "clients".* FROM "clients" +``` + +`unscoped` can also accept a block. ```ruby Client.unscoped { @@ -1392,6 +1459,36 @@ You can specify an exclamation point (`!`) on the end of the dynamic finders to If you want to find both by name and locked, you can chain these finders together by simply typing "`and`" between the fields. For example, `Client.find_by_first_name_and_locked("Ryan", true)`. +Enums +----- + +The `enum` macro maps an integer column to a set of possible values. + +```ruby +class Book < ApplicationRecord + enum availability: [:available, :unavailable] +end +``` + +This will automatically create the corresponding [scopes](#scopes) to query the +model. Methods to transition between states and query the current state are also +added. + +```ruby +# Both examples below query just available books. +Book.available +# or +Book.where(availability: :available) + +book = Book.new(availability: :available) +book.available? # => true +book.unavailable! # => true +book.available? # => false +``` + +Read the full documentation about enums +[in the Rails API docs](http://api.rubyonrails.org/classes/ActiveRecord/Enum.html). + Understanding The Method Chaining --------------------------------- @@ -1526,7 +1623,7 @@ now want the client named 'Nick': ```ruby nick = Client.find_or_initialize_by(first_name: 'Nick') -# => <Client id: nil, first_name: "Nick", orders_count: 0, locked: true, created_at: "2011-08-30 06:09:27", updated_at: "2011-08-30 06:09:27"> +# => #<Client id: nil, first_name: "Nick", orders_count: 0, locked: true, created_at: "2011-08-30 06:09:27", updated_at: "2011-08-30 06:09:27"> nick.persisted? # => false @@ -1558,10 +1655,10 @@ Client.find_by_sql("SELECT * FROM clients INNER JOIN orders ON clients.id = orders.client_id ORDER BY clients.created_at desc") # => [ - #<Client id: 1, first_name: "Lucas" >, - #<Client id: 2, first_name: "Jan" >, - # ... -] +# #<Client id: 1, first_name: "Lucas" >, +# #<Client id: 2, first_name: "Jan" >, +# ... +# ] ``` `find_by_sql` provides you with a simple way of making custom calls to the database and retrieving instantiated objects. @@ -1573,9 +1670,9 @@ Client.find_by_sql("SELECT * FROM clients ```ruby Client.connection.select_all("SELECT first_name, created_at FROM clients WHERE id = '1'") # => [ - {"first_name"=>"Rafael", "created_at"=>"2012-11-10 23:23:45.281189"}, - {"first_name"=>"Eileen", "created_at"=>"2013-12-09 11:22:35.221282"} -] +# {"first_name"=>"Rafael", "created_at"=>"2012-11-10 23:23:45.281189"}, +# {"first_name"=>"Eileen", "created_at"=>"2013-12-09 11:22:35.221282"} +# ] ``` ### `pluck` @@ -1620,7 +1717,7 @@ a large or often-running query. However, any model method overrides will not be available. For example: ```ruby -class Client < ActiveRecord::Base +class Client < ApplicationRecord def name "I am #{super}" end @@ -1655,7 +1752,7 @@ Person.ids ``` ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord self.primary_key = "person_id" end @@ -1828,7 +1925,7 @@ EXPLAIN for: SELECT `users`.* FROM `users` INNER JOIN `articles` ON `articles`.` 2 rows in set (0.00 sec) ``` -under MySQL. +under MySQL and MariaDB. Active Record performs a pretty printing that emulates that of the corresponding database shell. So, the same query running with the @@ -1888,7 +1985,7 @@ EXPLAIN for: SELECT `articles`.* FROM `articles` WHERE `articles`.`user_id` IN 1 row in set (0.00 sec) ``` -under MySQL. +under MySQL and MariaDB. ### Interpreting EXPLAIN @@ -1899,4 +1996,6 @@ following pointers may be helpful: * MySQL: [EXPLAIN Output Format](http://dev.mysql.com/doc/refman/5.7/en/explain-output.html) +* MariaDB: [EXPLAIN](https://mariadb.com/kb/en/mariadb/explain/) + * PostgreSQL: [Using EXPLAIN](http://www.postgresql.org/docs/current/static/using-explain.html) diff --git a/guides/source/active_record_validations.md b/guides/source/active_record_validations.md index fe42cec158..936d6a30b8 100644 --- a/guides/source/active_record_validations.md +++ b/guides/source/active_record_validations.md @@ -20,7 +20,7 @@ Validations Overview Here's an example of a very simple validation: ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord validates :name, presence: true end @@ -80,7 +80,7 @@ method to determine whether an object is already in the database or not. Consider the following simple Active Record class: ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord end ``` @@ -149,7 +149,7 @@ false` as an argument. This technique should be used with caution. ### `valid?` and `invalid?` -Before saving an ActiveRecord object, Rails runs your validations. +Before saving an Active Record object, Rails runs your validations. If these validations produce any errors, Rails does not save the object. You can also run these validations on your own. `valid?` triggers your validations @@ -157,7 +157,7 @@ and returns true if no errors were found in the object, and false otherwise. As you saw above: ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord validates :name, presence: true end @@ -175,7 +175,7 @@ even if it's technically invalid, because validations are automatically run only when the object is saved, such as with the `create` or `save` methods. ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord validates :name, presence: true end @@ -221,7 +221,7 @@ it doesn't verify the validity of the object as a whole. It only checks to see whether there are errors found on an individual attribute of the object. ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord validates :name, presence: true end @@ -239,7 +239,7 @@ To check which validations failed on an invalid attribute, you can use key to get the symbol of the validator: ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord validates :name, presence: true end @@ -278,30 +278,39 @@ form was submitted. This is typically used when the user needs to agree to your application's terms of service, confirm that some text is read, or any similar concept. -This validation is very specific to web applications and this -'acceptance' does not need to be recorded anywhere in your database. If you -don't have a field for it, the helper will just create a virtual attribute. If -the field does exist in your database, the `accept` option must be set to -`true` or else the validation will not run. - ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord validates :terms_of_service, acceptance: true end ``` This check is performed only if `terms_of_service` is not `nil`. The default error message for this helper is _"must be accepted"_. +You can also pass custom message via the `message` option. -It can receive an `:accept` option, which determines the value that will be -considered acceptance. It defaults to "1" and can be easily changed. +```ruby +class Person < ApplicationRecord + validates :terms_of_service, acceptance: true, message: 'must be abided' +end +``` + +It can also receive an `:accept` option, which determines the allowed values +that will be considered as accepted. It defaults to `['1', true]` and can be +easily changed. ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord validates :terms_of_service, acceptance: { accept: 'yes' } + validates :eula, acceptance: { accept: ['TRUE', 'accepted'] } end ``` +This validation is very specific to web applications and this +'acceptance' does not need to be recorded anywhere in your database. If you +don't have a field for it, the helper will just create a virtual attribute. If +the field does exist in your database, the `accept` option must be set to +or include `true` or else the validation will not run. + ### `validates_associated` You should use this helper when your model has associations with other models @@ -309,7 +318,7 @@ and they also need to be validated. When you try to save your object, `valid?` will be called upon each one of the associated objects. ```ruby -class Library < ActiveRecord::Base +class Library < ApplicationRecord has_many :books validates_associated :books end @@ -332,7 +341,7 @@ or a password. This validation creates a virtual attribute whose name is the name of the field that has to be confirmed with "_confirmation" appended. ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord validates :email, confirmation: true end ``` @@ -349,7 +358,7 @@ confirmation, make sure to add a presence check for the confirmation attribute (we'll take a look at `presence` later on in this guide): ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord validates :email, confirmation: true validates :email_confirmation, presence: true end @@ -360,7 +369,7 @@ confirmation constraint will be case sensitive or not. This option defaults to true. ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord validates :email, confirmation: { case_sensitive: false } end ``` @@ -373,7 +382,7 @@ This helper validates that the attributes' values are not included in a given set. In fact, this set can be any enumerable object. ```ruby -class Account < ActiveRecord::Base +class Account < ApplicationRecord validates :subdomain, exclusion: { in: %w(www us ca jp), message: "%{value} is reserved." } end @@ -393,7 +402,7 @@ This helper validates the attributes' values by testing whether they match a given regular expression, which is specified using the `:with` option. ```ruby -class Product < ActiveRecord::Base +class Product < ApplicationRecord validates :legacy_code, format: { with: /\A[a-zA-Z]+\z/, message: "only allows letters" } end @@ -409,7 +418,7 @@ This helper validates that the attributes' values are included in a given set. In fact, this set can be any enumerable object. ```ruby -class Coffee < ActiveRecord::Base +class Coffee < ApplicationRecord validates :size, inclusion: { in: %w(small medium large), message: "%{value} is not a valid size" } end @@ -428,7 +437,7 @@ This helper validates the length of the attributes' values. It provides a variety of options, so you can specify length constraints in different ways: ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord validates :name, length: { minimum: 2 } validates :bio, length: { maximum: 500 } validates :password, length: { in: 6..20 } @@ -451,7 +460,7 @@ number corresponding to the length constraint being used. You can still use the `:message` option to specify an error message. ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord validates :bio, length: { maximum: 1000, too_long: "%{count} characters is the maximum allowed" } end @@ -483,7 +492,7 @@ WARNING. Note that the regular expression above allows a trailing newline character. ```ruby -class Player < ActiveRecord::Base +class Player < ApplicationRecord validates :points, numericality: true validates :games_played, numericality: { only_integer: true } end @@ -505,6 +514,8 @@ constraints to acceptable values: * `:less_than_or_equal_to` - Specifies the value must be less than or equal to the supplied value. The default error message for this option is _"must be less than or equal to %{count}"_. +* `:other_than` - Specifies the value must be other than the supplied value. + The default error message for this option is _"must be other than %{count}"_. * `:odd` - Specifies the value must be an odd number if set to true. The default error message for this option is _"must be odd"_. * `:even` - Specifies the value must be an even number if set to true. The @@ -521,7 +532,7 @@ This helper validates that the specified attributes are not empty. It uses the is, a string that is either empty or consists of whitespace. ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord validates :name, :login, :email, presence: true end ``` @@ -531,7 +542,7 @@ whether the associated object itself is present, and not the foreign key used to map the association. ```ruby -class LineItem < ActiveRecord::Base +class LineItem < ApplicationRecord belongs_to :order validates :order, presence: true end @@ -541,7 +552,7 @@ In order to validate associated records whose presence is required, you must specify the `:inverse_of` option for the association: ```ruby -class Order < ActiveRecord::Base +class Order < ApplicationRecord has_many :line_items, inverse_of: :order end ``` @@ -568,7 +579,7 @@ This helper validates that the specified attributes are absent. It uses the is, a string that is either empty or consists of whitespace. ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord validates :name, :login, :email, absence: true end ``` @@ -578,7 +589,7 @@ whether the associated object itself is absent, and not the foreign key used to map the association. ```ruby -class LineItem < ActiveRecord::Base +class LineItem < ApplicationRecord belongs_to :order validates :order, absence: true end @@ -588,7 +599,7 @@ In order to validate associated records whose absence is required, you must specify the `:inverse_of` option for the association: ```ruby -class Order < ActiveRecord::Base +class Order < ApplicationRecord has_many :line_items, inverse_of: :order end ``` @@ -611,7 +622,7 @@ with the same value for a column that you intend to be unique. To avoid that, you must create a unique index on that column in your database. ```ruby -class Account < ActiveRecord::Base +class Account < ApplicationRecord validates :email, uniqueness: true end ``` @@ -623,7 +634,7 @@ There is a `:scope` option that you can use to specify one or more attributes th are used to limit the uniqueness check: ```ruby -class Holiday < ActiveRecord::Base +class Holiday < ApplicationRecord validates :name, uniqueness: { scope: :year, message: "should happen once per year" } end @@ -635,7 +646,7 @@ uniqueness constraint will be case sensitive or not. This option defaults to true. ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord validates :name, uniqueness: { case_sensitive: false } end ``` @@ -658,7 +669,7 @@ class GoodnessValidator < ActiveModel::Validator end end -class Person < ActiveRecord::Base +class Person < ApplicationRecord validates_with GoodnessValidator end ``` @@ -686,7 +697,7 @@ class GoodnessValidator < ActiveModel::Validator end end -class Person < ActiveRecord::Base +class Person < ApplicationRecord validates_with GoodnessValidator, fields: [:first_name, :last_name] end ``` @@ -699,7 +710,7 @@ If your validator is complex enough that you want instance variables, you can easily use a plain old Ruby object instead: ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord validate do |person| GoodnessValidator.new(person).validate end @@ -728,7 +739,7 @@ passed to `validates_each` will be tested against it. In the following example, we don't want names and surnames to begin with lower case. ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord validates_each :name, :surname do |record, attr, value| record.errors.add(attr, 'must start with upper case') if value =~ /\A[[:lower:]]/ end @@ -751,7 +762,7 @@ The `:allow_nil` option skips the validation when the value being validated is `nil`. ```ruby -class Coffee < ActiveRecord::Base +class Coffee < ApplicationRecord validates :size, inclusion: { in: %w(small medium large), message: "%{value} is not a valid size" }, allow_nil: true end @@ -764,7 +775,7 @@ will let validation pass if the attribute's value is `blank?`, like `nil` or an empty string for example. ```ruby -class Topic < ActiveRecord::Base +class Topic < ApplicationRecord validates :title, length: { is: 5 }, allow_blank: true end @@ -777,7 +788,36 @@ Topic.create(title: nil).valid? # => true As you've already seen, the `:message` option lets you specify the message that will be added to the `errors` collection when validation fails. When this option is not used, Active Record will use the respective default error message -for each validation helper. +for each validation helper. The `:message` option accepts a `String` or `Proc`. + +A `String` `:message` value can optionally contain any/all of `%{value}`, +`%{attribute}`, and `%{model}` which will be dynamically replaced when +validation fails. + +A `Proc` `:message` value is given two arguments: the object being validated, and +a hash with `:model`, `:attribute`, and `:value` key-value pairs. + +```ruby +class Person < ApplicationRecord + # Hard-coded message + validates :name, presence: { message: "must be given please" } + + # Message with dynamic attribute value. %{value} will be replaced with + # the actual value of the attribute. %{attribute} and %{model} also + # available. + validates :age, numericality: { message: "%{value} seems wrong" } + + # Proc + validates :username, + uniqueness: { + # object = person object being validated + # data = { model: "Person", attribute: "Username", value: <username> } + message: ->(object, data) do + "Hey #{object.name}!, #{data[:value]} is taken already! Try again #{Time.zone.tomorrow}" + end + } +end +``` ### `:on` @@ -789,7 +829,7 @@ new record is created or `on: :update` to run the validation only when a record is updated. ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord # it will be possible to update email with a duplicated value validates :email, uniqueness: true, on: :create @@ -801,6 +841,25 @@ class Person < ActiveRecord::Base end ``` +You can also use `on:` to define custom context. +Custom contexts need to be triggered explicitly +by passing name of the context to `valid?`, `invalid?` or `save`. + +```ruby +class Person < ApplicationRecord + validates :email, uniqueness: true, on: :account_setup + validates :age, numericality: true, on: :account_setup +end + +person = Person.new +``` + +`person.valid?(:account_setup)` executes both the validations +without saving the model. And `person.save(context: :account_setup)` +validates `person` in `account_setup` context before saving. +On explicit triggers, model is validated by +validations of only that context and validations without context. + Strict Validations ------------------ @@ -808,7 +867,7 @@ You can also specify validations to be strict and raise `ActiveModel::StrictValidationFailed` when the object is invalid. ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord validates :name, presence: { strict: true } end @@ -818,7 +877,7 @@ Person.new.valid? # => ActiveModel::StrictValidationFailed: Name can't be blank There is also the ability to pass a custom exception to the `:strict` option. ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord validates :token, presence: true, uniqueness: true, strict: TokenGenerationException end @@ -842,7 +901,7 @@ to the name of a method that will get called right before validation happens. This is the most commonly used option. ```ruby -class Order < ActiveRecord::Base +class Order < ApplicationRecord validates :card_number, presence: true, if: :paid_with_card? def paid_with_card? @@ -858,7 +917,7 @@ contain valid Ruby code. You should use this option only when the string represents a really short condition. ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord validates :surname, presence: true, if: "name.nil?" end ``` @@ -871,7 +930,7 @@ inline condition instead of a separate method. This option is best suited for one-liners. ```ruby -class Account < ActiveRecord::Base +class Account < ApplicationRecord validates :password, confirmation: true, unless: Proc.new { |a| a.password.blank? } end @@ -883,7 +942,7 @@ Sometimes it is useful to have multiple validations use one condition. It can be easily achieved using `with_options`. ```ruby -class User < ActiveRecord::Base +class User < ApplicationRecord with_options if: :is_admin? do |admin| admin.validates :password, length: { minimum: 10 } admin.validates :email, presence: true @@ -901,7 +960,7 @@ should happen, an `Array` can be used. Moreover, you can apply both `:if` and `:unless` to the same validation. ```ruby -class Computer < ActiveRecord::Base +class Computer < ApplicationRecord validates :mouse, presence: true, if: ["market.retail?", :desktop?], unless: Proc.new { |c| c.trackpad.present? } @@ -955,7 +1014,7 @@ class EmailValidator < ActiveModel::EachValidator end end -class Person < ActiveRecord::Base +class Person < ApplicationRecord validates :email, presence: true, email: true end ``` @@ -979,7 +1038,7 @@ so your custom validation methods should add errors to it when you wish validation to fail: ```ruby -class Invoice < ActiveRecord::Base +class Invoice < ApplicationRecord validate :expiration_date_cannot_be_in_the_past, :discount_cannot_be_greater_than_total_value @@ -1003,7 +1062,7 @@ custom validations by giving an `:on` option to the `validate` method, with either: `:create` or `:update`. ```ruby -class Invoice < ActiveRecord::Base +class Invoice < ApplicationRecord validate :active_customer, on: :create def active_customer @@ -1024,7 +1083,7 @@ The following is a list of the most commonly used methods. Please refer to the ` Returns an instance of the class `ActiveModel::Errors` containing all errors. Each key is the attribute name and the value is an array of strings with all errors. ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord validates :name, presence: true, length: { minimum: 3 } end @@ -1043,7 +1102,7 @@ person.errors.messages # => {} `errors[]` is used when you want to check the error messages for a specific attribute. It returns an array of strings with all error messages for the given attribute, each string with one error message. If there are no errors related to the attribute, it returns an empty array. ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord validates :name, presence: true, length: { minimum: 3 } end @@ -1068,7 +1127,7 @@ The `add` method lets you add an error message related to a particular attribute The `errors.full_messages` method (or its equivalent, `errors.to_a`) returns the error messages in a user-friendly format, with the capitalized attribute name prepended to each message, as shown in the examples below. ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord def a_method_used_for_validation_purposes errors.add(:name, "cannot contain the characters !@#%*()_-+=") end @@ -1086,7 +1145,7 @@ person.errors.full_messages An equivalent to `errors#add` is to use `<<` to append a message to the `errors.messages` array for an attribute: ```ruby - class Person < ActiveRecord::Base + class Person < ApplicationRecord def a_method_used_for_validation_purposes errors.messages[:name] << "cannot contain the characters !@#%*()_-+=" end @@ -1107,7 +1166,7 @@ You can specify a validator type to the returned error details hash using the `errors.add` method. ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord def a_method_used_for_validation_purposes errors.add(:name, :invalid_characters) end @@ -1123,7 +1182,7 @@ To improve the error details to contain the unallowed characters set for instanc you can pass additional keys to `errors.add`. ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord def a_method_used_for_validation_purposes errors.add(:name, :invalid_characters, not_allowed: "!@#%*()_-+=") end @@ -1143,7 +1202,7 @@ validator type. You can add error messages that are related to the object's state as a whole, instead of being related to a specific attribute. You can use this method when you want to say that the object is invalid, no matter the values of its attributes. Since `errors[:base]` is an array, you can simply add a string to it and it will be used as an error message. ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord def a_method_used_for_validation_purposes errors[:base] << "This person is invalid because ..." end @@ -1155,7 +1214,7 @@ end The `clear` method is used when you intentionally want to clear all the messages in the `errors` collection. Of course, calling `errors.clear` upon an invalid object won't actually make it valid: the `errors` collection will now be empty, but the next time you call `valid?` or any method that tries to save this object to the database, the validations will run again. If any of the validations fail, the `errors` collection will be filled again. ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord validates :name, presence: true, length: { minimum: 3 } end @@ -1167,9 +1226,9 @@ person.errors[:name] person.errors.clear person.errors.empty? # => true -p.save # => false +person.save # => false -p.errors[:name] +person.errors[:name] # => ["can't be blank", "is too short (minimum is 3 characters)"] ``` @@ -1178,7 +1237,7 @@ p.errors[:name] The `size` method returns the total number of error messages for the object. ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord validates :name, presence: true, length: { minimum: 3 } end diff --git a/guides/source/active_support_core_extensions.md b/guides/source/active_support_core_extensions.md index 181dca4b71..565c87c4b5 100644 --- a/guides/source/active_support_core_extensions.md +++ b/guides/source/active_support_core_extensions.md @@ -252,7 +252,7 @@ Note that `try` will swallow no-method errors, returning nil instead. If you wan ```ruby @number.try(:nest) # => nil -@number.try!(:nest) # NoMethodError: undefined method `nest' for 1:Fixnum +@number.try!(:nest) # NoMethodError: undefined method `nest' for 1:Integer ``` NOTE: Defined in `active_support/core_ext/object/try.rb`. @@ -397,7 +397,7 @@ The method `with_options` provides a way to factor out common options in a serie Given a default options hash, `with_options` yields a proxy object to a block. Within the block, methods called on the proxy are forwarded to the receiver with their options merged. For example, you get rid of the duplication in: ```ruby -class Account < ActiveRecord::Base +class Account < ApplicationRecord has_many :customers, dependent: :destroy has_many :products, dependent: :destroy has_many :invoices, dependent: :destroy @@ -408,7 +408,7 @@ end this way: ```ruby -class Account < ActiveRecord::Base +class Account < ApplicationRecord with_options dependent: :destroy do |assoc| assoc.has_many :customers assoc.has_many :products @@ -517,17 +517,17 @@ Extensions to `Module` Using plain Ruby you can wrap methods with other methods, that's called _alias chaining_. -For example, let's say you'd like params to be strings in functional tests, as they are in real requests, but still want the convenience of assigning integers and other kind of values. To accomplish that you could wrap `ActionController::TestCase#process` this way in `test/test_helper.rb`: +For example, let's say you'd like params to be strings in functional tests, as they are in real requests, but still want the convenience of assigning integers and other kind of values. To accomplish that you could wrap `ActionDispatch::IntegrationTest#process` this way in `test/test_helper.rb`: ```ruby -ActionController::TestCase.class_eval do +ActionDispatch::IntegrationTest.class_eval do # save a reference to the original process method alias_method :original_process, :process # now redefine process and delegate to original_process - def process(action, params=nil, session=nil, flash=nil, http_method='GET') + def process('GET', path, params: nil, headers: nil, env: nil, xhr: false) params = Hash[*params.map {|k, v| [k, v.to_s]}.flatten] - original_process(action, params, session, flash, http_method) + original_process('GET', path, params: params) end end ``` @@ -537,10 +537,10 @@ That's the method `get`, `post`, etc., delegate the work to. That technique has a risk, it could be the case that `:original_process` was taken. To try to avoid collisions people choose some label that characterizes what the chaining is about: ```ruby -ActionController::TestCase.class_eval do +ActionDispatch::IntegrationTest.class_eval do def process_with_stringified_params(...) params = Hash[*params.map {|k, v| [k, v.to_s]}.flatten] - process_without_stringified_params(action, params, session, flash, http_method) + process_without_stringified_params(method, path, params: params) end alias_method :process_without_stringified_params, :process alias_method :process, :process_with_stringified_params @@ -550,10 +550,10 @@ end The method `alias_method_chain` provides a shortcut for that pattern: ```ruby -ActionController::TestCase.class_eval do +ActionDispatch::IntegrationTest.class_eval do def process_with_stringified_params(...) params = Hash[*params.map {|k, v| [k, v.to_s]}.flatten] - process_without_stringified_params(action, params, session, flash, http_method) + process_without_stringified_params(method, path, params: params) end alias_method_chain :process, :stringified_params end @@ -568,7 +568,7 @@ NOTE: Defined in `active_support/core_ext/module/aliasing.rb`. Model attributes have a reader, a writer, and a predicate. You can alias a model attribute having the corresponding three methods defined for you in one shot. As in other aliasing methods, the new name is the first argument, and the old name is the second (one mnemonic is that they go in the same order as if you did an assignment): ```ruby -class User < ActiveRecord::Base +class User < ApplicationRecord # You can refer to the email column as "login". # This can be meaningful for authentication code. alias_attribute :login, :email @@ -632,8 +632,6 @@ module ActiveSupport mattr_accessor :load_once_paths mattr_accessor :autoloaded_constants mattr_accessor :explicitly_unloadable_constants - mattr_accessor :logger - mattr_accessor :log_activity mattr_accessor :constant_watch_stack mattr_accessor :constant_watch_stack_mutex end @@ -709,87 +707,6 @@ M.parents # => [X::Y, X, Object] NOTE: Defined in `active_support/core_ext/module/introspection.rb`. -### Constants - -The method `local_constants` returns the names of the constants that have been -defined in the receiver module: - -```ruby -module X - X1 = 1 - X2 = 2 - module Y - Y1 = :y1 - X1 = :overrides_X1_above - end -end - -X.local_constants # => [:X1, :X2, :Y] -X::Y.local_constants # => [:Y1, :X1] -``` - -The names are returned as symbols. - -NOTE: Defined in `active_support/core_ext/module/introspection.rb`. - -#### Qualified Constant Names - -The standard methods `const_defined?`, `const_get`, and `const_set` accept -bare constant names. Active Support extends this API to be able to pass -relative qualified constant names. - -The new methods are `qualified_const_defined?`, `qualified_const_get`, and -`qualified_const_set`. Their arguments are assumed to be qualified constant -names relative to their receiver: - -```ruby -Object.qualified_const_defined?("Math::PI") # => true -Object.qualified_const_get("Math::PI") # => 3.141592653589793 -Object.qualified_const_set("Math::Phi", 1.618034) # => 1.618034 -``` - -Arguments may be bare constant names: - -```ruby -Math.qualified_const_get("E") # => 2.718281828459045 -``` - -These methods are analogous to their built-in counterparts. In particular, -`qualified_constant_defined?` accepts an optional second argument to be -able to say whether you want the predicate to look in the ancestors. -This flag is taken into account for each constant in the expression while -walking down the path. - -For example, given - -```ruby -module M - X = 1 -end - -module N - class C - include M - end -end -``` - -`qualified_const_defined?` behaves this way: - -```ruby -N.qualified_const_defined?("C::X", false) # => false -N.qualified_const_defined?("C::X", true) # => true -N.qualified_const_defined?("C::X") # => true -``` - -As the last example implies, the second argument defaults to true, -as in `const_defined?`. - -For coherence with the built-in methods only relative paths are accepted. -Absolute qualified constant names like `::Math::PI` raise `NameError`. - -NOTE: Defined in `active_support/core_ext/module/qualified_const.rb`. - ### Reachable A named module is reachable if it is stored in its corresponding constant. It means you can reach the module object via the constant. @@ -876,7 +793,7 @@ The macro `delegate` offers an easy way to forward methods. Let's imagine that users in some application have login information in the `User` model but name and other data in a separate `Profile` model: ```ruby -class User < ActiveRecord::Base +class User < ApplicationRecord has_one :profile end ``` @@ -884,7 +801,7 @@ end With that configuration you get a user's name via their profile, `user.profile.name`, but it could be handy to still be able to access such attribute directly: ```ruby -class User < ActiveRecord::Base +class User < ApplicationRecord has_one :profile def name @@ -896,7 +813,7 @@ end That is what `delegate` does for you: ```ruby -class User < ActiveRecord::Base +class User < ApplicationRecord has_one :profile delegate :name, to: :profile @@ -1686,19 +1603,6 @@ Given a string with a qualified constant reference expression, `deconstantize` r "Admin::Hotel::ReservationUtils".deconstantize # => "Admin::Hotel" ``` -Active Support for example uses this method in `Module#qualified_const_set`: - -```ruby -def qualified_const_set(path, value) - QualifiedConstUtils.raise_if_absolute(path) - - const_name = path.demodulize - mod_name = path.deconstantize - mod = mod_name.empty? ? self : qualified_const_get(mod_name) - mod.const_set(const_name, value) -end -``` - NOTE: Defined in `active_support/core_ext/string/inflections.rb`. #### `parameterize` @@ -1767,7 +1671,7 @@ NOTE: Defined in `active_support/core_ext/string/inflections.rb`. The method `constantize` resolves the constant reference expression in its receiver: ```ruby -"Fixnum".constantize # => Fixnum +"Integer".constantize # => Integer module M X = 1 @@ -2024,12 +1928,14 @@ Produce a string representation of a number rounded to a precision: Produce a string representation of a number as a human-readable number of bytes: ```ruby -123.to_s(:human_size) # => 123 Bytes -1234.to_s(:human_size) # => 1.21 KB -12345.to_s(:human_size) # => 12.1 KB -1234567.to_s(:human_size) # => 1.18 MB -1234567890.to_s(:human_size) # => 1.15 GB -1234567890123.to_s(:human_size) # => 1.12 TB +123.to_s(:human_size) # => 123 Bytes +1234.to_s(:human_size) # => 1.21 KB +12345.to_s(:human_size) # => 12.1 KB +1234567.to_s(:human_size) # => 1.18 MB +1234567890.to_s(:human_size) # => 1.15 GB +1234567890123.to_s(:human_size) # => 1.12 TB +1234567890123456.to_s(:human_size) # => 1.1 PB +1234567890123456789.to_s(:human_size) # => 1.07 EB ``` Produce a string representation of a number in human-readable words: @@ -2238,7 +2144,7 @@ Similarly, `from` returns the tail from the element at the passed index to the e [].from(0) # => [] ``` -The methods `second`, `third`, `fourth`, and `fifth` return the corresponding element (`first` is built-in). Thanks to social wisdom and positive constructiveness all around, `forty_two` is also available. +The methods `second`, `third`, `fourth`, and `fifth` return the corresponding element, as do `second_to_last` and `third_to_last` (`first` and `last` are built-in). Thanks to social wisdom and positive constructiveness all around, `forty_two` is also available. ```ruby %w(a b c d).third # => "c" @@ -2372,7 +2278,7 @@ Contributor.limit(2).order(:rank).to_xml To do so it sends `to_xml` to every item in turn, and collects the results under a root node. All items must respond to `to_xml`, an exception is raised otherwise. -By default, the name of the root element is the underscorized and dasherized plural of the name of the class of the first item, provided the rest of elements belong to that type (checked with `is_a?`) and they are not hashes. In the example above that's "contributors". +By default, the name of the root element is the underscored and dasherized plural of the name of the class of the first item, provided the rest of elements belong to that type (checked with `is_a?`) and they are not hashes. In the example above that's "contributors". If there's any element that does not belong to the type of the first one the root node becomes "objects": @@ -2634,8 +2540,7 @@ To do so, the method loops over the pairs and builds nodes that depend on the _v ```ruby XML_TYPE_NAMES = { "Symbol" => "symbol", - "Fixnum" => "integer", - "Bignum" => "integer", + "Integer" => "integer", "BigDecimal" => "decimal", "Float" => "float", "TrueClass" => "boolean", @@ -3076,7 +2981,7 @@ INFO: The following calculation methods have edge cases in October 1582, since d #### `Date.current` -Active Support defines `Date.current` to be today in the current time zone. That's like `Date.today`, except that it honors the user time zone, if defined. It also defines `Date.yesterday` and `Date.tomorrow`, and the instance predicates `past?`, `today?`, and `future?`, all of them relative to `Date.current`. +Active Support defines `Date.current` to be today in the current time zone. That's like `Date.today`, except that it honors the user time zone, if defined. It also defines `Date.yesterday` and `Date.tomorrow`, and the instance predicates `past?`, `today?`, `future?`, `on_weekday?` and `on_weekend?`, all of them relative to `Date.current`. When making Date comparisons using methods which honor the user time zone, make sure to use `Date.current` and not `Date.today`. There are cases where the user time zone might be in the future compared to the system time zone, which `Date.today` uses by default. This means `Date.today` may equal `Date.yesterday`. @@ -3465,6 +3370,8 @@ years_ago years_since prev_year (last_year) next_year +on_weekday? +on_weekend? ``` The following methods are reimplemented so you do **not** need to load `active_support/core_ext/date/calculations.rb` for these ones: @@ -3651,6 +3558,8 @@ years_ago years_since prev_year (last_year) next_year +on_weekday? +on_weekend? ``` They are analogous. Please refer to their documentation above and take into account the following differences: diff --git a/guides/source/active_support_instrumentation.md b/guides/source/active_support_instrumentation.md index 0fd0112c9f..03af3cf819 100644 --- a/guides/source/active_support_instrumentation.md +++ b/guides/source/active_support_instrumentation.md @@ -112,6 +112,7 @@ Action Controller | `:controller` | The controller name | | `:action` | The action | | `:params` | Hash of request parameters without any filtered parameter | +| `:headers` | Request headers | | `:format` | html/js/json/xml etc | | `:method` | HTTP request verb | | `:path` | Request path | @@ -121,6 +122,7 @@ Action Controller controller: "PostsController", action: "new", params: { "action" => "new", "controller" => "posts" }, + headers: #<ActionDispatch::Http::Headers:0x0055a67a519b88>, format: :html, method: "GET", path: "/posts/new" @@ -134,6 +136,7 @@ Action Controller | `:controller` | The controller name | | `:action` | The action | | `:params` | Hash of request parameters without any filtered parameter | +| `:headers` | Request headers | | `:format` | html/js/json/xml etc | | `:method` | HTTP request verb | | `:path` | Request path | @@ -146,6 +149,7 @@ Action Controller controller: "PostsController", action: "index", params: {"action" => "index", "controller" => "posts"}, + headers: #<ActionDispatch::Http::Headers:0x0055a67a519b88>, format: :html, method: "GET", path: "/posts", diff --git a/guides/source/api_app.md b/guides/source/api_app.md index feaaff166a..485294dc02 100644 --- a/guides/source/api_app.md +++ b/guides/source/api_app.md @@ -8,13 +8,13 @@ In this guide you will learn: * What Rails provides for API-only applications * How to configure Rails to start without any browser features -* How to decide which middlewares you will want to include +* How to decide which middleware you will want to include * How to decide which modules to use in your controller -------------------------------------------------------------------------------- -What is an API app? -------------------- +What is an API Application? +--------------------------- Traditionally, when people said that they used Rails as an "API", they meant providing a programmatically accessible API alongside their web application. @@ -28,15 +28,14 @@ applications. For example, Twitter uses its [public API](https://dev.twitter.com) in its web application, which is built as a static site that consumes JSON resources. -Instead of using Rails to generate dynamic HTML that will communicate with the -server through forms and links, many developers are treating their web application -as just another client, delivered as static HTML, CSS and JavaScript consuming -a simple JSON API. +Instead of using Rails to generate HTML that communicates with the server +through forms and links, many developers are treating their web application as +just an API client delivered as HTML with JavaScript that consumes a JSON API. This guide covers building a Rails application that serves JSON resources to an -API client **or** a client-side framework. +API client, including client-side frameworks. -Why use Rails for JSON APIs? +Why Use Rails for JSON APIs? ---------------------------- The first question a lot of people have when thinking about building a JSON API @@ -44,11 +43,11 @@ using Rails is: "isn't using Rails to spit out some JSON overkill? Shouldn't I just use something like Sinatra?". For very simple APIs, this may be true. However, even in very HTML-heavy -applications, most of an application's logic is actually outside of the view +applications, most of an application's logic lives outside of the view layer. The reason most people use Rails is that it provides a set of defaults that -allows us to get up and running quickly without having to make a lot of trivial +allows developers to get up and running quickly, without having to make a lot of trivial decisions. Let's take a look at some of the things that Rails provides out of the box that are @@ -75,18 +74,16 @@ Handled at the middleware layer: URL-encoded String? No problem. Rails will decode the JSON for you and make it available in `params`. Want to use nested URL-encoded parameters? That works too. -- Conditional GETs: Rails handles conditional `GET`, (`ETag` and `Last-Modified`), +- Conditional GETs: Rails handles conditional `GET` (`ETag` and `Last-Modified`) processing request headers and returning the correct response headers and status code. All you need to do is use the [`stale?`](http://api.rubyonrails.org/classes/ActionController/ConditionalGet.html#method-i-stale-3F) check in your controller, and Rails will handle all of the HTTP details for you. -- Caching: If you use `dirty?` with public cache control, Rails will automatically - cache your responses. You can easily configure the cache store. - HEAD requests: Rails will transparently convert `HEAD` requests into `GET` ones, and return just the headers on the way out. This makes `HEAD` work reliably in all Rails APIs. -While you could obviously build these up in terms of existing Rack middlewares, +While you could obviously build these up in terms of existing Rack middleware, this list demonstrates that the default Rails middleware stack provides a lot of value, even if you're "just generating JSON". @@ -97,28 +94,28 @@ Handled at the Action Pack layer: means not having to spend time thinking about how to model your API in terms of HTTP. - URL Generation: The flip side of routing is URL generation. A good API based - on HTTP includes URLs (see [the GitHub gist API](http://developer.github.com/v3/gists/) + on HTTP includes URLs (see [the GitHub Gist API](http://developer.github.com/v3/gists/) for an example). - Header and Redirection Responses: `head :no_content` and `redirect_to user_url(current_user)` come in handy. Sure, you could manually add the response headers, but why? - Caching: Rails provides page, action and fragment caching. Fragment caching is especially helpful when building up a nested JSON object. -- Basic, Digest and Token Authentication: Rails comes with out-of-the-box support +- Basic, Digest, and Token Authentication: Rails comes with out-of-the-box support for three kinds of HTTP authentication. -- Instrumentation: Rails has an instrumentation API that will trigger registered +- Instrumentation: Rails has an instrumentation API that triggers registered handlers for a variety of events, such as action processing, sending a file or data, redirection, and database queries. The payload of each event comes with relevant information (for the action processing event, the payload includes the controller, action, parameters, request format, request method and the request's full path). -- Generators: This may be passé for advanced Rails users, but it can be nice to - generate a resource and get your model, controller, test stubs, and routes - created for you in a single command. +- Generators: It is often handy to generate a resource and get your model, + controller, test stubs, and routes created for you in a single command for + further tweaking. Same for migrations and others. - Plugins: Many third-party libraries come with support for Rails that reduce or eliminate the cost of setting up and gluing together the library and the web framework. This includes things like overriding default generators, adding - rake tasks, and honoring Rails choices (like the logger and cache back-end). + Rake tasks, and honoring Rails choices (like the logger and cache back-end). Of course, the Rails boot process also glues together all registered components. For example, the Rails boot process is what uses your `config/database.yml` file @@ -126,7 +123,7 @@ when configuring Active Record. **The short version is**: you may not have thought about which parts of Rails are still applicable even if you remove the view layer, but the answer turns out -to be "most of it". +to be most of it. The Basic Configuration ----------------------- @@ -135,6 +132,8 @@ If you're building a Rails application that will be an API server first and foremost, you can start with a more limited subset of Rails and add in features as needed. +### Creating a new application + You can generate a new api Rails app: ```bash @@ -143,16 +142,18 @@ $ rails new my_api --api This will do three main things for you: -- Configure your application to start with a more limited set of middlewares +- Configure your application to start with a more limited set of middleware than normal. Specifically, it will not include any middleware primarily useful for browser applications (like cookies support) by default. - Make `ApplicationController` inherit from `ActionController::API` instead of - `ActionController::Base`. As with middlewares, this will leave out any Action + `ActionController::Base`. As with middleware, this will leave out any Action Controller modules that provide functionalities primarily used by browser applications. - Configure the generators to skip generating views, helpers and assets when you generate a new resource. +### Changing an existing application + If you want to take an existing application and make it an API one, read the following steps. @@ -163,6 +164,23 @@ class definition: config.api_only = true ``` +In `config/environments/development.rb`, set `config.debug_exception_response_format` +to configure the format used in responses when errors occur in development mode. + +To render an HTML page with debugging information, use the value `:default`. + +```ruby +config.debug_exception_response_format = :default +``` + +To render debugging information preserving the response format, use the value `:api`. + +```ruby +config.debug_exception_response_format = :api +``` + +By default, `config.debug_exception_response_format` is set to `:api`, when `config.api_only` is set to true. + Finally, inside `app/controllers/application_controller.rb`, instead of: ```ruby @@ -177,18 +195,18 @@ class ApplicationController < ActionController::API end ``` -Choosing Middlewares +Choosing Middleware -------------------- -An API application comes with the following middlewares by default: +An API application comes with the following middleware by default: - `Rack::Sendfile` - `ActionDispatch::Static` -- `Rack::Lock` +- `ActionDispatch::Executor` - `ActiveSupport::Cache::Strategy::LocalCache::Middleware` +- `Rack::Runtime` - `ActionDispatch::RequestId` - `Rails::Rack::Logger` -- `Rack::Runtime` - `ActionDispatch::ShowExceptions` - `ActionDispatch::DebugExceptions` - `ActionDispatch::RemoteIp` @@ -198,17 +216,17 @@ An API application comes with the following middlewares by default: - `Rack::ConditionalGet` - `Rack::ETag` -See the [internal middlewares](rails_on_rack.html#internal-middleware-stack) +See the [internal middleware](rails_on_rack.html#internal-middleware-stack) section of the Rack guide for further information on them. -Other plugins, including Active Record, may add additional middlewares. In -general, these middlewares are agnostic to the type of application you are +Other plugins, including Active Record, may add additional middleware. In +general, these middleware are agnostic to the type of application you are building, and make sense in an API-only Rails application. -You can get a list of all middlewares in your application via: +You can get a list of all middleware in your application via: ```bash -$ rake middleware +$ rails middleware ``` ### Using the Cache Middleware @@ -221,7 +239,7 @@ For instance, using the `stale?` method: ```ruby def show - @post = Post.find(params[:id]) + @post = Post.find(params[:id]) if stale?(last_modified: @post.updated_at) render json: @post @@ -240,7 +258,7 @@ cross-client caching in the call to `stale?`: ```ruby def show - @post = Post.find(params[:id]) + @post = Post.find(params[:id]) if stale?(last_modified: @post.updated_at, public: true) render json: @post @@ -254,9 +272,6 @@ subsequent inbound requests for the same URL. Think of it as page caching using HTTP semantics. -NOTE: This middleware is always outside of the `Rack::Lock` mutex, even in -single-threaded applications. - ### Using Rack::Sendfile When you use the `send_file` method inside a Rails controller, it sets the @@ -274,7 +289,7 @@ You can learn more about how to use `Rack::Sendfile` with popular front-ends in [the Rack::Sendfile documentation](http://rubydoc.info/github/rack/rack/master/Rack/Sendfile). -Here are some values for popular servers, once they are configured, to support +Here are some values for this header for some popular servers, once these servers are configured to support accelerated file sending: ```ruby @@ -288,9 +303,6 @@ config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" Make sure to configure your server to support these options following the instructions in the `Rack::Sendfile` documentation. -NOTE: The `Rack::Sendfile` middleware is always outside of the `Rack::Lock` -mutex, even in single-threaded applications. - ### Using ActionDispatch::Request `ActionDispatch::Request#params` will take parameters from the client in the JSON @@ -319,9 +331,9 @@ will be: { :person => { :firstName => "Yehuda", :lastName => "Katz" } } ``` -### Other Middlewares +### Other Middleware -Rails ships with a number of other middlewares that you might want to use in an +Rails ships with a number of other middleware that you might want to use in an API application, especially if one of your API clients is the browser: - `Rack::MethodOverride` @@ -332,13 +344,13 @@ API application, especially if one of your API clients is the browser: * `ActionDispatch::Session::CookieStore` * `ActionDispatch::Session::MemCacheStore` -Any of these middlewares can be added via: +Any of these middleware can be added via: ```ruby config.middleware.use Rack::MethodOverride ``` -### Removing Middlewares +### Removing Middleware If you don't want to use a middleware that is included by default in the API-only middleware set, you can remove it with: @@ -347,7 +359,7 @@ middleware set, you can remove it with: config.middleware.delete ::Rack::Sendfile ``` -Keep in mind that removing these middlewares will remove support for certain +Keep in mind that removing these middleware will remove support for certain features in Action Controller. Choosing Controller Modules @@ -356,22 +368,24 @@ Choosing Controller Modules An API application (using `ActionController::API`) comes with the following controller modules by default: -- `ActionController::UrlFor`: Makes `url_for` and friends available. +- `ActionController::UrlFor`: Makes `url_for` and similar helpers available. - `ActionController::Redirecting`: Support for `redirect_to`. -- `ActionController::Rendering`: Basic support for rendering. +- `AbstractController::Rendering` and `ActionController::ApiRendering`: Basic support for rendering. - `ActionController::Renderers::All`: Support for `render :json` and friends. - `ActionController::ConditionalGet`: Support for `stale?`. -- `ActionController::ForceSSL`: Support for `force_ssl`. -- `ActionController::DataStreaming`: Support for `send_file` and `send_data`. -- `AbstractController::Callbacks`: Support for `before_action` and friends. -- `ActionController::Instrumentation`: Support for the instrumentation - hooks defined by Action Controller (see [the instrumentation - guide](active_support_instrumentation.html#action-controller)). -- `ActionController::Rescue`: Support for `rescue_from`. - `ActionController::BasicImplicitRender`: Makes sure to return an empty response if there's not an explicit one. - `ActionController::StrongParameters`: Support for parameters white-listing in combination with Active Model mass assignment. +- `ActionController::ForceSSL`: Support for `force_ssl`. +- `ActionController::DataStreaming`: Support for `send_file` and `send_data`. +- `AbstractController::Callbacks`: Support for `before_action` and + similar helpers. +- `ActionController::Rescue`: Support for `rescue_from`. +- `ActionController::Instrumentation`: Support for the instrumentation + hooks defined by Action Controller (see [the instrumentation + guide](active_support_instrumentation.html#action-controller) for +more information regarding this). - `ActionController::ParamsWrapper`: Wraps the parameters hash into a nested hash so you don't have to specify root elements sending POST requests for instance. @@ -381,6 +395,13 @@ included into `ActionController::API` in the rails console: ```bash $ bin/rails c >> ActionController::API.ancestors - ActionController::Metal.ancestors +=> [ActionController::API, + ActiveRecord::Railties::ControllerRuntime, + ActionDispatch::Routing::RouteSet::MountedHelpers, + ActionController::ParamsWrapper, + ... , + AbstractController::Rendering, + ActionView::ViewPaths] ``` ### Adding Other Modules @@ -395,10 +416,10 @@ Some common modules you might want to add: and translation methods. - `ActionController::HttpAuthentication::Basic` (or `Digest` or `Token`): Support for basic, digest or token HTTP authentication. -- `AbstractController::Layouts`: Support for layouts when rendering. +- `ActionView::Layouts`: Support for layouts when rendering. - `ActionController::MimeResponds`: Support for `respond_to`. - `ActionController::Cookies`: Support for `cookies`, which includes support for signed and encrypted cookies. This requires the cookies middleware. -The best place to add a module is in your `ApplicationController` but you can +The best place to add a module is in your `ApplicationController`, but you can also add modules to individual controllers. diff --git a/guides/source/api_documentation_guidelines.md b/guides/source/api_documentation_guidelines.md index 73e62eb6d9..5b34330936 100644 --- a/guides/source/api_documentation_guidelines.md +++ b/guides/source/api_documentation_guidelines.md @@ -20,7 +20,7 @@ The [Rails API documentation](http://api.rubyonrails.org) is generated with in the rails root directory, run `bundle install` and execute: ```bash - bundle exec rake rdoc + ./bin/rails rdoc ``` Resulting HTML files can be found in the ./doc/rdoc directory. @@ -120,7 +120,7 @@ On the other hand, big chunks of structured documentation may have a separate "E The results of expressions follow them and are introduced by "# => ", vertically aligned: ```ruby -# For checking if a fixnum is even or odd. +# For checking if an integer is even or odd. # # 1.even? # => false # 1.odd? # => true diff --git a/guides/source/asset_pipeline.md b/guides/source/asset_pipeline.md index 0f2283318a..e6631a513c 100644 --- a/guides/source/asset_pipeline.md +++ b/guides/source/asset_pipeline.md @@ -21,21 +21,20 @@ What is the Asset Pipeline? The asset pipeline provides a framework to concatenate and minify or compress JavaScript and CSS assets. It also adds the ability to write these assets in other languages and pre-processors such as CoffeeScript, Sass and ERB. +It allows assets in your application to be automatically combined with assets +from other gems. For example, jquery-rails includes a copy of jquery.js +and enables AJAX features in Rails. -The asset pipeline is technically no longer a core feature of Rails 4, it has -been extracted out of the framework into the -[sprockets-rails](https://github.com/rails/sprockets-rails) gem. - -The asset pipeline is enabled by default. - -You can disable the asset pipeline while creating a new application by +The asset pipeline is implemented by the +[sprockets-rails](https://github.com/rails/sprockets-rails) gem, +and is enabled by default. You can disable it while creating a new application by passing the `--skip-sprockets` option. ```bash rails new appname --skip-sprockets ``` -Rails 4 automatically adds the `sass-rails`, `coffee-rails` and `uglifier` +Rails automatically adds the `sass-rails`, `coffee-rails` and `uglifier` gems to your Gemfile, which are used by Sprockets for asset compression: ```ruby @@ -44,8 +43,8 @@ gem 'uglifier' gem 'coffee-rails' ``` -Using the `--skip-sprockets` option will prevent Rails 4 from adding -`sass-rails` and `uglifier` to Gemfile, so if you later want to enable +Using the `--skip-sprockets` option will prevent Rails from adding +them to your Gemfile, so if you later want to enable the asset pipeline you will have to add those gems to your Gemfile. Also, creating an application with the `--skip-sprockets` option will generate a slightly different `config/application.rb` file, with a require statement @@ -66,7 +65,7 @@ config.assets.js_compressor = :uglifier ``` NOTE: The `sass-rails` gem is automatically used for CSS compression if included -in Gemfile and no `config.assets.css_compressor` option is set. +in the Gemfile and no `config.assets.css_compressor` option is set. ### Main Features @@ -327,13 +326,13 @@ familiar `javascript_include_tag` and `stylesheet_link_tag`: <%= javascript_include_tag "application" %> ``` -If using the turbolinks gem, which is included by default in Rails 4, then +If using the turbolinks gem, which is included by default in Rails, then include the 'data-turbolinks-track' option which causes turbolinks to check if an asset has been updated and if so loads it into the page: ```erb -<%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => true %> -<%= javascript_include_tag "application", "data-turbolinks-track" => true %> +<%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => "reload" %> +<%= javascript_include_tag "application", "data-turbolinks-track" => "reload" %> ``` In regular views you can access images in the `public/assets/images` directory @@ -436,14 +435,14 @@ Sprockets uses manifest files to determine which assets to include and serve. These manifest files contain _directives_ - instructions that tell Sprockets which files to require in order to build a single CSS or JavaScript file. With these directives, Sprockets loads the files specified, processes them if -necessary, concatenates them into one single file and then compresses them (if -`Rails.application.config.assets.compress` is true). By serving one file rather -than many, the load time of pages can be greatly reduced because the browser -makes fewer requests. Compression also reduces file size, enabling the -browser to download them faster. +necessary, concatenates them into one single file and then compresses them +(based on value of `Rails.application.config.assets.js_compressor`). By serving +one file rather than many, the load time of pages can be greatly reduced because +the browser makes fewer requests. Compression also reduces file size, enabling +the browser to download them faster. -For example, a new Rails 4 application includes a default +For example, a new Rails application includes a default `app/assets/javascripts/application.js` file containing the following lines: ```js @@ -484,7 +483,7 @@ which contains these lines: */ ``` -Rails 4 creates both `app/assets/javascripts/application.js` and +Rails creates both `app/assets/javascripts/application.js` and `app/assets/stylesheets/application.css` regardless of whether the --skip-sprockets option is used when creating a new rails application. This is so you can easily add asset pipelining later if you like. @@ -667,7 +666,7 @@ anymore, delete these options from the `javascript_include_tag` and `stylesheet_link_tag`. The fingerprinting behavior is controlled by the `config.assets.digest` -initialization option (which defaults to `true` for production and development). +initialization option (which defaults to `true`). NOTE: Under normal circumstances the default `config.assets.digest` option should not be changed. If there are no digests in the filenames, and far-future @@ -676,7 +675,7 @@ content changes. ### Precompiling Assets -Rails comes bundled with a rake task to compile the asset manifests and other +Rails comes bundled with a task to compile the asset manifests and other files in the pipeline. Compiled assets are written to the location specified in `config.assets.prefix`. @@ -686,10 +685,10 @@ You can call this task on the server during deployment to create compiled versions of your assets directly on the server. See the next section for information on compiling locally. -The rake task is: +The task is: ```bash -$ RAILS_ENV=production bin/rake assets:precompile +$ RAILS_ENV=production bin/rails assets:precompile ``` Capistrano (v2.15.1 and above) includes a recipe to handle this in deployment. @@ -731,7 +730,7 @@ Rails.application.config.assets.precompile += ['admin.js', 'admin.css', 'swfObje NOTE. Always specify an expected compiled filename that ends with .js or .css, even if you want to add Sass or CoffeeScript files to the precompile array. -The rake task also generates a `manifest-md5hash.json` that contains a list with +The task also generates a `manifest-md5hash.json` that contains a list with all your assets and their respective fingerprints. This is used by the Rails helper methods to avoid handing the mapping requests back to Sprockets. A typical manifest file looks like: @@ -786,7 +785,6 @@ location ~ ^/assets/ { add_header Cache-Control public; add_header ETag ""; - break; } ``` @@ -898,7 +896,7 @@ your CDN server, you need to tell browsers to use your CDN to grab assets instead of your Rails server directly. You can do this by configuring Rails to set your CDN as the asset host instead of using a relative path. To set your asset host in Rails, you need to set `config.action_controller.asset_host` in -`config/production.rb`: +`config/environments/production.rb`: ```ruby config.action_controller.asset_host = 'mycdnsubdomain.fictional-cdn.com' @@ -1107,11 +1105,17 @@ NOTE: You will need an [ExecJS](https://github.com/rails/execjs#readme) supported runtime in order to use `uglifier`. If you are using Mac OS X or Windows you have a JavaScript runtime installed in your operating system. -NOTE: The `config.assets.compress` initialization option is no longer used in -Rails 4 to enable either CSS or JavaScript compression. Setting it will have no -effect on the application. Instead, setting `config.assets.css_compressor` and -`config.assets.js_compressor` will control compression of CSS and JavaScript -assets. + + +### Serving GZipped version of assets + +By default, gzipped version of compiled assets will be generated, along +with the non-gzipped version of assets. Gzipped assets help reduce the transmission of +data over the wire. You can configure this by setting the `gzip` flag. + +```ruby +config.assets.gzip = false # disable gzipped assets generation +``` ### Using Your Own Compressor @@ -1177,19 +1181,14 @@ TIP: For further details have a look at the docs of your production web server: Assets Cache Store ------------------ -The default Rails cache store will be used by Sprockets to cache assets in -development and production. This can be changed by setting -`config.assets.cache_store`: - -```ruby -config.assets.cache_store = :memory_store -``` - -The options accepted by the assets cache store are the same as the application's -cache store. +By default, Sprockets caches assets in `tmp/cache/assets` in development +and production environments. This can be changed as follows: ```ruby -config.assets.cache_store = :memory_store, { size: 32.megabytes } +config.assets.configure do |env| + env.cache = ActiveSupport::Cache.lookup_store(:memory_store, + { size: 32.megabytes }) +end ``` To disable the assets cache store: @@ -1280,25 +1279,27 @@ config.assets.debug = true And in `production.rb`: ```ruby -# Choose the compressors to use (if any) config.assets.js_compressor = -# :uglifier config.assets.css_compressor = :yui +# Choose the compressors to use (if any) +config.assets.js_compressor = :uglifier +# config.assets.css_compressor = :yui # Don't fallback to assets pipeline if a precompiled asset is missed config.assets.compile = false -# Generate digests for assets URLs. This is planned for deprecation. +# Generate digests for assets URLs. config.assets.digest = true # Precompile additional assets (application.js, application.css, and all -# non-JS/CSS are already added) config.assets.precompile += %w( search.js ) +# non-JS/CSS are already added) +# config.assets.precompile += %w( search.js ) ``` -Rails 4 no longer sets default config values for Sprockets in `test.rb`, so +Rails 4 and above no longer set default config values for Sprockets in `test.rb`, so `test.rb` now requires Sprockets configuration. The old defaults in the test environment are: `config.assets.compile = true`, `config.assets.compress = false`, `config.assets.debug = false` and `config.assets.digest = false`. -The following should also be added to `Gemfile`: +The following should also be added to your `Gemfile`: ```ruby gem 'sass-rails', "~> 3.2.3" diff --git a/guides/source/association_basics.md b/guides/source/association_basics.md index c272daac28..3993fdb1dd 100644 --- a/guides/source/association_basics.md +++ b/guides/source/association_basics.md @@ -16,54 +16,54 @@ After reading this guide, you will know: Why Associations? ----------------- -In Rails, an _association_ is a connection between two Active Record models. Why do we need associations between models? Because they make common operations simpler and easier in your code. For example, consider a simple Rails application that includes a model for customers and a model for orders. Each customer can have many orders. Without associations, the model declarations would look like this: +In Rails, an _association_ is a connection between two Active Record models. Why do we need associations between models? Because they make common operations simpler and easier in your code. For example, consider a simple Rails application that includes a model for authors and a model for books. Each author can have many books. Without associations, the model declarations would look like this: ```ruby -class Customer < ActiveRecord::Base +class Author < ApplicationRecord end -class Order < ActiveRecord::Base +class Book < ApplicationRecord end ``` -Now, suppose we wanted to add a new order for an existing customer. We'd need to do something like this: +Now, suppose we wanted to add a new book for an existing author. We'd need to do something like this: ```ruby -@order = Order.create(order_date: Time.now, customer_id: @customer.id) +@book = Book.create(published_at: Time.now, author_id: @author.id) ``` -Or consider deleting a customer, and ensuring that all of its orders get deleted as well: +Or consider deleting an author, and ensuring that all of its books get deleted as well: ```ruby -@orders = Order.where(customer_id: @customer.id) -@orders.each do |order| - order.destroy +@books = Book.where(author_id: @author.id) +@books.each do |book| + book.destroy end -@customer.destroy +@author.destroy ``` -With Active Record associations, we can streamline these - and other - operations by declaratively telling Rails that there is a connection between the two models. Here's the revised code for setting up customers and orders: +With Active Record associations, we can streamline these - and other - operations by declaratively telling Rails that there is a connection between the two models. Here's the revised code for setting up authors and books: ```ruby -class Customer < ActiveRecord::Base - has_many :orders, dependent: :destroy +class Author < ApplicationRecord + has_many :books, dependent: :destroy end -class Order < ActiveRecord::Base - belongs_to :customer +class Book < ApplicationRecord + belongs_to :author end ``` -With this change, creating a new order for a particular customer is easier: +With this change, creating a new book for a particular author is easier: ```ruby -@order = @customer.orders.create(order_date: Time.now) +@book = @author.books.create(published_at: Time.now) ``` -Deleting a customer and all of its orders is *much* easier: +Deleting an author and all of its books is *much* easier: ```ruby -@customer.destroy +@author.destroy ``` To learn more about the different types of associations, read the next section of this guide. That's followed by some tips and tricks for working with associations, and then by a complete reference to the methods and options for associations in Rails. @@ -86,32 +86,32 @@ In the remainder of this guide, you'll learn how to declare and use the various ### The `belongs_to` Association -A `belongs_to` association sets up a one-to-one connection with another model, such that each instance of the declaring model "belongs to" one instance of the other model. For example, if your application includes customers and orders, and each order can be assigned to exactly one customer, you'd declare the order model this way: +A `belongs_to` association sets up a one-to-one connection with another model, such that each instance of the declaring model "belongs to" one instance of the other model. For example, if your application includes authors and books, and each book can be assigned to exactly one author, you'd declare the book model this way: ```ruby -class Order < ActiveRecord::Base - belongs_to :customer +class Book < ApplicationRecord + belongs_to :author end ``` ![belongs_to Association Diagram](images/belongs_to.png) -NOTE: `belongs_to` associations _must_ use the singular term. If you used the pluralized form in the above example for the `customer` association in the `Order` model, you would be told that there was an "uninitialized constant Order::Customers". This is because Rails automatically infers the class name from the association name. If the association name is wrongly pluralized, then the inferred class will be wrongly pluralized too. +NOTE: `belongs_to` associations _must_ use the singular term. If you used the pluralized form in the above example for the `author` association in the `Book` model, you would be told that there was an "uninitialized constant Book::Authors". This is because Rails automatically infers the class name from the association name. If the association name is wrongly pluralized, then the inferred class will be wrongly pluralized too. The corresponding migration might look like this: ```ruby -class CreateOrders < ActiveRecord::Migration +class CreateBooks < ActiveRecord::Migration[5.0] def change - create_table :customers do |t| + create_table :authors do |t| t.string :name - t.timestamps null: false + t.timestamps end - create_table :orders do |t| - t.belongs_to :customer, index: true - t.datetime :order_date - t.timestamps null: false + create_table :books do |t| + t.belongs_to :author, index: true + t.datetime :published_at + t.timestamps end end end @@ -122,7 +122,7 @@ end A `has_one` association also sets up a one-to-one connection with another model, but with somewhat different semantics (and consequences). This association indicates that each instance of a model contains or possesses one instance of another model. For example, if each supplier in your application has only one account, you'd declare the supplier model like this: ```ruby -class Supplier < ActiveRecord::Base +class Supplier < ApplicationRecord has_one :account end ``` @@ -132,17 +132,17 @@ end The corresponding migration might look like this: ```ruby -class CreateSuppliers < ActiveRecord::Migration +class CreateSuppliers < ActiveRecord::Migration[5.0] def change create_table :suppliers do |t| t.string :name - t.timestamps null: false + t.timestamps end create_table :accounts do |t| t.belongs_to :supplier, index: true t.string :account_number - t.timestamps null: false + t.timestamps end end end @@ -161,11 +161,11 @@ end ### The `has_many` Association -A `has_many` association indicates a one-to-many connection with another model. You'll often find this association on the "other side" of a `belongs_to` association. This association indicates that each instance of the model has zero or more instances of another model. For example, in an application containing customers and orders, the customer model could be declared like this: +A `has_many` association indicates a one-to-many connection with another model. You'll often find this association on the "other side" of a `belongs_to` association. This association indicates that each instance of the model has zero or more instances of another model. For example, in an application containing authors and books, the author model could be declared like this: ```ruby -class Customer < ActiveRecord::Base - has_many :orders +class Author < ApplicationRecord + has_many :books end ``` @@ -176,17 +176,17 @@ NOTE: The name of the other model is pluralized when declaring a `has_many` asso The corresponding migration might look like this: ```ruby -class CreateCustomers < ActiveRecord::Migration +class CreateAuthors < ActiveRecord::Migration[5.0] def change - create_table :customers do |t| + create_table :authors do |t| t.string :name - t.timestamps null: false + t.timestamps end - create_table :orders do |t| - t.belongs_to :customer, index: true - t.datetime :order_date - t.timestamps null: false + create_table :books do |t| + t.belongs_to :author, index: true + t.datetime :published_at + t.timestamps end end end @@ -197,17 +197,17 @@ end A `has_many :through` association is often used to set up a many-to-many connection with another model. This association indicates that the declaring model can be matched with zero or more instances of another model by proceeding _through_ a third model. For example, consider a medical practice where patients make appointments to see physicians. The relevant association declarations could look like this: ```ruby -class Physician < ActiveRecord::Base +class Physician < ApplicationRecord has_many :appointments has_many :patients, through: :appointments end -class Appointment < ActiveRecord::Base +class Appointment < ApplicationRecord belongs_to :physician belongs_to :patient end -class Patient < ActiveRecord::Base +class Patient < ApplicationRecord has_many :appointments has_many :physicians, through: :appointments end @@ -218,23 +218,23 @@ end The corresponding migration might look like this: ```ruby -class CreateAppointments < ActiveRecord::Migration +class CreateAppointments < ActiveRecord::Migration[5.0] def change create_table :physicians do |t| t.string :name - t.timestamps null: false + t.timestamps end create_table :patients do |t| t.string :name - t.timestamps null: false + t.timestamps end create_table :appointments do |t| t.belongs_to :physician, index: true t.belongs_to :patient, index: true t.datetime :appointment_date - t.timestamps null: false + t.timestamps end end end @@ -255,17 +255,17 @@ WARNING: Automatic deletion of join models is direct, no destroy callbacks are t The `has_many :through` association is also useful for setting up "shortcuts" through nested `has_many` associations. For example, if a document has many sections, and a section has many paragraphs, you may sometimes want to get a simple collection of all paragraphs in the document. You could set that up this way: ```ruby -class Document < ActiveRecord::Base +class Document < ApplicationRecord has_many :sections has_many :paragraphs, through: :sections end -class Section < ActiveRecord::Base +class Section < ApplicationRecord belongs_to :document has_many :paragraphs end -class Paragraph < ActiveRecord::Base +class Paragraph < ApplicationRecord belongs_to :section end ``` @@ -284,17 +284,17 @@ For example, if each supplier has one account, and each account is associated wi supplier model could look like this: ```ruby -class Supplier < ActiveRecord::Base +class Supplier < ApplicationRecord has_one :account has_one :account_history, through: :account end -class Account < ActiveRecord::Base +class Account < ApplicationRecord belongs_to :supplier has_one :account_history end -class AccountHistory < ActiveRecord::Base +class AccountHistory < ApplicationRecord belongs_to :account end ``` @@ -304,23 +304,23 @@ end The corresponding migration might look like this: ```ruby -class CreateAccountHistories < ActiveRecord::Migration +class CreateAccountHistories < ActiveRecord::Migration[5.0] def change create_table :suppliers do |t| t.string :name - t.timestamps null: false + t.timestamps end create_table :accounts do |t| t.belongs_to :supplier, index: true t.string :account_number - t.timestamps null: false + t.timestamps end create_table :account_histories do |t| t.belongs_to :account, index: true t.integer :credit_rating - t.timestamps null: false + t.timestamps end end end @@ -331,11 +331,11 @@ end A `has_and_belongs_to_many` association creates a direct many-to-many connection with another model, with no intervening model. For example, if your application includes assemblies and parts, with each assembly having many parts and each part appearing in many assemblies, you could declare the models this way: ```ruby -class Assembly < ActiveRecord::Base +class Assembly < ApplicationRecord has_and_belongs_to_many :parts end -class Part < ActiveRecord::Base +class Part < ApplicationRecord has_and_belongs_to_many :assemblies end ``` @@ -345,16 +345,16 @@ end The corresponding migration might look like this: ```ruby -class CreateAssembliesAndParts < ActiveRecord::Migration +class CreateAssembliesAndParts < ActiveRecord::Migration[5.0] def change create_table :assemblies do |t| t.string :name - t.timestamps null: false + t.timestamps end create_table :parts do |t| t.string :part_number - t.timestamps null: false + t.timestamps end create_table :assemblies_parts, id: false do |t| @@ -372,11 +372,11 @@ If you want to set up a one-to-one relationship between two models, you'll need The distinction is in where you place the foreign key (it goes on the table for the class declaring the `belongs_to` association), but you should give some thought to the actual meaning of the data as well. The `has_one` relationship says that one of something is yours - that is, that something points back to you. For example, it makes more sense to say that a supplier owns an account than that an account owns a supplier. This suggests that the correct relationships are like this: ```ruby -class Supplier < ActiveRecord::Base +class Supplier < ApplicationRecord has_one :account end -class Account < ActiveRecord::Base +class Account < ApplicationRecord belongs_to :supplier end ``` @@ -384,17 +384,17 @@ end The corresponding migration might look like this: ```ruby -class CreateSuppliers < ActiveRecord::Migration +class CreateSuppliers < ActiveRecord::Migration[5.0] def change create_table :suppliers do |t| t.string :name - t.timestamps null: false + t.timestamps end create_table :accounts do |t| t.integer :supplier_id t.string :account_number - t.timestamps null: false + t.timestamps end add_index :accounts, :supplier_id @@ -409,11 +409,11 @@ NOTE: Using `t.integer :supplier_id` makes the foreign key naming obvious and ex Rails offers two different ways to declare a many-to-many relationship between models. The simpler way is to use `has_and_belongs_to_many`, which allows you to make the association directly: ```ruby -class Assembly < ActiveRecord::Base +class Assembly < ApplicationRecord has_and_belongs_to_many :parts end -class Part < ActiveRecord::Base +class Part < ApplicationRecord has_and_belongs_to_many :assemblies end ``` @@ -421,17 +421,17 @@ end The second way to declare a many-to-many relationship is to use `has_many :through`. This makes the association indirectly, through a join model: ```ruby -class Assembly < ActiveRecord::Base +class Assembly < ApplicationRecord has_many :manifests has_many :parts, through: :manifests end -class Manifest < ActiveRecord::Base +class Manifest < ApplicationRecord belongs_to :assembly belongs_to :part end -class Part < ActiveRecord::Base +class Part < ApplicationRecord has_many :manifests has_many :assemblies, through: :manifests end @@ -446,15 +446,15 @@ You should use `has_many :through` if you need validations, callbacks or extra a A slightly more advanced twist on associations is the _polymorphic association_. With polymorphic associations, a model can belong to more than one other model, on a single association. For example, you might have a picture model that belongs to either an employee model or a product model. Here's how this could be declared: ```ruby -class Picture < ActiveRecord::Base +class Picture < ApplicationRecord belongs_to :imageable, polymorphic: true end -class Employee < ActiveRecord::Base +class Employee < ApplicationRecord has_many :pictures, as: :imageable end -class Product < ActiveRecord::Base +class Product < ApplicationRecord has_many :pictures, as: :imageable end ``` @@ -466,13 +466,13 @@ Similarly, you can retrieve `@product.pictures`. If you have an instance of the `Picture` model, you can get to its parent via `@picture.imageable`. To make this work, you need to declare both a foreign key column and a type column in the model that declares the polymorphic interface: ```ruby -class CreatePictures < ActiveRecord::Migration +class CreatePictures < ActiveRecord::Migration[5.0] def change create_table :pictures do |t| t.string :name t.integer :imageable_id t.string :imageable_type - t.timestamps null: false + t.timestamps end add_index :pictures, [:imageable_type, :imageable_id] @@ -483,12 +483,12 @@ end This migration can be simplified by using the `t.references` form: ```ruby -class CreatePictures < ActiveRecord::Migration +class CreatePictures < ActiveRecord::Migration[5.0] def change create_table :pictures do |t| t.string :name t.references :imageable, polymorphic: true, index: true - t.timestamps null: false + t.timestamps end end end @@ -501,7 +501,7 @@ end In designing a data model, you will sometimes find a model that should have a relation to itself. For example, you may want to store all employees in a single database model, but be able to trace relationships such as between manager and subordinates. This situation can be modeled with self-joining associations: ```ruby -class Employee < ActiveRecord::Base +class Employee < ApplicationRecord has_many :subordinates, class_name: "Employee", foreign_key: "manager_id" @@ -514,11 +514,11 @@ With this setup, you can retrieve `@employee.subordinates` and `@employee.manage In your migrations/schema, you will add a references column to the model itself. ```ruby -class CreateEmployees < ActiveRecord::Migration +class CreateEmployees < ActiveRecord::Migration[5.0] def change create_table :employees do |t| t.references :manager, index: true - t.timestamps null: false + t.timestamps end end end @@ -540,17 +540,17 @@ Here are a few things you should know to make efficient use of Active Record ass All of the association methods are built around caching, which keeps the result of the most recent query available for further operations. The cache is even shared across methods. For example: ```ruby -customer.orders # retrieves orders from the database -customer.orders.size # uses the cached copy of orders -customer.orders.empty? # uses the cached copy of orders +author.books # retrieves books from the database +author.books.size # uses the cached copy of books +author.books.empty? # uses the cached copy of books ``` -But what if you want to reload the cache, because data might have been changed by some other part of the application? Just pass `true` to the association call: +But what if you want to reload the cache, because data might have been changed by some other part of the application? Just call `reload` on the association: ```ruby -customer.orders # retrieves orders from the database -customer.orders.size # uses the cached copy of orders -customer.orders(true).empty? # discards the cached copy of orders +author.books # retrieves books from the database +author.books.size # uses the cached copy of books +author.books.reload.empty? # discards the cached copy of books # and goes back to the database ``` @@ -567,23 +567,23 @@ Associations are extremely useful, but they are not magic. You are responsible f When you declare a `belongs_to` association, you need to create foreign keys as appropriate. For example, consider this model: ```ruby -class Order < ActiveRecord::Base - belongs_to :customer +class Book < ApplicationRecord + belongs_to :author end ``` -This declaration needs to be backed up by the proper foreign key declaration on the orders table: +This declaration needs to be backed up by the proper foreign key declaration on the books table: ```ruby -class CreateOrders < ActiveRecord::Migration +class CreateBooks < ActiveRecord::Migration[5.0] def change - create_table :orders do |t| - t.datetime :order_date - t.string :order_number - t.integer :customer_id + create_table :books do |t| + t.datetime :published_at + t.string :book_number + t.integer :author_id end - add_index :orders, :customer_id + add_index :books, :author_id end end ``` @@ -592,18 +592,18 @@ If you create an association some time after you build the underlying model, you #### Creating Join Tables for `has_and_belongs_to_many` Associations -If you create a `has_and_belongs_to_many` association, you need to explicitly create the joining table. Unless the name of the join table is explicitly specified by using the `:join_table` option, Active Record creates the name by using the lexical order of the class names. So a join between customer and order models will give the default join table name of "customers_orders" because "c" outranks "o" in lexical ordering. +If you create a `has_and_belongs_to_many` association, you need to explicitly create the joining table. Unless the name of the join table is explicitly specified by using the `:join_table` option, Active Record creates the name by using the lexical book of the class names. So a join between author and book models will give the default join table name of "authors_books" because "a" outranks "b" in lexical ordering. WARNING: The precedence between model names is calculated using the `<=>` operator for `String`. This means that if the strings are of different lengths, and the strings are equal when compared up to the shortest length, then the longer string is considered of higher lexical precedence than the shorter one. For example, one would expect the tables "paper_boxes" and "papers" to generate a join table name of "papers_paper_boxes" because of the length of the name "paper_boxes", but it in fact generates a join table name of "paper_boxes_papers" (because the underscore '\_' is lexicographically _less_ than 's' in common encodings). Whatever the name, you must manually generate the join table with an appropriate migration. For example, consider these associations: ```ruby -class Assembly < ActiveRecord::Base +class Assembly < ApplicationRecord has_and_belongs_to_many :parts end -class Part < ActiveRecord::Base +class Part < ApplicationRecord has_and_belongs_to_many :assemblies end ``` @@ -611,7 +611,7 @@ end These need to be backed up by a migration to create the `assemblies_parts` table. This table should be created without a primary key: ```ruby -class CreateAssembliesPartsJoinTable < ActiveRecord::Migration +class CreateAssembliesPartsJoinTable < ActiveRecord::Migration[5.0] def change create_table :assemblies_parts, id: false do |t| t.integer :assembly_id @@ -629,7 +629,7 @@ We pass `id: false` to `create_table` because that table does not represent a mo You can also use the method `create_join_table` ```ruby -class CreateAssembliesPartsJoinTable < ActiveRecord::Migration +class CreateAssembliesPartsJoinTable < ActiveRecord::Migration[5.0] def change create_join_table :assemblies, :parts do |t| t.index :assembly_id @@ -646,11 +646,11 @@ By default, associations look for objects only within the current module's scope ```ruby module MyApplication module Business - class Supplier < ActiveRecord::Base + class Supplier < ApplicationRecord has_one :account end - class Account < ActiveRecord::Base + class Account < ApplicationRecord belongs_to :supplier end end @@ -662,13 +662,13 @@ This will work fine, because both the `Supplier` and the `Account` class are def ```ruby module MyApplication module Business - class Supplier < ActiveRecord::Base + class Supplier < ApplicationRecord has_one :account end end module Billing - class Account < ActiveRecord::Base + class Account < ApplicationRecord belongs_to :supplier end end @@ -680,14 +680,14 @@ To associate a model with a model in a different namespace, you must specify the ```ruby module MyApplication module Business - class Supplier < ActiveRecord::Base + class Supplier < ApplicationRecord has_one :account, class_name: "MyApplication::Billing::Account" end end module Billing - class Account < ActiveRecord::Base + class Account < ApplicationRecord belongs_to :supplier, class_name: "MyApplication::Business::Supplier" end @@ -700,45 +700,45 @@ end It's normal for associations to work in two directions, requiring declaration on two different models: ```ruby -class Customer < ActiveRecord::Base - has_many :orders +class Author < ApplicationRecord + has_many :books end -class Order < ActiveRecord::Base - belongs_to :customer +class Book < ApplicationRecord + belongs_to :author end ``` By default, Active Record doesn't know about the connection between these associations. This can lead to two copies of an object getting out of sync: ```ruby -c = Customer.first -o = c.orders.first -c.first_name == o.customer.first_name # => true -c.first_name = 'Manny' -c.first_name == o.customer.first_name # => false +a = Author.first +b = a.books.first +a.first_name == b.author.first_name # => true +a.first_name = 'Manny' +a.first_name == b.author.first_name # => false ``` -This happens because `c` and `o.customer` are two different in-memory representations of the same data, and neither one is automatically refreshed from changes to the other. Active Record provides the `:inverse_of` option so that you can inform it of these relations: +This happens because `a` and `b.author` are two different in-memory representations of the same data, and neither one is automatically refreshed from changes to the other. Active Record provides the `:inverse_of` option so that you can inform it of these relations: ```ruby -class Customer < ActiveRecord::Base - has_many :orders, inverse_of: :customer +class Author < ApplicationRecord + has_many :books, inverse_of: :author end -class Order < ActiveRecord::Base - belongs_to :customer, inverse_of: :orders +class Book < ApplicationRecord + belongs_to :author, inverse_of: :books end ``` -With these changes, Active Record will only load one copy of the customer object, preventing inconsistencies and making your application more efficient: +With these changes, Active Record will only load one copy of the author object, preventing inconsistencies and making your application more efficient: ```ruby -c = Customer.first -o = c.orders.first -c.first_name == o.customer.first_name # => true -c.first_name = 'Manny' -c.first_name == o.customer.first_name # => true +a = Author.first +b = a.books.first +a.first_name == b.author.first_name # => true +a.first_name = 'Manny' +a.first_name == b.author.first_name # => true ``` There are a few limitations to `inverse_of` support: @@ -781,19 +781,19 @@ When you declare a `belongs_to` association, the declaring class automatically g In all of these methods, `association` is replaced with the symbol passed as the first argument to `belongs_to`. For example, given the declaration: ```ruby -class Order < ActiveRecord::Base - belongs_to :customer +class Book < ApplicationRecord + belongs_to :author end ``` -Each instance of the `Order` model will have these methods: +Each instance of the `Book` model will have these methods: ```ruby -customer -customer= -build_customer -create_customer -create_customer! +author +author= +build_author +create_author +create_author! ``` NOTE: When initializing a new `has_one` or `belongs_to` association you must use the `build_` prefix to build the association, rather than the `association.build` method that would be used for `has_many` or `has_and_belongs_to_many` associations. To create one, use the `create_` prefix. @@ -803,13 +803,13 @@ NOTE: When initializing a new `has_one` or `belongs_to` association you must use The `association` method returns the associated object, if any. If no associated object is found, it returns `nil`. ```ruby -@customer = @order.customer +@author = @book.author ``` If the associated object has already been retrieved from the database for this object, the cached version will be returned. To override this behavior (and force a database read), call `#reload` on the parent object. ```ruby -@customer = @order.reload.customer +@author = @book.reload.author ``` ##### `association=(associate)` @@ -817,7 +817,7 @@ If the associated object has already been retrieved from the database for this o The `association=` method assigns an associated object to this object. Behind the scenes, this means extracting the primary key from the associated object and setting this object's foreign key to the same value. ```ruby -@order.customer = @customer +@book.author = @author ``` ##### `build_association(attributes = {})` @@ -825,8 +825,8 @@ The `association=` method assigns an associated object to this object. Behind th The `build_association` method returns a new object of the associated type. This object will be instantiated from the passed attributes, and the link through this object's foreign key will be set, but the associated object will _not_ yet be saved. ```ruby -@customer = @order.build_customer(customer_number: 123, - customer_name: "John Doe") +@author = @book.build_author(author_number: 123, + author_name: "John Doe") ``` ##### `create_association(attributes = {})` @@ -834,8 +834,8 @@ The `build_association` method returns a new object of the associated type. This The `create_association` method returns a new object of the associated type. This object will be instantiated from the passed attributes, the link through this object's foreign key will be set, and, once it passes all of the validations specified on the associated model, the associated object _will_ be saved. ```ruby -@customer = @order.create_customer(customer_number: 123, - customer_name: "John Doe") +@author = @book.create_author(author_number: 123, + author_name: "John Doe") ``` ##### `create_association!(attributes = {})` @@ -848,8 +848,8 @@ Does the same as `create_association` above, but raises `ActiveRecord::RecordInv While Rails uses intelligent defaults that will work well in most situations, there may be times when you want to customize the behavior of the `belongs_to` association reference. Such customizations can easily be accomplished by passing options and scope blocks when you create the association. For example, this association uses two such options: ```ruby -class Order < ActiveRecord::Base - belongs_to :customer, dependent: :destroy, +class Book < ApplicationRecord + belongs_to :author, dependent: :destroy, counter_cache: true end ``` @@ -874,11 +874,11 @@ If you set the `:autosave` option to `true`, Rails will save any loaded members ##### `:class_name` -If the name of the other model cannot be derived from the association name, you can use the `:class_name` option to supply the model name. For example, if an order belongs to a customer, but the actual name of the model containing customers is `Patron`, you'd set things up this way: +If the name of the other model cannot be derived from the association name, you can use the `:class_name` option to supply the model name. For example, if a book belongs to an author, but the actual name of the model containing authors is `Patron`, you'd set things up this way: ```ruby -class Order < ActiveRecord::Base - belongs_to :customer, class_name: "Patron" +class Book < ApplicationRecord + belongs_to :author, class_name: "Patron" end ``` @@ -887,22 +887,22 @@ end The `:counter_cache` option can be used to make finding the number of belonging objects more efficient. Consider these models: ```ruby -class Order < ActiveRecord::Base - belongs_to :customer +class Book < ApplicationRecord + belongs_to :author end -class Customer < ActiveRecord::Base - has_many :orders +class Author < ApplicationRecord + has_many :books end ``` -With these declarations, asking for the value of `@customer.orders.size` requires making a call to the database to perform a `COUNT(*)` query. To avoid this call, you can add a counter cache to the _belonging_ model: +With these declarations, asking for the value of `@author.books.size` requires making a call to the database to perform a `COUNT(*)` query. To avoid this call, you can add a counter cache to the _belonging_ model: ```ruby -class Order < ActiveRecord::Base - belongs_to :customer, counter_cache: true +class Book < ApplicationRecord + belongs_to :author, counter_cache: true end -class Customer < ActiveRecord::Base - has_many :orders +class Author < ApplicationRecord + has_many :books end ``` @@ -911,18 +911,18 @@ With this declaration, Rails will keep the cache value up to date, and then retu Although the `:counter_cache` option is specified on the model that includes the `belongs_to` declaration, the actual column must be added to the _associated_ (`has_many`) model. In the case above, you would need to add a -column named `orders_count` to the `Customer` model. +column named `books_count` to the `Author` model. You can override the default column name by specifying a custom column name in the `counter_cache` declaration instead of `true`. For example, to use -`count_of_orders` instead of `orders_count`: +`count_of_books` instead of `books_count`: ```ruby -class Order < ActiveRecord::Base - belongs_to :customer, counter_cache: :count_of_orders +class Book < ApplicationRecord + belongs_to :author, counter_cache: :count_of_books end -class Customer < ActiveRecord::Base - has_many :orders +class Author < ApplicationRecord + has_many :books end ``` @@ -932,15 +932,13 @@ side of the association. Counter cache columns are added to the containing model's list of read-only attributes through `attr_readonly`. ##### `:dependent` -If you set the `:dependent` option to: +Controls what happens to associated objects when their owner is destroyed: -* `:destroy`, when the object is destroyed, `destroy` will be called on its -associated objects. -* `:delete_all`, when the object is destroyed, all its associated objects will be -deleted directly from the database without calling their `destroy` method. -* `:nullify`, causes the foreign key to be set to `NULL`. Callbacks are not executed. -* `:restrict_with_exception`, causes an exception to be raised if there is an associated record -* `:restrict_with_error`, causes an error to be added to the owner if there is an associated object +* `:destroy` causes the associated objects to also be destroyed. +* `:delete_all` causes the associated objects to be deleted directly from the database (callbacks are not executed). +* `:nullify` causes the foreign keys to be set to `NULL` (callbacks are not executed). +* `:restrict_with_exception` causes an exception to be raised if there are associated records. +* `:restrict_with_error` causes an error to be added to the owner if there are associated objects. WARNING: You should not specify this option on a `belongs_to` association that is connected with a `has_many` association on the other class. Doing so can lead to orphaned records in your database. @@ -949,8 +947,8 @@ WARNING: You should not specify this option on a `belongs_to` association that i By convention, Rails assumes that the column used to hold the foreign key on this model is the name of the association with the suffix `_id` added. The `:foreign_key` option lets you set the name of the foreign key directly: ```ruby -class Order < ActiveRecord::Base - belongs_to :customer, class_name: "Patron", +class Book < ApplicationRecord + belongs_to :author, class_name: "Patron", foreign_key: "patron_id" end ``` @@ -965,11 +963,11 @@ of its tables. The `:primary_key` option allows you to specify a different colum For example, given we have a `users` table with `guid` as the primary key. If we want a separate `todos` table to hold the foreign key `user_id` in the `guid` column, then we can use `primary_key` to achieve this like so: ```ruby -class User < ActiveRecord::Base +class User < ApplicationRecord self.primary_key = 'guid' # primary key is guid and not id end -class Todo < ActiveRecord::Base +class Todo < ApplicationRecord belongs_to :user, primary_key: 'guid' end ``` @@ -982,12 +980,12 @@ When we execute `@user.todos.create` then the `@todo` record will have its The `:inverse_of` option specifies the name of the `has_many` or `has_one` association that is the inverse of this association. Does not work in combination with the `:polymorphic` options. ```ruby -class Customer < ActiveRecord::Base - has_many :orders, inverse_of: :customer +class Author < ApplicationRecord + has_many :books, inverse_of: :author end -class Order < ActiveRecord::Base - belongs_to :customer, inverse_of: :orders +class Book < ApplicationRecord + belongs_to :author, inverse_of: :books end ``` @@ -1000,20 +998,20 @@ Passing `true` to the `:polymorphic` option indicates that this is a polymorphic If you set the `:touch` option to `true`, then the `updated_at` or `updated_on` timestamp on the associated object will be set to the current time whenever this object is saved or destroyed: ```ruby -class Order < ActiveRecord::Base - belongs_to :customer, touch: true +class Book < ApplicationRecord + belongs_to :author, touch: true end -class Customer < ActiveRecord::Base - has_many :orders +class Author < ApplicationRecord + has_many :books end ``` -In this case, saving or destroying an order will update the timestamp on the associated customer. You can also specify a particular timestamp attribute to update: +In this case, saving or destroying an book will update the timestamp on the associated author. You can also specify a particular timestamp attribute to update: ```ruby -class Order < ActiveRecord::Base - belongs_to :customer, touch: :orders_updated_at +class Book < ApplicationRecord + belongs_to :author, touch: :books_updated_at end ``` @@ -1031,8 +1029,8 @@ object won't be validated. By default, this option is set to `false`. There may be times when you wish to customize the query used by `belongs_to`. Such customizations can be achieved via a scope block. For example: ```ruby -class Order < ActiveRecord::Base - belongs_to :customer, -> { where active: true }, +class Book < ApplicationRecord + belongs_to :author, -> { where active: true }, dependent: :destroy end ``` @@ -1049,8 +1047,8 @@ You can use any of the standard [querying methods](active_record_querying.html) The `where` method lets you specify the conditions that the associated object must meet. ```ruby -class Order < ActiveRecord::Base - belongs_to :customer, -> { where active: true } +class book < ApplicationRecord + belongs_to :author, -> { where active: true } end ``` @@ -1059,38 +1057,38 @@ end You can use the `includes` method to specify second-order associations that should be eager-loaded when this association is used. For example, consider these models: ```ruby -class LineItem < ActiveRecord::Base - belongs_to :order +class LineItem < ApplicationRecord + belongs_to :book end -class Order < ActiveRecord::Base - belongs_to :customer +class Book < ApplicationRecord + belongs_to :author has_many :line_items end -class Customer < ActiveRecord::Base - has_many :orders +class Author < ApplicationRecord + has_many :books end ``` -If you frequently retrieve customers directly from line items (`@line_item.order.customer`), then you can make your code somewhat more efficient by including customers in the association from line items to orders: +If you frequently retrieve authors directly from line items (`@line_item.book.author`), then you can make your code somewhat more efficient by including authors in the association from line items to books: ```ruby -class LineItem < ActiveRecord::Base - belongs_to :order, -> { includes :customer } +class LineItem < ApplicationRecord + belongs_to :book, -> { includes :author } end -class Order < ActiveRecord::Base - belongs_to :customer +class Book < ApplicationRecord + belongs_to :author has_many :line_items end -class Customer < ActiveRecord::Base - has_many :orders +class Author < ApplicationRecord + has_many :books end ``` -NOTE: There's no need to use `includes` for immediate associations - that is, if you have `Order belongs_to :customer`, then the customer is eager-loaded automatically when it's needed. +NOTE: There's no need to use `includes` for immediate associations - that is, if you have `Book belongs_to :author`, then the author is eager-loaded automatically when it's needed. ##### `readonly` @@ -1107,8 +1105,8 @@ TIP: If you use the `select` method on a `belongs_to` association, you should al You can see if any associated objects exist by using the `association.nil?` method: ```ruby -if @order.customer.nil? - @msg = "No customer found for this order" +if @book.author.nil? + @msg = "No author found for this book" end ``` @@ -1133,7 +1131,7 @@ When you declare a `has_one` association, the declaring class automatically gain In all of these methods, `association` is replaced with the symbol passed as the first argument to `has_one`. For example, given the declaration: ```ruby -class Supplier < ActiveRecord::Base +class Supplier < ApplicationRecord has_one :account end ``` @@ -1197,7 +1195,7 @@ Does the same as `create_association` above, but raises `ActiveRecord::RecordInv While Rails uses intelligent defaults that will work well in most situations, there may be times when you want to customize the behavior of the `has_one` association reference. Such customizations can easily be accomplished by passing options when you create the association. For example, this association uses two such options: ```ruby -class Supplier < ActiveRecord::Base +class Supplier < ApplicationRecord has_one :account, class_name: "Billing", dependent: :nullify end ``` @@ -1229,7 +1227,7 @@ If you set the `:autosave` option to `true`, Rails will save any loaded members If the name of the other model cannot be derived from the association name, you can use the `:class_name` option to supply the model name. For example, if a supplier has an account, but the actual name of the model containing accounts is `Billing`, you'd set things up this way: ```ruby -class Supplier < ActiveRecord::Base +class Supplier < ApplicationRecord has_one :account, class_name: "Billing" end ``` @@ -1255,7 +1253,7 @@ unallowed `NULL` value. By convention, Rails assumes that the column used to hold the foreign key on the other model is the name of this model with the suffix `_id` added. The `:foreign_key` option lets you set the name of the foreign key directly: ```ruby -class Supplier < ActiveRecord::Base +class Supplier < ApplicationRecord has_one :account, foreign_key: "supp_id" end ``` @@ -1267,11 +1265,11 @@ TIP: In any case, Rails will not create foreign key columns for you. You need to The `:inverse_of` option specifies the name of the `belongs_to` association that is the inverse of this association. Does not work in combination with the `:through` or `:as` options. ```ruby -class Supplier < ActiveRecord::Base +class Supplier < ApplicationRecord has_one :account, inverse_of: :supplier end -class Account < ActiveRecord::Base +class Account < ApplicationRecord belongs_to :supplier, inverse_of: :account end ``` @@ -1301,7 +1299,7 @@ If you set the `:validate` option to `true`, then associated objects will be val There may be times when you wish to customize the query used by `has_one`. Such customizations can be achieved via a scope block. For example: ```ruby -class Supplier < ActiveRecord::Base +class Supplier < ApplicationRecord has_one :account, -> { where active: true } end ``` @@ -1318,7 +1316,7 @@ You can use any of the standard [querying methods](active_record_querying.html) The `where` method lets you specify the conditions that the associated object must meet. ```ruby -class Supplier < ActiveRecord::Base +class Supplier < ApplicationRecord has_one :account, -> { where "confirmed = 1" } end ``` @@ -1328,16 +1326,16 @@ end You can use the `includes` method to specify second-order associations that should be eager-loaded when this association is used. For example, consider these models: ```ruby -class Supplier < ActiveRecord::Base +class Supplier < ApplicationRecord has_one :account end -class Account < ActiveRecord::Base +class Account < ApplicationRecord belongs_to :supplier belongs_to :representative end -class Representative < ActiveRecord::Base +class Representative < ApplicationRecord has_many :accounts end ``` @@ -1345,16 +1343,16 @@ end If you frequently retrieve representatives directly from suppliers (`@supplier.account.representative`), then you can make your code somewhat more efficient by including representatives in the association from suppliers to accounts: ```ruby -class Supplier < ActiveRecord::Base +class Supplier < ApplicationRecord has_one :account, -> { includes :representative } end -class Account < ActiveRecord::Base +class Account < ApplicationRecord belongs_to :supplier belongs_to :representative end -class Representative < ActiveRecord::Base +class Representative < ApplicationRecord has_many :accounts end ``` @@ -1415,30 +1413,30 @@ When you declare a `has_many` association, the declaring class automatically gai In all of these methods, `collection` is replaced with the symbol passed as the first argument to `has_many`, and `collection_singular` is replaced with the singularized version of that symbol. For example, given the declaration: ```ruby -class Customer < ActiveRecord::Base - has_many :orders +class Author < ApplicationRecord + has_many :books end ``` -Each instance of the `Customer` model will have these methods: +Each instance of the `Author` model will have these methods: ```ruby -orders -orders<<(object, ...) -orders.delete(object, ...) -orders.destroy(object, ...) -orders=(objects) -order_ids -order_ids=(ids) -orders.clear -orders.empty? -orders.size -orders.find(...) -orders.where(...) -orders.exists?(...) -orders.build(attributes = {}, ...) -orders.create(attributes = {}) -orders.create!(attributes = {}) +books +books<<(object, ...) +books.delete(object, ...) +books.destroy(object, ...) +books=(objects) +book_ids +book_ids=(ids) +books.clear +books.empty? +books.size +books.find(...) +books.where(...) +books.exists?(...) +books.build(attributes = {}, ...) +books.create(attributes = {}) +books.create!(attributes = {}) ``` ##### `collection` @@ -1446,7 +1444,7 @@ orders.create!(attributes = {}) The `collection` method returns an array of all of the associated objects. If there are no associated objects, it returns an empty array. ```ruby -@orders = @customer.orders +@books = @author.books ``` ##### `collection<<(object, ...)` @@ -1454,7 +1452,7 @@ The `collection` method returns an array of all of the associated objects. If th The `collection<<` method adds one or more objects to the collection by setting their foreign keys to the primary key of the calling model. ```ruby -@customer.orders << @order1 +@author.books << @book1 ``` ##### `collection.delete(object, ...)` @@ -1462,7 +1460,7 @@ The `collection<<` method adds one or more objects to the collection by setting The `collection.delete` method removes one or more objects from the collection by setting their foreign keys to `NULL`. ```ruby -@customer.orders.delete(@order1) +@author.books.delete(@book1) ``` WARNING: Additionally, objects will be destroyed if they're associated with `dependent: :destroy`, and deleted if they're associated with `dependent: :delete_all`. @@ -1472,33 +1470,33 @@ WARNING: Additionally, objects will be destroyed if they're associated with `dep The `collection.destroy` method removes one or more objects from the collection by running `destroy` on each object. ```ruby -@customer.orders.destroy(@order1) +@author.books.destroy(@book1) ``` WARNING: Objects will _always_ be removed from the database, ignoring the `:dependent` option. ##### `collection=(objects)` -The `collection=` method makes the collection contain only the supplied objects, by adding and deleting as appropriate. +The `collection=` method makes the collection contain only the supplied objects, by adding and deleting as appropriate. The changes are persisted to the database. ##### `collection_singular_ids` The `collection_singular_ids` method returns an array of the ids of the objects in the collection. ```ruby -@order_ids = @customer.order_ids +@book_ids = @author.book_ids ``` ##### `collection_singular_ids=(ids)` -The `collection_singular_ids=` method makes the collection contain only the objects identified by the supplied primary key values, by adding and deleting as appropriate. +The `collection_singular_ids=` method makes the collection contain only the objects identified by the supplied primary key values, by adding and deleting as appropriate. The changes are persisted to the database. ##### `collection.clear` The `collection.clear` method removes all objects from the collection according to the strategy specified by the `dependent` option. If no option is given, it follows the default strategy. The default strategy for `has_many :through` associations is `delete_all`, and for `has_many` associations is to set the foreign keys to `NULL`. ```ruby -@customer.orders.clear +@author.books.clear ``` WARNING: Objects will be deleted if they're associated with `dependent: :destroy`, @@ -1509,8 +1507,8 @@ just like `dependent: :delete_all`. The `collection.empty?` method returns `true` if the collection does not contain any associated objects. ```erb -<% if @customer.orders.empty? %> - No Orders Found +<% if @author.books.empty? %> + No Books Found <% end %> ``` @@ -1519,7 +1517,7 @@ The `collection.empty?` method returns `true` if the collection does not contain The `collection.size` method returns the number of objects in the collection. ```ruby -@order_count = @customer.orders.size +@book_count = @author.books.size ``` ##### `collection.find(...)` @@ -1527,7 +1525,7 @@ The `collection.size` method returns the number of objects in the collection. The `collection.find` method finds objects within the collection. It uses the same syntax and options as `ActiveRecord::Base.find`. ```ruby -@open_orders = @customer.orders.find(1) +@available_books = @author.books.find(1) ``` ##### `collection.where(...)` @@ -1535,8 +1533,8 @@ The `collection.find` method finds objects within the collection. It uses the sa The `collection.where` method finds objects within the collection based on the conditions supplied but the objects are loaded lazily meaning that the database is queried only when the object(s) are accessed. ```ruby -@open_orders = @customer.orders.where(open: true) # No query yet -@open_order = @open_orders.first # Now the database will be queried +@available_books = @author.books.where(available: true) # No query yet +@available_book = @available_books.first # Now the database will be queried ``` ##### `collection.exists?(...)` @@ -1550,12 +1548,12 @@ conditions exists in the collection. It uses the same syntax and options as The `collection.build` method returns a single or array of new objects of the associated type. The object(s) will be instantiated from the passed attributes, and the link through their foreign key will be created, but the associated objects will _not_ yet be saved. ```ruby -@order = @customer.orders.build(order_date: Time.now, - order_number: "A12345") +@book = @author.books.build(published_at: Time.now, + book_number: "A12345") -@orders = @customer.orders.build([ - { order_date: Time.now, order_number: "A12346" }, - { order_date: Time.now, order_number: "A12347" } +@books = @author.books.build([ + { published_at: Time.now, book_number: "A12346" }, + { published_at: Time.now, book_number: "A12347" } ]) ``` @@ -1564,12 +1562,12 @@ The `collection.build` method returns a single or array of new objects of the as The `collection.create` method returns a single or array of new objects of the associated type. The object(s) will be instantiated from the passed attributes, the link through its foreign key will be created, and, once it passes all of the validations specified on the associated model, the associated object _will_ be saved. ```ruby -@order = @customer.orders.create(order_date: Time.now, - order_number: "A12345") +@book = @author.books.create(published_at: Time.now, + book_number: "A12345") -@orders = @customer.orders.create([ - { order_date: Time.now, order_number: "A12346" }, - { order_date: Time.now, order_number: "A12347" } +@books = @author.books.create([ + { published_at: Time.now, book_number: "A12346" }, + { published_at: Time.now, book_number: "A12347" } ]) ``` @@ -1582,8 +1580,8 @@ Does the same as `collection.create` above, but raises `ActiveRecord::RecordInva While Rails uses intelligent defaults that will work well in most situations, there may be times when you want to customize the behavior of the `has_many` association reference. Such customizations can easily be accomplished by passing options when you create the association. For example, this association uses two such options: ```ruby -class Customer < ActiveRecord::Base - has_many :orders, dependent: :delete_all, validate: false +class Author < ApplicationRecord + has_many :books, dependent: :delete_all, validate: false end ``` @@ -1612,11 +1610,11 @@ If you set the `:autosave` option to `true`, Rails will save any loaded members ##### `:class_name` -If the name of the other model cannot be derived from the association name, you can use the `:class_name` option to supply the model name. For example, if a customer has many orders, but the actual name of the model containing orders is `Transaction`, you'd set things up this way: +If the name of the other model cannot be derived from the association name, you can use the `:class_name` option to supply the model name. For example, if an author has many books, but the actual name of the model containing books is `Transaction`, you'd set things up this way: ```ruby -class Customer < ActiveRecord::Base - has_many :orders, class_name: "Transaction" +class Author < ApplicationRecord + has_many :books, class_name: "Transaction" end ``` @@ -1639,8 +1637,8 @@ Controls what happens to the associated objects when their owner is destroyed: By convention, Rails assumes that the column used to hold the foreign key on the other model is the name of this model with the suffix `_id` added. The `:foreign_key` option lets you set the name of the foreign key directly: ```ruby -class Customer < ActiveRecord::Base - has_many :orders, foreign_key: "cust_id" +class Author < ApplicationRecord + has_many :books, foreign_key: "cust_id" end ``` @@ -1651,12 +1649,12 @@ TIP: In any case, Rails will not create foreign key columns for you. You need to The `:inverse_of` option specifies the name of the `belongs_to` association that is the inverse of this association. Does not work in combination with the `:through` or `:as` options. ```ruby -class Customer < ActiveRecord::Base - has_many :orders, inverse_of: :customer +class Author < ApplicationRecord + has_many :books, inverse_of: :author end -class Order < ActiveRecord::Base - belongs_to :customer, inverse_of: :orders +class Book < ApplicationRecord + belongs_to :author, inverse_of: :books end ``` @@ -1670,7 +1668,7 @@ hold the `guid` column value as the foreign key and not `id` value. This can be achieved like this: ```ruby -class User < ActiveRecord::Base +class User < ApplicationRecord has_many :todos, primary_key: :guid end ``` @@ -1700,8 +1698,8 @@ If you set the `:validate` option to `false`, then associated objects will not b There may be times when you wish to customize the query used by `has_many`. Such customizations can be achieved via a scope block. For example: ```ruby -class Customer < ActiveRecord::Base - has_many :orders, -> { where processed: true } +class Author < ApplicationRecord + has_many :books, -> { where processed: true } end ``` @@ -1723,22 +1721,22 @@ You can use any of the standard [querying methods](active_record_querying.html) The `where` method lets you specify the conditions that the associated object must meet. ```ruby -class Customer < ActiveRecord::Base - has_many :confirmed_orders, -> { where "confirmed = 1" }, - class_name: "Order" +class Author < ApplicationRecord + has_many :confirmed_books, -> { where "confirmed = 1" }, + class_name: "Book" end ``` You can also set conditions via a hash: ```ruby -class Customer < ActiveRecord::Base - has_many :confirmed_orders, -> { where confirmed: true }, - class_name: "Order" +class Author < ApplicationRecord + has_many :confirmed_books, -> { where confirmed: true }, + class_name: "Book" end ``` -If you use a hash-style `where` option, then record creation via this association will be automatically scoped using the hash. In this case, using `@customer.confirmed_orders.create` or `@customer.confirmed_orders.build` will create orders where the confirmed column has the value `true`. +If you use a hash-style `where` option, then record creation via this association will be automatically scoped using the hash. In this case, using `@author.confirmed_books.create` or `@author.confirmed_books.build` will create books where the confirmed column has the value `true`. ##### `extending` @@ -1749,9 +1747,9 @@ The `extending` method specifies a named module to extend the association proxy. The `group` method supplies an attribute name to group the result set by, using a `GROUP BY` clause in the finder SQL. ```ruby -class Customer < ActiveRecord::Base - has_many :line_items, -> { group 'orders.id' }, - through: :orders +class Author < ApplicationRecord + has_many :line_items, -> { group 'books.id' }, + through: :books end ``` @@ -1760,34 +1758,34 @@ end You can use the `includes` method to specify second-order associations that should be eager-loaded when this association is used. For example, consider these models: ```ruby -class Customer < ActiveRecord::Base - has_many :orders +class Author < ApplicationRecord + has_many :books end -class Order < ActiveRecord::Base - belongs_to :customer +class Book < ApplicationRecord + belongs_to :author has_many :line_items end -class LineItem < ActiveRecord::Base - belongs_to :order +class LineItem < ApplicationRecord + belongs_to :book end ``` -If you frequently retrieve line items directly from customers (`@customer.orders.line_items`), then you can make your code somewhat more efficient by including line items in the association from customers to orders: +If you frequently retrieve line items directly from authors (`@author.books.line_items`), then you can make your code somewhat more efficient by including line items in the association from authors to books: ```ruby -class Customer < ActiveRecord::Base - has_many :orders, -> { includes :line_items } +class Author < ApplicationRecord + has_many :books, -> { includes :line_items } end -class Order < ActiveRecord::Base - belongs_to :customer +class Book < ApplicationRecord + belongs_to :author has_many :line_items end -class LineItem < ActiveRecord::Base - belongs_to :order +class LineItem < ApplicationRecord + belongs_to :book end ``` @@ -1796,10 +1794,10 @@ end The `limit` method lets you restrict the total number of objects that will be fetched through an association. ```ruby -class Customer < ActiveRecord::Base - has_many :recent_orders, - -> { order('order_date desc').limit(100) }, - class_name: "Order", +class Author < ApplicationRecord + has_many :recent_books, + -> { order('published_at desc').limit(100) }, + class_name: "Book", end ``` @@ -1812,8 +1810,8 @@ The `offset` method lets you specify the starting offset for fetching objects vi The `order` method dictates the order in which associated objects will be received (in the syntax used by an SQL `ORDER BY` clause). ```ruby -class Customer < ActiveRecord::Base - has_many :orders, -> { order "date_confirmed DESC" } +class Author < ApplicationRecord + has_many :books, -> { order "date_confirmed DESC" } end ``` @@ -1833,7 +1831,7 @@ Use the `distinct` method to keep the collection free of duplicates. This is mostly useful together with the `:through` option. ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord has_many :readings has_many :articles, through: :readings end @@ -1872,11 +1870,21 @@ If you want to make sure that, upon insertion, all of the records in the persisted association are distinct (so that you can be sure that when you inspect the association that you will never find duplicate records), you should add a unique index on the table itself. For example, if you have a table named -`person_articles` and you want to make sure all the articles are unique, you could -add the following in a migration: +`readings` and you want to make sure the articles can only be added to a person once, +you could add the following in a migration: ```ruby -add_index :person_articles, :article, unique: true +add_index :readings, [:person_id, :article_id], unique: true +``` + +Once you have this unique index, attempting to add the article to a person twice +will raise an `ActiveRecord::RecordNotUnique` error: + +```ruby +person = Person.create(name: 'Honda') +article = Article.create(name: 'a1') +person.articles << article +person.articles << article # => ActiveRecord::RecordNotUnique ``` Note that checking for uniqueness using something like `include?` is subject @@ -1927,7 +1935,7 @@ When you declare a `has_and_belongs_to_many` association, the declaring class au In all of these methods, `collection` is replaced with the symbol passed as the first argument to `has_and_belongs_to_many`, and `collection_singular` is replaced with the singularized version of that symbol. For example, given the declaration: ```ruby -class Part < ActiveRecord::Base +class Part < ApplicationRecord has_and_belongs_to_many :assemblies end ``` @@ -1998,7 +2006,7 @@ The `collection.destroy` method removes one or more objects from the collection ##### `collection=(objects)` -The `collection=` method makes the collection contain only the supplied objects, by adding and deleting as appropriate. +The `collection=` method makes the collection contain only the supplied objects, by adding and deleting as appropriate. The changes are persisted to the database. ##### `collection_singular_ids` @@ -2010,7 +2018,7 @@ The `collection_singular_ids` method returns an array of the ids of the objects ##### `collection_singular_ids=(ids)` -The `collection_singular_ids=` method makes the collection contain only the objects identified by the supplied primary key values, by adding and deleting as appropriate. +The `collection_singular_ids=` method makes the collection contain only the objects identified by the supplied primary key values, by adding and deleting as appropriate. The changes are persisted to the database. ##### `collection.clear` @@ -2081,7 +2089,7 @@ Does the same as `collection.create`, but raises `ActiveRecord::RecordInvalid` i While Rails uses intelligent defaults that will work well in most situations, there may be times when you want to customize the behavior of the `has_and_belongs_to_many` association reference. Such customizations can easily be accomplished by passing options when you create the association. For example, this association uses two such options: ```ruby -class Parts < ActiveRecord::Base +class Parts < ApplicationRecord has_and_belongs_to_many :assemblies, -> { readonly }, autosave: true end @@ -2103,7 +2111,7 @@ By convention, Rails assumes that the column in the join table used to hold the TIP: The `:foreign_key` and `:association_foreign_key` options are useful when setting up a many-to-many self-join. For example: ```ruby -class User < ActiveRecord::Base +class User < ApplicationRecord has_and_belongs_to_many :friends, class_name: "User", foreign_key: "this_user_id", @@ -2120,7 +2128,7 @@ If you set the `:autosave` option to `true`, Rails will save any loaded members If the name of the other model cannot be derived from the association name, you can use the `:class_name` option to supply the model name. For example, if a part has many assemblies, but the actual name of the model containing assemblies is `Gadget`, you'd set things up this way: ```ruby -class Parts < ActiveRecord::Base +class Parts < ApplicationRecord has_and_belongs_to_many :assemblies, class_name: "Gadget" end ``` @@ -2130,7 +2138,7 @@ end By convention, Rails assumes that the column in the join table used to hold the foreign key pointing to this model is the name of this model with the suffix `_id` added. The `:foreign_key` option lets you set the name of the foreign key directly: ```ruby -class User < ActiveRecord::Base +class User < ApplicationRecord has_and_belongs_to_many :friends, class_name: "User", foreign_key: "this_user_id", @@ -2151,7 +2159,7 @@ If you set the `:validate` option to `false`, then associated objects will not b There may be times when you wish to customize the query used by `has_and_belongs_to_many`. Such customizations can be achieved via a scope block. For example: ```ruby -class Parts < ActiveRecord::Base +class Parts < ApplicationRecord has_and_belongs_to_many :assemblies, -> { where active: true } end ``` @@ -2174,7 +2182,7 @@ You can use any of the standard [querying methods](active_record_querying.html) The `where` method lets you specify the conditions that the associated object must meet. ```ruby -class Parts < ActiveRecord::Base +class Parts < ApplicationRecord has_and_belongs_to_many :assemblies, -> { where "factory = 'Seattle'" } end @@ -2183,7 +2191,7 @@ end You can also set conditions via a hash: ```ruby -class Parts < ActiveRecord::Base +class Parts < ApplicationRecord has_and_belongs_to_many :assemblies, -> { where factory: 'Seattle' } end @@ -2200,7 +2208,7 @@ The `extending` method specifies a named module to extend the association proxy. The `group` method supplies an attribute name to group the result set by, using a `GROUP BY` clause in the finder SQL. ```ruby -class Parts < ActiveRecord::Base +class Parts < ApplicationRecord has_and_belongs_to_many :assemblies, -> { group "factory" } end ``` @@ -2214,7 +2222,7 @@ You can use the `includes` method to specify second-order associations that shou The `limit` method lets you restrict the total number of objects that will be fetched through an association. ```ruby -class Parts < ActiveRecord::Base +class Parts < ApplicationRecord has_and_belongs_to_many :assemblies, -> { order("created_at DESC").limit(50) } end @@ -2229,7 +2237,7 @@ The `offset` method lets you specify the starting offset for fetching objects vi The `order` method dictates the order in which associated objects will be received (in the syntax used by an SQL `ORDER BY` clause). ```ruby -class Parts < ActiveRecord::Base +class Parts < ApplicationRecord has_and_belongs_to_many :assemblies, -> { order "assembly_name ASC" } end @@ -2271,10 +2279,10 @@ Association callbacks are similar to normal callbacks, but they are triggered by You define association callbacks by adding options to the association declaration. For example: ```ruby -class Customer < ActiveRecord::Base - has_many :orders, before_add: :check_credit_limit +class Author < ApplicationRecord + has_many :books, before_add: :check_credit_limit - def check_credit_limit(order) + def check_credit_limit(book) ... end end @@ -2285,15 +2293,15 @@ Rails passes the object being added or removed to the callback. You can stack callbacks on a single event by passing them as an array: ```ruby -class Customer < ActiveRecord::Base - has_many :orders, +class Author < ApplicationRecord + has_many :books, before_add: [:check_credit_limit, :calculate_shipping_charges] - def check_credit_limit(order) + def check_credit_limit(book) ... end - def calculate_shipping_charges(order) + def calculate_shipping_charges(book) ... end end @@ -2306,10 +2314,10 @@ If a `before_add` callback throws an exception, the object does not get added to You're not limited to the functionality that Rails automatically builds into association proxy objects. You can also extend these objects through anonymous modules, adding new finders, creators, or other methods. For example: ```ruby -class Customer < ActiveRecord::Base - has_many :orders do - def find_by_order_prefix(order_number) - find_by(region_id: order_number[0..2]) +class Author < ApplicationRecord + has_many :books do + def find_by_book_prefix(book_number) + find_by(category_id: book_number[0..2]) end end end @@ -2324,11 +2332,11 @@ module FindRecentExtension end end -class Customer < ActiveRecord::Base - has_many :orders, -> { extending FindRecentExtension } +class Author < ApplicationRecord + has_many :books, -> { extending FindRecentExtension } end -class Supplier < ActiveRecord::Base +class Supplier < ApplicationRecord has_many :deliveries, -> { extending FindRecentExtension } end ``` diff --git a/guides/source/autoloading_and_reloading_constants.md b/guides/source/autoloading_and_reloading_constants.md index 2b6d7e4044..61657023e7 100644 --- a/guides/source/autoloading_and_reloading_constants.md +++ b/guides/source/autoloading_and_reloading_constants.md @@ -181,14 +181,14 @@ constant. That is, ```ruby -class Project < ActiveRecord::Base +class Project < ApplicationRecord end ``` performs a constant assignment equivalent to ```ruby -Project = Class.new(ActiveRecord::Base) +Project = Class.new(ApplicationRecord) ``` including setting the name of the class as a side-effect: @@ -449,9 +449,10 @@ Alright, Rails has a collection of directories similar to `$LOAD_PATH` in which to look up `post.rb`. That collection is called `autoload_paths` and by default it contains: -* All subdirectories of `app` in the application and engines. For example, - `app/controllers`. They do not need to be the default ones, any custom - directories like `app/workers` belong automatically to `autoload_paths`. +* All subdirectories of `app` in the application and engines present at boot + time. For example, `app/controllers`. They do not need to be the default + ones, any custom directories like `app/workers` belong automatically to + `autoload_paths`. * Any existing second level directories called `app/*/concerns` in the application and engines. @@ -524,7 +525,7 @@ On the contrary, if `ApplicationController` is unknown, the constant is considered missing and an autoload is going to be attempted by Rails. In order to load `ApplicationController`, Rails iterates over `autoload_paths`. -First checks if `app/assets/application_controller.rb` exists. If it does not, +First it checks if `app/assets/application_controller.rb` exists. If it does not, which is normally the case, it continues and finds `app/controllers/application_controller.rb`. @@ -624,7 +625,7 @@ file is loaded. If the file actually defines `Post` all is fine, otherwise ### Qualified References When a qualified constant is missing Rails does not look for it in the parent -namespaces. But there is a caveat: When a constant is missing, Rails is +namespaces. But there is a caveat: when a constant is missing, Rails is unable to tell if the trigger was a relative reference or a qualified one. For example, consider @@ -685,7 +686,7 @@ to trigger the heuristic is defined in the conflicting place. ### Automatic Modules When a module acts as a namespace, Rails does not require the application to -defines a file for it, a directory matching the namespace is enough. +define a file for it, a directory matching the namespace is enough. Suppose an application has a back office whose controllers are stored in `app/controllers/admin`. If the `Admin` module is not yet loaded when @@ -790,7 +791,7 @@ Constant Reloading When `config.cache_classes` is false Rails is able to reload autoloaded constants. -For example, in you're in a console session and edit some file behind the +For example, if you're in a console session and edit some file behind the scenes, the code can be reloaded with the `reload!` command: ``` @@ -912,7 +913,7 @@ these classes: ```ruby # app/models/polygon.rb -class Polygon < ActiveRecord::Base +class Polygon < ApplicationRecord end # app/models/triangle.rb @@ -987,7 +988,7 @@ root class: ```ruby # app/models/polygon.rb -class Polygon < ActiveRecord::Base +class Polygon < ApplicationRecord end require_dependency ‘square’ ``` diff --git a/guides/source/caching_with_rails.md b/guides/source/caching_with_rails.md index 9a56233e4a..6c734c1d78 100644 --- a/guides/source/caching_with_rails.md +++ b/guides/source/caching_with_rails.md @@ -100,8 +100,8 @@ called key-based expiration. Cache fragments will also be expired when the view fragment changes (e.g., the HTML in the view changes). The string of characters at the end of the key is a -template tree digest. It is an md5 hash computed based on the contents of the -view fragment you are caching. If you change the view fragment, the md5 hash +template tree digest. It is an MD5 hash computed based on the contents of the +view fragment you are caching. If you change the view fragment, the MD5 hash will change, expiring the existing file. TIP: Cache stores like Memcached will automatically delete old cache files. @@ -119,25 +119,16 @@ If you want to cache a fragment under certain conditions, you can use The `render` helper can also cache individual templates rendered for a collection. It can even one up the previous example with `each` by reading all cache -templates at once instead of one by one. This is done automatically if the template -rendered by the collection includes a `cache` call. Take a collection that renders -a `products/_product.html.erb` partial for each element: - -```ruby -render products -``` - -If `products/_product.html.erb` starts with a `cache` call like so: +templates at once instead of one by one. This is done by passing `cached: true` when rendering the collection: ```html+erb -<% cache product do %> - <%= product.name %> -<% end %> +<%= render partial: 'products/product', collection: @products, cached: true %> ``` -All the cached templates from previous renders will be fetched at once with much -greater speed. There's more info on how to make your templates [eligible for -collection caching](http://api.rubyonrails.org/classes/ActionView/Template/Handlers/ERB.html#method-i-resource_cache_call_pattern). +All cached templates from previous renders will be fetched at once with much +greater speed. Additionally, the templates that haven't yet been cached will be +written to cache and multi fetched on the next render. + ### Russian Doll Caching @@ -175,11 +166,11 @@ your app will serve stale data. To fix this, we tie the models together with the `touch` method: ```ruby -class Product < ActiveRecord::Base +class Product < ApplicationRecord has_many :games end -class Game < ActiveRecord::Base +class Game < ApplicationRecord belongs_to :product, touch: true end ``` @@ -267,7 +258,7 @@ comment format anywhere in the template, like: If you use a helper method, for example, inside a cached block and you then update that helper, you'll have to bump the cache as well. It doesn't really matter how -you do it, but the md5 of the template file must change. One recommendation is to +you do it, but the MD5 of the template file must change. One recommendation is to simply be explicit in a comment, like: ```html+erb @@ -284,7 +275,7 @@ The most efficient way to implement low-level caching is using the `Rails.cache. Consider the following example. An application has a `Product` model with an instance method that looks up the product’s price on a competing website. The data returned by this method would be perfect for low-level caching: ```ruby -class Product < ActiveRecord::Base +class Product < ApplicationRecord def competing_price Rails.cache.fetch("#{cache_key}/competing_price", expires_in: 12.hours) do Competitor::API.find_price(id) @@ -521,6 +512,40 @@ class ProductsController < ApplicationController end ``` +### Strong v/s Weak ETags + +Rails generates weak ETags by default. Weak ETags allow semantically equivalent +responses to have the same ETags, even if their bodies do not match exactly. +This is useful when we don't want the page to be regenerated for minor changes in +response body. + +Weak ETags have a leading `W/` to differentiate them from strong ETags. + +``` + W/"618bbc92e2d35ea1945008b42799b0e7" → Weak ETag + "618bbc92e2d35ea1945008b42799b0e7" → Strong ETag +``` + +Unlike weak ETag, strong ETag implies that response should be exactly the same +and byte by byte identical. Useful when doing Range requests within a +large video or PDF file. Some CDNs support only strong ETags, like Akamai. +If you absolutely need to generate a strong ETag, it can be done as follows. + +```ruby + class ProductsController < ApplicationController + def show + @product = Product.find(params[:id]) + fresh_when last_modified: @product.published_at.utc, strong_etag: @product + end + end +``` + +You can also set the strong ETag directly on the response. + +```ruby + response.strong_etag = response.body # => "618bbc92e2d35ea1945008b42799b0e7" +``` + References ---------- diff --git a/guides/source/command_line.md b/guides/source/command_line.md index e85f9fc9c6..0e6d119681 100644 --- a/guides/source/command_line.md +++ b/guides/source/command_line.md @@ -21,7 +21,7 @@ There are a few commands that are absolutely critical to your everyday usage of * `rails console` * `rails server` -* `rake` +* `bin/rails` * `rails generate` * `rails dbconsole` * `rails new app_name` @@ -39,7 +39,7 @@ INFO: You can install the rails gem by typing `gem install rails`, if you don't ```bash $ rails new commandsapp create - create README.rdoc + create README.md create Rakefile create config.ru create .gitignore @@ -55,20 +55,22 @@ Rails will set you up with what seems like a huge amount of stuff for such a tin ### `rails server` -The `rails server` command launches a small web server named WEBrick which comes bundled with Ruby. You'll use this any time you want to access your application through a web browser. +The `rails server` command launches a web server named Puma which comes bundled with Rails. You'll use this any time you want to access your application through a web browser. With no further work, `rails server` will run our new shiny Rails app: ```bash $ cd commandsapp $ bin/rails server -=> Booting WEBrick -=> Rails 5.0.0 application starting in development on http://localhost:3000 +=> Booting Puma +=> Rails 5.0.0 application starting in development on http://0.0.0.0:3000 => Run `rails server -h` for more startup options -=> Ctrl-C to shutdown server -[2013-08-07 02:00:01] INFO WEBrick 1.3.1 -[2013-08-07 02:00:01] INFO ruby 2.2.2 (2015-06-27) [x86_64-darwin11.2.0] -[2013-08-07 02:00:01] INFO WEBrick::HTTPServer#start: pid=69680 port=3000 +Puma starting in single mode... +* Version 3.0.2 (ruby 2.3.0-p0), codename: Plethora of Penguin Pinatas +* Min threads: 5, max threads: 5 +* Environment: development +* Listening on tcp://localhost:3000 +Use Ctrl-C to stop ``` With just three commands we whipped up a Rails server listening on port 3000. Go to your browser and open [http://localhost:3000](http://localhost:3000), you will see a basic Rails app running. @@ -181,7 +183,7 @@ Fire up your server using `rails server`. ```bash $ bin/rails server -=> Booting WEBrick... +=> Booting Puma... ``` The URL will be [http://localhost:3000/greetings/hello](http://localhost:3000/greetings/hello). @@ -250,10 +252,10 @@ $ bin/rails generate scaffold HighScore game:string score:integer The generator checks that there exist the directories for models, controllers, helpers, layouts, functional and unit tests, stylesheets, creates the views, controller, model and database migration for HighScore (creating the `high_scores` table and fields), takes care of the route for the **resource**, and new tests for everything. -The migration requires that we **migrate**, that is, run some Ruby code (living in that `20130717151933_create_high_scores.rb`) to modify the schema of our database. Which database? The SQLite3 database that Rails will create for you when we run the `rake db:migrate` command. We'll talk more about Rake in-depth in a little while. +The migration requires that we **migrate**, that is, run some Ruby code (living in that `20130717151933_create_high_scores.rb`) to modify the schema of our database. Which database? The SQLite3 database that Rails will create for you when we run the `bin/rails db:migrate` command. We'll talk more about bin/rails in-depth in a little while. ```bash -$ bin/rake db:migrate +$ bin/rails db:migrate == CreateHighScores: migrating =============================================== -- create_table(:high_scores) -> 0.0017s @@ -324,7 +326,7 @@ With the `helper` method it is possible to access Rails and your application's h ### `rails dbconsole` -`rails dbconsole` figures out which database you're using and drops you into whichever command line interface you would use with it (and figures out the command line parameters to give to it, too!). It supports MySQL, PostgreSQL, SQLite and SQLite3. +`rails dbconsole` figures out which database you're using and drops you into whichever command line interface you would use with it (and figures out the command line parameters to give to it, too!). It supports MySQL (including MariaDB), PostgreSQL and SQLite3. INFO: You can also use the alias "db" to invoke the dbconsole: `rails db`. @@ -375,44 +377,63 @@ $ bin/rails destroy model Oops remove test/fixtures/oops.yml ``` -Rake ----- +bin/rails +--------- -Rake is Ruby Make, a standalone Ruby utility that replaces the Unix utility 'make', and uses a 'Rakefile' and `.rake` files to build up a list of tasks. In Rails, Rake is used for common administration tasks, especially sophisticated ones that build off of each other. +Since Rails 5.0+ has rake commands built into the rails executable, `bin/rails` is the new default for running commands. -You can get a list of Rake tasks available to you, which will often depend on your current directory, by typing `rake --tasks`. Each task has a description, and should help you find the thing you need. - -To get the full backtrace for running rake task you can pass the option `--trace` to command line, for example `rake db:create --trace`. +You can get a list of bin/rails tasks available to you, which will often depend on your current directory, by typing `bin/rails --help`. Each task has a description, and should help you find the thing you need. ```bash -$ bin/rake --tasks -rake about # List versions of all Rails frameworks and the environment -rake assets:clean # Remove old compiled assets -rake assets:clobber # Remove compiled assets -rake assets:precompile # Compile all the assets named in config.assets.precompile -rake db:create # Create the database from config/database.yml for the current Rails.env +$ bin/rails --help +Usage: rails COMMAND [ARGS] + +The most common rails commands are: +generate Generate new code (short-cut alias: "g") +console Start the Rails console (short-cut alias: "c") +server Start the Rails server (short-cut alias: "s") +... + +All commands can be run with -h (or --help) for more information. + +In addition to those commands, there are: +about List versions of all Rails ... +assets:clean[keep] Remove old compiled assets +assets:clobber Remove compiled assets +assets:environment Load asset compile environment +assets:precompile Compile all the assets ... ... -rake log:clear # Truncates all *.log files in log/ to zero bytes (specify which logs with LOGS=test,development) -rake middleware # Prints out your Rack middleware stack +db:fixtures:load Loads fixtures into the ... +db:migrate Migrate the database ... +db:migrate:status Display status of migrations +db:rollback Rolls the schema back to ... +db:schema:cache:clear Clears a db/schema_cache.dump file +db:schema:cache:dump Creates a db/schema_cache.dump file +db:schema:dump Creates a db/schema.rb file ... +db:schema:load Loads a schema.rb file ... +db:seed Loads the seed data ... +db:structure:dump Dumps the database structure ... +db:structure:load Recreates the databases ... +db:version Retrieves the current schema ... ... -rake tmp:clear # Clear cache and socket files from tmp/ (narrow w/ tmp:cache:clear, tmp:sockets:clear) -rake tmp:create # Creates tmp directories for cache, sockets, and pids +restart Restart app by touching ... +tmp:create Creates tmp directories ... ``` -INFO: You can also use `rake -T` to get the list of tasks. +INFO: You can also use `bin/rails -T` to get the list of tasks. ### `about` -`rake about` gives information about version numbers for Ruby, RubyGems, Rails, the Rails subcomponents, your application's folder, the current Rails environment name, your app's database adapter, and schema version. It is useful when you need to ask for help, check if a security patch might affect you, or when you need some stats for an existing Rails installation. +`bin/rails about` gives information about version numbers for Ruby, RubyGems, Rails, the Rails subcomponents, your application's folder, the current Rails environment name, your app's database adapter, and schema version. It is useful when you need to ask for help, check if a security patch might affect you, or when you need some stats for an existing Rails installation. ```bash -$ bin/rake about +$ bin/rails about About your application's environment Rails version 5.0.0 Ruby version 2.2.2 (x86_64-linux) RubyGems version 2.4.6 Rack version 1.6 JavaScript Runtime Node.js (V8) -Middleware Rack::Sendfile, ActionDispatch::Static, Rack::Lock, #<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x007ffd131a7c88>, Rack::Runtime, Rack::MethodOverride, ActionDispatch::RequestId, Rails::Rack::Logger, ActionDispatch::ShowExceptions, ActionDispatch::DebugExceptions, ActionDispatch::RemoteIp, ActionDispatch::Reloader, ActionDispatch::Callbacks, ActiveRecord::Migration::CheckPending, ActiveRecord::ConnectionAdapters::ConnectionManagement, ActiveRecord::QueryCache, ActionDispatch::Cookies, ActionDispatch::Session::CookieStore, ActionDispatch::Flash, Rack::Head, Rack::ConditionalGet, Rack::ETag +Middleware Rack::Sendfile, ActionDispatch::Static, ActionDispatch::Executor, #<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x007ffd131a7c88>, Rack::Runtime, Rack::MethodOverride, ActionDispatch::RequestId, Rails::Rack::Logger, ActionDispatch::ShowExceptions, ActionDispatch::DebugExceptions, ActionDispatch::RemoteIp, ActionDispatch::Reloader, ActionDispatch::Callbacks, ActiveRecord::Migration::CheckPending, ActiveRecord::ConnectionAdapters::ConnectionManagement, ActiveRecord::QueryCache, ActionDispatch::Cookies, ActionDispatch::Session::CookieStore, ActionDispatch::Flash, Rack::Head, Rack::ConditionalGet, Rack::ETag Application root /home/foobar/commandsapp Environment development Database adapter sqlite3 @@ -421,22 +442,22 @@ Database schema version 20110805173523 ### `assets` -You can precompile the assets in `app/assets` using `rake assets:precompile`, and remove older compiled assets using `rake assets:clean`. The `assets:clean` task allows for rolling deploys that may still be linking to an old asset while the new assets are being built. +You can precompile the assets in `app/assets` using `bin/rails assets:precompile`, and remove older compiled assets using `bin/rails assets:clean`. The `assets:clean` task allows for rolling deploys that may still be linking to an old asset while the new assets are being built. -If you want to clear `public/assets` completely, you can use `rake assets:clobber`. +If you want to clear `public/assets` completely, you can use `bin/rails assets:clobber`. ### `db` -The most common tasks of the `db:` Rake namespace are `migrate` and `create`, and it will pay off to try out all of the migration rake tasks (`up`, `down`, `redo`, `reset`). `rake db:version` is useful when troubleshooting, telling you the current version of the database. +The most common tasks of the `db:` bin/rails namespace are `migrate` and `create`, and it will pay off to try out all of the migration bin/rails tasks (`up`, `down`, `redo`, `reset`). `bin/rails db:version` is useful when troubleshooting, telling you the current version of the database. More information about migrations can be found in the [Migrations](active_record_migrations.html) guide. ### `notes` -`rake notes` will search through your code for comments beginning with FIXME, OPTIMIZE or TODO. The search is done in files with extension `.builder`, `.rb`, `.rake`, `.yml`, `.yaml`, `.ruby`, `.css`, `.js` and `.erb` for both default and custom annotations. +`bin/rails notes` will search through your code for comments beginning with FIXME, OPTIMIZE or TODO. The search is done in files with extension `.builder`, `.rb`, `.rake`, `.yml`, `.yaml`, `.ruby`, `.css`, `.js` and `.erb` for both default and custom annotations. ```bash -$ bin/rake notes +$ bin/rails notes (in /home/foobar/commandsapp) app/controllers/admin/users_controller.rb: * [ 20] [TODO] any other way to do this? @@ -453,10 +474,10 @@ You can add support for new file extensions using `config.annotations.register_e config.annotations.register_extensions("scss", "sass", "less") { |annotation| /\/\/\s*(#{annotation}):?\s*(.*)$/ } ``` -If you are looking for a specific annotation, say FIXME, you can use `rake notes:fixme`. Note that you have to lower case the annotation's name. +If you are looking for a specific annotation, say FIXME, you can use `bin/rails notes:fixme`. Note that you have to lower case the annotation's name. ```bash -$ bin/rake notes:fixme +$ bin/rails notes:fixme (in /home/foobar/commandsapp) app/controllers/admin/users_controller.rb: * [132] high priority for next deploy @@ -465,10 +486,10 @@ app/models/school.rb: * [ 17] ``` -You can also use custom annotations in your code and list them using `rake notes:custom` by specifying the annotation using an environment variable `ANNOTATION`. +You can also use custom annotations in your code and list them using `bin/rails notes:custom` by specifying the annotation using an environment variable `ANNOTATION`. ```bash -$ bin/rake notes:custom ANNOTATION=BUG +$ bin/rails notes:custom ANNOTATION=BUG (in /home/foobar/commandsapp) app/models/article.rb: * [ 23] Have to fix this one before pushing! @@ -476,11 +497,11 @@ app/models/article.rb: NOTE. When using specific annotations and custom annotations, the annotation name (FIXME, BUG etc) is not displayed in the output lines. -By default, `rake notes` will look in the `app`, `config`, `db`, `lib` and `test` directories. If you would like to search other directories, you can provide them as a comma separated list in an environment variable `SOURCE_ANNOTATION_DIRECTORIES`. +By default, `rails notes` will look in the `app`, `config`, `db`, `lib` and `test` directories. If you would like to search other directories, you can provide them as a comma separated list in an environment variable `SOURCE_ANNOTATION_DIRECTORIES`. ```bash $ export SOURCE_ANNOTATION_DIRECTORIES='spec,vendor' -$ bin/rake notes +$ bin/rails notes (in /home/foobar/commandsapp) app/models/user.rb: * [ 35] [FIXME] User should have a subscription at this point @@ -490,7 +511,7 @@ spec/models/user_spec.rb: ### `routes` -`rake routes` will list all of your defined routes, which is useful for tracking down routing problems in your app, or giving you a good overview of the URLs in an app you're trying to get familiar with. +`rails routes` will list all of your defined routes, which is useful for tracking down routing problems in your app, or giving you a good overview of the URLs in an app you're trying to get familiar with. ### `test` @@ -504,16 +525,16 @@ The `Rails.root/tmp` directory is, like the *nix /tmp directory, the holding pla The `tmp:` namespaced tasks will help you clear and create the `Rails.root/tmp` directory: -* `rake tmp:cache:clear` clears `tmp/cache`. -* `rake tmp:sockets:clear` clears `tmp/sockets`. -* `rake tmp:clear` clears all cache and sockets files. -* `rake tmp:create` creates tmp directories for cache, sockets and pids. +* `rails tmp:cache:clear` clears `tmp/cache`. +* `rails tmp:sockets:clear` clears `tmp/sockets`. +* `rails tmp:clear` clears all cache and sockets files. +* `rails tmp:create` creates tmp directories for cache, sockets and pids. ### Miscellaneous -* `rake stats` is great for looking at statistics on your code, displaying things like KLOCs (thousands of lines of code) and your code to test ratio. -* `rake secret` will give you a pseudo-random key to use for your session secret. -* `rake time:zones:all` lists all the timezones Rails knows about. +* `rails stats` is great for looking at statistics on your code, displaying things like KLOCs (thousands of lines of code) and your code to test ratio. +* `rails secret` will give you a pseudo-random key to use for your session secret. +* `rails time:zones:all` lists all the timezones Rails knows about. ### Custom Rake Tasks @@ -551,9 +572,9 @@ end Invocation of the tasks will look like: ```bash -$ bin/rake task_name -$ bin/rake "task_name[value 1]" # entire argument string should be quoted -$ bin/rake db:nothing +$ bin/rails task_name +$ bin/rails "task_name[value 1]" # entire argument string should be quoted +$ bin/rails db:nothing ``` NOTE: If your need to interact with your application models, perform database queries and so on, your task should depend on the `environment` task, which will load your application code. @@ -584,8 +605,8 @@ $ rails new . --git --database=postgresql create tmp/pids create Rakefile add 'Rakefile' - create README.rdoc -add 'README.rdoc' + create README.md +add 'README.md' create app/controllers/application_controller.rb add 'app/controllers/application_controller.rb' create app/helpers/application_helper.rb @@ -598,7 +619,7 @@ We had to create the **gitapp** directory and initialize an empty git repository ```bash $ cat config/database.yml -# PostgreSQL. Versions 8.2 and up are supported. +# PostgreSQL. Versions 9.1 and up are supported. # # Install the pg driver: # gem install pg diff --git a/guides/source/configuring.md b/guides/source/configuring.md index 28388e4957..66aae112d8 100644 --- a/guides/source/configuring.md +++ b/guides/source/configuring.md @@ -35,7 +35,7 @@ In general, the work of configuring Rails means configuring the components of Ra For example, the `config/application.rb` file includes this setting: ```ruby -config.autoload_paths += %W(#{config.root}/extras) +config.time_zone = 'Central Time (US & Canada)' ``` This is a setting for Rails itself. If you want to pass settings to individual Rails components, you can do so via the same `config` object in `config/application.rb`: @@ -60,11 +60,11 @@ These configuration methods are to be called on a `Rails::Railtie` object, such * `config.asset_host` sets the host for the assets. Useful when CDNs are used for hosting assets, or when you want to work around the concurrency constraints built-in in browsers using different domain aliases. Shorter version of `config.action_controller.asset_host`. -* `config.autoload_once_paths` accepts an array of paths from which Rails will autoload constants that won't be wiped per request. Relevant if `config.cache_classes` is false, which is the case in development mode by default. Otherwise, all autoloading happens only once. All elements of this array must also be in `autoload_paths`. Default is an empty array. +* `config.autoload_once_paths` accepts an array of paths from which Rails will autoload constants that won't be wiped per request. Relevant if `config.cache_classes` is `false`, which is the case in development mode by default. Otherwise, all autoloading happens only once. All elements of this array must also be in `autoload_paths`. Default is an empty array. * `config.autoload_paths` accepts an array of paths from which Rails will autoload constants. Default is all directories under `app`. -* `config.cache_classes` controls whether or not application classes and modules should be reloaded on each request. Defaults to false in development mode, and true in test and production modes. +* `config.cache_classes` controls whether or not application classes and modules should be reloaded on each request. Defaults to `false` in development mode, and `true` in test and production modes. * `config.action_view.cache_template_loading` controls whether or not templates should be reloaded on each request. Defaults to whatever is set for `config.cache_classes`. @@ -73,9 +73,9 @@ application. Accepts a valid week day symbol (e.g. `:monday`). * `config.cache_store` configures which cache store to use for Rails caching. Options include one of the symbols `:memory_store`, `:file_store`, `:mem_cache_store`, `:null_store`, or an object that implements the cache API. Defaults to `:file_store` if the directory `tmp/cache` exists, and to `:memory_store` otherwise. -* `config.colorize_logging` specifies whether or not to use ANSI color codes when logging information. Defaults to true. +* `config.colorize_logging` specifies whether or not to use ANSI color codes when logging information. Defaults to `true`. -* `config.consider_all_requests_local` is a flag. If true then any error will cause detailed debugging information to be dumped in the HTTP response, and the `Rails::Info` controller will show the application runtime context in `/rails/info/properties`. True by default in development and test environments, and false in production mode. For finer-grained control, set this to false and implement `local_request?` in controllers to specify which requests should provide debugging information on errors. +* `config.consider_all_requests_local` is a flag. If `true` then any error will cause detailed debugging information to be dumped in the HTTP response, and the `Rails::Info` controller will show the application runtime context in `/rails/info/properties`. `true` by default in development and test environments, and `false` in production mode. For finer-grained control, set this to `false` and implement `local_request?` in controllers to specify which requests should provide debugging information on errors. * `config.console` allows you to set class that will be used as console you run `rails console`. It's best to run it in `console` block: @@ -88,9 +88,9 @@ application. Accepts a valid week day symbol (e.g. `:monday`). end ``` -* `config.eager_load` when true, eager loads all registered `config.eager_load_namespaces`. This includes your application, engines, Rails frameworks and any other registered namespace. +* `config.eager_load` when `true`, eager loads all registered `config.eager_load_namespaces`. This includes your application, engines, Rails frameworks and any other registered namespace. -* `config.eager_load_namespaces` registers namespaces that are eager loaded when `config.eager_load` is true. All namespaces in the list must respond to the `eager_load!` method. +* `config.eager_load_namespaces` registers namespaces that are eager loaded when `config.eager_load` is `true`. All namespaces in the list must respond to the `eager_load!` method. * `config.eager_load_paths` accepts an array of paths from which Rails will eager load on boot if cache classes is enabled. Defaults to every folder in the `app` directory of the application. @@ -98,15 +98,17 @@ application. Accepts a valid week day symbol (e.g. `:monday`). * `config.exceptions_app` sets the exceptions application invoked by the ShowException middleware when an exception happens. Defaults to `ActionDispatch::PublicExceptions.new(Rails.public_path)`. -* `config.file_watcher` the class used to detect file updates in the filesystem when `config.reload_classes_only_on_change` is true. Must conform to `ActiveSupport::FileUpdateChecker` API. +* `config.debug_exception_response_format` sets the format used in responses when errors occur in development mode. Defaults to `:api` for API only apps and `:default` for normal apps. + +* `config.file_watcher` is the class used to detect file updates in the file system when `config.reload_classes_only_on_change` is `true`. Rails ships with `ActiveSupport::FileUpdateChecker`, the default, and `ActiveSupport::EventedFileUpdateChecker` (this one depends on the [listen](https://github.com/guard/listen) gem). Custom classes must conform to the `ActiveSupport::FileUpdateChecker` API. * `config.filter_parameters` used for filtering out the parameters that you don't want shown in the logs, such as passwords or credit card -numbers. New applications filter out passwords by adding the following `config.filter_parameters+=[:password]` in `config/initializers/filter_parameter_logging.rb`. +numbers. By default, Rails filters out passwords by adding `Rails.application.config.filter_parameters += [:password]` in `config/initializers/filter_parameter_logging.rb`. Parameters filter works by partial matching regular expression. -* `config.force_ssl` forces all requests to be under HTTPS protocol by using `ActionDispatch::SSL` middleware. +* `config.force_ssl` forces all requests to be served over HTTPS by using the `ActionDispatch::SSL` middleware, and sets `config.action_mailer.default_url_options` to be `{ protocol: 'https' }`. This can be configured by setting `config.ssl_options` - see the [ActionDispatch::SSL documentation](http://edgeapi.rubyonrails.org/classes/ActionDispatch/SSL.html) for details. -* `config.log_formatter` defines the formatter of the Rails logger. This option defaults to an instance of `ActiveSupport::Logger::SimpleFormatter` for all modes except production, where it defaults to `Logger::Formatter`. +* `config.log_formatter` defines the formatter of the Rails logger. This option defaults to an instance of `ActiveSupport::Logger::SimpleFormatter` for all modes except production, where it defaults to `Logger::Formatter`. If you are setting a value for `config.logger` you must manually pass the value of your formatter to your logger before it is wrapped in an `ActiveSupport::TaggedLogging` instance, Rails will not do it for you. * `config.log_level` defines the verbosity of the Rails logger. This option defaults to `:debug` for all environments. The available log levels are: `:debug`, @@ -114,15 +116,29 @@ defaults to `:debug` for all environments. The available log levels are: `:debug * `config.log_tags` accepts a list of: methods that the `request` object responds to, a `Proc` that accepts the `request` object, or something that responds to `to_s`. This makes it easy to tag log lines with debug information like subdomain and request id - both very helpful in debugging multi-user production applications. -* `config.logger` accepts a logger conforming to the interface of Log4r or the default Ruby `Logger` class. Defaults to an instance of `ActiveSupport::Logger`. +* `config.logger` is the logger that will be used for `Rails.logger` and any related Rails logging such as `ActiveRecord::Base.logger`. It defaults to an instance of `ActiveSupport::TaggedLogging` that wraps an instance of `ActiveSupport::Logger` which outputs a log to the `log/` directory. You can supply a custom logger, to get full compatibility you must follow these guidelines: + * To support a formatter, you must manually assign a formatter from the `config.log_formatter` value to the logger. + * To support tagged logs, the log instance must be wrapped with `ActiveSupport::TaggedLogging`. + * To support silencing, the logger must include `LoggerSilence` and `ActiveSupport::LoggerThreadSafeLevel` modules. The `ActiveSupport::Logger` class already includes these modules. + + ```ruby + class MyLogger < ::Logger + include ActiveSupport::LoggerThreadSafeLevel + include LoggerSilence + end + + mylogger = MyLogger.new(STDOUT) + mylogger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(mylogger) + ``` * `config.middleware` allows you to configure the application's middleware. This is covered in depth in the [Configuring Middleware](#configuring-middleware) section below. -* `config.reload_classes_only_on_change` enables or disables reloading of classes only when tracked files change. By default tracks everything on autoload paths and is set to true. If `config.cache_classes` is true, this option is ignored. +* `config.reload_classes_only_on_change` enables or disables reloading of classes only when tracked files change. By default tracks everything on autoload paths and is set to `true`. If `config.cache_classes` is `true`, this option is ignored. * `secrets.secret_key_base` is used for specifying a key which allows sessions for the application to be verified against a known secure key to prevent tampering. Applications get `secrets.secret_key_base` initialized to a random key present in `config/secrets.yml`. -* `config.public_file_server.enabled` configures Rails to serve static files from the public directory. This option defaults to true, but in the production environment it is set to false because the server software (e.g. NGINX or Apache) used to run the application should serve static files instead. If you are running or testing your app in production mode using WEBrick (it is not recommended to use WEBrick in production) set the option to true. Otherwise, you won't be able to use page caching and request for files that exist under the public directory. +* `config.public_file_server.enabled` configures Rails to serve static files from the public directory. This option defaults to `true`, but in the production environment it is set to `false` because the server software (e.g. NGINX or Apache) used to run the application should serve static files instead. If you are running or testing your app in production mode using WEBrick (it is not recommended to use WEBrick in production) set the option to `true.` Otherwise, you won't be able to use page caching and request for files that exist under the public directory. * `config.session_store` is usually set up in `config/initializers/session_store.rb` and specifies what class to use to store the session. Possible values are `:cookie_store` which is the default, `:mem_cache_store`, and `:disabled`. The last one tells Rails not to deal with sessions. Custom session stores can also be specified: @@ -137,16 +153,16 @@ defaults to `:debug` for all environments. The available log levels are: `:debug ### Configuring Assets * `config.assets.enabled` a flag that controls whether the asset -pipeline is enabled. It is set to true by default. +pipeline is enabled. It is set to `true` by default. * `config.assets.raise_runtime_errors` Set this flag to `true` to enable additional runtime error checking. Recommended in `config/environments/development.rb` to minimize unexpected behavior when deploying to `production`. -* `config.assets.compress` a flag that enables the compression of compiled assets. It is explicitly set to true in `config/environments/production.rb`. - * `config.assets.css_compressor` defines the CSS compressor to use. It is set by default by `sass-rails`. The unique alternative value at the moment is `:yui`, which uses the `yui-compressor` gem. * `config.assets.js_compressor` defines the JavaScript compressor to use. Possible values are `:closure`, `:uglifier` and `:yui` which require the use of the `closure-compiler`, `uglifier` or `yui-compressor` gems respectively. +* `config.assets.gzip` a flag that enables the creation of gzipped version of compiled assets, along with non-gzipped assets. Set to `true` by default. + * `config.assets.paths` contains the paths which are used to look for assets. Appending paths to this configuration option will cause those paths to be used in the search for assets. * `config.assets.precompile` allows you to specify additional assets (other than `application.css` and `application.js`) which are to be precompiled when `rake assets:precompile` is run. @@ -155,15 +171,13 @@ pipeline is enabled. It is set to true by default. * `config.assets.manifest` defines the full path to be used for the asset precompiler's manifest file. Defaults to a file named `manifest-<random>.json` in the `config.assets.prefix` directory within the public folder. -* `config.assets.digest` enables the use of MD5 fingerprints in asset names. Set to `true` by default in `production.rb` and `development.rb`. +* `config.assets.digest` enables the use of MD5 fingerprints in asset names. Set to `true` by default. * `config.assets.debug` disables the concatenation and compression of assets. Set to `true` by default in `development.rb`. -* `config.assets.cache_store` defines the cache store that Sprockets will use. The default is the Rails file store. - * `config.assets.compile` is a boolean that can be used to turn on live Sprockets compilation in production. -* `config.assets.logger` accepts a logger conforming to the interface of Log4r or the default Ruby `Logger` class. Defaults to the same configured at `config.logger`. Setting `config.assets.logger` to false will turn off served assets logging. +* `config.assets.logger` accepts a logger conforming to the interface of Log4r or the default Ruby `Logger` class. Defaults to the same configured at `config.logger`. Setting `config.assets.logger` to `false` will turn off served assets logging. ### Configuring Generators @@ -191,6 +205,7 @@ The full set of methods that can be used in this block are as follows: * `scaffold_controller` different from `resource_controller`, defines which generator to use for generating a _scaffolded_ controller when using `rails generate scaffold`. Defaults to `:scaffold_controller`. * `stylesheets` turns on the hook for stylesheets in generators. Used in Rails for when the `scaffold` generator is run, but this hook can be used in other generates as well. Defaults to `true`. * `stylesheet_engine` configures the stylesheet engine (for eg. sass) to be used when generating assets. Defaults to `:css`. +* `scaffold_stylesheet` creates `scaffold.css` when generating a scaffolded resource. Defaults to `true`. * `test_framework` defines which test framework to use. Defaults to `false` and will use Minitest by default. * `template_engine` defines which template engine to use, such as ERB or Haml. Defaults to `:erb`. @@ -198,9 +213,9 @@ The full set of methods that can be used in this block are as follows: Every Rails application comes with a standard set of middleware which it uses in this order in the development environment: -* `ActionDispatch::SSL` forces every request to be under HTTPS protocol. Will be available if `config.force_ssl` is set to `true`. Options passed to this can be configured by using `config.ssl_options`. -* `ActionDispatch::Static` is used to serve static assets. Disabled if `config.public_file_server.enabled` is `false`. Set `config.static_index` if you need to serve a static directory index file that is not named `index`. For example, to serve `main.html` instead of `index.html` for directory requests, set `config.static_index` to `"main"`. -* `Rack::Lock` wraps the app in mutex so it can only be called by a single thread at a time. Only enabled when `config.cache_classes` is `false`. +* `ActionDispatch::SSL` forces every request to be served using HTTPS. Enabled if `config.force_ssl` is set to `true`. Options passed to this can be configured by setting `config.ssl_options`. +* `ActionDispatch::Static` is used to serve static assets. Disabled if `config.public_file_server.enabled` is `false`. Set `config.public_file_server.index_name` if you need to serve a static directory index file that is not named `index`. For example, to serve `main.html` instead of `index.html` for directory requests, set `config.public_file_server.index_name` to `"main"`. +* `ActionDispatch::Executor` allows thread safe code reloading. Disabled if `config.allow_concurrency` is `false`, which causes `Rack::Lock` to be loaded. `Rack::Lock` wraps the app in mutex so it can only be called by a single thread at a time. * `ActiveSupport::Cache::Strategy::LocalCache` serves as a basic memory backed cache. This cache is not thread safe and is intended only for serving as a temporary memory cache for a single thread. * `Rack::Runtime` sets an `X-Runtime` header, containing the time (in seconds) taken to execute the request. * `Rails::Rack::Logger` notifies the logs that the request has begun. After request is complete, flushes all the logs. @@ -266,8 +281,8 @@ All these configuration options are delegated to the `I18n` library. * `config.active_record.logger` accepts a logger conforming to the interface of Log4r or the default Ruby Logger class, which is then passed on to any new database connections made. You can retrieve this logger by calling `logger` on either an Active Record model class or an Active Record model instance. Set to `nil` to disable logging. * `config.active_record.primary_key_prefix_type` lets you adjust the naming for primary key columns. By default, Rails assumes that primary key columns are named `id` (and this configuration option doesn't need to be set.) There are two other choices: - * `:table_name` would make the primary key for the Customer class `customerid` - * `:table_name_with_underscore` would make the primary key for the Customer class `customer_id` + * `:table_name` would make the primary key for the Customer class `customerid`. + * `:table_name_with_underscore` would make the primary key for the Customer class `customer_id`. * `config.active_record.table_name_prefix` lets you set a global string to be prepended to table names. If you set this to `northwest_`, then the Customer class will look for `northwest_customers` as its table. The default is an empty string. @@ -275,15 +290,17 @@ All these configuration options are delegated to the `I18n` library. * `config.active_record.schema_migrations_table_name` lets you set a string to be used as the name of the schema migrations table. -* `config.active_record.pluralize_table_names` specifies whether Rails will look for singular or plural table names in the database. If set to true (the default), then the Customer class will use the `customers` table. If set to false, then the Customer class will use the `customer` table. +* `config.active_record.pluralize_table_names` specifies whether Rails will look for singular or plural table names in the database. If set to `true` (the default), then the Customer class will use the `customers` table. If set to false, then the Customer class will use the `customer` table. * `config.active_record.default_timezone` determines whether to use `Time.local` (if set to `:local`) or `Time.utc` (if set to `:utc`) when pulling dates and times from the database. The default is `:utc`. * `config.active_record.schema_format` controls the format for dumping the database schema to a file. The options are `:ruby` (the default) for a database-independent version that depends on migrations, or `:sql` for a set of (potentially database-dependent) SQL statements. -* `config.active_record.timestamped_migrations` controls whether migrations are numbered with serial integers or with timestamps. The default is true, to use timestamps, which are preferred if there are multiple developers working on the same application. +* `config.active_record.error_on_ignored_order_or_limit` specifies if an error should be raised if the order or limit of a query is ignored during a batch query. The options are `true` (raise error) or `false` (warn). Default is `false`. -* `config.active_record.lock_optimistically` controls whether Active Record will use optimistic locking and is true by default. +* `config.active_record.timestamped_migrations` controls whether migrations are numbered with serial integers or with timestamps. The default is `true`, to use timestamps, which are preferred if there are multiple developers working on the same application. + +* `config.active_record.lock_optimistically` controls whether Active Record will use optimistic locking and is `true` by default. * `config.active_record.cache_timestamp_format` controls the format of the timestamp value in the cache key. Default is `:nsec`. @@ -291,13 +308,13 @@ All these configuration options are delegated to the `I18n` library. * `config.active_record.partial_writes` is a boolean value and controls whether or not partial writes are used (i.e. whether updates only set attributes that are dirty). Note that when using partial writes, you should also use optimistic locking `config.active_record.lock_optimistically` since concurrent updates may write attributes based on a possibly stale read state. The default value is `true`. -* `config.active_record.maintain_test_schema` is a boolean value which controls whether Active Record should try to keep your test database schema up-to-date with `db/schema.rb` (or `db/structure.sql`) when you run your tests. The default is true. +* `config.active_record.maintain_test_schema` is a boolean value which controls whether Active Record should try to keep your test database schema up-to-date with `db/schema.rb` (or `db/structure.sql`) when you run your tests. The default is `true`. * `config.active_record.dump_schema_after_migration` is a flag which controls whether or not schema dump should happen (`db/schema.rb` or - `db/structure.sql`) when you run migrations. This is set to false in + `db/structure.sql`) when you run migrations. This is set to `false` in `config/environments/production.rb` which is generated by Rails. The - default value is true if this configuration is not set. + default value is `true` if this configuration is not set. * `config.active_record.dump_schemas` controls which database schemas will be dumped when calling db:structure:dump. The options are `:schema_search_path` (the default) which dumps any schemas listed in schema_search_path, @@ -315,11 +332,11 @@ All these configuration options are delegated to the `I18n` library. * `config.active_record.index_nested_attribute_errors` allows errors for nested has_many relationships to be displayed with an index as well as the error. - Defaults to false. + Defaults to `false`. The MySQL adapter adds one additional configuration option: -* `ActiveRecord::ConnectionAdapters::MysqlAdapter.emulate_booleans` controls whether Active Record will consider all `tinyint(1)` columns in a MySQL database to be booleans and is true by default. +* `ActiveRecord::ConnectionAdapters::Mysql2Adapter.emulate_booleans` controls whether Active Record will consider all `tinyint(1)` columns as booleans. Defaults to `true`. The schema dumper adds one additional configuration option: @@ -331,13 +348,11 @@ The schema dumper adds one additional configuration option: * `config.action_controller.asset_host` sets the host for the assets. Useful when CDNs are used for hosting assets rather than the application server itself. -* `config.action_controller.perform_caching` configures whether the application should perform the caching features provided by the Action Controller component or not. Set to false in development mode, true in production. +* `config.action_controller.perform_caching` configures whether the application should perform the caching features provided by the Action Controller component or not. Set to `false` in development mode, `true` in production. * `config.action_controller.default_static_extension` configures the extension used for cached pages. Defaults to `.html`. -* `config.action_controller.default_charset` specifies the default character set for all renders. The default is "utf-8". - -* `config.action_controller.include_all_helpers` configures whether all view helpers are available everywhere or are scoped to the corresponding controller. If set to `false`, `UsersHelper` methods are only available for views rendered as part of `UsersController`. If `true`, `UsersHelper` methods are available everywhere. The default is `true`. +* `config.action_controller.include_all_helpers` configures whether all view helpers are available everywhere or are scoped to the corresponding controller. If set to `false`, `UsersHelper` methods are only available for views rendered as part of `UsersController`. If `true`, `UsersHelper` methods are available everywhere. The default configuration behavior (when this option is not explicitly set to `true` or `false`) is that all view helpers are available to each controller. * `config.action_controller.logger` accepts a logger conforming to the interface of Log4r or the default Ruby Logger class, which is then used to log information from Action Controller. Set to `nil` to disable logging. @@ -345,6 +360,10 @@ The schema dumper adds one additional configuration option: * `config.action_controller.allow_forgery_protection` enables or disables CSRF protection. By default this is `false` in test mode and `true` in all other modes. +* `config.action_controller.forgery_protection_origin_check` configures whether the HTTP `Origin` header should be checked against the site's origin as an additional CSRF defense. + +* `config.action_controller.per_form_csrf_tokens` configures whether CSRF tokens are only valid for the method/action they were generated for. + * `config.action_controller.relative_url_root` can be used to tell Rails that you are [deploying to a subdirectory](configuring.html#deploy-to-a-subdirectory-relative-url-root). The default is `ENV['RAILS_RELATIVE_URL_ROOT']`. * `config.action_controller.permit_all_parameters` sets all the parameters for mass assignment to be permitted by default. The default value is `false`. @@ -367,8 +386,14 @@ The schema dumper adds one additional configuration option: } ``` +* `config.action_dispatch.default_charset` specifies the default character set for all renders. Defaults to `nil`. + * `config.action_dispatch.tld_length` sets the TLD (top-level domain) length for the application. Defaults to `1`. +* `config.action_dispatch.ignore_accept_header` is used to determine whether to ignore accept headers from a request. Defaults to `false`. + +* `config.action_dispatch.x_sendfile_header` specifies server specific X-Sendfile header. This is useful for accelerated file sending from server. For example it can be set to 'X-Sendfile' for Apache. + * `config.action_dispatch.http_auth_salt` sets the HTTP Auth salt value. Defaults to `'http authentication'`. @@ -383,7 +408,7 @@ encrypted cookies salt value. Defaults to `'signed encrypted cookie'`. * `config.action_dispatch.perform_deep_munge` configures whether `deep_munge` method should be performed on the parameters. See [Security Guide](security.html#unsafe-query-generation) - for more information. It defaults to true. + for more information. It defaults to `true`. * `config.action_dispatch.rescue_responses` configures what exceptions are assigned to an HTTP status. It accepts a hash and you can specify pairs of exception/status. By default, this is defined as: @@ -438,7 +463,7 @@ encrypted cookies salt value. Defaults to `'signed encrypted cookie'`. * `config.action_view.embed_authenticity_token_in_remote_forms` allows you to set the default behavior for `authenticity_token` in forms with `remote: - true`. By default it's set to false, which means that remote forms will not + true`. By default it's set to `false`, which means that remote forms will not include `authenticity_token`, which is helpful when you're fragment-caching the form. Remote forms get the authenticity from the `meta` tag, so embedding is unnecessary unless you support browsers without JavaScript. In such case @@ -457,7 +482,9 @@ encrypted cookies salt value. Defaults to `'signed encrypted cookie'`. error should be raised for missing translations. * `config.action_view.automatically_disable_submit_tag` determines whether - submit_tag should automatically disable on click, this defaults to true. + submit_tag should automatically disable on click, this defaults to `true`. + +* `config.action_view.debug_missing_translation` determines whether to wrap the missing translations key in a `<span>` tag or not. This defaults to `true`. ### Configuring Action Mailer @@ -472,16 +499,19 @@ There are a number of settings available on `config.action_mailer`: * `:user_name` - If your mail server requires authentication, set the username in this setting. * `:password` - If your mail server requires authentication, set the password in this setting. * `:authentication` - If your mail server requires authentication, you need to specify the authentication type here. This is a symbol and one of `:plain`, `:login`, `:cram_md5`. + * `:enable_starttls_auto` - Detects if STARTTLS is enabled in your SMTP server and starts to use it. It defaults to `true`. + * `:openssl_verify_mode` - When using TLS, you can set how OpenSSL checks the certificate. This is useful if you need to validate a self-signed and/or a wildcard certificate. This can be one of the OpenSSL verify constants, `:none`, `:peer`, `:client_once`, `:fail_if_no_peer_cert`, or the constant directly `OpenSSL::SSL::VERIFY_NONE`. + * `:ssl/:tls` - Enables the SMTP connection to use SMTP/TLS (SMTPS: SMTP over direct TLS connection). * `config.action_mailer.sendmail_settings` allows detailed configuration for the `sendmail` delivery method. It accepts a hash of options, which can include any of these options: * `:location` - The location of the sendmail executable. Defaults to `/usr/sbin/sendmail`. * `:arguments` - The command line arguments. Defaults to `-i -t`. -* `config.action_mailer.raise_delivery_errors` specifies whether to raise an error if email delivery cannot be completed. It defaults to true. +* `config.action_mailer.raise_delivery_errors` specifies whether to raise an error if email delivery cannot be completed. It defaults to `true`. -* `config.action_mailer.delivery_method` defines the delivery method and defaults to `:smtp`. See the [configuration section in the Action Mailer guide](http://guides.rubyonrails.org/action_mailer_basics.html#action-mailer-configuration) for more info. +* `config.action_mailer.delivery_method` defines the delivery method and defaults to `:smtp`. See the [configuration section in the Action Mailer guide](action_mailer_basics.html#action-mailer-configuration) for more info. -* `config.action_mailer.perform_deliveries` specifies whether mail will actually be delivered and is true by default. It can be convenient to set it to false for testing. +* `config.action_mailer.perform_deliveries` specifies whether mail will actually be delivered and is true by default. It can be convenient to set it to `false` for testing. * `config.action_mailer.default_options` configures Action Mailer defaults. Use to set options like `from` or `reply_to` for every mailer. These default to: @@ -527,6 +557,9 @@ There are a number of settings available on `config.action_mailer`: * `config.action_mailer.deliver_later_queue_name` specifies the queue name for mailers. By default this is `mailers`. +* `config.action_mailer.perform_caching` specifies whether the mailer templates should perform fragment caching or not. By default this is `false` in all environments. + + ### Configuring Active Support There are a few configuration options available in Active Support: @@ -541,7 +574,7 @@ There are a few configuration options available in Active Support: * `config.active_support.time_precision` sets the precision of JSON encoded time values. Defaults to `3`. -* `ActiveSupport.halt_callback_chains_on_return_false` specifies whether Active Record and Active Model callback chains can be halted by returning `false` in a 'before' callback. Defaults to `true`. +* `ActiveSupport.halt_callback_chains_on_return_false` specifies whether Active Record and Active Model callback chains can be halted by returning `false` in a 'before' callback. When set to `false`, callback chains are halted only when explicitly done so with `throw(:abort)`. When set to `true`, callback chains are halted when a callback returns `false` (the previous behavior before Rails 5) and a deprecation warning is given. Defaults to `true` during the deprecation period. New Rails 5 apps generate an initializer file called `callback_terminator.rb` which sets the value to `false`. This file is *not* added when running `rails app:update`, so returning `false` will still work on older apps ported to Rails 5 and display a deprecation warning to prompt users to update their code. * `ActiveSupport::Logger.silencer` is set to `false` to disable the ability to silence logging in a block. The default is `true`. @@ -557,7 +590,7 @@ There are a few configuration options available in Active Support: `config.active_job` provides the following configuration options: -* `config.active_job.queue_adapter` sets the adapter for the queueing backend. The default adapter is `:inline` which will perform jobs immediately. For an up-to-date list of built-in adapters see the [ActiveJob::QueueAdapters API documentation](http://api.rubyonrails.org/classes/ActiveJob/QueueAdapters.html). +* `config.active_job.queue_adapter` sets the adapter for the queueing backend. The default adapter is `:async`. For an up-to-date list of built-in adapters see the [ActiveJob::QueueAdapters API documentation](http://api.rubyonrails.org/classes/ActiveJob/QueueAdapters.html). ```ruby # Be sure to have the adapter's gem in your Gemfile @@ -606,6 +639,17 @@ There are a few configuration options available in Active Support: * `config.active_job.logger` accepts a logger conforming to the interface of Log4r or the default Ruby Logger class, which is then used to log information from Active Job. You can retrieve this logger by calling `logger` on either an Active Job class or an Active Job instance. Set to `nil` to disable logging. +### Configuring Action Cable + +* `config.action_cable.url` accepts a string for the URL for where + you are hosting your Action Cable server. You would use this option +if you are running Action Cable servers that are separated from your +main application. +* `config.action_cable.mount_path` accepts a string for where to mount Action + Cable, as part of the main server process. Defaults to `/cable`. +You can set this as nil to not mount Action Cable as part of your +normal Rails server. + ### Configuring a Database Just about every Rails application will interact with a database. You can connect to the database by setting an environment variable `ENV['DATABASE_URL']` or by using a configuration file called `config/database.yml`. @@ -747,11 +791,11 @@ development: timeout: 5000 ``` -NOTE: Rails uses an SQLite3 database for data storage by default because it is a zero configuration database that just works. Rails also supports MySQL and PostgreSQL "out of the box", and has plugins for many database systems. If you are using a database in a production environment Rails most likely has an adapter for it. +NOTE: Rails uses an SQLite3 database for data storage by default because it is a zero configuration database that just works. Rails also supports MySQL (including MariaDB) and PostgreSQL "out of the box", and has plugins for many database systems. If you are using a database in a production environment Rails most likely has an adapter for it. -#### Configuring a MySQL Database +#### Configuring a MySQL or MariaDB Database -If you choose to use MySQL instead of the shipped SQLite3 database, your `config/database.yml` will look a little different. Here's the development section: +If you choose to use MySQL or MariaDB instead of the shipped SQLite3 database, your `config/database.yml` will look a little different. Here's the development section: ```yaml development: @@ -764,7 +808,7 @@ development: socket: /tmp/mysql.sock ``` -If your development computer's MySQL installation includes a root user with an empty password, this configuration should work for you. Otherwise, change the username and password in the `development` section as appropriate. +If your development database has a root user with an empty password, this configuration should work for you. Otherwise, change the username and password in the `development` section as appropriate. #### Configuring a PostgreSQL Database @@ -806,9 +850,9 @@ development: database: db/development.sqlite3 ``` -#### Configuring a MySQL Database for JRuby Platform +#### Configuring a MySQL or MariaDB Database for JRuby Platform -If you choose to use MySQL and are using JRuby, your `config/database.yml` will look a little different. Here's the development section: +If you choose to use MySQL or MariaDB and are using JRuby, your `config/database.yml` will look a little different. Here's the development section: ```yaml development: @@ -861,7 +905,7 @@ Rails will now prepend "/app1" when generating links. #### Using Passenger -Passenger makes it easy to run your application in a subdirectory. You can find the relevant configuration in the [Passenger manual](http://www.modrails.com/documentation/Users%20guide%20Apache.html#deploying_rails_to_sub_uri). +Passenger makes it easy to run your application in a subdirectory. You can find the relevant configuration in the [Passenger manual](https://www.phusionpassenger.com/library/deploy/apache/deploy/ruby/#deploying-an-app-to-a-sub-uri-or-subdirectory). #### Using a Reverse Proxy @@ -986,98 +1030,110 @@ Because `Rails::Application` inherits from `Rails::Railtie` (indirectly), you ca Below is a comprehensive list of all the initializers found in Rails in the order that they are defined (and therefore run in, unless otherwise stated). -* `load_environment_hook` Serves as a placeholder so that `:load_environment_config` can be defined to run before it. +* `load_environment_hook`: Serves as a placeholder so that `:load_environment_config` can be defined to run before it. + +* `load_active_support`: Requires `active_support/dependencies` which sets up the basis for Active Support. Optionally requires `active_support/all` if `config.active_support.bare` is un-truthful, which is the default. + +* `initialize_logger`: Initializes the logger (an `ActiveSupport::Logger` object) for the application and makes it accessible at `Rails.logger`, provided that no initializer inserted before this point has defined `Rails.logger`. -* `load_active_support` Requires `active_support/dependencies` which sets up the basis for Active Support. Optionally requires `active_support/all` if `config.active_support.bare` is un-truthful, which is the default. +* `initialize_cache`: If `Rails.cache` isn't set yet, initializes the cache by referencing the value in `config.cache_store` and stores the outcome as `Rails.cache`. If this object responds to the `middleware` method, its middleware is inserted before `Rack::Runtime` in the middleware stack. -* `initialize_logger` Initializes the logger (an `ActiveSupport::Logger` object) for the application and makes it accessible at `Rails.logger`, provided that no initializer inserted before this point has defined `Rails.logger`. +* `set_clear_dependencies_hook`: This initializer - which runs only if `cache_classes` is set to `false` - uses `ActionDispatch::Callbacks.after` to remove the constants which have been referenced during the request from the object space so that they will be reloaded during the following request. -* `initialize_cache` If `Rails.cache` isn't set yet, initializes the cache by referencing the value in `config.cache_store` and stores the outcome as `Rails.cache`. If this object responds to the `middleware` method, its middleware is inserted before `Rack::Runtime` in the middleware stack. +* `initialize_dependency_mechanism`: If `config.cache_classes` is true, configures `ActiveSupport::Dependencies.mechanism` to `require` dependencies rather than `load` them. -* `set_clear_dependencies_hook` Provides a hook for `active_record.set_dispatch_hooks` to use, which will run before this initializer. This initializer - which runs only if `cache_classes` is set to `false` - uses `ActionDispatch::Callbacks.after` to remove the constants which have been referenced during the request from the object space so that they will be reloaded during the following request. +* `bootstrap_hook`: Runs all configured `before_initialize` blocks. -* `initialize_dependency_mechanism` If `config.cache_classes` is true, configures `ActiveSupport::Dependencies.mechanism` to `require` dependencies rather than `load` them. +* `i18n.callbacks`: In the development environment, sets up a `to_prepare` callback which will call `I18n.reload!` if any of the locales have changed since the last request. In production mode this callback will only run on the first request. -* `bootstrap_hook` Runs all configured `before_initialize` blocks. +* `active_support.deprecation_behavior`: Sets up deprecation reporting for environments, defaulting to `:log` for development, `:notify` for production and `:stderr` for test. If a value isn't set for `config.active_support.deprecation` then this initializer will prompt the user to configure this line in the current environment's `config/environments` file. Can be set to an array of values. -* `i18n.callbacks` In the development environment, sets up a `to_prepare` callback which will call `I18n.reload!` if any of the locales have changed since the last request. In production mode this callback will only run on the first request. +* `active_support.initialize_time_zone`: Sets the default time zone for the application based on the `config.time_zone` setting, which defaults to "UTC". -* `active_support.deprecation_behavior` Sets up deprecation reporting for environments, defaulting to `:log` for development, `:notify` for production and `:stderr` for test. If a value isn't set for `config.active_support.deprecation` then this initializer will prompt the user to configure this line in the current environment's `config/environments` file. Can be set to an array of values. +* `active_support.initialize_beginning_of_week`: Sets the default beginning of week for the application based on `config.beginning_of_week` setting, which defaults to `:monday`. -* `active_support.initialize_time_zone` Sets the default time zone for the application based on the `config.time_zone` setting, which defaults to "UTC". +* `active_support.set_configs`: Sets up Active Support by using the settings in `config.active_support` by `send`'ing the method names as setters to `ActiveSupport` and passing the values through. -* `active_support.initialize_beginning_of_week` Sets the default beginning of week for the application based on `config.beginning_of_week` setting, which defaults to `:monday`. +* `action_dispatch.configure`: Configures the `ActionDispatch::Http::URL.tld_length` to be set to the value of `config.action_dispatch.tld_length`. -* `action_dispatch.configure` Configures the `ActionDispatch::Http::URL.tld_length` to be set to the value of `config.action_dispatch.tld_length`. +* `action_view.set_configs`: Sets up Action View by using the settings in `config.action_view` by `send`'ing the method names as setters to `ActionView::Base` and passing the values through. -* `action_view.set_configs` Sets up Action View by using the settings in `config.action_view` by `send`'ing the method names as setters to `ActionView::Base` and passing the values through. +* `action_controller.assets_config`: Initializes the `config.actions_controller.assets_dir` to the app's public directory if not explicitly configured. -* `action_controller.logger` Sets `ActionController::Base.logger` - if it's not already set - to `Rails.logger`. +* `action_controller.set_helpers_path`: Sets Action Controller's `helpers_path` to the application's `helpers_path`. -* `action_controller.initialize_framework_caches` Sets `ActionController::Base.cache_store` - if it's not already set - to `Rails.cache`. +* `action_controller.parameters_config`: Configures strong parameters options for `ActionController::Parameters`. -* `action_controller.set_configs` Sets up Action Controller by using the settings in `config.action_controller` by `send`'ing the method names as setters to `ActionController::Base` and passing the values through. +* `action_controller.set_configs`: Sets up Action Controller by using the settings in `config.action_controller` by `send`'ing the method names as setters to `ActionController::Base` and passing the values through. -* `action_controller.compile_config_methods` Initializes methods for the config settings specified so that they are quicker to access. +* `action_controller.compile_config_methods`: Initializes methods for the config settings specified so that they are quicker to access. -* `active_record.initialize_timezone` Sets `ActiveRecord::Base.time_zone_aware_attributes` to true, as well as setting `ActiveRecord::Base.default_timezone` to UTC. When attributes are read from the database, they will be converted into the time zone specified by `Time.zone`. +* `active_record.initialize_timezone`: Sets `ActiveRecord::Base.time_zone_aware_attributes` to `true`, as well as setting `ActiveRecord::Base.default_timezone` to UTC. When attributes are read from the database, they will be converted into the time zone specified by `Time.zone`. -* `active_record.logger` Sets `ActiveRecord::Base.logger` - if it's not already set - to `Rails.logger`. +* `active_record.logger`: Sets `ActiveRecord::Base.logger` - if it's not already set - to `Rails.logger`. -* `active_record.set_configs` Sets up Active Record by using the settings in `config.active_record` by `send`'ing the method names as setters to `ActiveRecord::Base` and passing the values through. +* `active_record.migration_error`: Configures middleware to check for pending migrations. -* `active_record.initialize_database` Loads the database configuration (by default) from `config/database.yml` and establishes a connection for the current environment. +* `active_record.check_schema_cache_dump`: Loads the schema cache dump if configured and available. -* `active_record.log_runtime` Includes `ActiveRecord::Railties::ControllerRuntime` which is responsible for reporting the time taken by Active Record calls for the request back to the logger. +* `active_record.warn_on_records_fetched_greater_than`: Enables warnings when queries return large numbers of records. -* `active_record.set_dispatch_hooks` Resets all reloadable connections to the database if `config.cache_classes` is set to `false`. +* `active_record.set_configs`: Sets up Active Record by using the settings in `config.active_record` by `send`'ing the method names as setters to `ActiveRecord::Base` and passing the values through. -* `active_job.logger` Sets `ActiveJob::Base.logger` - if it's not already set - +* `active_record.initialize_database`: Loads the database configuration (by default) from `config/database.yml` and establishes a connection for the current environment. + +* `active_record.log_runtime`: Includes `ActiveRecord::Railties::ControllerRuntime` which is responsible for reporting the time taken by Active Record calls for the request back to the logger. + +* `active_record.set_reloader_hooks`: Resets all reloadable connections to the database if `config.cache_classes` is set to `false`. + +* `active_record.add_watchable_files`: Adds `schema.rb` and `structure.sql` files to watchable files. + +* `active_job.logger`: Sets `ActiveJob::Base.logger` - if it's not already set - to `Rails.logger`. -* `active_job.set_configs` Sets up Active Job by using the settings in `config.active_job` by `send`'ing the method names as setters to `ActiveJob::Base` and passing the values through. +* `active_job.set_configs`: Sets up Active Job by using the settings in `config.active_job` by `send`'ing the method names as setters to `ActiveJob::Base` and passing the values through. -* `action_mailer.logger` Sets `ActionMailer::Base.logger` - if it's not already set - to `Rails.logger`. +* `action_mailer.logger`: Sets `ActionMailer::Base.logger` - if it's not already set - to `Rails.logger`. -* `action_mailer.set_configs` Sets up Action Mailer by using the settings in `config.action_mailer` by `send`'ing the method names as setters to `ActionMailer::Base` and passing the values through. +* `action_mailer.set_configs`: Sets up Action Mailer by using the settings in `config.action_mailer` by `send`'ing the method names as setters to `ActionMailer::Base` and passing the values through. -* `action_mailer.compile_config_methods` Initializes methods for the config settings specified so that they are quicker to access. +* `action_mailer.compile_config_methods`: Initializes methods for the config settings specified so that they are quicker to access. -* `set_load_path` This initializer runs before `bootstrap_hook`. Adds the `vendor`, `lib`, all directories of `app` and any paths specified by `config.load_paths` to `$LOAD_PATH`. +* `set_load_path`: This initializer runs before `bootstrap_hook`. Adds paths specified by `config.load_paths` and all autoload paths to `$LOAD_PATH`. -* `set_autoload_paths` This initializer runs before `bootstrap_hook`. Adds all sub-directories of `app` and paths specified by `config.autoload_paths` to `ActiveSupport::Dependencies.autoload_paths`. +* `set_autoload_paths`: This initializer runs before `bootstrap_hook`. Adds all sub-directories of `app` and paths specified by `config.autoload_paths`, `config.eager_load_paths` and `config.autoload_once_paths` to `ActiveSupport::Dependencies.autoload_paths`. -* `add_routing_paths` Loads (by default) all `config/routes.rb` files (in the application and railties, including engines) and sets up the routes for the application. +* `add_routing_paths`: Loads (by default) all `config/routes.rb` files (in the application and railties, including engines) and sets up the routes for the application. -* `add_locales` Adds the files in `config/locales` (from the application, railties and engines) to `I18n.load_path`, making available the translations in these files. +* `add_locales`: Adds the files in `config/locales` (from the application, railties and engines) to `I18n.load_path`, making available the translations in these files. -* `add_view_paths` Adds the directory `app/views` from the application, railties and engines to the lookup path for view files for the application. +* `add_view_paths`: Adds the directory `app/views` from the application, railties and engines to the lookup path for view files for the application. -* `load_environment_config` Loads the `config/environments` file for the current environment. +* `load_environment_config`: Loads the `config/environments` file for the current environment. -* `prepend_helpers_path` Adds the directory `app/helpers` from the application, railties and engines to the lookup path for helpers for the application. +* `prepend_helpers_path`: Adds the directory `app/helpers` from the application, railties and engines to the lookup path for helpers for the application. -* `load_config_initializers` Loads all Ruby files from `config/initializers` in the application, railties and engines. The files in this directory can be used to hold configuration settings that should be made after all of the frameworks are loaded. +* `load_config_initializers`: Loads all Ruby files from `config/initializers` in the application, railties and engines. The files in this directory can be used to hold configuration settings that should be made after all of the frameworks are loaded. -* `engines_blank_point` Provides a point-in-initialization to hook into if you wish to do anything before engines are loaded. After this point, all railtie and engine initializers are run. +* `engines_blank_point`: Provides a point-in-initialization to hook into if you wish to do anything before engines are loaded. After this point, all railtie and engine initializers are run. -* `add_generator_templates` Finds templates for generators at `lib/templates` for the application, railties and engines and adds these to the `config.generators.templates` setting, which will make the templates available for all generators to reference. +* `add_generator_templates`: Finds templates for generators at `lib/templates` for the application, railties and engines and adds these to the `config.generators.templates` setting, which will make the templates available for all generators to reference. -* `ensure_autoload_once_paths_as_subset` Ensures that the `config.autoload_once_paths` only contains paths from `config.autoload_paths`. If it contains extra paths, then an exception will be raised. +* `ensure_autoload_once_paths_as_subset`: Ensures that the `config.autoload_once_paths` only contains paths from `config.autoload_paths`. If it contains extra paths, then an exception will be raised. -* `add_to_prepare_blocks` The block for every `config.to_prepare` call in the application, a railtie or engine is added to the `to_prepare` callbacks for Action Dispatch which will be run per request in development, or before the first request in production. +* `add_to_prepare_blocks`: The block for every `config.to_prepare` call in the application, a railtie or engine is added to the `to_prepare` callbacks for Action Dispatch which will be run per request in development, or before the first request in production. -* `add_builtin_route` If the application is running under the development environment then this will append the route for `rails/info/properties` to the application routes. This route provides the detailed information such as Rails and Ruby version for `public/index.html` in a default Rails application. +* `add_builtin_route`: If the application is running under the development environment then this will append the route for `rails/info/properties` to the application routes. This route provides the detailed information such as Rails and Ruby version for `public/index.html` in a default Rails application. -* `build_middleware_stack` Builds the middleware stack for the application, returning an object which has a `call` method which takes a Rack environment object for the request. +* `build_middleware_stack`: Builds the middleware stack for the application, returning an object which has a `call` method which takes a Rack environment object for the request. -* `eager_load!` If `config.eager_load` is true, runs the `config.before_eager_load` hooks and then calls `eager_load!` which will load all `config.eager_load_namespaces`. +* `eager_load!`: If `config.eager_load` is `true`, runs the `config.before_eager_load` hooks and then calls `eager_load!` which will load all `config.eager_load_namespaces`. -* `finisher_hook` Provides a hook for after the initialization of process of the application is complete, as well as running all the `config.after_initialize` blocks for the application, railties and engines. +* `finisher_hook`: Provides a hook for after the initialization of process of the application is complete, as well as running all the `config.after_initialize` blocks for the application, railties and engines. -* `set_routes_reloader` Configures Action Dispatch to reload the routes file using `ActionDispatch::Callbacks.to_prepare`. +* `set_routes_reloader`: Configures Action Dispatch to reload the routes file using `ActionDispatch::Callbacks.to_prepare`. -* `disable_dependency_loading` Disables the automatic dependency loading if the `config.eager_load` is set to true. +* `disable_dependency_loading`: Disables the automatic dependency loading if the `config.eager_load` is set to `true`. Database pooling ---------------- @@ -1113,21 +1169,48 @@ NOTE. If you are running in a multi-threaded environment, there could be a chanc Custom configuration -------------------- -You can configure your own code through the Rails configuration object with custom configuration under the `config.x` property. It works like this: +You can configure your own code through the Rails configuration object with custom configuration. It works like this: ```ruby - config.x.payment_processing.schedule = :daily - config.x.payment_processing.retries = 3 - config.x.super_debugger = true + config.payment_processing.schedule = :daily + config.payment_processing.retries = 3 + config.super_debugger = true ``` These configuration points are then available through the configuration object: ```ruby - Rails.configuration.x.payment_processing.schedule # => :daily - Rails.configuration.x.payment_processing.retries # => 3 - Rails.configuration.x.super_debugger # => true - Rails.configuration.x.super_debugger.not_set # => nil + Rails.configuration.payment_processing.schedule # => :daily + Rails.configuration.payment_processing.retries # => 3 + Rails.configuration.super_debugger # => true + Rails.configuration.super_debugger.not_set # => nil + ``` + +You can also use `Rails::Application.config_for` to load whole configuration files: + + ```ruby + # config/payment.yml: + production: + environment: production + merchant_id: production_merchant_id + public_key: production_public_key + private_key: production_private_key + development: + environment: sandbox + merchant_id: development_merchant_id + public_key: development_public_key + private_key: development_private_key + + # config/application.rb + module MyApp + class Application < Rails::Application + config.payment = config_for(:payment) + end + end + ``` + + ```ruby + Rails.configuration.payment['merchant_id'] # => production_merchant_id or development_merchant_id ``` Search Engines Indexing @@ -1149,3 +1232,25 @@ Disallow: / To block just specific pages, it's necessary to use a more complex syntax. Learn it on the [official documentation](http://www.robotstxt.org/robotstxt.html). + +Evented File System Monitor +--------------------------- + +If the [listen gem](https://github.com/guard/listen) is loaded Rails uses an +evented file system monitor to detect changes when `config.cache_classes` is +`false`: + +```ruby +group :development do + gem 'listen', '~> 3.0.4' +end +``` + +Otherwise, in every request Rails walks the application tree to check if +anything has changed. + +On Linux and Mac OS X no additional gems are needed, but some are required +[for *BSD](https://github.com/guard/listen#on-bsd) and +[for Windows](https://github.com/guard/listen#on-windows). + +Note that [some setups are unsupported](https://github.com/guard/listen#issues--limitations). diff --git a/guides/source/contributing_to_ruby_on_rails.md b/guides/source/contributing_to_ruby_on_rails.md index 53c3cbf80b..59c902e148 100644 --- a/guides/source/contributing_to_ruby_on_rails.md +++ b/guides/source/contributing_to_ruby_on_rails.md @@ -16,7 +16,7 @@ After reading this guide, you will know: Ruby on Rails is not "someone else's framework." Over the years, hundreds of people have contributed to Ruby on Rails ranging from a single character to massive architectural changes or significant documentation - all with the goal of making Ruby on Rails better for everyone. Even if you don't feel up to writing code or documentation yet, there are a variety of other ways that you can contribute, from reporting issues to testing patches. As mentioned in [Rails -README](https://github.com/rails/rails/blob/master/README.md), everyone interacting in Rails and its sub-projects' codebases, issue trackers, chat rooms, and mailing lists is expected to follow the Rails [code of conduct](https://github.com/rails/rails/blob/master/CODE_OF_CONDUCT.md). +README](https://github.com/rails/rails/blob/master/README.md), everyone interacting in Rails and its sub-projects' codebases, issue trackers, chat rooms, and mailing lists is expected to follow the Rails [code of conduct](http://rubyonrails.org/conduct/). -------------------------------------------------------------------------------- @@ -105,7 +105,7 @@ $ git checkout -b testing_branch Then you can use their remote branch to update your codebase. For example, let's say the GitHub user JohnSmith has forked and pushed to a topic branch "orange" located at https://github.com/JohnSmith/rails. ```bash -$ git remote add JohnSmith git://github.com/JohnSmith/rails.git +$ git remote add JohnSmith https://github.com/JohnSmith/rails.git $ git pull JohnSmith orange ``` @@ -130,11 +130,11 @@ learn about Ruby on Rails, and the API, which serves as a reference. You can help improve the Rails guides by making them more coherent, consistent or readable, adding missing information, correcting factual errors, fixing typos, or bringing them up to date with the latest edge Rails. -You can either open a pull request to [Rails](http://github.com/rails/rails) or +You can either open a pull request to [Rails](https://github.com/rails/rails) or ask the [Rails core team](http://rubyonrails.org/core) for commit access on docrails if you contribute regularly. Please do not open pull requests in docrails, if you'd like to get feedback on your -change, ask for it in [Rails](http://github.com/rails/rails) instead. +change, ask for it in [Rails](https://github.com/rails/rails) instead. Docrails is merged with master regularly, so you are effectively editing the Ruby on Rails documentation. @@ -148,6 +148,42 @@ NOTE: To help our CI servers you should add [ci skip] to your documentation comm WARNING: Docrails has a very strict policy: no code can be touched whatsoever, no matter how trivial or small the change. Only RDoc and guides can be edited via docrails. Also, CHANGELOGs should never be edited in docrails. +Translating Rails Guides +------------------------ + +We are happy to have people volunteer to translate the Rails guides into their own language. +If you want to translate the Rails guides in your own language, follows these steps: + +* Fork the project (rails/rails). +* Add a source folder for your own language, for example: *guides/source/it-IT* for Italian. +* Copy the contents of *guides/source* into your own language directory and translate them. +* Do NOT translate the HTML files, as they are automatically generated. + +To generate the guides in HTML format cd into the *guides* directory then run (eg. for it-IT): + +```bash +$ bundle install +$ bundle exec rake guides:generate:html GUIDES_LANGUAGE=it-IT +``` + +This will generate the guides in an *output* directory. + +NOTE: The instructions are for Rails > 4. The Redcarpet Gem doesn't work with JRuby. + +Translation efforts we know about (various versions): + +* **Italian**: [https://github.com/rixlabs/docrails](https://github.com/rixlabs/docrails) +* **Spanish**: [http://wiki.github.com/gramos/docrails](http://wiki.github.com/gramos/docrails) +* **Polish**: [https://github.com/apohllo/docrails/tree/master](https://github.com/apohllo/docrails/tree/master) +* **French** : [https://github.com/railsfrance/docrails](https://github.com/railsfrance/docrails) +* **Czech** : [https://github.com/rubyonrails-cz/docrails/tree/czech](https://github.com/rubyonrails-cz/docrails/tree/czech) +* **Turkish** : [https://github.com/ujk/docrails/tree/master](https://github.com/ujk/docrails/tree/master) +* **Korean** : [https://github.com/rorlakr/rails-guides](https://github.com/rorlakr/rails-guides) +* **Simplified Chinese** : [https://github.com/ruby-china/guides](https://github.com/ruby-china/guides) +* **Traditional Chinese** : [https://github.com/docrails-tw/guides](https://github.com/docrails-tw/guides) +* **Russian** : [https://github.com/morsbox/rusrails](https://github.com/morsbox/rusrails) +* **Japanese** : [https://github.com/yasslab/railsguides.jp](https://github.com/yasslab/railsguides.jp) + Contributing to the Rails Code ------------------------------ @@ -168,7 +204,7 @@ In case you can't use the Rails development box, see [this other guide](developm To be able to contribute code, you need to clone the Rails repository: ```bash -$ git clone git://github.com/rails/rails.git +$ git clone https://github.com/rails/rails.git ``` and create a dedicated branch: @@ -321,7 +357,6 @@ $ bundle exec rake test:sqlite3 You can now run the tests as you did for `sqlite3`. The tasks are respectively: ```bash -test:mysql test:mysql2 test:postgresql ``` @@ -332,7 +367,7 @@ Finally, $ bundle exec rake test ``` -will now run the four of them in turn. +will now run the three of them in turn. You can also run any single test separately: @@ -471,7 +506,7 @@ Navigate to the Rails [GitHub repository](https://github.com/rails/rails) and pr Add the new remote to your local repository on your local machine: ```bash -$ git remote add mine git@github.com:<your user name>/rails.git +$ git remote add mine https://github.com:<your user name>/rails.git ``` Push to your remote: @@ -485,7 +520,7 @@ You might have cloned your forked repository into your machine and might want to In the directory you cloned your fork: ```bash -$ git remote add rails git://github.com/rails/rails.git +$ git remote add rails https://github.com/rails/rails.git ``` Download new commits and branches from the official repository: diff --git a/guides/source/debugging_rails_applications.md b/guides/source/debugging_rails_applications.md index a05abb61d6..f0d0f9753a 100644 --- a/guides/source/debugging_rails_applications.md +++ b/guides/source/debugging_rails_applications.md @@ -109,18 +109,18 @@ It can also be useful to save information to log files at runtime. Rails maintai Rails makes use of the `ActiveSupport::Logger` class to write log information. Other loggers, such as `Log4r`, may also be substituted. -You can specify an alternative logger in `environment.rb` or any other environment file, for example: +You can specify an alternative logger in `config/application.rb` or any other environment file, for example: ```ruby -Rails.logger = Logger.new(STDOUT) -Rails.logger = Log4r::Logger.new("Application Log") +config.logger = Logger.new(STDOUT) +config.logger = Log4r::Logger.new("Application Log") ``` Or in the `Initializer` section, add _any_ of the following ```ruby -config.logger = Logger.new(STDOUT) -config.logger = Log4r::Logger.new("Application Log") +Rails.logger = Logger.new(STDOUT) +Rails.logger = Log4r::Logger.new("Application Log") ``` TIP: By default, each log is created under `Rails.root/log/` and the log file is named after the environment in which the application is running. @@ -255,7 +255,8 @@ is your best companion. The debugger can also help you if you want to learn about the Rails source code but don't know where to start. Just debug any request to your application and -use this guide to learn how to move from the code you have written into the underlying Rails code. +use this guide to learn how to move from the code you have written into the +underlying Rails code. ### Setup @@ -311,16 +312,15 @@ processing the entire request. For example: ```bash -=> Booting WEBrick +=> Booting Puma => Rails 5.0.0 application starting in development on http://0.0.0.0:3000 => Run `rails server -h` for more startup options -=> Notice: server is listening on all interfaces (0.0.0.0). Consider using 127.0.0.1 (--binding option) -=> Ctrl-C to shutdown server -[2014-04-11 13:11:47] INFO WEBrick 1.3.1 -[2014-04-11 13:11:47] INFO ruby 2.2.2 (2015-04-13) [i686-linux] -[2014-04-11 13:11:47] INFO WEBrick::HTTPServer#start: pid=6370 port=3000 - - +Puma starting in single mode... +* Version 3.4.0 (ruby 2.3.1-p112), codename: Owl Bowl Brawl +* Min threads: 5, max threads: 5 +* Environment: development +* Listening on tcp://localhost:3000 +Use Ctrl-C to stop Started GET "/" for 127.0.0.1 at 2014-04-11 13:11:48 +0200 ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations".* FROM "schema_migrations" Processing by ArticlesController#index as HTML @@ -336,7 +336,6 @@ Processing by ArticlesController#index as HTML 10: respond_to do |format| 11: format.html # index.html.erb 12: format.json { render json: @articles } - (byebug) ``` @@ -346,11 +345,45 @@ by asking the debugger for help. Type: `help` ``` (byebug) help - h[elp][ <cmd>[ <subcmd>]] + break -- Sets breakpoints in the source code + catch -- Handles exception catchpoints + condition -- Sets conditions on breakpoints + continue -- Runs until program ends, hits a breakpoint or reaches a line + debug -- Spawns a subdebugger + delete -- Deletes breakpoints + disable -- Disables breakpoints or displays + display -- Evaluates expressions every time the debugger stops + down -- Moves to a lower frame in the stack trace + edit -- Edits source files + enable -- Enables breakpoints or displays + finish -- Runs the program until frame returns + frame -- Moves to a frame in the call stack + help -- Helps you using byebug + history -- Shows byebug's history of commands + info -- Shows several informations about the program being debugged + interrupt -- Interrupts the program + irb -- Starts an IRB session + kill -- Sends a signal to the current process + list -- Lists lines of source code + method -- Shows methods of an object, class or module + next -- Runs one or more lines of code + pry -- Starts a Pry session + quit -- Exits byebug + restart -- Restarts the debugged program + save -- Saves current byebug session to a file + set -- Modifies byebug settings + show -- Shows byebug settings + source -- Restores a previously saved byebug session + step -- Steps into blocks or methods one or more times + thread -- Commands to manipulate threads + tracevar -- Enables tracing of a global variable + undisplay -- Stops displaying all or some expressions when program stops + untracevar -- Stops tracing a global variable + up -- Moves to a higher frame in the stack trace + var -- Shows variables and its values + where -- Displays the backtrace - help -- prints this help. - help <cmd> -- prints help on command <cmd>. - help <cmd> <subcmd> -- prints help on <cmd>'s subcommand <subcmd>. +(byebug) ``` To see the previous ten lines you should type `list-` (or `l-`). @@ -369,12 +402,11 @@ To see the previous ten lines you should type `list-` (or `l-`). 8 @articles = Article.find_recent 9 10 respond_to do |format| - ``` -This way you can move inside the file and see the code above -the line where you added the `byebug` call. Finally, to see where you are in -the code again you can type `list=` +This way you can move inside the file and see the code above the line where you +added the `byebug` call. Finally, to see where you are in the code again you can +type `list=` ``` (byebug) list= @@ -390,7 +422,6 @@ the code again you can type `list=` 10: respond_to do |format| 11: format.html # index.html.erb 12: format.json { render json: @articles } - (byebug) ``` @@ -412,46 +443,45 @@ then `backtrace` will supply the answer. ``` (byebug) where --> #0 ArticlesController.index - at /PathTo/project/test_app/app/controllers/articles_controller.rb:8 - #1 ActionController::ImplicitRender.send_action(method#String, *args#Array) - at /PathToGems/actionpack-5.0.0/lib/action_controller/metal/implicit_render.rb:4 + at /PathToProject/app/controllers/articles_controller.rb:8 + #1 ActionController::BasicImplicitRender.send_action(method#String, *args#Array) + at /PathToGems/actionpack-5.0.0/lib/action_controller/metal/basic_implicit_render.rb:4 #2 AbstractController::Base.process_action(action#NilClass, *args#Array) - at /PathToGems/actionpack-5.0.0/lib/abstract_controller/base.rb:189 - #3 ActionController::Rendering.process_action(action#NilClass, *args#NilClass) - at /PathToGems/actionpack-5.0.0/lib/action_controller/metal/rendering.rb:10 + at /PathToGems/actionpack-5.0.0/lib/abstract_controller/base.rb:181 + #3 ActionController::Rendering.process_action(action, *args) + at /PathToGems/actionpack-5.0.0/lib/action_controller/metal/rendering.rb:30 ... ``` The current frame is marked with `-->`. You can move anywhere you want in this -trace (thus changing the context) by using the `frame _n_` command, where _n_ is +trace (thus changing the context) by using the `frame n` command, where _n_ is the specified frame number. If you do that, `byebug` will display your new context. ``` (byebug) frame 2 -[184, 193] in /PathToGems/actionpack-5.0.0/lib/abstract_controller/base.rb - 184: # is the intended way to override action dispatching. - 185: # - 186: # Notice that the first argument is the method to be dispatched - 187: # which is *not* necessarily the same as the action name. - 188: def process_action(method_name, *args) -=> 189: send_action(method_name, *args) - 190: end - 191: - 192: # Actually call the method associated with the action. Override - 193: # this method if you wish to change how action methods are called, - +[176, 185] in /PathToGems/actionpack-5.0.0/lib/abstract_controller/base.rb + 176: # is the intended way to override action dispatching. + 177: # + 178: # Notice that the first argument is the method to be dispatched + 179: # which is *not* necessarily the same as the action name. + 180: def process_action(method_name, *args) +=> 181: send_action(method_name, *args) + 182: end + 183: + 184: # Actually call the method associated with the action. Override + 185: # this method if you wish to change how action methods are called, (byebug) ``` The available variables are the same as if you were running the code line by line. After all, that's what debugging is. -You can also use `up [n]` (`u` for abbreviated) and `down [n]` commands in order -to change the context _n_ frames up or down the stack respectively. _n_ defaults -to one. Up in this case is towards higher-numbered stack frames, and down is -towards lower-numbered stack frames. +You can also use `up [n]` and `down [n]` commands in order to change the context +_n_ frames up or down the stack respectively. _n_ defaults to one. Up in this +case is towards higher-numbered stack frames, and down is towards lower-numbered +stack frames. ### Threads @@ -460,11 +490,11 @@ the `thread` command (or the abbreviated `th`). This command has a handful of options: * `thread`: shows the current thread. -* `thread list`: is used to list all threads and their statuses. The plus + -character and the number indicates the current thread of execution. -* `thread stop _n_`: stop thread _n_. -* `thread resume _n_`: resumes thread _n_. -* `thread switch _n_`: switches the current thread context to _n_. +* `thread list`: is used to list all threads and their statuses. The current +thread is marked with a plus (+) sign. +* `thread stop n`: stops thread _n_. +* `thread resume n`: resumes thread _n_. +* `thread switch n`: switches the current thread context to _n_. This command is very helpful when you are debugging concurrent threads and need to verify that there are no race conditions in your code. @@ -491,9 +521,9 @@ current context: 12: format.json { render json: @articles } (byebug) instance_variables -[:@_action_has_layout, :@_routes, :@_headers, :@_status, :@_request, - :@_response, :@_prefixes, :@_lookup_context, :@_action_name, - :@_response_body, :@marked_for_same_origin_verification, :@_config] +[:@_action_has_layout, :@_routes, :@_request, :@_response, :@_lookup_context, + :@_action_name, :@_response_body, :@marked_for_same_origin_verification, + :@_config] ``` As you may have figured out, all of the variables that you can access from a @@ -503,6 +533,7 @@ command later in this guide). ``` (byebug) next + [5, 14] in /PathTo/project/app/controllers/articles_controller.rb 5 # GET /articles.json 6 def index @@ -522,29 +553,35 @@ And then ask again for the instance_variables: ``` (byebug) instance_variables -[:@_action_has_layout, :@_routes, :@_headers, :@_status, :@_request, - :@_response, :@_prefixes, :@_lookup_context, :@_action_name, - :@_response_body, :@marked_for_same_origin_verification, :@_config, - :@articles] +[:@_action_has_layout, :@_routes, :@_request, :@_response, :@_lookup_context, + :@_action_name, :@_response_body, :@marked_for_same_origin_verification, + :@_config, :@articles] ``` -Now `@articles` is included in the instance variables, because the line defining it -was executed. +Now `@articles` is included in the instance variables, because the line defining +it was executed. TIP: You can also step into **irb** mode with the command `irb` (of course!). -This will start an irb session within the context you invoked it. But -be warned: this is an experimental feature. +This will start an irb session within the context you invoked it. The `var` method is the most convenient way to show variables and their values. Let's have `byebug` help us with it. ``` (byebug) help var -v[ar] cl[ass] show class variables of self -v[ar] const <object> show constants of object -v[ar] g[lobal] show global variables -v[ar] i[nstance] <object> show instance variables of object -v[ar] l[ocal] show local variables + + [v]ar <subcommand> + + Shows variables and its values + + + var all -- Shows local, global and instance variables of self. + var args -- Information about arguments of the current scope + var const -- Shows constants of an object. + var global -- Shows global variables. + var instance -- Shows instance variables of self or a specific object. + var local -- Shows local variables in current scope. + ``` This is a great way to inspect the values of the current context variables. For @@ -562,16 +599,17 @@ You can also inspect for an object method this way: @_start_transaction_state = {} @aggregation_cache = {} @association_cache = {} -@attributes = {"id"=>nil, "created_at"=>nil, "updated_at"=>nil} -@attributes_cache = {} -@changed_attributes = nil -... +@attributes = #<ActiveRecord::AttributeSet:0x007fd0682a9b18 @attributes={"id"=>#<ActiveRecord::Attribute::FromDatabase:0x007fd0682a9a00 @name="id", @value_be... +@destroyed = false +@destroyed_by_association = nil +@marked_for_destruction = false +@new_record = true +@readonly = false +@transaction_state = nil +@txn = nil ``` -TIP: The commands `p` (print) and `pp` (pretty print) can be used to evaluate -Ruby expressions and display the value of variables to the console. - -You can use also `display` to start watching variables. This is a good way of +You can also use `display` to start watching variables. This is a good way of tracking the values of a variable while the execution goes on. ``` @@ -580,7 +618,7 @@ tracking the values of a variable while the execution goes on. ``` The variables inside the displayed list will be printed with their values after -you move in the stack. To stop displaying a variable use `undisplay _n_` where +you move in the stack. To stop displaying a variable use `undisplay n` where _n_ is the variable number (1 in the last example). ### Step by Step @@ -590,32 +628,23 @@ available variables. But let's continue and move on with the application execution. Use `step` (abbreviated `s`) to continue running your program until the next -logical stopping point and return control to the debugger. - -You may also use `next` which is similar to step, but function or method calls -that appear within the line of code are executed without stopping. - -TIP: You can also use `step n` or `next n` to move forwards `n` steps at once. - -The difference between `next` and `step` is that `step` stops at the next line -of code executed, doing just a single step, while `next` moves to the next line -without descending inside methods. +logical stopping point and return control to the debugger. `next` is similar to +`step`, but while `step` stops at the next line of code executed, doing just a +single step, `next` moves to the next line without descending inside methods. For example, consider the following situation: -```ruby +``` Started GET "/" for 127.0.0.1 at 2014-04-11 13:39:23 +0200 Processing by ArticlesController#index as HTML -[1, 8] in /home/davidr/Proyectos/test_app/app/models/article.rb - 1: class Article < ActiveRecord::Base - 2: - 3: def self.find_recent(limit = 10) - 4: byebug -=> 5: where('created_at > ?', 1.week.ago).limit(limit) - 6: end - 7: - 8: end +[1, 6] in /PathToProject/app/models/article.rb + 1: class Article < ApplicationRecord + 2: def self.find_recent(limit = 10) + 3: byebug +=> 4: where('created_at > ?', 1.week.ago).limit(limit) + 5: end + 6: end (byebug) ``` @@ -627,11 +656,7 @@ method. ``` (byebug) next - -Next advances to the next line (line 6: `end`), which returns to the next line -of the caller method: - -[4, 13] in /PathTo/project/test_app/app/controllers/articles_controller.rb +[4, 13] in /PathToProject/app/controllers/articles_controller.rb 4: # GET /articles 5: # GET /articles.json 6: def index @@ -652,23 +677,24 @@ Ruby instruction to be executed -- in this case, Active Support's `week` method. ``` (byebug) step -[50, 59] in /PathToGems/activesupport-5.0.0/lib/active_support/core_ext/numeric/time.rb - 50: ActiveSupport::Duration.new(self * 24.hours, [[:days, self]]) - 51: end - 52: alias :day :days - 53: - 54: def weeks -=> 55: ActiveSupport::Duration.new(self * 7.days, [[:days, self * 7]]) - 56: end - 57: alias :week :weeks - 58: - 59: def fortnights - +[49, 58] in /PathToGems/activesupport-5.0.0/lib/active_support/core_ext/numeric/time.rb + 49: + 50: # Returns a Duration instance matching the number of weeks provided. + 51: # + 52: # 2.weeks # => 14 days + 53: def weeks +=> 54: ActiveSupport::Duration.new(self * 7.days, [[:days, self * 7]]) + 55: end + 56: alias :week :weeks + 57: + 58: # Returns a Duration instance matching the number of fortnights provided. (byebug) ``` This is one of the best ways to find bugs in your code. +TIP: You can also use `step n` or `next n` to move forward `n` steps at once. + ### Breakpoints A breakpoint makes your application stop whenever a certain point in the program @@ -677,19 +703,18 @@ is reached. The debugger shell is invoked in that line. You can add breakpoints dynamically with the command `break` (or just `b`). There are 3 possible ways of adding breakpoints manually: -* `break line`: set breakpoint in the _line_ in the current source file. -* `break file:line [if expression]`: set breakpoint in the _line_ number inside -the _file_. If an _expression_ is given it must evaluated to _true_ to fire up -the debugger. +* `break n`: set breakpoint in line number _n_ in the current source file. +* `break file:n [if expression]`: set breakpoint in line number _n_ inside +file named _file_. If an _expression_ is given it must evaluated to _true_ to +fire up the debugger. * `break class(.|\#)method [if expression]`: set breakpoint in _method_ (. and \# for class and instance method respectively) defined in _class_. The -_expression_ works the same way as with file:line. - +_expression_ works the same way as with file:n. For example, in the previous situation ``` -[4, 13] in /PathTo/project/app/controllers/articles_controller.rb +[4, 13] in /PathToProject/app/controllers/articles_controller.rb 4: # GET /articles 5: # GET /articles.json 6: def index @@ -702,20 +727,20 @@ For example, in the previous situation 13: end (byebug) break 11 -Created breakpoint 1 at /PathTo/project/app/controllers/articles_controller.rb:11 +Successfully created breakpoint with id 1 ``` -Use `info breakpoints _n_` or `info break _n_` to list breakpoints. If you -supply a number, it lists that breakpoint. Otherwise it lists all breakpoints. +Use `info breakpoints` to list breakpoints. If you supply a number, it lists +that breakpoint. Otherwise it lists all breakpoints. ``` (byebug) info breakpoints Num Enb What -1 y at /PathTo/project/app/controllers/articles_controller.rb:11 +1 y at /PathToProject/app/controllers/articles_controller.rb:11 ``` -To delete breakpoints: use the command `delete _n_` to remove the breakpoint +To delete breakpoints: use the command `delete n` to remove the breakpoint number _n_. If no number is specified, it deletes all breakpoints that are currently active. @@ -727,10 +752,11 @@ No breakpoints. You can also enable or disable breakpoints: -* `enable breakpoints`: allow a _breakpoints_ list or all of them if no list is -specified, to stop your program. This is the default state when you create a +* `enable breakpoints [n [m [...]]]`: allows a specific breakpoint list or all +breakpoints to stop your program. This is the default state when you create a breakpoint. -* `disable breakpoints`: the _breakpoints_ will have no effect on your program. +* `disable breakpoints [n [m [...]]]`: make certain (or all) breakpoints have +no effect on your program. ### Catching Exceptions @@ -745,24 +771,22 @@ To list all active catchpoints use `catch`. There are two ways to resume execution of an application that is stopped in the debugger: -* `continue [line-specification]` \(or `c`): resume program execution, at the -address where your script last stopped; any breakpoints set at that address are -bypassed. The optional argument line-specification allows you to specify a line -number to set a one-time breakpoint which is deleted when that breakpoint is -reached. -* `finish [frame-number]` \(or `fin`): execute until the selected stack frame -returns. If no frame number is given, the application will run until the -currently selected frame returns. The currently selected frame starts out the -most-recent frame or 0 if no frame positioning (e.g up, down or frame) has been -performed. If a frame number is given it will run until the specified frame -returns. +* `continue [n]`: resumes program execution at the address where your script last +stopped; any breakpoints set at that address are bypassed. The optional argument +`n` allows you to specify a line number to set a one-time breakpoint which is +deleted when that breakpoint is reached. +* `finish [n]`: execute until the selected stack frame returns. If no frame +number is given, the application will run until the currently selected frame +returns. The currently selected frame starts out the most-recent frame or 0 if +no frame positioning (e.g up, down or frame) has been performed. If a frame +number is given it will run until the specified frame returns. ### Editing Two commands allow you to open code from the debugger into an editor: -* `edit [file:line]`: edit _file_ using the editor specified by the EDITOR -environment variable. A specific _line_ can also be given. +* `edit [file:n]`: edit file named _file_ using the editor specified by the +EDITOR environment variable. A specific line _n_ can also be given. ### Quitting @@ -776,21 +800,43 @@ will be stopped and you will have to start it again. `byebug` has a few available options to tweak its behavior: -* `set autoreload`: Reload source code when changed (defaults: true). -* `set autolist`: Execute `list` command on every breakpoint (defaults: true). -* `set listsize _n_`: Set number of source lines to list by default to _n_ -(defaults: 10) -* `set forcestep`: Make sure the `next` and `step` commands always move to a new -line. +``` +(byebug) help set + + set <setting> <value> -You can see the full list by using `help set`. Use `help set _subcommand_` to -learn about a particular `set` command. + Modifies byebug settings + + Boolean values take "on", "off", "true", "false", "1" or "0". If you + don't specify a value, the boolean setting will be enabled. Conversely, + you can use "set no<setting>" to disable them. + + You can see these environment settings with the "show" command. + + List of supported settings: + + autosave -- Automatically save command history record on exit + autolist -- Invoke list command on every stop + width -- Number of characters per line in byebug's output + autoirb -- Invoke IRB on every stop + basename -- <file>:<line> information after every stop uses short paths + linetrace -- Enable line execution tracing + autopry -- Invoke Pry on every stop + stack_on_error -- Display stack trace when `eval` raises an exception + fullpath -- Display full file names in backtraces + histfile -- File where cmd history is saved to. Default: ./.byebug_history + listsize -- Set number of source lines to list by default + post_mortem -- Enable/disable post-mortem mode + callstyle -- Set how you want method call parameters to be displayed + histsize -- Maximum number of commands that can be stored in byebug history + savefile -- File where settings are saved to. Default: ~/.byebug_save +``` TIP: You can save these settings in an `.byebugrc` file in your home directory. The debugger reads these global settings when it starts. For example: ```bash -set forcestep +set callstyle short set listsize 25 ``` @@ -862,8 +908,8 @@ such as Valgrind. ### Valgrind -[Valgrind](http://valgrind.org/) is a Linux-only application for detecting -C-based memory leaks and race conditions. +[Valgrind](http://valgrind.org/) is an application for detecting C-based memory +leaks and race conditions. There are Valgrind tools that can automatically detect many memory management and threading bugs, and profile your programs in detail. For example, if a C diff --git a/guides/source/development_dependencies_install.md b/guides/source/development_dependencies_install.md index 4322f03d05..cc24e6f666 100644 --- a/guides/source/development_dependencies_install.md +++ b/guides/source/development_dependencies_install.md @@ -30,7 +30,6 @@ Ruby on Rails uses Git for source code control. The [Git homepage](http://git-sc * [Try Git course](http://try.github.io/) is an interactive course that will teach you the basics. * The [official Documentation](http://git-scm.com/documentation) is pretty comprehensive and also contains some videos with the basics of Git. * [Everyday Git](http://schacon.github.io/git/everyday.html) will teach you just enough about Git to get by. -* The [PeepCode screencast](https://peepcode.com/products/git) on Git is easier to follow. * [GitHub](http://help.github.com) offers links to a variety of Git resources. * [Pro Git](http://git-scm.com/book) is an entire book about Git with a Creative Commons license. @@ -165,7 +164,7 @@ $ bundle exec ruby -Itest path/to/test.rb -n test_name ### Active Record Setup -The test suite of Active Record attempts to run four times: once for SQLite3, once for each of the two MySQL gems (`mysql` and `mysql2`), and once for PostgreSQL. We are going to see now how to set up the environment for them. +Active Record's test suite runs three times: once for SQLite3, once for MySQL, and once for PostgreSQL. We are going to see now how to set up the environment for them. WARNING: If you're working with Active Record code, you _must_ ensure that the tests pass for at least MySQL, PostgreSQL, and SQLite3. Subtle differences between the various adapters have been behind the rejection of many patches that looked OK when tested only against MySQL. diff --git a/guides/source/documents.yaml b/guides/source/documents.yaml index 4473eba478..a5b8a75509 100644 --- a/guides/source/documents.yaml +++ b/guides/source/documents.yaml @@ -116,7 +116,7 @@ name: The Rails Initialization Process work_in_progress: true url: initialization.html - description: This guide explains the internals of the Rails initialization process as of Rails 4. + description: This guide explains the internals of the Rails initialization process. - name: Autoloading and Reloading Constants url: autoloading_and_reloading_constants.html @@ -135,6 +135,14 @@ work_in_progress: true url: profiling.html description: This guide explains how to profile your Rails applications to improve performance. + - + name: Using Rails for API-only Applications + url: api_app.html + description: This guide explains how to effectively use Rails to develop a JSON API application. + - + name: Action Cable Overview + url: action_cable_overview.html + description: This guide explains how Action Cable works, and how to use WebSockets to create real-time features. - name: Extending Rails diff --git a/guides/source/engines.md b/guides/source/engines.md index f961b799f1..eafac4828c 100644 --- a/guides/source/engines.md +++ b/guides/source/engines.md @@ -239,6 +239,27 @@ NOTE: The `ApplicationController` class inside an engine is named just like a Rails application in order to make it easier for you to convert your applications into engines. +NOTE: Because of the way that Ruby does constant lookup you may run into a situation +where your engine controller is inheriting from the main application controller and +not your engine's application controller. Ruby is able to resolve the `ApplicationController` constant, and therefore the autoloading mechanism is not triggered. See the section [When Constants Aren't Missed](autoloading_and_reloading_constants.html#when-constants-aren-t-missed) of the [Autoloading and Reloading Constants](autoloading_and_reloading_constants.html) guide for further details. The best way to prevent this from +happening is to use `require_dependency` to ensure that the engine's application +controller is loaded. For example: + +``` ruby +# app/controllers/blorgh/articles_controller.rb: +require_dependency "blorgh/application_controller" + +module Blorgh + class ArticlesController < ApplicationController + ... + end +end +``` + +WARNING: Don't use `require` because it will break the automatic reloading of classes +in the development environment - using `require_dependency` ensures that classes are +loaded and unloaded in the correct manner. + Lastly, the `app/views` directory contains a `layouts` folder, which contains a file at `blorgh/application.html.erb`. This file allows you to specify a layout for the engine. If this engine is to be used as a stand-alone engine, then you @@ -381,8 +402,8 @@ module Blorgh end ``` -NOTE: The `ApplicationController` class being inherited from here is the -`Blorgh::ApplicationController`, not an application's `ApplicationController`. +NOTE: The `ArticlesController` class inherits from +`Blorgh::ApplicationController`, not the application's `ApplicationController`. The helper inside `app/helpers/blorgh/articles_helper.rb` is also namespaced: @@ -402,7 +423,7 @@ Finally, the assets for this resource are generated in two files: `app/assets/stylesheets/blorgh/articles.css`. You'll see how to use these a little later. -You can see what the engine has so far by running `rake db:migrate` at the root +You can see what the engine has so far by running `bin/rails db:migrate` at the root of our engine to run the migration generated by the scaffold generator, and then running `rails server` in `test/dummy`. When you open `http://localhost:3000/blorgh/articles` you will see the default scaffold that has @@ -440,7 +461,7 @@ model, a comment controller and then modify the articles scaffold to display comments and allow people to create new ones. From the application root, run the model generator. Tell it to generate a -`Comment` model, with the related table having two columns: a `article_id` integer +`Comment` model, with the related table having two columns: an `article_id` integer and `text` text column. ```bash @@ -464,7 +485,7 @@ called `Blorgh::Comment`. Now run the migration to create our blorgh_comments table: ```bash -$ rake db:migrate +$ bin/rails db:migrate ``` To show the comments on an article, edit `app/views/blorgh/articles/show.html.erb` and @@ -487,7 +508,7 @@ Turning the model into this: ```ruby module Blorgh - class Article < ActiveRecord::Base + class Article < ApplicationRecord has_many :comments end end @@ -673,14 +694,14 @@ engine's models can query them correctly. To copy these migrations into the application run the following command from the `test/dummy` directory of your Rails engine: ```bash -$ rake blorgh:install:migrations +$ bin/rails blorgh:install:migrations ``` If you have multiple engines that need migrations copied over, use `railties:install:migrations` instead: ```bash -$ rake railties:install:migrations +$ bin/rails railties:install:migrations ``` This command, when run for the first time, will copy over all the migrations @@ -698,7 +719,7 @@ timestamp (`[timestamp_2]`) will be the current time plus a second. The reason for this is so that the migrations for the engine are run after any existing migrations in the application. -To run these migrations within the context of the application, simply run `rake +To run these migrations within the context of the application, simply run `bin/rails db:migrate`. When accessing the engine through `http://localhost:3000/blog`, the articles will be empty. This is because the table created inside the application is different from the one created within the engine. Go ahead, play around with the @@ -709,14 +730,14 @@ If you would like to run migrations only from one engine, you can do it by specifying `SCOPE`: ```bash -rake db:migrate SCOPE=blorgh +bin/rails db:migrate SCOPE=blorgh ``` This may be useful if you want to revert engine's migrations before removing it. To revert all migrations from blorgh engine you can run code such as: ```bash -rake db:migrate SCOPE=blorgh VERSION=0 +bin/rails db:migrate SCOPE=blorgh VERSION=0 ``` ### Using a Class Provided by the Application @@ -743,7 +764,7 @@ application: rails g model user name:string ``` -The `rake db:migrate` command needs to be run here to ensure that our +The `bin/rails db:migrate` command needs to be run here to ensure that our application has the `users` table for future use. Also, to keep it simple, the articles form will have a new text field called @@ -778,7 +799,7 @@ before the article is saved. It will also need to have an `attr_accessor` set up for this field, so that the setter and getter methods are defined for it. To do all this, you'll need to add the `attr_accessor` for `author_name`, the -association for the author and the `before_save` call into +association for the author and the `before_validation` call into `app/models/blorgh/article.rb`. The `author` association will be hard-coded to the `User` class for the time being. @@ -786,7 +807,7 @@ association for the author and the `before_save` call into attr_accessor :author_name belongs_to :author, class_name: "User" -before_save :set_author +before_validation :set_author private def set_author @@ -815,7 +836,7 @@ This migration will need to be run on the application. To do that, it must first be copied using this command: ```bash -$ rake blorgh:install:migrations +$ bin/rails blorgh:install:migrations ``` Notice that only _one_ migration was copied over here. This is because the first @@ -830,7 +851,7 @@ Copied migration [timestamp]_add_author_id_to_blorgh_articles.blorgh.rb from blo Run the migration using: ```bash -$ rake db:migrate +$ bin/rails db:migrate ``` Now with all the pieces in place, an action will take place that will associate @@ -1012,9 +1033,11 @@ typical `GET` to a controller in a controller's functional test like this: ```ruby module Blorgh - class FooControllerTest < ActionController::TestCase + class FooControllerTest < ActionDispatch::IntegrationTest + include Engine.routes.url_helpers + def test_index - get :index + get foos_url ... end end @@ -1028,13 +1051,15 @@ in your setup code: ```ruby module Blorgh - class FooControllerTest < ActionController::TestCase + class FooControllerTest < ActionDispatch::IntegrationTest + include Engine.routes.url_helpers + setup do @routes = Engine.routes end def test_index - get :index + get foos_url ... end end @@ -1108,7 +1133,7 @@ end ```ruby # Blorgh/app/models/article.rb -class Article < ActiveRecord::Base +class Article < ApplicationRecord has_many :comments end ``` @@ -1129,7 +1154,7 @@ end ```ruby # Blorgh/app/models/article.rb -class Article < ActiveRecord::Base +class Article < ApplicationRecord has_many :comments def summary "#{title}" @@ -1150,7 +1175,7 @@ classes at run time allowing you to significantly modularize your code. ```ruby # MyApp/app/models/blorgh/article.rb -class Blorgh::Article < ActiveRecord::Base +class Blorgh::Article < ApplicationRecord include Blorgh::Concerns::Models::Article def time_since_created @@ -1166,7 +1191,7 @@ end ```ruby # Blorgh/app/models/article.rb -class Article < ActiveRecord::Base +class Article < ApplicationRecord include Blorgh::Concerns::Models::Article end ``` @@ -1184,7 +1209,7 @@ module Blorgh::Concerns::Models::Article attr_accessor :author_name belongs_to :author, class_name: "User" - before_save :set_author + before_validation :set_author private def set_author @@ -1333,7 +1358,7 @@ need to require `admin.css` or `admin.js`. Only the gem's admin layout needs these assets. It doesn't make sense for the host app to include `"blorgh/admin.css"` in its stylesheets. In this situation, you should explicitly define these assets for precompilation. This tells sprockets to add -your engine assets when `rake assets:precompile` is triggered. +your engine assets when `bin/rails assets:precompile` is triggered. You can define assets for precompilation in `engine.rb`: diff --git a/guides/source/form_helpers.md b/guides/source/form_helpers.md index 93bb51557a..048fe190e8 100644 --- a/guides/source/form_helpers.md +++ b/guides/source/form_helpers.md @@ -174,7 +174,6 @@ URL fields, email fields, number fields and range fields: <%= search_field(:user, :name) %> <%= telephone_field(:user, :phone) %> <%= date_field(:user, :born_on) %> -<%= datetime_field(:user, :meeting_time) %> <%= datetime_local_field(:user, :graduation_day) %> <%= month_field(:user, :birthday_month) %> <%= week_field(:user, :birthday_week) %> @@ -195,7 +194,6 @@ Output: <input id="user_name" name="user[name]" type="search" /> <input id="user_phone" name="user[phone]" type="tel" /> <input id="user_born_on" name="user[born_on]" type="date" /> -<input id="user_meeting_time" name="user[meeting_time]" type="datetime" /> <input id="user_graduation_day" name="user[graduation_day]" type="datetime-local" /> <input id="user_birthday_month" name="user[birthday_month]" type="month" /> <input id="user_birthday_week" name="user[birthday_week]" type="week" /> @@ -317,7 +315,7 @@ The Article model is directly available to users of the application, so - follow resources :articles ``` -TIP: Declaring a resource has a number of side-affects. See [Rails Routing From the Outside In](routing.html#resource-routing-the-rails-default) for more information on setting up and using resources. +TIP: Declaring a resource has a number of side effects. See [Rails Routing From the Outside In](routing.html#resource-routing-the-rails-default) for more information on setting up and using resources. When dealing with RESTful resources, calls to `form_for` can get significantly easier if you rely on **record identification**. In short, you can just pass the model instance and have Rails figure out model name and the rest: @@ -880,12 +878,12 @@ Many apps grow beyond simple forms editing a single object. For example, when cr Active Record provides model level support via the `accepts_nested_attributes_for` method: ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord has_many :addresses accepts_nested_attributes_for :addresses end -class Address < ActiveRecord::Base +class Address < ApplicationRecord belongs_to :person end ``` @@ -973,7 +971,7 @@ private You can allow users to delete associated objects by passing `allow_destroy: true` to `accepts_nested_attributes_for` ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord has_many :addresses accepts_nested_attributes_for :addresses, allow_destroy: true end @@ -1014,7 +1012,7 @@ end It is often useful to ignore sets of fields that the user has not filled in. You can control this by passing a `:reject_if` proc to `accepts_nested_attributes_for`. This proc will be called with each hash of attributes submitted by the form. If the proc returns `false` then Active Record will not build an associated object for that hash. The example below only tries to build an address if the `kind` attribute is set. ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord has_many :addresses accepts_nested_attributes_for :addresses, reject_if: lambda {|attributes| attributes['kind'].blank?} end diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md index 5700e71103..65fdd7ca0d 100644 --- a/guides/source/getting_started.md +++ b/guides/source/getting_started.md @@ -37,6 +37,7 @@ curve diving straight into Rails. There are several curated lists of online reso for learning Ruby: * [Official Ruby Programming Language website](https://www.ruby-lang.org/en/documentation/) +* [List of Free Programming Books](https://github.com/vhf/free-programming-books/blob/master/free-programming-books.md#ruby) Be aware that some resources, while still excellent, cover versions of Ruby as old as 1.6, and commonly 1.8, and will not include some syntax that you will see in day-to-day @@ -92,7 +93,7 @@ current version of Ruby installed: ```bash $ ruby -v -ruby 2.2.2p95 +ruby 2.3.1p112 ``` TIP: A number of tools exist to help you quickly install Ruby and Ruby @@ -163,7 +164,7 @@ of the files and folders that Rails created by default: | File/Folder | Purpose | | ----------- | ------- | -|app/|Contains the controllers, models, views, helpers, mailers and assets for your application. You'll focus on this folder for the remainder of this guide.| +|app/|Contains the controllers, models, views, helpers, mailers, channels, jobs and assets for your application. You'll focus on this folder for the remainder of this guide.| |bin/|Contains the rails script that starts your app and can contain other scripts you use to setup, update, deploy or run your application.| |config/|Configure your application's routes, database, and more. This is covered in more detail in [Configuring Rails Applications](configuring.html).| |config.ru|Rack configuration for Rack based servers used to start the application.| @@ -173,7 +174,7 @@ of the files and folders that Rails created by default: |log/|Application log files.| |public/|The only folder seen by the world as-is. Contains static files and compiled assets.| |Rakefile|This file locates and loads tasks that can be run from the command line. The task definitions are defined throughout the components of Rails. Rather than changing Rakefile, you should add your own tasks by adding files to the lib/tasks directory of your application.| -|README.rdoc|This is a brief instruction manual for your application. You should edit this file to tell others what your application does, how to set it up, and so on.| +|README.md|This is a brief instruction manual for your application. You should edit this file to tell others what your application does, how to set it up, and so on.| |test/|Unit tests, fixtures, and other test apparatus. These are covered in [Testing Rails Applications](testing.html).| |tmp/|Temporary files (like cache and pid files).| |vendor/|A place for all third-party code. In a typical Rails application this includes vendored gems.| @@ -207,7 +208,7 @@ commented line for new apps and you can uncomment if you need it. default to the `Gemfile` in apps generated under JRuby. You can investigate all the supported runtimes at [ExecJS](https://github.com/rails/execjs#readme). -This will fire up WEBrick, a web server distributed with Ruby by default. To see +This will fire up Puma, a web server distributed with Rails by default. To see your application in action, open a browser window and navigate to <http://localhost:3000>. You should see the Rails default information page: @@ -222,8 +223,7 @@ the server. The "Welcome aboard" page is the _smoke test_ for a new Rails application: it makes sure that you have your software configured correctly enough to serve a -page. You can also click on the _About your application's environment_ link to -see a summary of your application's environment. +page. ### Say "Hello", Rails @@ -244,11 +244,11 @@ Ruby) which is processed by the request cycle in Rails before being sent to the user. To create a new controller, you will need to run the "controller" generator and -tell it you want a controller called "welcome" with an action called "index", +tell it you want a controller called "Welcome" with an action called "index", just like this: ```bash -$ bin/rails generate controller welcome index +$ bin/rails generate controller Welcome index ``` Rails will create several files and a route for you. @@ -263,6 +263,7 @@ invoke test_unit create test/controllers/welcome_controller_test.rb invoke helper create app/helpers/welcome_helper.rb +invoke test_unit invoke assets invoke coffee create app/assets/javascripts/welcome.coffee @@ -297,33 +298,37 @@ Open the file `config/routes.rb` in your editor. Rails.application.routes.draw do get 'welcome/index' - # The priority is based upon order of creation: - # first created -> highest priority. - # See how all your routes lay out with "rake routes". - # - # You can have the root of your site routed with "root" - # root 'welcome#index' - # - # ... + # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html + + # Serve websocket cable requests in-process + # mount ActionCable.server => '/cable' +end ``` This is your application's _routing file_ which holds entries in a special [DSL (domain-specific language)](http://en.wikipedia.org/wiki/Domain-specific_language) that tells Rails how to connect incoming requests to -controllers and actions. This file contains many sample routes on commented -lines, and one of them actually shows you how to connect the root of your site -to a specific controller and action. Find the line beginning with `root` and -uncomment it. It should look something like the following: +controllers and actions. +Edit this file by adding the line of code `root 'welcome#index'`. +It should look something like the following: ```ruby -root 'welcome#index' +Rails.application.routes.draw do + get 'welcome/index' + + # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html + + # Serve websocket cable requests in-process + # mount ActionCable.server => '/cable' + root 'welcome#index' +end ``` `root 'welcome#index'` tells Rails to map requests to the root of the application to the welcome controller's index action and `get 'welcome/index'` tells Rails to map requests to <http://localhost:3000/welcome/index> to the welcome controller's index action. This was created earlier when you ran the -controller generator (`bin/rails generate controller welcome index`). +controller generator (`bin/rails generate controller Welcome index`). Launch the web server again if you stopped it to generate the controller (`bin/rails server`) and navigate to <http://localhost:3000> in your browser. You'll see the @@ -347,7 +352,7 @@ operations are referred to as _CRUD_ operations. Rails provides a `resources` method which can be used to declare a standard REST resource. You need to add the _article resource_ to the -`config/routes.rb` as follows: +`config/routes.rb` so the file will look as follows: ```ruby Rails.application.routes.draw do @@ -358,13 +363,13 @@ Rails.application.routes.draw do end ``` -If you run `bin/rake routes`, you'll see that it has defined routes for all the +If you run `bin/rails routes`, you'll see that it has defined routes for all the standard RESTful actions. The meaning of the prefix column (and other columns) will be seen later, but for now notice that Rails has inferred the singular form `article` and makes meaningful use of the distinction. ```bash -$ bin/rake routes +$ bin/rails routes Prefix Verb URI Pattern Controller#Action articles GET /articles(.:format) articles#index POST /articles(.:format) articles#create @@ -386,7 +391,7 @@ create and read. The form for doing this will look like this: It will look a little basic for now, but that's ok. We'll look at improving the styling for it afterwards. -### Laying down the ground work +### Laying down the groundwork Firstly, you need a place within the application to create a new article. A great place for that would be at `/articles/new`. With the route already @@ -402,7 +407,7 @@ a controller called `ArticlesController`. You can do this by running this command: ```bash -$ bin/rails generate controller articles +$ bin/rails generate controller Articles ``` If you open up the newly generated `app/controllers/articles_controller.rb` @@ -470,7 +475,7 @@ one here because the `ArticlesController` inherits from `ApplicationController`. The next part of the message contains a hash. The `:locale` key in this hash simply indicates which spoken language template should be retrieved. By default, this is the English - or "en" - template. The next key, `:formats` specifies the -format of template to be served in response. The default format is `:html`, and +format of the template to be served in response. The default format is `:html`, and so Rails is looking for an HTML template. The final key, `:handlers`, is telling us what _template handlers_ could be used to render our template. `:erb` is most commonly used for HTML templates, `:builder` is used for XML templates, and @@ -558,10 +563,10 @@ this: In this example, the `articles_path` helper is passed to the `:url` option. To see what Rails will do with this, we look back at the output of -`bin/rake routes`: +`bin/rails routes`: ```bash -$ bin/rake routes +$ bin/rails routes Prefix Verb URI Pattern Controller#Action articles GET /articles(.:format) articles#index POST /articles(.:format) articles#create @@ -624,7 +629,7 @@ end The `render` method here is taking a very simple hash with a key of `:plain` and value of `params[:article].inspect`. The `params` method is the object which represents the parameters (or fields) coming in from the form. The `params` -method returns an `ActiveSupport::HashWithIndifferentAccess` object, which +method returns an `ActionController::Parameters` object, which allows you to access the keys of the hash using either strings or symbols. In this situation, the only parameters that matter are the ones from the form. @@ -634,7 +639,7 @@ If you re-submit the form one more time you'll now no longer get the missing template error. Instead, you'll see something that looks like the following: ```ruby -{"title"=>"First article!", "text"=>"This is my first article."} +<ActionController::Parameters {"title"=>"First Article!", "text"=>"This is my first article."} permitted: false> ``` This action is now displaying the parameters for the article that are coming in @@ -652,7 +657,7 @@ run this command in your terminal: $ bin/rails generate model Article title:string text:text ``` -With that command we told Rails that we want a `Article` model, together +With that command we told Rails that we want an `Article` model, together with a _title_ attribute of type string, and a _text_ attribute of type text. Those attributes are automatically added to the `articles` table in the database and mapped to the `Article` model. @@ -679,13 +684,13 @@ If you look in the `db/migrate/YYYYMMDDHHMMSS_create_articles.rb` file (remember, yours will have a slightly different name), here's what you'll find: ```ruby -class CreateArticles < ActiveRecord::Migration +class CreateArticles < ActiveRecord::Migration[5.0] def change create_table :articles do |t| t.string :title t.text :text - t.timestamps null: false + t.timestamps end end end @@ -701,10 +706,10 @@ two timestamp fields to allow Rails to track article creation and update times. TIP: For more information about migrations, refer to [Rails Database Migrations] (migrations.html). -At this point, you can use a rake command to run the migration: +At this point, you can use a bin/rails command to run the migration: ```bash -$ bin/rake db:migrate +$ bin/rails db:migrate ``` Rails will execute this migration command and tell you it created the Articles @@ -721,7 +726,7 @@ NOTE. Because you're working in the development environment by default, this command will apply to the database defined in the `development` section of your `config/database.yml` file. If you would like to execute migrations in another environment, for instance in production, you must explicitly pass it when -invoking the command: `bin/rake db:migrate RAILS_ENV=production`. +invoking the command: `bin/rails db:migrate RAILS_ENV=production`. ### Saving data in the controller @@ -766,7 +771,7 @@ Why do you have to bother? The ability to grab and automatically assign all controller parameters to your model in one shot makes the programmer's job easier, but this convenience also allows malicious use. What if a request to the server was crafted to look like a new article form submit but also included -extra fields with values that violated your applications integrity? They would +extra fields with values that violated your application's integrity? They would be 'mass assigned' into your model and then into the database along with the good stuff - potentially breaking your application or worse. @@ -808,7 +813,7 @@ If you submit the form again now, Rails will complain about not finding the `show` action. That's not very useful though, so let's add the `show` action before proceeding. -As we have seen in the output of `bin/rake routes`, the route for `show` action is +As we have seen in the output of `bin/rails routes`, the route for `show` action is as follows: ``` @@ -870,7 +875,7 @@ Visit <http://localhost:3000/articles/new> and give it a try! ### Listing all articles We still need a way to list all our articles, so let's do that. -The route for this as per output of `bin/rake routes` is: +The route for this as per output of `bin/rails routes` is: ``` articles GET /articles(.:format) articles#index @@ -990,21 +995,22 @@ and restart the web server when a change is made. The model file, `app/models/article.rb` is about as simple as it can get: ```ruby -class Article < ActiveRecord::Base +class Article < ApplicationRecord end ``` There isn't much to this file - but note that the `Article` class inherits from -`ActiveRecord::Base`. Active Record supplies a great deal of functionality to -your Rails models for free, including basic database CRUD (Create, Read, Update, -Destroy) operations, data validation, as well as sophisticated search support -and the ability to relate multiple models to one another. +`ApplicationRecord`. `ApplicationRecord` inherits from `ActiveRecord::Base` +which supplies a great deal of functionality to your Rails models for free, +including basic database CRUD (Create, Read, Update, Destroy) operations, data +validation, as well as sophisticated search support and the ability to relate +multiple models to one another. Rails includes methods to help you validate the data that you send to models. Open the `app/models/article.rb` file and edit it: ```ruby -class Article < ActiveRecord::Base +class Article < ApplicationRecord validates :title, presence: true, length: { minimum: 5 } end @@ -1364,7 +1370,7 @@ Then do the same for the `app/views/articles/edit.html.erb` view: We're now ready to cover the "D" part of CRUD, deleting articles from the database. Following the REST convention, the route for -deleting articles as per output of `bin/rake routes` is: +deleting articles as per output of `bin/rails routes` is: ```ruby DELETE /articles/:id(.:format) articles#destroy @@ -1529,7 +1535,7 @@ This command will generate four files: First, take a look at `app/models/comment.rb`: ```ruby -class Comment < ActiveRecord::Base +class Comment < ApplicationRecord belongs_to :article end ``` @@ -1538,18 +1544,23 @@ This is very similar to the `Article` model that you saw earlier. The difference is the line `belongs_to :article`, which sets up an Active Record _association_. You'll learn a little about associations in the next section of this guide. +The (`:references`) keyword used in the bash command is a special data type for models. +It creates a new column on your database table with the provided model name appended with an `_id` +that can hold integer values. You can get a better understanding after analyzing the +`db/schema.rb` file below. + In addition to the model, Rails has also made a migration to create the corresponding database table: ```ruby -class CreateComments < ActiveRecord::Migration +class CreateComments < ActiveRecord::Migration[5.0] def change create_table :comments do |t| t.string :commenter t.text :body - t.references :article, index: true, foreign_key: true + t.references :article, foreign_key: true - t.timestamps null: false + t.timestamps end end end @@ -1560,7 +1571,7 @@ for it, and a foreign key constraint that points to the `id` column of the `arti table. Go ahead and run the migration: ```bash -$ bin/rake db:migrate +$ bin/rails db:migrate ``` Rails is smart enough to only execute the migrations that have not already been @@ -1587,7 +1598,7 @@ association. You've already seen the line of code inside the `Comment` model (app/models/comment.rb) that makes each comment belong to an Article: ```ruby -class Comment < ActiveRecord::Base +class Comment < ApplicationRecord belongs_to :article end ``` @@ -1596,7 +1607,7 @@ You'll need to edit `app/models/article.rb` to add the other side of the association: ```ruby -class Article < ActiveRecord::Base +class Article < ApplicationRecord has_many :comments validates :title, presence: true, length: { minimum: 5 } @@ -1962,7 +1973,7 @@ you to use the `dependent` option of an association to achieve this. Modify the Article model, `app/models/article.rb`, as follows: ```ruby -class Article < ActiveRecord::Base +class Article < ApplicationRecord has_many :comments, dependent: :destroy validates :title, presence: true, length: { minimum: 5 } diff --git a/guides/source/i18n.md b/guides/source/i18n.md index 87d2fafaf3..0edfa072f8 100644 --- a/guides/source/i18n.md +++ b/guides/source/i18n.md @@ -25,7 +25,7 @@ After reading this guide, you will know: * How I18n works in Ruby on Rails * How to correctly use I18n into a RESTful application in various ways -* How to use I18n to translate ActiveRecord errors or ActionMailer E-mail subjects +* How to use I18n to translate Active Record errors or Action Mailer E-mail subjects * Some other tools to go further with the translation process of your application -------------------------------------------------------------------------------- @@ -470,7 +470,7 @@ OK! Now let's add a timestamp to the view, so we can demo the **date/time locali ```erb # app/views/home/index.html.erb <h1><%=t :hello_world %></h1> -<p><%= flash[:notice] %></p +<p><%= flash[:notice] %></p> <p><%= l Time.now, format: :short %></p> ``` @@ -805,6 +805,8 @@ en: Then `User.human_attribute_name("gender.female")` will return "Female". +NOTE: If you are using a class which includes `ActiveModel` and does not inherit from `ActiveRecord::Base`, replace `activerecord` with `activemodel` in the above key paths. + #### Error Message Scopes Active Record validation error messages can also be translated easily. Active Record gives you a couple of namespaces where you can place your message translations in order to provide different messages and translation for certain models, attributes, and/or validations. It also transparently takes single table inheritance into account. @@ -814,7 +816,7 @@ This gives you quite powerful means to flexibly adjust your messages to your app Consider a User model with a validation for the name attribute like this: ```ruby -class User < ActiveRecord::Base +class User < ApplicationRecord validates :name, presence: true end ``` @@ -1111,7 +1113,7 @@ Conclusion At this point you should have a good overview about how I18n support in Ruby on Rails works and are ready to start translating your project. -If you find anything missing or wrong in this guide, please file a ticket on our [issue tracker](http://i18n.lighthouseapp.com/projects/14948-rails-i18n/overview). If you want to discuss certain portions or have questions, please sign up to our [mailing list](http://groups.google.com/group/rails-i18n). +If you want to discuss certain portions or have questions, please sign up to the [rails-i18n mailing list](http://groups.google.com/group/rails-i18n). Contributing to Rails I18n @@ -1128,10 +1130,8 @@ Resources --------- * [Google group: rails-i18n](http://groups.google.com/group/rails-i18n) - The project's mailing list. -* [GitHub: rails-i18n](https://github.com/svenfuchs/rails-i18n/tree/master) - Code repository for the rails-i18n project. Most importantly you can find lots of [example translations](https://github.com/svenfuchs/rails-i18n/tree/master/rails/locale) for Rails that should work for your application in most cases. -* [GitHub: i18n](https://github.com/svenfuchs/i18n/tree/master) - Code repository for the i18n gem. -* [Lighthouse: rails-i18n](http://i18n.lighthouseapp.com/projects/14948-rails-i18n/overview) - Issue tracker for the rails-i18n project. -* [Lighthouse: i18n](http://i18n.lighthouseapp.com/projects/14947-ruby-i18n/overview) - Issue tracker for the i18n gem. +* [GitHub: rails-i18n](https://github.com/svenfuchs/rails-i18n) - Code repository and issue tracker for the rails-i18n project. Most importantly you can find lots of [example translations](https://github.com/svenfuchs/rails-i18n/tree/master/rails/locale) for Rails that should work for your application in most cases. +* [GitHub: i18n](https://github.com/svenfuchs/i18n) - Code repository and issue tracker for the i18n gem. Authors diff --git a/guides/source/initialization.md b/guides/source/initialization.md index ebe1cb206a..89e5346d86 100644 --- a/guides/source/initialization.md +++ b/guides/source/initialization.md @@ -3,8 +3,8 @@ The Rails Initialization Process ================================ -This guide explains the internals of the initialization process in Rails -as of Rails 4. It is an extremely in-depth guide and recommended for advanced Rails developers. +This guide explains the internals of the initialization process in Rails. +It is an extremely in-depth guide and recommended for advanced Rails developers. After reading this guide, you will know: @@ -139,7 +139,8 @@ aliases = { "c" => "console", "s" => "server", "db" => "dbconsole", - "r" => "runner" + "r" => "runner", + "t" => "test" } command = ARGV.shift @@ -156,21 +157,22 @@ snippet. If we had used `s` rather than `server`, Rails would have used the `aliases` defined here to find the matching command. -### `rails/commands/command_tasks.rb` +### `rails/commands/commands_tasks.rb` -When one types an incorrect rails command, the `run_command` is responsible for -throwing an error message. If the command is valid, a method of the same name -is called. +When one types a valid Rails command, `run_command!` a method of the same name +is called. If Rails doesn't recognize the command, it tries to run a Rake task +of the same name. ```ruby COMMAND_WHITELIST = %w(plugin generate destroy console server dbconsole application runner new version help) def run_command!(command) command = parse_command(command) + if COMMAND_WHITELIST.include?(command) send(command) else - write_error_message(command) + run_rake_task(command) end end ``` @@ -354,8 +356,6 @@ private def print_boot_information ... puts "=> Run `rails server -h` for more startup options" - ... - puts "=> Ctrl-C to shutdown server" unless options[:daemonize] end def create_tmp_directories @@ -528,16 +528,17 @@ This file is responsible for requiring all the individual frameworks of Rails: require "rails" %w( - active_record - action_controller - action_view - action_mailer - active_job - rails/test_unit - sprockets -).each do |framework| + active_record/railtie + action_controller/railtie + action_view/railtie + action_mailer/railtie + active_job/railtie + action_cable/engine + rails/test_unit/railtie + sprockets/railtie +).each do |railtie| begin - require "#{framework}/railtie" + require "#{railtie}" rescue LoadError end end diff --git a/guides/source/layout.html.erb b/guides/source/layout.html.erb index 1005057ca9..6db76b528e 100644 --- a/guides/source/layout.html.erb +++ b/guides/source/layout.html.erb @@ -29,14 +29,11 @@ More Ruby on Rails </span> <ul class="more-info-links s-hidden"> - <li class="more-info"><a href="http://rubyonrails.org/">Overview</a></li> - <li class="more-info"><a href="http://rubyonrails.org/download">Download</a></li> - <li class="more-info"><a href="http://rubyonrails.org/deploy">Deploy</a></li> - <li class="more-info"><a href="https://github.com/rails/rails">Code</a></li> - <li class="more-info"><a href="http://rubyonrails.org/screencasts">Screencasts</a></li> - <li class="more-info"><a href="http://rubyonrails.org/documentation">Documentation</a></li> - <li class="more-info"><a href="http://rubyonrails.org/community">Community</a></li> <li class="more-info"><a href="http://weblog.rubyonrails.org/">Blog</a></li> + <li class="more-info"><a href="http://guides.rubyonrails.org/">Guides</a></li> + <li class="more-info"><a href="http://api.rubyonrails.org/">API</a></li> + <li class="more-info"><a href="http://stackoverflow.com/questions/tagged/ruby-on-rails">Ask for help</a></li> + <li class="more-info"><a href="https://github.com/rails/rails">Contribute on GitHub</a></li> </ul> </div> </div> diff --git a/guides/source/layouts_and_rendering.md b/guides/source/layouts_and_rendering.md index 71cc030f6a..2722789c49 100644 --- a/guides/source/layouts_and_rendering.md +++ b/guides/source/layouts_and_rendering.md @@ -149,23 +149,22 @@ render template: "products/show" #### Rendering an Arbitrary File -The `render` method can also use a view that's entirely outside of your application (perhaps you're sharing views between two Rails applications): - -```ruby -render "/u/apps/warehouse_app/current/app/views/products/show" -``` - -Rails determines that this is a file render because of the leading slash character. To be explicit, you can use the `:file` option (which was required on Rails 2.2 and earlier): +The `render` method can also use a view that's entirely outside of your application: ```ruby render file: "/u/apps/warehouse_app/current/app/views/products/show" ``` -The `:file` option takes an absolute file-system path. Of course, you need to have rights to the view that you're using to render the content. +The `:file` option takes an absolute file-system path. Of course, you need to have rights +to the view that you're using to render the content. + +NOTE: Using the `:file` option in combination with users input can lead to security problems +since an attacker could use this action to access security sensitive files in your file system. NOTE: By default, the file is rendered using the current layout. -TIP: If you're running Rails on Microsoft Windows, you should use the `:file` option to render a file, because Windows filenames do not have the same format as Unix filenames. +TIP: If you're running Rails on Microsoft Windows, you should use the `:file` option to +render a file, because Windows filenames do not have the same format as Unix filenames. #### Wrapping it up @@ -238,7 +237,7 @@ TIP: This is useful when you're rendering a small snippet of HTML code. However, you might want to consider moving it to a template file if the markup is complex. -NOTE: This option will escape HTML entities if the string is not HTML safe. +NOTE: When using `html:` option, HTML entities will be escaped if the string is not marked as HTML safe by using `html_safe` method. #### Rendering JSON @@ -555,7 +554,7 @@ class Admin::ProductsController < AdminController end ``` -The lookup order for a `admin/products#index` action will be: +The lookup order for an `admin/products#index` action will be: * `app/views/admin/products/` * `app/views/admin/` @@ -622,10 +621,13 @@ Another way to handle returning responses to an HTTP request is with `redirect_t redirect_to photos_url ``` -You can use `redirect_to` with any arguments that you could use with `link_to` or `url_for`. There's also a special redirect that sends the user back to the page they just came from: +You can use `redirect_back` to return the user to the page they just came from. +This location is pulled from the `HTTP_REFERER` header which is not guaranteed +to be set by the browser, so you must provide the `fallback_location` +to use in this case. ```ruby -redirect_to :back +redirect_back(fallback_location: root_path) ``` #### Getting a Different Redirect Status Code @@ -697,7 +699,7 @@ This would detect that there are no books with the specified ID, populate the `@ ### Using `head` To Build Header-Only Responses -The `head` method can be used to send responses with only headers to the browser. It provides a more obvious alternative to calling `render :nothing`. The `head` method accepts a number or symbol (see [reference table](#the-status-option)) representing a HTTP status code. The options argument is interpreted as a hash of header names and values. For example, you can return only an error header: +The `head` method can be used to send responses with only headers to the browser. The `head` method accepts a number or symbol (see [reference table](#the-status-option)) representing an HTTP status code. The options argument is interpreted as a hash of header names and values. For example, you can return only an error header: ```ruby head :bad_request @@ -1154,14 +1156,12 @@ To pass a local variable to a partial in only specific cases use the `local_assi * `_articles.html.erb` ```erb - <%= content_tag_for :article, article do |article| %> - <h2><%= article.title %></h2> + <h2><%= article.title %></h2> - <% if local_assigns[:full] %> - <%= simple_format article.body %> - <% else %> - <%= truncate article.body %> - <% end %> + <% if local_assigns[:full] %> + <%= simple_format article.body %> + <% else %> + <%= truncate article.body %> <% end %> ``` diff --git a/guides/source/maintenance_policy.md b/guides/source/maintenance_policy.md index 50308f505a..f99b6ebd31 100644 --- a/guides/source/maintenance_policy.md +++ b/guides/source/maintenance_policy.md @@ -44,7 +44,7 @@ from. In special situations, where someone from the Core Team agrees to support more series, they are included in the list of supported series. -**Currently included series:** `4.2.Z`, `4.1.Z` (Supported by Rafael França). +**Currently included series:** `5.0.Z`. Security Issues --------------- @@ -59,7 +59,7 @@ be built from 1.2.2, and then added to the end of 1-2-stable. This means that security releases are easy to upgrade to if you're running the latest version of Rails. -**Currently included series:** `4.2.Z`, `4.1.Z`. +**Currently included series:** `5.0.Z`, `4.2.Z`. Severe Security Issues ---------------------- @@ -68,7 +68,7 @@ For severe security issues we will provide new versions as above, and also the last major release series will receive patches and new versions. The classification of the security issue is judged by the core team. -**Currently included series:** `4.2.Z`, `4.1.Z`, `3.2.Z`. +**Currently included series:** `5.0.Z`, `4.2.Z`. Unsupported Release Series -------------------------- diff --git a/guides/source/nested_model_forms.md b/guides/source/nested_model_forms.md index 121cf2b185..71efa4b0d0 100644 --- a/guides/source/nested_model_forms.md +++ b/guides/source/nested_model_forms.md @@ -32,7 +32,7 @@ For an ActiveRecord::Base model and association this writer method is commonly d #### has_one ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord has_one :address accepts_nested_attributes_for :address end @@ -41,7 +41,7 @@ end #### belongs_to ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord belongs_to :firm accepts_nested_attributes_for :firm end @@ -50,7 +50,7 @@ end #### has_many / has_and_belongs_to_many ```ruby -class Person < ActiveRecord::Base +class Person < ApplicationRecord has_many :projects accepts_nested_attributes_for :projects end diff --git a/guides/source/plugins.md b/guides/source/plugins.md index b94c26a1ae..8f055f8fe3 100644 --- a/guides/source/plugins.md +++ b/guides/source/plugins.md @@ -17,7 +17,7 @@ After reading this guide, you will know: This guide describes how to build a test-driven plugin that will: * Extend core Ruby classes like Hash and String. -* Add methods to `ActiveRecord::Base` in the tradition of the `acts_as` plugins. +* Add methods to `ApplicationRecord` in the tradition of the `acts_as` plugins. * Give you information about where to put generators in your plugin. For the purpose of this guide pretend for a moment that you are an avid bird watcher. @@ -37,7 +37,7 @@ different rails applications using RubyGems and Bundler if desired. Rails ships with a `rails plugin new` command which creates a skeleton for developing any kind of Rails extension with the ability -to run integration tests using a dummy Rails application. Create your +to run integration tests using a dummy Rails application. Create your plugin with the command: ```bash @@ -54,7 +54,7 @@ Testing Your Newly Generated Plugin ----------------------------------- You can navigate to the directory that contains the plugin, run the `bundle install` command - and run the one generated test using the `rake` command. + and run the one generated test using the `bin/test` command. You should see: @@ -83,13 +83,23 @@ class CoreExtTest < ActiveSupport::TestCase end ``` -Run `rake` to run the test. This test should fail because we haven't implemented the `to_squawk` method: +Run `bin/test` to run the test. This test should fail because we haven't implemented the `to_squawk` method: ```bash - 1) Error: - CoreExtTest#test_to_squawk_prepends_the_word_squawk: - NoMethodError: undefined method `to_squawk' for "Hello World":String - /path/to/yaffle/test/core_ext_test.rb:5:in `test_to_squawk_prepends_the_word_squawk' +E + +Error: +CoreExtTest#test_to_squawk_prepends_the_word_squawk: +NoMethodError: undefined method `to_squawk' for "Hello World":String + + +bin/test /path/to/yaffle/test/core_ext_test.rb:4 + +. + +Finished in 0.003358s, 595.6483 runs/s, 297.8242 assertions/s. + +2 runs, 1 assertions, 0 failures, 1 errors, 0 skips ``` Great - now you are ready to start development. @@ -117,7 +127,7 @@ String.class_eval do end ``` -To test that your method does what it says it does, run the unit tests with `rake` from your plugin directory. +To test that your method does what it says it does, run the unit tests with `bin/test` from your plugin directory. ```bash 2 runs, 2 assertions, 0 failures, 0 errors, 0 skips @@ -182,7 +192,6 @@ To start out, write a failing test that shows the behavior you'd like: require 'test_helper' class ActsAsYaffleTest < ActiveSupport::TestCase - def test_a_hickwalls_yaffle_text_field_should_be_last_squawk assert_equal "last_squawk", Hickwall.yaffle_text_field end @@ -190,24 +199,37 @@ class ActsAsYaffleTest < ActiveSupport::TestCase def test_a_wickwalls_yaffle_text_field_should_be_last_tweet assert_equal "last_tweet", Wickwall.yaffle_text_field end - end ``` -When you run `rake`, you should see the following: +When you run `bin/test`, you should see the following: ``` - 1) Error: - ActsAsYaffleTest#test_a_hickwalls_yaffle_text_field_should_be_last_squawk: - NameError: uninitialized constant ActsAsYaffleTest::Hickwall - /path/to/yaffle/test/acts_as_yaffle_test.rb:6:in `test_a_hickwalls_yaffle_text_field_should_be_last_squawk' +# Running: + +..E + +Error: +ActsAsYaffleTest#test_a_wickwalls_yaffle_text_field_should_be_last_tweet: +NameError: uninitialized constant ActsAsYaffleTest::Wickwall - 2) Error: - ActsAsYaffleTest#test_a_wickwalls_yaffle_text_field_should_be_last_tweet: - NameError: uninitialized constant ActsAsYaffleTest::Wickwall - /path/to/yaffle/test/acts_as_yaffle_test.rb:10:in `test_a_wickwalls_yaffle_text_field_should_be_last_tweet' - 4 runs, 2 assertions, 0 failures, 2 errors, 0 skips +bin/test /path/to/yaffle/test/acts_as_yaffle_test.rb:8 + +E + +Error: +ActsAsYaffleTest#test_a_hickwalls_yaffle_text_field_should_be_last_squawk: +NameError: uninitialized constant ActsAsYaffleTest::Hickwall + + +bin/test /path/to/yaffle/test/acts_as_yaffle_test.rb:4 + + + +Finished in 0.004812s, 831.2949 runs/s, 415.6475 assertions/s. + +4 runs, 2 assertions, 0 failures, 2 errors, 0 skips ``` This tells us that we don't have the necessary models (Hickwall and Wickwall) that we are trying to test. @@ -225,7 +247,7 @@ and migrating the database. First, run: ```bash $ cd test/dummy -$ bin/rake db:migrate +$ bin/rails db:migrate ``` While you are here, change the Hickwall and Wickwall models so that they know that they are supposed to act @@ -234,22 +256,22 @@ like yaffles. ```ruby # test/dummy/app/models/hickwall.rb -class Hickwall < ActiveRecord::Base +class Hickwall < ApplicationRecord acts_as_yaffle end # test/dummy/app/models/wickwall.rb -class Wickwall < ActiveRecord::Base +class Wickwall < ApplicationRecord acts_as_yaffle yaffle_text_field: :last_tweet end - ``` We will also add code to define the `acts_as_yaffle` method. ```ruby # yaffle/lib/yaffle/acts_as_yaffle.rb + module Yaffle module ActsAsYaffle extend ActiveSupport::Concern @@ -265,26 +287,43 @@ module Yaffle end end -ActiveRecord::Base.include(Yaffle::ActsAsYaffle) +# test/dummy/app/models/application_record.rb + +class ApplicationRecord < ActiveRecord::Base + include Yaffle::ActsAsYaffle + + self.abstract_class = true +end ``` -You can then return to the root directory (`cd ../..`) of your plugin and rerun the tests using `rake`. +You can then return to the root directory (`cd ../..`) of your plugin and rerun the tests using `bin/test`. ``` - 1) Error: - ActsAsYaffleTest#test_a_hickwalls_yaffle_text_field_should_be_last_squawk: - NoMethodError: undefined method `yaffle_text_field' for #<Class:0x007fd105e3b218> - activerecord (4.1.5) lib/active_record/dynamic_matchers.rb:26:in `method_missing' - /path/to/yaffle/test/acts_as_yaffle_test.rb:6:in `test_a_hickwalls_yaffle_text_field_should_be_last_squawk' +# Running: + +.E + +Error: +ActsAsYaffleTest#test_a_hickwalls_yaffle_text_field_should_be_last_squawk: +NoMethodError: undefined method `yaffle_text_field' for #<Class:0x0055974ebbe9d8> + + +bin/test /path/to/yaffle/test/acts_as_yaffle_test.rb:4 + +E + +Error: +ActsAsYaffleTest#test_a_wickwalls_yaffle_text_field_should_be_last_tweet: +NoMethodError: undefined method `yaffle_text_field' for #<Class:0x0055974eb8cfc8> + - 2) Error: - ActsAsYaffleTest#test_a_wickwalls_yaffle_text_field_should_be_last_tweet: - NoMethodError: undefined method `yaffle_text_field' for #<Class:0x007fd105e409c0> - activerecord (4.1.5) lib/active_record/dynamic_matchers.rb:26:in `method_missing' - /path/to/yaffle/test/acts_as_yaffle_test.rb:10:in `test_a_wickwalls_yaffle_text_field_should_be_last_tweet' +bin/test /path/to/yaffle/test/acts_as_yaffle_test.rb:8 - 4 runs, 2 assertions, 0 failures, 2 errors, 0 skips +. +Finished in 0.008263s, 484.0999 runs/s, 242.0500 assertions/s. + +4 runs, 2 assertions, 0 failures, 2 errors, 0 skips ``` Getting closer... Now we will implement the code of the `acts_as_yaffle` method to make the tests pass. @@ -294,7 +333,7 @@ Getting closer... Now we will implement the code of the `acts_as_yaffle` method module Yaffle module ActsAsYaffle - extend ActiveSupport::Concern + extend ActiveSupport::Concern included do end @@ -308,10 +347,16 @@ module Yaffle end end -ActiveRecord::Base.include(Yaffle::ActsAsYaffle) +# test/dummy/app/models/application_record.rb + +class ApplicationRecord < ActiveRecord::Base + include Yaffle::ActsAsYaffle + + self.abstract_class = true +end ``` -When you run `rake`, you should see the tests all pass: +When you run `bin/test`, you should see the tests all pass: ```bash 4 runs, 4 assertions, 0 failures, 0 errors, 0 skips @@ -329,7 +374,6 @@ To start out, write a failing test that shows the behavior you'd like: require 'test_helper' class ActsAsYaffleTest < ActiveSupport::TestCase - def test_a_hickwalls_yaffle_text_field_should_be_last_squawk assert_equal "last_squawk", Hickwall.yaffle_text_field end @@ -382,10 +426,16 @@ module Yaffle end end -ActiveRecord::Base.include(Yaffle::ActsAsYaffle) +# test/dummy/app/models/application_record.rb + +class ApplicationRecord < ActiveRecord::Base + include Yaffle::ActsAsYaffle + + self.abstract_class = true +end ``` -Run `rake` one final time and you should see: +Run `bin/test` one final time and you should see: ``` 6 runs, 6 assertions, 0 failures, 0 errors, 0 skips diff --git a/guides/source/rails_application_templates.md b/guides/source/rails_application_templates.md index edd54826cf..3b773d84f8 100644 --- a/guides/source/rails_application_templates.md +++ b/guides/source/rails_application_templates.md @@ -22,11 +22,11 @@ $ rails new blog -m ~/template.rb $ rails new blog -m http://example.com/template.rb ``` -You can use the rake task `rails:template` to apply templates to an existing Rails application. The location of the template needs to be passed in to an environment variable named LOCATION. Again, this can either be path to a file or a URL. +You can use the task `app:template` to apply templates to an existing Rails application. The location of the template needs to be passed in to an environment variable named LOCATION. Again, this can either be path to a file or a URL. ```bash -$ bin/rake rails:template LOCATION=~/template.rb -$ bin/rake rails:template LOCATION=http://example.com/template.rb +$ bin/rails app:template LOCATION=~/template.rb +$ bin/rails app:template LOCATION=http://example.com/template.rb ``` Template API @@ -38,7 +38,7 @@ The Rails templates API is easy to understand. Here's an example of a typical Ra # template.rb generate(:scaffold, "person name:string") route "root to: 'people#index'" -rake("db:migrate") +rails_command("db:migrate") after_bundle do git :init @@ -175,18 +175,24 @@ Executes an arbitrary command. Just like the backticks. Let's say you want to re run "rm README.rdoc" ``` -### rake(command, options = {}) +### rails_command(command, options = {}) -Runs the supplied rake tasks in the Rails application. Let's say you want to migrate the database: +Runs the supplied task in the Rails application. Let's say you want to migrate the database: ```ruby -rake "db:migrate" +rails_command "db:migrate" ``` -You can also run rake tasks with a different Rails environment: +You can also run tasks with a different Rails environment: ```ruby -rake "db:migrate", env: 'production' +rails_command "db:migrate", env: 'production' +``` + +You can also run tasks as a super-user: + +```ruby +rails_command "log:clear", sudo: true ``` ### route(routing_code) @@ -226,7 +232,7 @@ CODE These methods let you ask questions from templates and decide the flow based on the user's answer. Let's say you want to Freeze Rails only if the user wants to: ```ruby -rake("rails:freeze:gems") if yes?("Freeze rails gems?") +rails_command("rails:freeze:gems") if yes?("Freeze rails gems?") # no?(question) acts just the opposite. ``` diff --git a/guides/source/rails_on_rack.md b/guides/source/rails_on_rack.md index 273fbc08e2..d67702f52e 100644 --- a/guides/source/rails_on_rack.md +++ b/guides/source/rails_on_rack.md @@ -93,10 +93,10 @@ NOTE: `ActionDispatch::MiddlewareStack` is Rails equivalent of `Rack::Builder`, ### Inspecting Middleware Stack -Rails has a handy rake task for inspecting the middleware stack in use: +Rails has a handy task for inspecting the middleware stack in use: ```bash -$ bin/rake middleware +$ bin/rails middleware ``` For a freshly generated Rails application, this might produce something like: @@ -104,7 +104,7 @@ For a freshly generated Rails application, this might produce something like: ```ruby use Rack::Sendfile use ActionDispatch::Static -use Rack::Lock +use ActionDispatch::Executor use #<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x000000029a0838> use Rack::Runtime use Rack::MethodOverride @@ -171,14 +171,14 @@ Add the following lines to your application configuration: ```ruby # config/application.rb -config.middleware.delete Rack::Lock +config.middleware.delete Rack::Runtime ``` -And now if you inspect the middleware stack, you'll find that `Rack::Lock` is +And now if you inspect the middleware stack, you'll find that `Rack::Runtime` is not a part of it. ```bash -$ bin/rake middleware +$ bin/rails middleware (in /Users/lifo/Rails/blog) use ActionDispatch::Static use #<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x00000001c304c8> @@ -219,6 +219,10 @@ Much of Action Controller's functionality is implemented as Middlewares. The fol * Sets `env["rack.multithread"]` flag to `false` and wraps the application within a Mutex. +**`ActionDispatch::Executor`** + +* Used for thread safe code reloading during development. + **`ActiveSupport::Cache::Strategy::LocalCache::Middleware`** * Used for memory caching. This cache is not thread safe. diff --git a/guides/source/routing.md b/guides/source/routing.md index 245689932b..81321c7405 100644 --- a/guides/source/routing.md +++ b/guides/source/routing.md @@ -142,10 +142,10 @@ Sometimes, you have a resource that clients always look up without referencing a get 'profile', to: 'users#show' ``` -Passing a `String` to `get` will expect a `controller#action` format, while passing a `Symbol` will map directly to an action: +Passing a `String` to `get` will expect a `controller#action` format, while passing a `Symbol` will map directly to an action but you must also specify the `controller:` to use: ```ruby -get 'profile', to: :show +get 'profile', to: :show, controller: 'users' ``` This resourceful route: @@ -252,11 +252,11 @@ TIP: _If you need to use a different controller namespace inside a `namespace` b It's common to have resources that are logically children of other resources. For example, suppose your application includes these models: ```ruby -class Magazine < ActiveRecord::Base +class Magazine < ApplicationRecord has_many :ads end -class Ad < ActiveRecord::Base +class Ad < ApplicationRecord belongs_to :magazine end ``` @@ -392,7 +392,7 @@ The comments resource here will have the following routes generated for it: ### Routing concerns -Routing Concerns allows you to declare common routes that can be reused inside other resources and routes. To define a concern: +Routing concerns allow you to declare common routes that can be reused inside other resources and routes. To define a concern: ```ruby concern :commentable do @@ -706,6 +706,8 @@ end NOTE: Request constraints work by calling a method on the [Request object](action_controller_overview.html#the-request-object) with the same name as the hash key and then compare the return value with the hash value. Therefore, constraint values should match the corresponding Request object method return type. For example: `constraints: { subdomain: 'api' }` will match an `api` subdomain as expected, however using a symbol `constraints: { subdomain: :api }` will not, because `request.subdomain` returns `'api'` as a String. +NOTE: There is an exception for the `format` constraint: while it's a method on the Request object, it's also an implicit optional parameter on every path. Segment constraints take precedence and the `format` constraint is only applied as such when enforced through a hash. For example, `get 'foo', constraints: { format: 'json' }` will match `GET /foo` because the format is optional by default. However, you can [use a lambda](#advanced-constraints) like in `get 'foo', constraints: lambda { |req| req.format == :json }` and the route will only match explicit JSON requests. + ### Advanced Constraints If you have a more advanced constraint, you can provide an object that responds to `matches?` that Rails should use. Let's say you wanted to route all users on a blacklist to the `BlacklistController`. You could do: @@ -810,10 +812,10 @@ In all of these cases, if you don't provide the leading host (`http://www.exampl Instead of a String like `'articles#index'`, which corresponds to the `index` action in the `ArticlesController`, you can specify any [Rack application](rails_on_rack.html) as the endpoint for a matcher: ```ruby -match '/application.js', to: Sprockets, via: :all +match '/application.js', to: MyRackApp, via: :all ``` -As long as `Sprockets` responds to `call` and returns a `[status, headers, body]`, the router won't know the difference between the Rack application and an action. This is an appropriate use of `via: :all`, as you will want to allow your Rack application to handle all verbs as it considers appropriate. +As long as `MyRackApp` responds to `call` and returns a `[status, headers, body]`, the router won't know the difference between the Rack application and an action. This is an appropriate use of `via: :all`, as you will want to allow your Rack application to handle all verbs as it considers appropriate. NOTE: For the curious, `'articles#index'` actually expands out to `ArticlesController.action(:index)`, which returns a valid Rack application. @@ -1099,7 +1101,7 @@ You can override `ActiveRecord::Base#to_param` of a related model to construct a URL: ```ruby -class Video < ActiveRecord::Base +class Video < ApplicationRecord def to_param identifier end @@ -1116,7 +1118,7 @@ Rails offers facilities for inspecting and testing your routes. ### Listing Existing Routes -To get a complete list of the available routes in your application, visit `http://localhost:3000/rails/info/routes` in your browser while your server is running in the **development** environment. You can also execute the `rake routes` command in your terminal to produce the same output. +To get a complete list of the available routes in your application, visit `http://localhost:3000/rails/info/routes` in your browser while your server is running in the **development** environment. You can also execute the `rails routes` command in your terminal to produce the same output. Both methods will list all of your routes, in the same order that they appear in `config/routes.rb`. For each route, you'll see: @@ -1125,7 +1127,7 @@ Both methods will list all of your routes, in the same order that they appear in * The URL pattern to match * The routing parameters for the route -For example, here's a small section of the `rake routes` output for a RESTful route: +For example, here's a small section of the `rails routes` output for a RESTful route: ``` users GET /users(.:format) users#index @@ -1134,13 +1136,24 @@ For example, here's a small section of the `rake routes` output for a RESTful ro edit_user GET /users/:id/edit(.:format) users#edit ``` -You may restrict the listing to the routes that map to a particular controller setting the `CONTROLLER` environment variable: +You can search through your routes with the grep option: -g. This outputs any routes that partially match the URL helper method name, the HTTP verb, or the URL path. + +``` +$ bin/rails routes -g new_comment +$ bin/rails routes -g POST +$ bin/rails routes -g admin +``` + +If you only want to see the routes that map to a specific controller, there's the -c option. -```bash -$ CONTROLLER=users bin/rake routes +``` +$ bin/rails routes -c users +$ bin/rails routes -c admin/users +$ bin/rails routes -c Comments +$ bin/rails routes -c Articles::CommentsController ``` -TIP: You'll find that the output from `rake routes` is much more readable if you widen your terminal window until the output lines don't wrap. +TIP: You'll find that the output from `rails routes` is much more readable if you widen your terminal window until the output lines don't wrap. ### Testing Routes diff --git a/guides/source/security.md b/guides/source/security.md index df8c24864e..ca985134e6 100644 --- a/guides/source/security.md +++ b/guides/source/security.md @@ -23,7 +23,7 @@ Web application frameworks are made to help developers build web applications. S In general there is no such thing as plug-n-play security. Security depends on the people using the framework, and sometimes on the development method. And it depends on all layers of a web application environment: The back-end storage, the web server and the web application itself (and possibly other layers or applications). -The Gartner Group however estimates that 75% of attacks are at the web application layer, and found out "that out of 300 audited sites, 97% are vulnerable to attack". This is because web applications are relatively easy to attack, as they are simple to understand and manipulate, even by the lay person. +The Gartner Group, however, estimates that 75% of attacks are at the web application layer, and found out "that out of 300 audited sites, 97% are vulnerable to attack". This is because web applications are relatively easy to attack, as they are simple to understand and manipulate, even by the lay person. The threats against web applications include user account hijacking, bypass of access control, reading or modifying sensitive data, or presenting fraudulent content. Or an attacker might be able to install a Trojan horse program or unsolicited e-mail sending software, aim at financial enrichment or cause brand name damage by modifying company resources. In order to prevent attacks, minimize their impact and remove points of attack, first of all, you have to fully understand the attack methods in order to find the correct countermeasures. That is what this guide aims at. @@ -41,28 +41,28 @@ NOTE: _HTTP is a stateless protocol. Sessions make it stateful._ Most applications need to keep track of certain state of a particular user. This could be the contents of a shopping basket or the user id of the currently logged in user. Without the idea of sessions, the user would have to identify, and probably authenticate, on every request. Rails will create a new session automatically if a new user accesses the application. It will load an existing session if the user has already used the application. -A session usually consists of a hash of values and a session id, usually a 32-character string, to identify the hash. Every cookie sent to the client's browser includes the session id. And the other way round: the browser will send it to the server on every request from the client. In Rails you can save and retrieve values using the session method: +A session usually consists of a hash of values and a session ID, usually a 32-character string, to identify the hash. Every cookie sent to the client's browser includes the session ID. And the other way round: the browser will send it to the server on every request from the client. In Rails you can save and retrieve values using the session method: ```ruby session[:user_id] = @current_user.id User.find(session[:user_id]) ``` -### Session id +### Session ID -NOTE: _The session id is a 32 byte long MD5 hash value._ +NOTE: _The session ID is a 32-character random hex string._ -A session id consists of the hash value of a random string. The random string is the current time, a random number between 0 and 1, the process id number of the Ruby interpreter (also basically a random number) and a constant string. Currently it is not feasible to brute-force Rails' session ids. To date MD5 is uncompromised, but there have been collisions, so it is theoretically possible to create another input text with the same hash value. But this has had no security impact to date. +The session ID is generated using `SecureRandom.hex` which generates a random hex string using platform specific methods (such as OpenSSL, /dev/urandom or Win32) for generating cryptographically secure random numbers. Currently it is not feasible to brute-force Rails' session IDs. ### Session Hijacking -WARNING: _Stealing a user's session id lets an attacker use the web application in the victim's name._ +WARNING: _Stealing a user's session ID lets an attacker use the web application in the victim's name._ -Many web applications have an authentication system: a user provides a user name and password, the web application checks them and stores the corresponding user id in the session hash. From now on, the session is valid. On every request the application will load the user, identified by the user id in the session, without the need for new authentication. The session id in the cookie identifies the session. +Many web applications have an authentication system: a user provides a user name and password, the web application checks them and stores the corresponding user id in the session hash. From now on, the session is valid. On every request the application will load the user, identified by the user id in the session, without the need for new authentication. The session ID in the cookie identifies the session. Hence, the cookie serves as temporary authentication for the web application. Anyone who seizes a cookie from someone else, may use the web application as this user - with possibly severe consequences. Here are some ways to hijack a session, and their countermeasures: -* Sniff the cookie in an insecure network. A wireless LAN can be an example of such a network. In an unencrypted wireless LAN it is especially easy to listen to the traffic of all connected clients. For the web application builder this means to _provide a secure connection over SSL_. In Rails 3.1 and later, this could be accomplished by always forcing SSL connection in your application config file: +* Sniff the cookie in an insecure network. A wireless LAN can be an example of such a network. In an unencrypted wireless LAN, it is especially easy to listen to the traffic of all connected clients. For the web application builder this means to _provide a secure connection over SSL_. In Rails 3.1 and later, this could be accomplished by always forcing SSL connection in your application config file: ```ruby config.force_ssl = true @@ -89,7 +89,7 @@ This will also be a good idea, if you modify the structure of an object and old NOTE: _Rails provides several storage mechanisms for the session hashes. The most important is `ActionDispatch::Session::CookieStore`._ -Rails 2 introduced a new default session storage, CookieStore. CookieStore saves the session hash directly in a cookie on the client-side. The server retrieves the session hash from the cookie and eliminates the need for a session id. That will greatly increase the speed of the application, but it is a controversial storage option and you have to think about the security implications of it: +Rails 2 introduced a new default session storage, CookieStore. CookieStore saves the session hash directly in a cookie on the client-side. The server retrieves the session hash from the cookie and eliminates the need for a session ID. That will greatly increase the speed of the application, but it is a controversial storage option and you have to think about the security implications of it: * Cookies imply a strict size limit of 4kB. This is fine as you should not store large amounts of data in a session anyway, as described before. _Storing the current user's database id in a session is usually ok_. @@ -102,7 +102,7 @@ Thus the session becomes a more secure place to store data. The encryption is done using a server-side secret key `secrets.secret_key_base` stored in `config/secrets.yml`. -That means the security of this storage depends on this secret (and on the digest algorithm, which defaults to SHA1, for compatibility). So _don't use a trivial secret, i.e. a word from a dictionary, or one which is shorter than 30 characters, use `rake secret` instead_. +That means the security of this storage depends on this secret (and on the digest algorithm, which defaults to SHA1, for compatibility). So _don't use a trivial secret, i.e. a word from a dictionary, or one which is shorter than 30 characters, use `rails secret` instead_. `secrets.secret_key_base` is used for specifying a key which allows sessions for the application to be verified against a known secure key to prevent tampering. Applications get `secrets.secret_key_base` initialized to a random key present in `config/secrets.yml`, e.g.: @@ -137,16 +137,16 @@ The best _solution against it is not to store this kind of data in a session, bu ### Session Fixation -NOTE: _Apart from stealing a user's session id, the attacker may fix a session id known to them. This is called session fixation._ +NOTE: _Apart from stealing a user's session ID, the attacker may fix a session ID known to them. This is called session fixation._ ![Session fixation](images/session_fixation.png) -This attack focuses on fixing a user's session id known to the attacker, and forcing the user's browser into using this id. It is therefore not necessary for the attacker to steal the session id afterwards. Here is how this attack works: +This attack focuses on fixing a user's session ID known to the attacker, and forcing the user's browser into using this ID. It is therefore not necessary for the attacker to steal the session ID afterwards. Here is how this attack works: -* The attacker creates a valid session id: They load the login page of the web application where they want to fix the session, and take the session id in the cookie from the response (see number 1 and 2 in the image). +* The attacker creates a valid session ID: They load the login page of the web application where they want to fix the session, and take the session ID in the cookie from the response (see number 1 and 2 in the image). * They maintain the session by accessing the web application periodically in order to keep an expiring session alive. -* The attacker forces the user's browser into using this session id (see number 3 in the image). As you may not change a cookie of another domain (because of the same origin policy), the attacker has to run a JavaScript from the domain of the target web application. Injecting the JavaScript code into the application by XSS accomplishes this attack. Here is an example: `<script>document.cookie="_session_id=16d5b78abb28e3d6206b60f22a03c8d9";</script>`. Read more about XSS and injection later on. -* The attacker lures the victim to the infected page with the JavaScript code. By viewing the page, the victim's browser will change the session id to the trap session id. +* The attacker forces the user's browser into using this session ID (see number 3 in the image). As you may not change a cookie of another domain (because of the same origin policy), the attacker has to run a JavaScript from the domain of the target web application. Injecting the JavaScript code into the application by XSS accomplishes this attack. Here is an example: `<script>document.cookie="_session_id=16d5b78abb28e3d6206b60f22a03c8d9";</script>`. Read more about XSS and injection later on. +* The attacker lures the victim to the infected page with the JavaScript code. By viewing the page, the victim's browser will change the session ID to the trap session ID. * As the new trap session is unused, the web application will require the user to authenticate. * From now on, the victim and the attacker will co-use the web application with the same session: The session became valid and the victim didn't notice the attack. @@ -160,7 +160,7 @@ The most effective countermeasure is to _issue a new session identifier_ and dec reset_session ``` -If you use the popular RestfulAuthentication plugin for user management, add reset_session to the SessionsController#create action. Note that this removes any value from the session, _you have to transfer them to the new session_. +If you use the popular [Devise](https://rubygems.org/gems/devise) gem for user management, it will automatically expire sessions on sign in and sign out for you. If you roll your own, remember to expire the session after your sign in action (when the session is created). This will remove values from the session, therefore _you will have to transfer them to the new session_. Another countermeasure is to _save user-specific properties in the session_, verify them every time a request comes in, and deny access, if the information does not match. Such properties could be the remote IP address or the user agent (the web browser name), though the latter is less user-specific. When saving the IP address, you have to bear in mind that there are Internet service providers or large organizations that put their users behind proxies. _These might change over the course of a session_, so these users will not be able to use your application, or only in a limited way. @@ -168,10 +168,10 @@ Another countermeasure is to _save user-specific properties in the session_, ver NOTE: _Sessions that never expire extend the time-frame for attacks such as cross-site request forgery (CSRF), session hijacking and session fixation._ -One possibility is to set the expiry time-stamp of the cookie with the session id. However the client can edit cookies that are stored in the web browser so expiring sessions on the server is safer. Here is an example of how to _expire sessions in a database table_. Call `Session.sweep("20 minutes")` to expire sessions that were used longer than 20 minutes ago. +One possibility is to set the expiry time-stamp of the cookie with the session ID. However the client can edit cookies that are stored in the web browser so expiring sessions on the server is safer. Here is an example of how to _expire sessions in a database table_. Call `Session.sweep("20 minutes")` to expire sessions that were used longer than 20 minutes ago. ```ruby -class Session < ActiveRecord::Base +class Session < ApplicationRecord def self.sweep(time = 1.hour) if time.is_a?(String) time = time.split.inject { |count, unit| count.to_i.send(unit) } @@ -196,11 +196,11 @@ This attack method works by including malicious code or a link in a page that ac ![](images/csrf.png) -In the [session chapter](#sessions) you have learned that most Rails applications use cookie-based sessions. Either they store the session id in the cookie and have a server-side session hash, or the entire session hash is on the client-side. In either case the browser will automatically send along the cookie on every request to a domain, if it can find a cookie for that domain. The controversial point is that if the request comes from a site of a different domain, it will also send the cookie. Let's start with an example: +In the [session chapter](#sessions) you have learned that most Rails applications use cookie-based sessions. Either they store the session ID in the cookie and have a server-side session hash, or the entire session hash is on the client-side. In either case the browser will automatically send along the cookie on every request to a domain, if it can find a cookie for that domain. The controversial point is that if the request comes from a site of a different domain, it will also send the cookie. Let's start with an example: * Bob browses a message board and views a post from a hacker where there is a crafted HTML image element. The element references a command in Bob's project management application, rather than an image file: `<img src="http://www.webapp.com/project/1/destroy">` * Bob's session at `www.webapp.com` is still alive, because he didn't log out a few minutes ago. -* By viewing the post, the browser finds an image tag. It tries to load the suspected image from `www.webapp.com`. As explained before, it will also send along the cookie with the valid session id. +* By viewing the post, the browser finds an image tag. It tries to load the suspected image from `www.webapp.com`. As explained before, it will also send along the cookie with the valid session ID. * The web application at `www.webapp.com` verifies the user information in the corresponding session hash and destroys the project with the ID 1. It then returns a result page which is an unexpected result for the browser, so it will not display the image. * Bob doesn't notice the attack - but a few days later he finds out that project number one is gone. @@ -381,9 +381,9 @@ Refer to the Injection section for countermeasures against XSS. It is _recommend **CSRF** Cross-Site Request Forgery (CSRF), also known as Cross-Site Reference Forgery (XSRF), is a gigantic attack method, it allows the attacker to do everything the administrator or Intranet user may do. As you have already seen above how CSRF works, here are a few examples of what attackers can do in the Intranet or admin interface. -A real-world example is a [router reconfiguration by CSRF](http://www.h-online.com/security/news/item/Symantec-reports-first-active-attack-on-a-DSL-router-735883.html). The attackers sent a malicious e-mail, with CSRF in it, to Mexican users. The e-mail claimed there was an e-card waiting for them, but it also contained an image tag that resulted in a HTTP-GET request to reconfigure the user's router (which is a popular model in Mexico). The request changed the DNS-settings so that requests to a Mexico-based banking site would be mapped to the attacker's site. Everyone who accessed the banking site through that router saw the attacker's fake web site and had their credentials stolen. +A real-world example is a [router reconfiguration by CSRF](http://www.h-online.com/security/news/item/Symantec-reports-first-active-attack-on-a-DSL-router-735883.html). The attackers sent a malicious e-mail, with CSRF in it, to Mexican users. The e-mail claimed there was an e-card waiting for the user, but it also contained an image tag that resulted in an HTTP-GET request to reconfigure the user's router (which is a popular model in Mexico). The request changed the DNS-settings so that requests to a Mexico-based banking site would be mapped to the attacker's site. Everyone who accessed the banking site through that router saw the attacker's fake web site and had their credentials stolen. -Another example changed Google Adsense's e-mail address and password by. If the victim was logged into Google Adsense, the administration interface for Google advertisements campaigns, an attacker could change their credentials.
 +Another example changed Google Adsense's e-mail address and password. If the victim was logged into Google Adsense, the administration interface for Google advertisement campaigns, an attacker could change the credentials of the victim.
 Another popular attack is to spam your web application, your blog or forum to propagate malicious XSS. Of course, the attacker has to know the URL structure, but most Rails URLs are quite straightforward or they will be easy to find out, if it is an open-source application's admin interface. The attacker may even do 1,000 lucky guesses by just including malicious IMG-tags which try every possible combination. @@ -453,7 +453,7 @@ However, the attacker may also take over the account by changing the e-mail addr #### Other -Depending on your web application, there may be more ways to hijack the user's account. In many cases CSRF and XSS will help to do so. For example, as in a CSRF vulnerability in [Google Mail](http://www.gnucitizen.org/blog/google-gmail-e-mail-hijack-technique/). In this proof-of-concept attack, the victim would have been lured to a web site controlled by the attacker. On that site is a crafted IMG-tag which results in a HTTP GET request that changes the filter settings of Google Mail. If the victim was logged in to Google Mail, the attacker would change the filters to forward all e-mails to their e-mail address. This is nearly as harmful as hijacking the entire account. As a countermeasure, _review your application logic and eliminate all XSS and CSRF vulnerabilities_. +Depending on your web application, there may be more ways to hijack the user's account. In many cases CSRF and XSS will help to do so. For example, as in a CSRF vulnerability in [Google Mail](http://www.gnucitizen.org/blog/google-gmail-e-mail-hijack-technique/). In this proof-of-concept attack, the victim would have been lured to a web site controlled by the attacker. On that site is a crafted IMG-tag which results in an HTTP GET request that changes the filter settings of Google Mail. If the victim was logged in to Google Mail, the attacker would change the filters to forward all e-mails to their e-mail address. This is nearly as harmful as hijacking the entire account. As a countermeasure, _review your application logic and eliminate all XSS and CSRF vulnerabilities_. ### CAPTCHAs @@ -466,7 +466,7 @@ The problem with CAPTCHAs is that they have a negative impact on the user experi Most bots are really dumb. They crawl the web and put their spam into every form's field they can find. Negative CAPTCHAs take advantage of that and include a "honeypot" field in the form which will be hidden from the human user by CSS or JavaScript. -Note that negative CAPTCHAs are only effective against dumb bots and won't suffice to protect critical applications from targeted bots. Still, the negative and positive CAPTCHAs can be combined to increase the performance, e.g., if the "honeypot" field is not empty (bot detected), you won't need to verify the positive CAPTCHA, which would require a HTTPS request to Google ReCaptcha before computing the response. +Note that negative CAPTCHAs are only effective against dumb bots and won't suffice to protect critical applications from targeted bots. Still, the negative and positive CAPTCHAs can be combined to increase the performance, e.g., if the "honeypot" field is not empty (bot detected), you won't need to verify the positive CAPTCHA, which would require an HTTPS request to Google ReCaptcha before computing the response. Here are some ideas how to hide honeypot fields by JavaScript and/or CSS: @@ -494,6 +494,8 @@ By default, Rails logs all requests being made to the web application. But log f config.filter_parameters << :password ``` +NOTE: Provided parameters will be filtered out by partial matching regular expression. Rails adds default `:password` in the appropriate initializer (`initializers/filter_parameter_logging.rb`) and cares about typical application parameters `password` and `password_confirmation`. + ### Good Passwords INFO: _Do you find it hard to remember all your passwords? Don't write them down, but use the initial letters of each word in an easy to remember sentence._ @@ -565,7 +567,7 @@ This is alright for some web applications, but certainly not if the user is not Depending on your web application, there will be many more parameters the user can tamper with. As a rule of thumb, _no user input data is secure, until proven otherwise, and every parameter from the user is potentially manipulated_. -Don't be fooled by security by obfuscation and JavaScript security. The Web Developer Toolbar for Mozilla Firefox lets you review and change every form's hidden fields. _JavaScript can be used to validate user input data, but certainly not to prevent attackers from sending malicious requests with unexpected values_. The Live Http Headers plugin for Mozilla Firefox logs every request and may repeat and change them. That is an easy way to bypass any JavaScript validations. And there are even client-side proxies that allow you to intercept any request and response from and to the Internet. +Don't be fooled by security by obfuscation and JavaScript security. Developer tools let you review and change every form's hidden fields. _JavaScript can be used to validate user input data, but certainly not to prevent attackers from sending malicious requests with unexpected values_. The Firebug addon for Mozilla Firefox logs every request and may repeat and change them. That is an easy way to bypass any JavaScript validations. And there are even client-side proxies that allow you to intercept any request and response from and to the Internet. Injection --------- @@ -675,14 +677,12 @@ INFO: _The most widespread, and one of the most devastating security vulnerabili An entry point is a vulnerable URL and its parameters where an attacker can start an attack. -The most common entry points are message posts, user comments, and guest books, but project titles, document names and search result pages have also been vulnerable - just about everywhere where the user can input data. But the input does not necessarily have to come from input boxes on web sites, it can be in any URL parameter - obvious, hidden or internal. Remember that the user may intercept any traffic. Applications, such as the [Live HTTP Headers Firefox plugin](http://livehttpheaders.mozdev.org/), or client-site proxies make it easy to change requests. +The most common entry points are message posts, user comments, and guest books, but project titles, document names and search result pages have also been vulnerable - just about everywhere where the user can input data. But the input does not necessarily have to come from input boxes on web sites, it can be in any URL parameter - obvious, hidden or internal. Remember that the user may intercept any traffic. Applications or client-site proxies make it easy to change requests. There are also other attack vectors like banner advertisements. XSS attacks work like this: An attacker injects some code, the web application saves it and displays it on a page, later presented to a victim. Most XSS examples simply display an alert box, but it is more powerful than that. XSS can steal the cookie, hijack the session, redirect the victim to a fake website, display advertisements for the benefit of the attacker, change elements on the web site to get confidential information or install malicious software through security holes in the web browser. During the second half of 2007, there were 88 vulnerabilities reported in Mozilla browsers, 22 in Safari, 18 in IE, and 12 in Opera. The [Symantec Global Internet Security threat report](http://eval.symantec.com/mktginfo/enterprise/white_papers/b-whitepaper_internet_security_threat_report_xiii_04-2008.en-us.pdf) also documented 239 browser plug-in vulnerabilities in the last six months of 2007. [Mpack](http://pandalabs.pandasecurity.com/mpack-uncovered/) is a very active and up-to-date attack framework which exploits these vulnerabilities. For criminal hackers, it is very attractive to exploit an SQL-Injection vulnerability in a web application framework and insert malicious code in every textual table column. In April 2008 more than 510,000 sites were hacked like this, among them the British government, United Nations, and many more high targets. -A relatively new, and unusual, form of entry points are banner advertisements. In earlier 2008, malicious code appeared in banner ads on popular sites, such as MySpace and Excite, according to [Trend Micro](http://blog.trendmicro.com/myspace-excite-and-blick-serve-up-malicious-banner-ads/). - #### HTML/JavaScript Injection The most common XSS language is of course the most popular client-side scripting language JavaScript, often in combination with HTML. _Escaping user input is essential_. @@ -720,7 +720,7 @@ The log files on www.attacker.com will read like this: GET http://www.attacker.com/_app_session=836c1c25278e5b321d6bea4f19cb57e2 ``` -You can mitigate these attacks (in the obvious way) by adding the **httpOnly** flag to cookies, so that document.cookie may not be read by JavaScript. Http only cookies can be used from IE v6.SP1, Firefox v2.0.0.5 and Opera 9.5. Safari is still considering, it ignores the option. But other, older browsers (such as WebTV and IE 5.5 on Mac) can actually cause the page to fail to load. Be warned that cookies [will still be visible using Ajax](https://www.owasp.org/index.php/HTTPOnly#Browsers_Supporting_HttpOnly), though. +You can mitigate these attacks (in the obvious way) by adding the **httpOnly** flag to cookies, so that document.cookie may not be read by JavaScript. HTTP only cookies can be used from IE v6.SP1, Firefox v2.0.0.5, Opera 9.5, Safari 4 and Chrome 1.0.154 onwards. But other, older browsers (such as WebTV and IE 5.5 on Mac) can actually cause the page to fail to load. Be warned that cookies [will still be visible using Ajax](https://www.owasp.org/index.php/HTTPOnly#Browsers_Supporting_HttpOnly), though. ##### Defacement @@ -787,7 +787,7 @@ The following is an excerpt from the [Js.Yamanner@m](http://www.symantec.com/sec var IDList = ''; var CRumb = ''; function makeRequest(url, Func, Method,Param) { ... ``` -The worms exploits a hole in Yahoo's HTML/JavaScript filter, which usually filters all target and onload attributes from tags (because there can be JavaScript). The filter is applied only once, however, so the onload attribute with the worm code stays in place. This is a good example why blacklist filters are never complete and why it is hard to allow HTML/JavaScript in a web application. +The worms exploit a hole in Yahoo's HTML/JavaScript filter, which usually filters all targets and onload attributes from tags (because there can be JavaScript). The filter is applied only once, however, so the onload attribute with the worm code stays in place. This is a good example why blacklist filters are never complete and why it is hard to allow HTML/JavaScript in a web application. Another proof-of-concept webmail worm is Nduja, a cross-domain worm for four Italian webmail services. Find more details on [Rosario Valotta's paper](http://www.xssed.com/news/37/Nduja_Connection_A_cross_webmail_worm_XWW/). Both webmail worms have the goal to harvest email addresses, something a criminal hacker could make money with. diff --git a/guides/source/testing.md b/guides/source/testing.md index 2f941a8280..050bdda9e3 100644 --- a/guides/source/testing.md +++ b/guides/source/testing.md @@ -54,10 +54,12 @@ NOTE: Your tests are run under `RAILS_ENV=test`. ### Rails meets Minitest -If you remember when you used the `rails generate scaffold` command from the [Getting Started with Rails](getting_started.html) guide. We created our first resource among other things it created test stubs in the `test` directory: +If you remember, we used the `rails generate model` command in the +[Getting Started with Rails](getting_started.html) guide. We created our first +model, and among other things it created test stubs in the `test` directory: ```bash -$ bin/rails generate scaffold article title:string body:text +$ bin/rails generate model article title:string body:text ... create app/models/article.rb create test/models/article_test.rb @@ -83,13 +85,13 @@ A line by line examination of this file will help get you oriented to Rails test require 'test_helper' ``` -By requiring this file, `test_helper.rb` the default configuration to run our tests is loaded. We will include this with all the tests we write, so any methods added to this file are available to all your tests. +By requiring this file, `test_helper.rb` the default configuration to run our tests is loaded. We will include this with all the tests we write, so any methods added to this file are available to all our tests. ```ruby class ArticleTest < ActiveSupport::TestCase ``` -The `ArticleTest` class defines a _test case_ because it inherits from `ActiveSupport::TestCase`. `ArticleTest` thus has all the methods available from `ActiveSupport::TestCase`. Later in this guide, you'll see some of the methods it gives you. +The `ArticleTest` class defines a _test case_ because it inherits from `ActiveSupport::TestCase`. `ArticleTest` thus has all the methods available from `ActiveSupport::TestCase`. Later in this guide, we'll see some of the methods it gives us. Any method defined within a class inherited from `Minitest::Test` (which is the superclass of `ActiveSupport::TestCase`) that begins with `test_` (case sensitive) is simply called a test. So, methods defined as `test_password` and `test_valid_password` are legal test names and are run automatically when the test case is run. @@ -127,7 +129,7 @@ An assertion is a line of code that evaluates an object (or expression) for expe * does this line of code throw an exception? * is the user's password greater than 5 characters? -Every test must contain at least one assertion, with no restriction as to how many assertions are allowed. Only when all the assertions are successful will the test pass. +Every test may contain one or more assertions, with no restriction as to how many assertions are allowed. Only when all the assertions are successful will the test pass. #### Your first failing test @@ -155,7 +157,7 @@ Failed assertion, no message given. 1 tests, 1 assertions, 1 failures, 0 errors, 0 skips ``` -In the output, `F` denotes a failure. You can see the corresponding trace shown under `1)` along with the name of the failing test. The next few lines contain the stack trace followed by a message which mentions the actual value and the expected value by the assertion. The default assertion messages provide just enough information to help pinpoint the error. To make the assertion failure message more readable, every assertion provides an optional message parameter, as shown here: +In the output, `F` denotes a failure. You can see the corresponding trace shown under `1)` along with the name of the failing test. The next few lines contain the stack trace followed by a message that mentions the actual value and the expected value by the assertion. The default assertion messages provide just enough information to help pinpoint the error. To make the assertion failure message more readable, every assertion provides an optional message parameter, as shown here: ```ruby test "should not save article without title" do @@ -175,7 +177,7 @@ Saved the article without a title Now to get this test to pass we can add a model level validation for the _title_ field. ```ruby -class Article < ActiveRecord::Base +class Article < ApplicationRecord validates :title, presence: true end ``` @@ -263,7 +265,7 @@ By now you've caught a glimpse of some of the assertions that are available. Ass Here's an extract of the assertions you can use with [`Minitest`](https://github.com/seattlerb/minitest), the default testing library used by Rails. The `[msg]` parameter is an optional string message you can -specify to make your test failure messages clearer. It's not required. +specify to make your test failure messages clearer. | Assertion | Purpose | | ---------------------------------------------------------------- | ------- | @@ -285,7 +287,7 @@ specify to make your test failure messages clearer. It's not required. | `assert_not_in_delta( expected, actual, [delta], [msg] )` | Ensures that the numbers `expected` and `actual` are not within `delta` of each other.| | `assert_throws( symbol, [msg] ) { block }` | Ensures that the given block throws the symbol.| | `assert_raises( exception1, exception2, ... ) { block }` | Ensures that the given block raises one of the given exceptions.| -| `assert_nothing_raised( exception1, exception2, ... ) { block }` | Ensures that the given block doesn't raise one of the given exceptions.| +| `assert_nothing_raised { block }` | Ensures that the given block doesn't raise any exceptions.| | `assert_instance_of( class, obj, [msg] )` | Ensures that `obj` is an instance of `class`.| | `assert_not_instance_of( class, obj, [msg] )` | Ensures that `obj` is not an instance of `class`.| | `assert_kind_of( class, obj, [msg] )` | Ensures that `obj` is an instance of `class` or is descending from it.| @@ -296,7 +298,7 @@ specify to make your test failure messages clearer. It's not required. | `assert_not_operator( obj1, operator, [obj2], [msg] )` | Ensures that `obj1.operator(obj2)` is false.| | `assert_predicate ( obj, predicate, [msg] )` | Ensures that `obj.predicate` is true, e.g. `assert_predicate str, :empty?`| | `assert_not_predicate ( obj, predicate, [msg] )` | Ensures that `obj.predicate` is false, e.g. `assert_not_predicate str, :empty?`| -| `assert_send( array, [msg] )` | Ensures that executing the method listed in `array[1]` on the object in `array[0]` with the parameters of `array[2 and up]` is true. This one is weird eh?| +| `assert_send( array, [msg] )` | Ensures that executing the method listed in `array[1]` on the object in `array[0]` with the parameters of `array[2 and up]` is true, e.g. assert_send [@user, :full_name, 'Sam Smith']. This one is weird eh?| | `flunk( [msg] )` | Ensures failure. This is useful to explicitly mark a test that isn't finished yet.| The above are a subset of assertions that minitest supports. For an exhaustive & @@ -314,12 +316,12 @@ Rails adds some custom assertions of its own to the `minitest` framework: | Assertion | Purpose | | --------------------------------------------------------------------------------- | ------- | -| `assert_difference(expressions, difference = 1, message = nil) {...}` | Test numeric difference between the return value of an expression as a result of what is evaluated in the yielded block.| -| `assert_no_difference(expressions, message = nil, &block)` | Asserts that the numeric result of evaluating an expression is not changed before and after invoking the passed in block.| -| `assert_recognizes(expected_options, path, extras={}, message=nil)` | Asserts that the routing of the given path was handled correctly and that the parsed options (given in the expected_options hash) match path. Basically, it asserts that Rails recognizes the route given by expected_options.| -| `assert_generates(expected_path, options, defaults={}, extras = {}, message=nil)` | Asserts that the provided options can be used to generate the provided path. This is the inverse of assert_recognizes. The extras parameter is used to tell the request the names and values of additional request parameters that would be in a query string. The message parameter allows you to specify a custom error message for assertion failures.| -| `assert_response(type, message = nil)` | Asserts that the response comes with a specific status code. You can specify `:success` to indicate 200-299, `:redirect` to indicate 300-399, `:missing` to indicate 404, or `:error` to match the 500-599 range. You can also pass an explicit status number or its symbolic equivalent. For more information, see [full list of status codes](http://rubydoc.info/github/rack/rack/master/Rack/Utils#HTTP_STATUS_CODES-constant) and how their [mapping](http://rubydoc.info/github/rack/rack/master/Rack/Utils#SYMBOL_TO_STATUS_CODE-constant) works.| -| `assert_redirected_to(options = {}, message=nil)` | Asserts that the redirection options passed in match those of the redirect called in the latest action. This match can be partial, such that `assert_redirected_to(controller: "weblog")` will also match the redirection of `redirect_to(controller: "weblog", action: "show")` and so on. You can also pass named routes such as `assert_redirected_to root_path` and Active Record objects such as `assert_redirected_to @article`.| +| [`assert_difference(expressions, difference = 1, message = nil) {...}`](http://api.rubyonrails.org/classes/ActiveSupport/Testing/Assertions.html#method-i-assert_difference) | Test numeric difference between the return value of an expression as a result of what is evaluated in the yielded block.| +| [`assert_no_difference(expressions, message = nil, &block)`](http://api.rubyonrails.org/classes/ActiveSupport/Testing/Assertions.html#method-i-assert_no_difference) | Asserts that the numeric result of evaluating an expression is not changed before and after invoking the passed in block.| +| [`assert_recognizes(expected_options, path, extras={}, message=nil)`](http://api.rubyonrails.org/classes/ActionDispatch/Assertions/RoutingAssertions.html#method-i-assert_recognizes) | Asserts that the routing of the given path was handled correctly and that the parsed options (given in the expected_options hash) match path. Basically, it asserts that Rails recognizes the route given by expected_options.| +| [`assert_generates(expected_path, options, defaults={}, extras = {}, message=nil)`](http://api.rubyonrails.org/classes/ActionDispatch/Assertions/RoutingAssertions.html#method-i-assert_generates) | Asserts that the provided options can be used to generate the provided path. This is the inverse of assert_recognizes. The extras parameter is used to tell the request the names and values of additional request parameters that would be in a query string. The message parameter allows you to specify a custom error message for assertion failures.| +| [`assert_response(type, message = nil)`](http://api.rubyonrails.org/classes/ActionDispatch/Assertions/ResponseAssertions.html#method-i-assert_response) | Asserts that the response comes with a specific status code. You can specify `:success` to indicate 200-299, `:redirect` to indicate 300-399, `:missing` to indicate 404, or `:error` to match the 500-599 range. You can also pass an explicit status number or its symbolic equivalent. For more information, see [full list of status codes](http://rubydoc.info/github/rack/rack/master/Rack/Utils#HTTP_STATUS_CODES-constant) and how their [mapping](http://rubydoc.info/github/rack/rack/master/Rack/Utils#SYMBOL_TO_STATUS_CODE-constant) works.| +| [`assert_redirected_to(options = {}, message=nil)`](http://api.rubyonrails.org/classes/ActionDispatch/Assertions/ResponseAssertions.html#method-i-assert_redirected_to) | Asserts that the redirection options passed in match those of the redirect called in the latest action. This match can be partial, such that `assert_redirected_to(controller: "weblog")` will also match the redirection of `redirect_to(controller: "weblog", action: "show")` and so on. You can also pass named routes such as `assert_redirected_to root_path` and Active Record objects such as `assert_redirected_to @article`.| You'll see the usage of some of these assertions in the next chapter. @@ -327,12 +329,11 @@ You'll see the usage of some of these assertions in the next chapter. All the basic assertions such as `assert_equal` defined in `Minitest::Assertions` are also available in the classes we use in our own test cases. In fact, Rails provides the following classes for you to inherit from: -* `ActiveSupport::TestCase` -* `ActionController::TestCase` -* `ActionMailer::TestCase` -* `ActionView::TestCase` -* `ActionDispatch::IntegrationTest` -* `ActiveJob::TestCase` +* [`ActiveSupport::TestCase`](http://api.rubyonrails.org/classes/ActiveSupport/TestCase.html) +* [`ActionMailer::TestCase`](http://api.rubyonrails.org/classes/ActionMailer/TestCase.html) +* [`ActionView::TestCase`](http://api.rubyonrails.org/classes/ActionView/TestCase.html) +* [`ActionDispatch::IntegrationTest`](http://api.rubyonrails.org/classes/ActionDispatch/IntegrationTest.html) +* [`ActiveJob::TestCase`](http://api.rubyonrails.org/classes/ActiveJob/TestCase.html) Each of these classes include `Minitest::Assertions`, allowing us to use all of the basic assertions in our tests. @@ -395,14 +396,14 @@ A dedicated test database allows you to set up and interact with test data in is In order to run your tests, your test database will need to have the current structure. The test helper checks whether your test database has any pending -migrations. If so, it will try to load your `db/schema.rb` or `db/structure.sql` +migrations. It will try to load your `db/schema.rb` or `db/structure.sql` into the test database. If migrations are still pending, an error will be raised. Usually this indicates that your schema is not fully migrated. Running -the migrations against the development database (`bin/rake db:migrate`) will +the migrations against the development database (`bin/rails db:migrate`) will bring the schema up to date. -NOTE: If existing migrations required modifications, the test database needs to -be rebuilt. This can be done by executing `bin/rake db:test:prepare`. +NOTE: If there were modifications to existing migrations, the test database needs to +be rebuilt. This can be done by executing `bin/rails db:test:prepare`. ### The Low-Down on Fixtures @@ -414,6 +415,8 @@ You can find comprehensive documentation in the [Fixtures API documentation](htt _Fixtures_ is a fancy word for sample data. Fixtures allow you to populate your testing database with predefined data before your tests run. Fixtures are database independent and written in YAML. There is one file per model. +NOTE: Fixtures are not designed to create every object that your tests need, and are best managed when only used for default data that can be applied to the common case. + You'll find fixtures under your `test/fixtures` directory. When you run `rails generate model` to create a new model, Rails automatically creates fixture stubs in this directory. #### YAML @@ -447,15 +450,15 @@ about: name: About # In fixtures/articles.yml -one: +first: title: Welcome to Rails! body: Hello world! category: about ``` -Notice the `category` key of the `one` article found in `fixtures/articles.yml` has a value of `about`. This tells Rails to load the category `about` found in `fixtures/categories.yml`. +Notice the `category` key of the `first` article found in `fixtures/articles.yml` has a value of `about`. This tells Rails to load the category `about` found in `fixtures/categories.yml`. -NOTE: For associations to reference one another by name, you cannot specify the `id:` attribute on the associated fixtures. Rails will auto assign a primary key to be consistent between runs. For more information on this association behavior please read the [Fixtures API documentation](http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html). +NOTE: For associations to reference one another by name, you can use the fixture name instead of specifying the `id:` attribute on the associated fixtures. Rails will auto assign a primary key to be consistent between runs. For more information on this association behavior please read the [Fixtures API documentation](http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html). #### ERB'in It Up @@ -492,7 +495,8 @@ users(:david) users(:david).id # one can also access methods available on the User class -email(david.partner.email, david.location_tonight) +david = users(:david) +david.call(david.partner) ``` To get multiple fixtures at once, you can pass in a list of fixture names. For example: @@ -517,15 +521,15 @@ create test/models/article_test.rb create test/fixtures/articles.yml ``` -Model tests don't have their own superclass like `ActionMailer::TestCase` instead they inherit from `ActiveSupport::TestCase`. +Model tests don't have their own superclass like `ActionMailer::TestCase` instead they inherit from [`ActiveSupport::TestCase`](http://api.rubyonrails.org/classes/ActiveSupport/TestCase.html). Integration Testing ------------------- -Integration tests are used to test how various parts of your application interact. They are generally used to test important work flows within your application. +Integration tests are used to test how various parts of your application interact. They are generally used to test important workflows within our application. -For creating Rails integration tests, we use the 'test/integration' directory for your application. Rails provides a generator to create an integration test skeleton for you. +For creating Rails integration tests, we use the 'test/integration' directory for our application. Rails provides a generator to create an integration test skeleton for us. ```bash $ bin/rails generate integration_test user_flows @@ -545,17 +549,17 @@ class UserFlowsTest < ActionDispatch::IntegrationTest end ``` -Inheriting from `ActionDispatch::IntegrationTest` comes with some advantages. This makes available some additional helpers to use in your integration tests. +Here the test is inheriting from `ActionDispatch::IntegrationTest`. This makes some additional helpers available for us to use in our integration tests. ### Helpers Available for Integration Tests -In addition to the standard testing helpers, inheriting `ActionDispatch::IntegrationTest` comes with some additional helpers available when writing integration tests. Let's briefly introduce you to the three categories of helpers you get to choose from. +In addition to the standard testing helpers, inheriting from `ActionDispatch::IntegrationTest` comes with some additional helpers available when writing integration tests. Let's get briefly introduced to the three categories of helpers we get to choose from. For dealing with the integration test runner, see [`ActionDispatch::Integration::Runner`](http://api.rubyonrails.org/classes/ActionDispatch/Integration/Runner.html). -When performing requests, you will have [`ActionDispatch::Integration::RequestHelpers`](http://api.rubyonrails.org/classes/ActionDispatch/Integration/RequestHelpers.html) available for your use. +When performing requests, we will have [`ActionDispatch::Integration::RequestHelpers`](http://api.rubyonrails.org/classes/ActionDispatch/Integration/RequestHelpers.html) available for our use. -If you'd like to modify the session, or state of your integration test you should look for [`ActionDispatch::Integration::Session`](http://api.rubyonrails.org/classes/ActionDispatch/Integration/Session.html) to help. +If we need to modify the session, or state of our integration test, take a look at [`ActionDispatch::Integration::Session`](http://api.rubyonrails.org/classes/ActionDispatch/Integration/Session.html) to help. ### Implementing an integration test @@ -568,7 +572,7 @@ $ bin/rails generate integration_test blog_flow ``` It should have created a test file placeholder for us. With the output of the -previous command you should see: +previous command we should see: ```bash invoke test_unit @@ -588,9 +592,9 @@ class BlogFlowTest < ActionDispatch::IntegrationTest end ``` -If you remember from earlier in the "Testing Views" section we covered `assert_select` to query the resulting HTML of a request. +We will take a look at `assert_select` to query the resulting HTML of a request in the "Testing Views" section below. It is used for testing the response of our request by asserting the presence of key HTML elements and their content. -When visit our root path, we should see `welcome/index.html.erb` rendered for the view. So this assertion should pass. +When we visit our root path, we should see `welcome/index.html.erb` rendered for the view. So this assertion should pass. #### Creating articles integration @@ -637,9 +641,9 @@ We were able to successfully test a very small workflow for visiting our blog an Functional Tests for Your Controllers ------------------------------------- -In Rails, testing the various actions of a controller is a form of writing functional tests. Remember your controllers handle the incoming web requests to your application and eventually respond with a rendered view. When writing functional tests, you're testing how your actions handle the requests and the expected result, or response in some cases an HTML view. +In Rails, testing the various actions of a controller is a form of writing functional tests. Remember your controllers handle the incoming web requests to your application and eventually respond with a rendered view. When writing functional tests, you are testing how your actions handle the requests and the expected result or response, in some cases an HTML view. -### What to Include in your Functional Tests +### What to include in your Functional Tests You should test for things such as: @@ -649,23 +653,39 @@ You should test for things such as: * was the correct object stored in the response template? * was the appropriate message displayed to the user in the view? -Now that we have used Rails scaffold generator for our `Article` resource, it has already created the controller code and tests. You can take look at the file `articles_controller_test.rb` in the `test/controllers` directory. +The easiest way to see functional tests in action is to generate a controller using the scaffold generator: + +```bash +$ bin/rails generate scaffold_controller article title:string body:text +... +create app/controllers/articles_controller.rb +... +invoke test_unit +create test/controllers/articles_controller_test.rb +... +``` + +This will generate the controller code and tests for an `Article` resource. +You can take a look at the file `articles_controller_test.rb` in the `test/controllers` directory. -The following command will generate a controller test case with a filled up -test for each of the seven default actions. +If you already have a controller and just want to generate the test scaffold code for +each of the seven default actions, you can use the following command: ```bash $ bin/rails generate test_unit:scaffold article +... +invoke test_unit create test/controllers/articles_controller_test.rb +... ``` -Let me take you through one such test, `test_should_get_index` from the file `articles_controller_test.rb`. +Let's take a look at one such test, `test_should_get_index` from the file `articles_controller_test.rb`. ```ruby # articles_controller_test.rb -class ArticlesControllerTest < ActionController::TestCase +class ArticlesControllerTest < ActionDispatch::IntegrationTest test "should get index" do - get :index + get '/articles' assert_response :success assert_includes @response.body, 'Articles' end @@ -675,10 +695,10 @@ end In the `test_should_get_index` test, Rails simulates a request on the action called `index`, making sure the request was successful and also ensuring that the right response body has been generated. -The `get` method kicks off the web request and populates the results into the response. It accepts 4 arguments: +The `get` method kicks off the web request and populates the results into the `@response`. It accepts 4 arguments: * The action of the controller you are requesting. - This can be in the form of a string or a symbol. + This can be in the form of a string or a route (i.e. `articles_url`). * `params`: option with a hash of request parameters to pass into the action (e.g. query string parameters or article variables). @@ -687,7 +707,7 @@ The `get` method kicks off the web request and populates the results into the re * `flash`: option with a hash of flash values. -All the keyword arguments are optional. +All of these keyword arguments are optional. Example: Calling the `:show` action, passing an `id` of 12 as the `params` and setting a `user_id` of 5 in the session: @@ -698,7 +718,7 @@ get(:show, params: { id: 12 }, session: { user_id: 5 }) Another example: Calling the `:view` action, passing an `id` of 12 as the `params`, this time with no session, but with a flash message. ```ruby -get(:view, params: { id: 12 }, flash: { message: 'booya!' }) +get(view_url, params: { id: 12 }, flash: { message: 'booya!' }) ``` NOTE: If you try running `test_should_create_article` test from `articles_controller_test.rb` it will fail on account of the newly added model level validation and rightly so. @@ -708,7 +728,7 @@ Let us modify `test_should_create_article` test in `articles_controller_test.rb` ```ruby test "should create article" do assert_difference('Article.count') do - post :create, params: { article: { title: 'Some title' } } + post '/article', params: { article: { title: 'Some title' } } end assert_redirected_to article_path(Article.last) @@ -735,11 +755,12 @@ NOTE: Functional tests do not verify whether the specified request type is accep ### Testing XHR (AJAX) requests To test AJAX requests, you can specify the `xhr: true` option to `get`, `post`, -`patch`, `put`, and `delete` methods: +`patch`, `put`, and `delete` methods. For example: ```ruby test "ajax request" do - get :show, params: { id: articles(:first).id }, xhr: true + article = articles(:first) + get article_url(article), xhr: true assert_equal 'hello world', @response.body assert_equal "text/javascript", @response.content_type @@ -778,18 +799,18 @@ and can be set directly on the `@request` instance variable: ```ruby -# setting a HTTP Header +# setting an HTTP Header @request.headers["Accept"] = "text/plain, text/html" -get :index # simulate the request with custom header +get articles_url # simulate the request with custom header # setting a CGI variable @request.headers["HTTP_REFERER"] = "http://example.com/home" -post :create # simulate the request with custom env variable +post article_url # simulate the request with custom env variable ``` ### Testing `flash` notices -If you remember from earlier one of the Three Hashes of the Apocalypse was `flash`. +If you remember from earlier, one of the Three Hashes of the Apocalypse was `flash`. We want to add a `flash` message to our blog application whenever someone successfully creates a new Article. @@ -799,7 +820,7 @@ Let's start by adding this assertion to our `test_should_create_article` test: ```ruby test "should create article" do assert_difference('Article.count') do - post :create, params: { article: { title: 'Some title' } } + post article_url, params: { article: { title: 'Some title' } } end assert_redirected_to article_path(Article.last) @@ -810,7 +831,7 @@ end If we run our test now, we should see a failure: ```bash -$ bin/rails test test/controllers/articles_controller_test.rb test_should_create_article +$ bin/rails test test/controllers/articles_controller_test.rb -n test_should_create_article Run options: -n test_should_create_article --seed 32266 # Running: @@ -848,7 +869,7 @@ end Now if we run our tests, we should see it pass: ```bash -$ bin/rails test test/controllers/articles_controller_test.rb test_should_create_article +$ bin/rails test test/controllers/articles_controller_test.rb -n test_should_create_article Run options: -n test_should_create_article --seed 18981 # Running: @@ -869,12 +890,12 @@ Let's write a test for the `:show` action: ```ruby test "should show article" do article = articles(:one) - get :show, params: { id: article.id } + get '/article', params: { id: article.id } assert_response :success end ``` -Remember from our discussion earlier on fixtures the `articles()` method will give us access to our Articles fixtures. +Remember from our discussion earlier on fixtures, the `articles()` method will give us access to our Articles fixtures. How about deleting an existing Article? @@ -882,7 +903,7 @@ How about deleting an existing Article? test "should destroy article" do article = articles(:one) assert_difference('Article.count', -1) do - delete :destroy, params: { id: article.id } + delete article_url(article) end assert_redirected_to articles_path @@ -894,19 +915,24 @@ We can also add a test for updating an existing Article. ```ruby test "should update article" do article = articles(:one) - patch :update, params: { id: article.id, article: { title: "updated" } } + + patch '/article', params: { id: article.id, article: { title: "updated" } } + assert_redirected_to article_path(article) + # Reload association to fetch updated data and assert that title is updated. + article.reload + assert_equal "updated", article.title end ``` Notice we're starting to see some duplication in these three tests, they both access the same Article fixture data. We can D.R.Y. this up by using the `setup` and `teardown` methods provided by `ActiveSupport::Callbacks`. -Our test should now look something like this, disregard the other tests we're leaving them out for brevity. +Our test should now look something as what follows. Disregard the other tests for now, we're leaving them out for brevity. ```ruby require 'test_helper' -class ArticlesControllerTest < ActionController::TestCase +class ArticlesControllerTest < ActionDispatch::IntegrationTest # called before every single test setup do @article = articles(:one) @@ -920,21 +946,25 @@ class ArticlesControllerTest < ActionController::TestCase test "should show article" do # Reuse the @article instance variable from setup - get :show, params: { id: @article.id } + get article_url(@article) assert_response :success end test "should destroy article" do assert_difference('Article.count', -1) do - delete :destroy, params: { id: @article.id } + delete article_url(@article) end assert_redirected_to articles_path end test "should update article" do - patch :update, params: { id: @article.id, article: { title: "updated" } } + patch '/article', params: { id: @article.id, article: { title: "updated" } } + assert_redirected_to article_path(@article) + # Reload association to fetch updated data and assert that title is updated. + @article.reload + assert_equal "updated", @article.title end end ``` @@ -947,7 +977,7 @@ To avoid code duplication, you can add your own test helpers. Sign in helper can be a good example: ```ruby -test/test_helper.rb +#test/test_helper.rb module SignInHelper def sign_in(user) @@ -955,7 +985,7 @@ module SignInHelper end end -class ActionController::TestCase +class ActionDispatch::IntegrationTest include SignInHelper end ``` @@ -963,13 +993,13 @@ end ```ruby require 'test_helper' -class ProfileControllerTest < ActionController::TestCase +class ProfileControllerTest < ActionDispatch::IntegrationTest test "should show profile" do # helper is now reusable from any controller test case sign_in users(:david) - get :show + get profile_url assert_response :success end end @@ -980,6 +1010,8 @@ Testing Routes Like everything else in your Rails application, you can test your routes. +NOTE: If your application has complex routes, Rails provides a number of useful helpers to test them. + For more information on routing assertions available in Rails, see the API documentation for [`ActionDispatch::Assertions::RoutingAssertions`](http://api.rubyonrails.org/classes/ActionDispatch/Assertions/RoutingAssertions.html). Testing Views @@ -1026,7 +1058,7 @@ assert_select "ol" do end ``` -This assertion is quite powerful. For more advanced usage, refer to its [documentation](http://www.rubydoc.info/github/rails/rails-dom-testing). +This assertion is quite powerful. For more advanced usage, refer to its [documentation](https://github.com/rails/rails-dom-testing/blob/master/lib/rails/dom/testing/assertions/selector_assertions.rb). #### Additional View-Based Assertions @@ -1049,27 +1081,31 @@ end Testing Helpers --------------- +A helper is just a simple module where you can define methods which are +available into your views. + In order to test helpers, all you need to do is check that the output of the helper method matches what you'd expect. Tests related to the helpers are located under the `test/helpers` directory. -A helper test looks like so: +Given we have the following helper: ```ruby -require 'test_helper' - -class UserHelperTest < ActionView::TestCase +module UserHelper + def link_to_user(user) + link_to "#{user.first_name} #{user.last_name}", user + end end ``` -A helper is just a simple module where you can define methods which are -available into your views. To test the output of the helper's methods, you just -have to use a mixin like this: +We can test the output of this method like this: ```ruby class UserHelperTest < ActionView::TestCase - test "should return the user name" do - # ... + test "should return the user's full name" do + user = users(:david) + + assert_dom_equal %{<a href="/user/#{user.id}">David Heinemeier Hansson</a>}, link_to_user(user) end end ``` @@ -1104,7 +1140,7 @@ In order to test that your mailer is working as expected, you can use unit tests For the purposes of unit testing a mailer, fixtures are used to provide an example of how the output _should_ look. Because these are example emails, and not Active Record data like the other fixtures, they are kept in their own subdirectory apart from the other fixtures. The name of the directory within `test/fixtures` directly corresponds to the name of the mailer. So, for a mailer named `UserMailer`, the fixtures should reside in `test/fixtures/user_mailer` directory. -When you generated your mailer, the generator creates stub fixtures for each of the mailers actions. If you didn't use the generator you'll have to make those files yourself. +When you generated your mailer, the generator creates stub fixtures for each of the mailers actions. If you didn't use the generator, you'll have to create those files yourself. #### The Basic Test Case @@ -1156,9 +1192,9 @@ testing) but instead it will be appended to an array (`ActionMailer::Base.deliveries`). NOTE: The `ActionMailer::Base.deliveries` array is only reset automatically in -`ActionMailer::TestCase` tests. If you want to have a clean slate outside Action -Mailer tests, you can reset it manually with: -`ActionMailer::Base.deliveries.clear` +`ActionMailer::TestCase` and `ActionDispatch::IntegrationTest` tests. +If you want to have a clean slate outside these test cases, you can reset it +manually with: `ActionMailer::Base.deliveries.clear` ### Functional Testing @@ -1167,10 +1203,10 @@ Functional testing for mailers involves more than just checking that the email b ```ruby require 'test_helper' -class UserControllerTest < ActionController::TestCase +class UserControllerTest < ActionDispatch::IntegrationTest test "invite friend" do assert_difference 'ActionMailer::Base.deliveries.size', +1 do - post :invite_friend, params: { email: 'friend@example.com' } + post invite_friend_url, params: { email: 'friend@example.com' } end invite_email = ActionMailer::Base.deliveries.last @@ -1185,7 +1221,7 @@ Testing Jobs ------------ Since your custom jobs can be queued at different levels inside your application, -you'll need to test both jobs themselves (their behavior when they get enqueued) +you'll need to test both, the jobs themselves (their behavior when they get enqueued) and that other entities correctly enqueue them. ### A Basic Test Case @@ -1232,3 +1268,26 @@ class ProductTest < ActiveJob::TestCase end end ``` + +Additional Testing Resources +---------------------------- + +### Testing Time-Dependent Code + +Rails provides built-in helper methods that enable you to assert that your time-sensitive code works as expected. + +Here is an example using the [`travel_to`](http://api.rubyonrails.org/classes/ActiveSupport/Testing/TimeHelpers.html#method-i-travel_to) helper: + +```ruby +# Lets say that a user is eligible for gifting a month after they register. +user = User.create(name: 'Gaurish', activation_date: Date.new(2004, 10, 24)) +assert_not user.applicable_for_gifting? +travel_to Date.new(2004, 11, 24) do + assert_equal Date.new(2004, 10, 24), user.activation_date # inside the travel_to block `Date.current` is mocked + assert user.applicable_for_gifting? +end +assert_equal Date.new(2004, 10, 24), user.activation_date # The change was visible only inside the `travel_to` block. +``` + +Please see [`ActiveSupport::Testing::TimeHelpers` API Documentation](http://api.rubyonrails.org/classes/ActiveSupport/Testing/TimeHelpers.html) +for in-depth information about the available time helpers. diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md index fa6a01671b..82080c4def 100644 --- a/guides/source/upgrading_ruby_on_rails.md +++ b/guides/source/upgrading_ruby_on_rails.md @@ -16,6 +16,21 @@ Before attempting to upgrade an existing application, you should be sure you hav The best way to be sure that your application still works after upgrading is to have good test coverage before you start the process. If you don't have automated tests that exercise the bulk of your application, you'll need to spend time manually exercising all the parts that have changed. In the case of a Rails upgrade, that will mean every single piece of functionality in the application. Do yourself a favor and make sure your test coverage is good _before_ you start an upgrade. +### The Upgrade Process + +When changing Rails versions, it's best to move slowly, one minor version at a time, in order to make good use of the deprecation warnings. Rails version numbers are in the form Major.Minor.Patch. Major and Minor versions are allowed to make changes to the public API, so this may cause errors in your application. Patch versions only include bug fixes, and don't change any public API. + +The process should go as follows: + +1. Write tests and make sure they pass. +2. Move to the latest patch version after your current version. +3. Fix tests and deprecated features. +4. Move to the latest patch version of the next minor version. + +Repeat this process until you reach your target Rails version. Each time you move versions, you will need to change the Rails version number in the Gemfile (and possibly other gem versions) and run `bundle update`. Then run the Update task mentioned below to update configuration files, then run your tests. + +You can find a list of all released Rails versions [here](https://rubygems.org/gems/rails/versions). + ### Ruby Versions Rails generally stays close to the latest released Ruby version when it's released: @@ -27,15 +42,15 @@ Rails generally stays close to the latest released Ruby version when it's releas TIP: Ruby 1.8.7 p248 and p249 have marshaling bugs that crash Rails. Ruby Enterprise Edition has these fixed since the release of 1.8.7-2010.02. On the 1.9 front, Ruby 1.9.1 is not usable because it outright segfaults, so if you want to use 1.9.x, jump straight to 1.9.3 for smooth sailing. -### The Rake Task +### The Update Task -Rails provides the `rails:update` rake task. After updating the Rails version -in the Gemfile, run this rake task. +Rails provides the `app:update` task (`rails:update` on 4.2 and earlier). After updating the Rails version +in the Gemfile, run this task. This will help you with the creation of new files and changes of old files in an interactive session. ```bash -$ rake rails:update +$ rails app:update identical config/boot.rb exist config conflict config/routes.rb @@ -53,7 +68,31 @@ Don't forget to review the difference, to see if there were any unexpected chang Upgrading from Rails 4.2 to Rails 5.0 ------------------------------------- -### Halting callback chains by returning `false` +### Ruby 2.2.2+ + +From Ruby on Rails 5.0 onwards, Ruby 2.2.2+ is the only supported version. +Make sure you are on Ruby 2.2.2 version or greater, before you proceed. + +### Active Record models now inherit from ApplicationRecord by default + +In Rails 4.2 an Active Record model inherits from `ActiveRecord::Base`. In Rails 5.0, +all models inherit from `ApplicationRecord`. + +`ApplicationRecord` is a new superclass for all app models, analogous to app +controllers subclassing `ApplicationController` instead of +`ActionController::Base`. This gives apps a single spot to configure app-wide +model behavior. + +When upgrading from Rails 4.2 to Rails 5.0 you need to create an +`application_record.rb` file in `app/models/` and add the following content: + +``` +class ApplicationRecord < ActiveRecord::Base + self.abstract_class = true +end +``` + +### Halting callback chains via `throw(:abort)` In Rails 4.2, when a 'before' callback returns `false` in Active Record and Active Model, then the entire callback chain is halted. In other words, @@ -145,7 +184,7 @@ the logs. In the next version, these errors will no longer be suppressed. Instead, the errors will propagate normally just like in other Active Record callbacks. -When you define a `after_rollback` or `after_commit` callback, you +When you define an `after_rollback` or `after_commit` callback, you will receive a deprecation warning about this upcoming change. When you are ready, you can opt into the new behavior and remove the deprecation warning by adding following configuration to your @@ -842,7 +881,7 @@ Rails 4.0 no longer supports loading plugins from `vendor/plugins`. You must rep * Rails 4.0 has removed the identity map from Active Record, due to [some inconsistencies with associations](https://github.com/rails/rails/commit/302c912bf6bcd0fa200d964ec2dc4a44abe328a6). If you have manually enabled it in your application, you will have to remove the following config that has no effect anymore: `config.active_record.identity_map`. -* The `delete` method in collection associations can now receive `Fixnum` or `String` arguments as record ids, besides records, pretty much like the `destroy` method does. Previously it raised `ActiveRecord::AssociationTypeMismatch` for such arguments. From Rails 4.0 on `delete` automatically tries to find the records matching the given ids before deleting them. +* The `delete` method in collection associations can now receive `Integer` or `String` arguments as record ids, besides records, pretty much like the `destroy` method does. Previously it raised `ActiveRecord::AssociationTypeMismatch` for such arguments. From Rails 4.0 on `delete` automatically tries to find the records matching the given ids before deleting them. * In Rails 4.0 when a column or a table is renamed the related indexes are also renamed. If you have migrations which rename the indexes, they are no longer needed. @@ -944,7 +983,7 @@ Please read [Pull Request #9978](https://github.com/rails/rails/pull/9978) for d * Rails 4.0 has removed the XML parameters parser. You will need to add the `actionpack-xml_parser` gem if you require this feature. -* Rails 4.0 changes the default `layout` lookup set using symbols or procs that return nil. To get the "no layout" behavior, return false instead of nil. +* Rails 4.0 changes the default `layout` lookup set using symbols or procs that return nil. To get the "no layout" behavior, return false instead of nil. * Rails 4.0 changes the default memcached client from `memcache-client` to `dalli`. To upgrade, simply add `gem 'dalli'` to your `Gemfile`. diff --git a/guides/source/working_with_javascript_in_rails.md b/guides/source/working_with_javascript_in_rails.md index 1c42ff2914..c1dfcab6f3 100644 --- a/guides/source/working_with_javascript_in_rails.md +++ b/guides/source/working_with_javascript_in_rails.md @@ -81,7 +81,7 @@ Awkward, right? We could pull the function definition out of the click handler, and turn it into CoffeeScript: ```coffeescript -paintIt = (element, backgroundColor, textColor) -> +@paintIt = (element, backgroundColor, textColor) -> element.style.backgroundColor = backgroundColor if textColor? element.style.color = textColor @@ -107,7 +107,7 @@ attribute to our link, and then bind a handler to the click event of every link that has that attribute: ```coffeescript -paintIt = (element, backgroundColor, textColor) -> +@paintIt = (element, backgroundColor, textColor) -> element.style.backgroundColor = backgroundColor if textColor? element.style.color = textColor @@ -148,10 +148,10 @@ and Rails has got your back in those cases. Because of Unobtrusive JavaScript, the Rails "Ajax helpers" are actually in two parts: the JavaScript half and the Ruby half. +Unless you have disabled the Asset Pipeline, [rails.js](https://github.com/rails/jquery-ujs/blob/master/src/rails.js) provides the JavaScript half, and the regular Ruby view helpers add appropriate -tags to your DOM. The CoffeeScript in rails.js then listens for these -attributes, and attaches appropriate handlers. +tags to your DOM. ### form_for @@ -328,7 +328,7 @@ this: respond_to do |format| if @user.save format.html { redirect_to @user, notice: 'User was successfully created.' } - format.js {} + format.js format.json { render json: @user, status: :created, location: @user } else format.html { render action: "new" } @@ -350,8 +350,8 @@ $("<%= escape_javascript(render @user) %>").appendTo("#users"); Turbolinks ---------- -Rails 4 ships with the [Turbolinks gem](https://github.com/rails/turbolinks). -This gem uses Ajax to speed up page rendering in most applications. +Rails ships with the [Turbolinks library](https://github.com/turbolinks/turbolinks), +which uses Ajax to speed up page rendering in most applications. ### How Turbolinks Works @@ -364,14 +364,14 @@ will then use PushState to change the URL to the correct one, preserving refresh semantics and giving you pretty URLs. The only thing you have to do to enable Turbolinks is have it in your Gemfile, -and put `//= require turbolinks` in your CoffeeScript manifest, which is usually +and put `//= require turbolinks` in your JavaScript manifest, which is usually `app/assets/javascripts/application.js`. -If you want to disable Turbolinks for certain links, add a `data-no-turbolink` +If you want to disable Turbolinks for certain links, add a `data-turbolinks="false"` attribute to the tag: ```html -<a href="..." data-no-turbolink>No turbolinks here</a>. +<a href="..." data-turbolinks="false">No turbolinks here</a>. ``` ### Page Change Events @@ -389,13 +389,13 @@ event that this relies on will not be fired. If you have code that looks like this, you must change your code to do this instead: ```coffeescript -$(document).on "page:change", -> +$(document).on "turbolinks:load", -> alert "page has loaded!" ``` For more details, including other events you can bind to, check out [the Turbolinks -README](https://github.com/rails/turbolinks/blob/master/README.md). +README](https://github.com/turbolinks/turbolinks/blob/master/README.md). Other Resources --------------- |