diff options
Diffstat (limited to 'guides')
63 files changed, 1243 insertions, 958 deletions
diff --git a/guides/CHANGELOG.md b/guides/CHANGELOG.md index 4cfc5b1f10..14ad4fd424 100644 --- a/guides/CHANGELOG.md +++ b/guides/CHANGELOG.md @@ -1,13 +1,9 @@ -* Fixed missing line and shadow on service pages(404, 422, 500). +* Updates the maintenance policy to match the latest versions of Rails - *Dmitry Korotkov* - -* Removed repetitive th tags. Instead of them added one th tag with a colspan attribute. - - *Sıtkı Bağdat* + *Matias Korhonen* -* Added the Rails maintenance policy to the guides. +* Switched the order of `Applying a default scope` and `Merging of scopes` subsections so default scopes are introduced first. - *Matias Korhonen* + *Alex Riabov* -Please check [4-0-stable](https://github.com/rails/rails/blob/4-0-stable/guides/CHANGELOG.md) for previous changes. +Please check [4-1-stable](https://github.com/rails/rails/blob/4-1-stable/guides/CHANGELOG.md) for previous changes. diff --git a/guides/Rakefile b/guides/Rakefile index d6dd950d01..94d4be8c0a 100644 --- a/guides/Rakefile +++ b/guides/Rakefile @@ -13,8 +13,8 @@ namespace :guides do desc "Generate .mobi file. The kindlegen executable must be in your PATH. You can get it for free from http://www.amazon.com/kindlepublishing" task :kindle do - unless `kindlerb -v 2> /dev/null` =~ /kindlerb 0.1.1/ - abort "Please `gem install kindlerb`" + unless `kindlerb -v 2> /dev/null` =~ /kindlerb 0.1.1/ + abort "Please `gem install kindlerb` and make sure you have `kindlegen` in your PATH" end unless `convert` =~ /convert/ abort "Please install ImageMagick`" diff --git a/guides/assets/images/getting_started/article_with_comments.png b/guides/assets/images/getting_started/article_with_comments.png Binary files differindex 1918e9bf28..117a78a39f 100644 --- a/guides/assets/images/getting_started/article_with_comments.png +++ b/guides/assets/images/getting_started/article_with_comments.png diff --git a/guides/assets/images/getting_started/challenge.png b/guides/assets/images/getting_started/challenge.png Binary files differindex cc12162677..5b88a842b2 100644 --- a/guides/assets/images/getting_started/challenge.png +++ b/guides/assets/images/getting_started/challenge.png diff --git a/guides/assets/images/getting_started/confirm_dialog.png b/guides/assets/images/getting_started/confirm_dialog.png Binary files differindex e57d4b409e..9755f581a6 100644 --- a/guides/assets/images/getting_started/confirm_dialog.png +++ b/guides/assets/images/getting_started/confirm_dialog.png diff --git a/guides/assets/images/getting_started/forbidden_attributes_for_new_article.png b/guides/assets/images/getting_started/forbidden_attributes_for_new_article.png Binary files differindex e263f7f8b2..9f32c68472 100644 --- a/guides/assets/images/getting_started/forbidden_attributes_for_new_article.png +++ b/guides/assets/images/getting_started/forbidden_attributes_for_new_article.png diff --git a/guides/assets/images/getting_started/form_with_errors.png b/guides/assets/images/getting_started/form_with_errors.png Binary files differindex 04ff8b1e2d..98bff37d4a 100644 --- a/guides/assets/images/getting_started/form_with_errors.png +++ b/guides/assets/images/getting_started/form_with_errors.png diff --git a/guides/assets/images/getting_started/index_action_with_edit_link.png b/guides/assets/images/getting_started/index_action_with_edit_link.png Binary files differindex 22f994d993..0566a3ffde 100644 --- a/guides/assets/images/getting_started/index_action_with_edit_link.png +++ b/guides/assets/images/getting_started/index_action_with_edit_link.png diff --git a/guides/assets/images/getting_started/new_article.png b/guides/assets/images/getting_started/new_article.png Binary files differindex 89fc0b2605..bd3ae4fa67 100644 --- a/guides/assets/images/getting_started/new_article.png +++ b/guides/assets/images/getting_started/new_article.png diff --git a/guides/assets/images/getting_started/rails_welcome.jpg b/guides/assets/images/getting_started/rails_welcome.jpg Binary files differdeleted file mode 100644 index 65a44cdfe5..0000000000 --- a/guides/assets/images/getting_started/rails_welcome.jpg +++ /dev/null diff --git a/guides/assets/images/getting_started/rails_welcome.png b/guides/assets/images/getting_started/rails_welcome.png Binary files differnew file mode 100644 index 0000000000..3e07c948a0 --- /dev/null +++ b/guides/assets/images/getting_started/rails_welcome.png diff --git a/guides/assets/images/getting_started/routing_error_no_controller.png b/guides/assets/images/getting_started/routing_error_no_controller.png Binary files differindex ae83b6a68c..ed62862291 100644 --- a/guides/assets/images/getting_started/routing_error_no_controller.png +++ b/guides/assets/images/getting_started/routing_error_no_controller.png diff --git a/guides/assets/images/getting_started/routing_error_no_route_matches.png b/guides/assets/images/getting_started/routing_error_no_route_matches.png Binary files differindex 1cbddfa0f1..08c54f921f 100644 --- a/guides/assets/images/getting_started/routing_error_no_route_matches.png +++ b/guides/assets/images/getting_started/routing_error_no_route_matches.png diff --git a/guides/assets/images/getting_started/show_action_for_articles.png b/guides/assets/images/getting_started/show_action_for_articles.png Binary files differindex 9467df6a07..4dad704f89 100644 --- a/guides/assets/images/getting_started/show_action_for_articles.png +++ b/guides/assets/images/getting_started/show_action_for_articles.png diff --git a/guides/assets/images/getting_started/template_is_missing_articles_new.png b/guides/assets/images/getting_started/template_is_missing_articles_new.png Binary files differindex ba630cfc23..4e636d09ff 100644 --- a/guides/assets/images/getting_started/template_is_missing_articles_new.png +++ b/guides/assets/images/getting_started/template_is_missing_articles_new.png diff --git a/guides/assets/images/getting_started/unknown_action_create_for_articles.png b/guides/assets/images/getting_started/unknown_action_create_for_articles.png Binary files differindex ed89c4f3d7..fd20cd53dc 100644 --- a/guides/assets/images/getting_started/unknown_action_create_for_articles.png +++ b/guides/assets/images/getting_started/unknown_action_create_for_articles.png diff --git a/guides/assets/images/getting_started/unknown_action_new_for_articles.png b/guides/assets/images/getting_started/unknown_action_new_for_articles.png Binary files differindex e8f2b9a16a..e948a51e4a 100644 --- a/guides/assets/images/getting_started/unknown_action_new_for_articles.png +++ b/guides/assets/images/getting_started/unknown_action_new_for_articles.png diff --git a/guides/code/getting_started/Gemfile b/guides/code/getting_started/Gemfile index ecb6e7aa1a..c3d7e96c4d 100644 --- a/guides/code/getting_started/Gemfile +++ b/guides/code/getting_started/Gemfile @@ -27,7 +27,7 @@ gem 'sdoc', '~> 0.4.0', group: :doc gem 'spring', group: :development # Use ActiveModel has_secure_password -# gem 'bcrypt-ruby', '~> 3.1.2' +# gem 'bcrypt', '~> 3.1.7' # Use unicorn as the app server # gem 'unicorn' diff --git a/guides/code/getting_started/Rakefile b/guides/code/getting_started/Rakefile index 05de8bb536..ba6b733dd2 100644 --- a/guides/code/getting_started/Rakefile +++ b/guides/code/getting_started/Rakefile @@ -3,4 +3,4 @@ require File.expand_path('../config/application', __FILE__) -Blog::Application.load_tasks +Rails.application.load_tasks diff --git a/guides/code/getting_started/config.ru b/guides/code/getting_started/config.ru index ddf869e921..5bc2a619e8 100644 --- a/guides/code/getting_started/config.ru +++ b/guides/code/getting_started/config.ru @@ -1,4 +1,4 @@ # This file is used by Rack-based servers to start the application. require ::File.expand_path('../config/environment', __FILE__) -run Blog::Application +run Rails.application diff --git a/guides/code/getting_started/config/environment.rb b/guides/code/getting_started/config/environment.rb index e7e341c960..ee8d90dc65 100644 --- a/guides/code/getting_started/config/environment.rb +++ b/guides/code/getting_started/config/environment.rb @@ -2,4 +2,4 @@ require File.expand_path('../application', __FILE__) # Initialize the Rails application. -Blog::Application.initialize! +Rails.application.initialize! diff --git a/guides/code/getting_started/config/environments/development.rb b/guides/code/getting_started/config/environments/development.rb index 7e5692b08b..ae9ffe209a 100644 --- a/guides/code/getting_started/config/environments/development.rb +++ b/guides/code/getting_started/config/environments/development.rb @@ -1,4 +1,4 @@ -Blog::Application.configure do +Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. # In the development environment your application's code is reloaded on diff --git a/guides/code/getting_started/config/environments/production.rb b/guides/code/getting_started/config/environments/production.rb index 8c514e065e..c8ae858574 100644 --- a/guides/code/getting_started/config/environments/production.rb +++ b/guides/code/getting_started/config/environments/production.rb @@ -1,4 +1,4 @@ -Blog::Application.configure do +Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. # Code is not reloaded between requests. diff --git a/guides/code/getting_started/config/environments/test.rb b/guides/code/getting_started/config/environments/test.rb index 34ab1530d1..680d0b9e06 100644 --- a/guides/code/getting_started/config/environments/test.rb +++ b/guides/code/getting_started/config/environments/test.rb @@ -1,4 +1,4 @@ -Blog::Application.configure do +Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. # The test environment is used exclusively to run your application's diff --git a/guides/code/getting_started/config/initializers/secret_token.rb b/guides/code/getting_started/config/initializers/secret_token.rb index aaf57731be..c2a549c299 100644 --- a/guides/code/getting_started/config/initializers/secret_token.rb +++ b/guides/code/getting_started/config/initializers/secret_token.rb @@ -9,4 +9,4 @@ # Make sure your secret_key_base is kept private # if you're sharing your code publicly. -Blog::Application.config.secret_key_base = 'e8aab50cec8a06a75694111a4cbaf6e22fc288ccbc6b268683aae7273043c69b15ca07d10c92a788dd6077a54762cbfcc55f19c3459f7531221b3169f8171a53' +Rails.application.config.secret_key_base = 'e8aab50cec8a06a75694111a4cbaf6e22fc288ccbc6b268683aae7273043c69b15ca07d10c92a788dd6077a54762cbfcc55f19c3459f7531221b3169f8171a53' diff --git a/guides/code/getting_started/config/initializers/session_store.rb b/guides/code/getting_started/config/initializers/session_store.rb index 3b2ca93ab9..1b9fa324d4 100644 --- a/guides/code/getting_started/config/initializers/session_store.rb +++ b/guides/code/getting_started/config/initializers/session_store.rb @@ -1,3 +1,3 @@ # Be sure to restart your server when you modify this file. -Blog::Application.config.session_store :cookie_store, key: '_blog_session' +Rails.application.config.session_store :cookie_store, key: '_blog_session' diff --git a/guides/code/getting_started/config/routes.rb b/guides/code/getting_started/config/routes.rb index 0155b613a3..65d273b58d 100644 --- a/guides/code/getting_started/config/routes.rb +++ b/guides/code/getting_started/config/routes.rb @@ -1,4 +1,4 @@ -Blog::Application.routes.draw do +Rails.application.routes.draw do resources :posts do resources :comments end diff --git a/guides/source/3_0_release_notes.md b/guides/source/3_0_release_notes.md index dd81ec58f9..2d4be0cda7 100644 --- a/guides/source/3_0_release_notes.md +++ b/guides/source/3_0_release_notes.md @@ -294,7 +294,7 @@ NOTE. The old style `map` commands still work as before with a backwards compati Deprecations * The catch all route for non-REST applications (`/:controller/:action/:id`) is now commented out. -* Routes :path\_prefix no longer exists and :name\_prefix now automatically adds "\_" at the end of the given value. +* Routes `:path_prefix` no longer exists and `:name_prefix` now automatically adds "_" at the end of the given value. More Information: * [The Rails 3 Router: Rack it Up](http://yehudakatz.com/2009/12/26/the-rails-3-router-rack-it-up/) diff --git a/guides/source/3_2_release_notes.md b/guides/source/3_2_release_notes.md index ce811a583b..cdcde67869 100644 --- a/guides/source/3_2_release_notes.md +++ b/guides/source/3_2_release_notes.md @@ -187,7 +187,7 @@ Action Pack Rails will use `layouts/single_car` when a request comes in `:show` action, and use `layouts/application` (or `layouts/cars`, if exists) when a request comes in for any other actions. -* `form\_for` is changed to use `#{action}\_#{as}` as the css class and id if `:as` option is provided. Earlier versions used `#{as}\_#{action}`. +* `form_for` is changed to use `#{action}_#{as}` as the css class and id if `:as` option is provided. Earlier versions used `#{as}_#{action}`. * `ActionController::ParamsWrapper` on Active Record models now only wrap `attr_accessible` attributes if they were set. If not, only the attributes returned by the class method `attribute_names` will be wrapped. This fixes the wrapping of nested attributes by adding them to `attr_accessible`. diff --git a/guides/source/4_1_release_notes.md b/guides/source/4_1_release_notes.md index a859553b1b..822943d81e 100644 --- a/guides/source/4_1_release_notes.md +++ b/guides/source/4_1_release_notes.md @@ -291,6 +291,10 @@ for detailed changes. with `config.active_record.maintain_test_schema = false`. ([Pull Request](https://github.com/rails/rails/pull/13528)) +* Introduce `Rails.gem_version` as a convenience method to return + `Gem::Version.new(Rails.version)`, suggesting a more reliable way to perform + version comparison. ([Pull Request](https://github.com/rails/rails/pull/14103)) + Action Pack ----------- @@ -346,10 +350,14 @@ for detailed changes. params "deep munging" that was used to address security vulnerability CVE-2013-0155. ([Pull Request](https://github.com/rails/rails/pull/13188)) -* New config option `config.action_dispatch.cookies_serializer` for specifying - a serializer for the signed and encrypted cookie jars. (Pull Requests [1](https://github.com/rails/rails/pull/13692), [2](https://github.com/rails/rails/pull/13945) / [More Details](upgrading_ruby_on_rails.html#cookies-serializer)) +* New config option `config.action_dispatch.cookies_serializer` for specifying a + serializer for the signed and encrypted cookie jars. (Pull Requests + [1](https://github.com/rails/rails/pull/13692), + [2](https://github.com/rails/rails/pull/13945) / + [More Details](upgrading_ruby_on_rails.html#cookies-serializer)) -* Added `render :plain`, `render :html` and `render :body`. ([Pull Request](https://github.com/rails/rails/pull/14062) / +* Added `render :plain`, `render :html` and `render + :body`. ([Pull Request](https://github.com/rails/rails/pull/14062) / [More Details](upgrading_ruby_on_rails.html#rendering-content-from-string)) @@ -388,7 +396,7 @@ for detailed changes. * Removed deprecated `scope` use without passing a callable object. * Removed deprecated `transaction_joinable=` in favor of `begin_transaction` - with `d:joinable` option. + with a `:joinable` option. * Removed deprecated `decrement_open_transactions`. @@ -457,10 +465,10 @@ for detailed changes. ### Notable changes -* Default scopes are no longer overriden by chained conditions. +* Default scopes are no longer overridden by chained conditions. Before this change when you defined a `default_scope` in a model - it was overriden by chained conditions in the same field. Now it + it was overridden by chained conditions in the same field. Now it is merged like any other scope. [More Details](upgrading_ruby_on_rails.html#changes-on-default-scopes). * Added `ActiveRecord::Base.to_param` for convenient "pretty" URLs derived from @@ -543,15 +551,15 @@ for detailed changes. * Make `touch` fire the `after_commit` and `after_rollback` callbacks. ([Pull Request](https://github.com/rails/rails/pull/12031)) -* Enable partial indexes for `sqlite >= - 3.8.0`. ([Pull Request](https://github.com/rails/rails/pull/13350)) +* Enable partial indexes for `sqlite >= 3.8.0`. + ([Pull Request](https://github.com/rails/rails/pull/13350)) * Make `change_column_null` - revertable. ([Commit](https://github.com/rails/rails/commit/724509a9d5322ff502aefa90dd282ba33a281a96)) + revertible. ([Commit](https://github.com/rails/rails/commit/724509a9d5322ff502aefa90dd282ba33a281a96)) * Added a flag to disable schema dump after migration. This is set to `false` - by defualt in the production environment for new applications. ([Pull Request](https://github.com/rails/rails/pull/13948)) - + by default in the production environment for new applications. + ([Pull Request](https://github.com/rails/rails/pull/13948)) Active Model ------------ @@ -703,13 +711,14 @@ for detailed changes. * Default the new `I18n.enforce_available_locales` config to `true`, meaning `I18n` will make sure that all locales passed to it must be declared in the `available_locales` - list. ([Pull Request](https://github.com/rails/rails/commit/8e21ae37ad9fef6b7393a84f9b5f2e18a831e49a)) + list. ([Pull Request](https://github.com/rails/rails/pull/13341)) -* Introduce Module#concerning: a natural, low-ceremony way to separate +* Introduce `Module#concerning`: a natural, low-ceremony way to separate responsibilities within a class. ([Commit](https://github.com/rails/rails/commit/1eee0ca6de975b42524105a59e0521d18b38ab81)) -* Added `Object#present_in` to simplify value whitelisting. ([Commit](https://github.com/rails/rails/commit/4edca106daacc5a159289eae255207d160f22396)) +* Added `Object#presence_in` to simplify value whitelisting. + ([Commit](https://github.com/rails/rails/commit/4edca106daacc5a159289eae255207d160f22396)) Credits diff --git a/guides/source/_welcome.html.erb b/guides/source/_welcome.html.erb index 9fd930963a..7e39f761f2 100644 --- a/guides/source/_welcome.html.erb +++ b/guides/source/_welcome.html.erb @@ -10,11 +10,14 @@ </p> <% else %> <p> - These are the new guides for Rails 4.0 based on <a href="https://github.com/rails/rails/tree/<%= @version %>"><%= @version %></a>. + These are the new guides for Rails 4.1 based on <a href="https://github.com/rails/rails/tree/<%= @version %>"><%= @version %></a>. These guides are designed to make you immediately productive with Rails, and to help you understand how all of the pieces fit together. </p> <% end %> <p> + The guides for Rails 4.0.x are available at <a href="http://guides.rubyonrails.org/v4.0.4/">http://guides.rubyonrails.org/v4.0.4/</a>. +</p> +<p> The guides for Rails 3.2.x are available at <a href="http://guides.rubyonrails.org/v3.2.17/">http://guides.rubyonrails.org/v3.2.17/</a>. </p> <p> diff --git a/guides/source/action_controller_overview.md b/guides/source/action_controller_overview.md index 5b5f53c9be..1735188f27 100644 --- a/guides/source/action_controller_overview.md +++ b/guides/source/action_controller_overview.md @@ -34,7 +34,7 @@ The naming convention of controllers in Rails favors pluralization of the last w Following this convention will allow you to use the default route generators (e.g. `resources`, etc) without needing to qualify each `:path` or `:controller`, and keeps URL and path helpers' usage consistent throughout your application. See [Layouts & Rendering Guide](layouts_and_rendering.html) for more details. -NOTE: The controller naming convention differs from the naming convention of models, which expected to be named in singular form. +NOTE: The controller naming convention differs from the naming convention of models, which are expected to be named in singular form. Methods and Actions @@ -260,7 +260,7 @@ used: params.require(:log_entry).permit! ``` -This will mark the `:log_entry` parameters hash and any subhash of it +This will mark the `:log_entry` parameters hash and any sub-hash of it permitted. Extreme care should be taken when using `permit!` as it will allow all current and future model attributes to be mass-assigned. @@ -364,33 +364,48 @@ If you need a different session storage mechanism, you can change it in the `con # Use the database for sessions instead of the cookie-based default, # which shouldn't be used to store highly confidential information # (create the session table with "rails g active_record:session_migration") -# YourApp::Application.config.session_store :active_record_store +# Rails.application.config.session_store :active_record_store ``` Rails sets up a session key (the name of the cookie) when signing the session data. These can also be changed in `config/initializers/session_store.rb`: ```ruby # Be sure to restart your server when you modify this file. -YourApp::Application.config.session_store :cookie_store, key: '_your_app_session' +Rails.application.config.session_store :cookie_store, key: '_your_app_session' ``` You can also pass a `:domain` key and specify the domain name for the cookie: ```ruby # Be sure to restart your server when you modify this file. -YourApp::Application.config.session_store :cookie_store, key: '_your_app_session', domain: ".example.com" +Rails.application.config.session_store :cookie_store, key: '_your_app_session', domain: ".example.com" ``` -Rails sets up (for the CookieStore) a secret key used for signing the session data. This can be changed in `config/initializers/secret_token.rb` +Rails sets up (for the CookieStore) a secret key used for signing the session data. This can be changed in `config/secrets.yml` ```ruby # Be sure to restart your server when you modify this file. -# Your secret key for verifying the integrity of signed cookies. +# Your secret key is used for verifying the integrity of signed cookies. # If you change this key, all old signed cookies will become invalid! + # Make sure the secret is at least 30 characters and all random, # no regular words or you'll be exposed to dictionary attacks. -YourApp::Application.config.secret_key_base = '49d3f3de9ed86c74b94ad6bd0...' +# You can use `rake secret` to generate a secure secret key. + +# Make sure the secrets in this file are kept private +# if you're sharing your code publicly. + +development: + secret_key_base: a75d... + +test: + secret_key_base: 492f... + +# Do not keep production secrets in the repository, +# instead read values from the environment. +production: + secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> ``` NOTE: Changing the secret when using the `CookieStore` will invalidate all existing sessions. @@ -604,6 +619,30 @@ It is also possible to pass a custom serializer that responds to `load` and Rails.application.config.action_dispatch.cookies_serializer = MyCustomSerializer ``` +When using the `:json` or `:hybrid` serializer, you should beware that not all +Ruby objects can be serialized as JSON. For example, `Date` and `Time` objects +will be serialized as strings, and `Hash`es will have their keys stringified. + +```ruby +class CookiesController < ApplicationController + def set_cookie + cookies.encrypted[:expiration_date] = Date.tomorrow # => Thu, 20 Mar 2014 + redirect_to action: 'read_cookie' + end + + def read_cookie + cookies.encrypted[:expiration_date] # => "2014-03-20" + end +end +``` + +It's advisable that you only store simple data (strings and numbers) in cookies. +If you have to store complex objects, you would need to handle the conversion +manually when reading the values on subsequent requests. + +If you use the cookie session store, this would apply to the `session` and +`flash` hash as well. + Rendering XML and JSON data --------------------------- diff --git a/guides/source/action_view_overview.md b/guides/source/action_view_overview.md index 6a355a5177..74f95bfcfd 100644 --- a/guides/source/action_view_overview.md +++ b/guides/source/action_view_overview.md @@ -1550,7 +1550,7 @@ end Sanitizes a block of CSS code. -#### strip_links(html) +#### strip_links(html) Strips all link tags from text leaving just the link text. ```ruby @@ -1568,9 +1568,9 @@ strip_links('Blog: <a href="http://myblog.com/">Visit</a>.') # => Blog: Visit. ``` -#### strip_tags(html) +#### strip_tags(html) -Strips all HTML tags from the html, including comments. +Strips all HTML tags from the html, including comments. This uses the html-scanner tokenizer and so its HTML parsing ability is limited by that of html-scanner. ```ruby @@ -1585,6 +1585,17 @@ strip_tags("<b>Bold</b> no more! <a href='more.html'>See more</a>") NB: The output may still contain unescaped '<', '>', '&' characters and confuse browsers. +### CsrfHelper + +Returns meta tags "csrf-param" and "csrf-token" with the name of the cross-site +request forgery protection parameter and token, respectively. + +```html +<%= csrf_meta_tags %> +``` + +NOTE: Regular forms generate hidden fields so they do not use these tags. More +details can be found in the [Rails Security Guide](security.html#cross-site-request-forgery-csrf). Localized Views --------------- diff --git a/guides/source/active_record_callbacks.md b/guides/source/active_record_callbacks.md index 667433285f..fbcce325ed 100644 --- a/guides/source/active_record_callbacks.md +++ b/guides/source/active_record_callbacks.md @@ -92,6 +92,7 @@ Here is a list with all the available Active Record callbacks, listed in the sam * `around_create` * `after_create` * `after_save` +* `after_commit/after_rollback` ### Updating an Object @@ -103,12 +104,14 @@ Here is a list with all the available Active Record callbacks, listed in the sam * `around_update` * `after_update` * `after_save` +* `after_commit/after_rollback` ### Destroying an Object * `before_destroy` * `around_destroy` * `after_destroy` +* `after_commit/after_rollback` WARNING. `after_save` runs both on create and update, but always _after_ the more specific callbacks `after_create` and `after_update`, no matter the order in which the macro calls were executed. diff --git a/guides/source/active_record_querying.md b/guides/source/active_record_querying.md index 4900f176a6..2a76df156c 100644 --- a/guides/source/active_record_querying.md +++ b/guides/source/active_record_querying.md @@ -961,7 +961,7 @@ SELECT clients.* FROM clients LEFT OUTER JOIN addresses ON addresses.client_id = WARNING: This method only works with `INNER JOIN`. -Active Record lets you use the names of the [associations](association_basics.html) defined on the model as a shortcut for specifying `JOIN` clause for those associations when using the `joins` method. +Active Record lets you use the names of the [associations](association_basics.html) defined on the model as a shortcut for specifying `JOIN` clauses for those associations when using the `joins` method. For example, consider the following `Category`, `Post`, `Comment`, `Guest` and `Tag` models: @@ -1231,6 +1231,35 @@ Using a class method is the preferred way to accept arguments for scopes. These category.posts.created_before(time) ``` +### 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 + default_scope { where("removed_at IS NULL") } +end +``` + +When queries are executed on this model, the SQL query will now look something like +this: + +```sql +SELECT * FROM clients WHERE removed_at IS NULL +``` + +If you need to do more complex things with a default scope, you can alternatively +define it as a class method: + +```ruby +class Client < ActiveRecord::Base + def self.default_scope + # Should return an ActiveRecord::Relation. + end +end +``` + ### Merging of scopes Just like `where` clauses scopes are merged using `AND` conditions. @@ -1284,36 +1313,6 @@ User.where(state: 'inactive') As you can see above the `default_scope` is being merged in both `scope` and `where` conditions. - -### 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 - default_scope { where("removed_at IS NULL") } -end -``` - -When queries are executed on this model, the SQL query will now look something like -this: - -```sql -SELECT * FROM clients WHERE removed_at IS NULL -``` - -If you need to do more complex things with a default scope, you can alternatively -define it as a class method: - -```ruby -class Client < ActiveRecord::Base - def self.default_scope - # Should return an ActiveRecord::Relation. - end -end -``` - ### Removing All Scoping If we wish to remove scoping for any reason we can use the `unscoped` method. This is diff --git a/guides/source/active_support_core_extensions.md b/guides/source/active_support_core_extensions.md index 2ad09f599b..5a4e15cfa9 100644 --- a/guides/source/active_support_core_extensions.md +++ b/guides/source/active_support_core_extensions.md @@ -157,9 +157,9 @@ Active Support provides `duplicable?` to programmatically query an object about ```ruby "foo".duplicable? # => true -"".duplicable? # => true +"".duplicable? # => true 0.0.duplicable? # => false -false.duplicable? # => false +false.duplicable? # => false ``` By definition all objects are `duplicable?` except `nil`, `false`, `true`, symbols, numbers, class, and module objects. @@ -761,7 +761,7 @@ Arguments may be bare constant names: Math.qualified_const_get("E") # => 2.718281828459045 ``` -These methods are analogous to their builtin counterparts. In particular, +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 @@ -792,7 +792,7 @@ 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 builtin methods only relative paths are accepted. +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`. @@ -964,20 +964,7 @@ NOTE: Defined in `active_support/core_ext/module/delegation.rb` There are cases where you need to define a method with `define_method`, but don't know whether a method with that name already exists. If it does, a warning is issued if they are enabled. No big deal, but not clean either. -The method `redefine_method` prevents such a potential warning, removing the existing method before if needed. Rails uses it in a few places, for instance when it generates an association's API: - -```ruby -redefine_method("#{reflection.name}=") do |new_value| - association = association_instance_get(reflection.name) - - if association.nil? || association.target != new_value - association = association_proxy_class.new(self, reflection) - end - - association.replace(new_value) - association_instance_set(reflection.name, new_value.nil? ? nil : association) -end -``` +The method `redefine_method` prevents such a potential warning, removing the existing method before if needed. NOTE: Defined in `active_support/core_ext/module/remove_method.rb` @@ -1644,6 +1631,9 @@ Given a string with a qualified constant name, `demodulize` returns the very con "Product".demodulize # => "Product" "Backoffice::UsersController".demodulize # => "UsersController" "Admin::Hotel::ReservationUtils".demodulize # => "ReservationUtils" +"::Inflections".demodulize # => "Inflections" +"".demodulize # => "" + ``` Active Record for example uses this method to compute the name of a counter cache column: @@ -2719,11 +2709,14 @@ The method `transform_keys` accepts a block and returns a hash that has applied # => {"" => nil, "A" => :a, "1" => 1} ``` -The result in case of collision is undefined: +In case of key collision, one of the values will be chosen. The chosen value may not always be the same given the same hash: ```ruby {"a" => 1, a: 2}.transform_keys { |key| key.to_s.upcase } -# => {"A" => 2}, in my test, can't rely on this result though +# The result could either be +# => {"A"=>2} +# or +# => {"A"=>1} ``` This method may be useful for example to build specialized conversions. For instance `stringify_keys` and `symbolize_keys` use `transform_keys` to perform their key conversions: @@ -2758,11 +2751,14 @@ The method `stringify_keys` returns a hash that has a stringified version of the # => {"" => nil, "a" => :a, "1" => 1} ``` -The result in case of collision is undefined: +In case of key collision, one of the values will be chosen. The chosen value may not always be the same given the same hash: ```ruby {"a" => 1, a: 2}.stringify_keys -# => {"a" => 2}, in my test, can't rely on this result though +# The result could either be +# => {"a"=>2} +# or +# => {"a"=>1} ``` This method may be useful for example to easily accept both symbols and strings as options. For instance `ActionView::Helpers::FormHelper` defines: @@ -2799,11 +2795,14 @@ The method `symbolize_keys` returns a hash that has a symbolized version of the WARNING. Note in the previous example only one key was symbolized. -The result in case of collision is undefined: +In case of key collision, one of the values will be chosen. The chosen value may not always be the same given the same hash: ```ruby {"a" => 1, a: 2}.symbolize_keys -# => {:a=>2}, in my test, can't rely on this result though +# The result could either be +# => {:a=>2} +# or +# => {:a=>1} ``` This method may be useful for example to easily accept both symbols and strings as options. For instance `ActionController::UrlRewriter` defines @@ -2911,7 +2910,7 @@ NOTE: Defined in `active_support/core_ext/hash/indifferent_access.rb`. ### Compacting -The methods `compact` and `compact!` return a Hash without items with `nil` value. +The methods `compact` and `compact!` return a Hash without items with `nil` value. ```ruby {a: 1, b: 2, c: nil}.compact # => {a: 1, b: 2} @@ -3838,7 +3837,7 @@ rescue NameError => e end ``` -NOTE: Defined in `actionpack/lib/abstract_controller/helpers.rb`. +NOTE: Defined in `active_support/core_ext/name_error.rb`. Extensions to `LoadError` ------------------------- @@ -3861,4 +3860,4 @@ rescue NameError => e end ``` -NOTE: Defined in `actionpack/lib/abstract_controller/helpers.rb`. +NOTE: Defined in `active_support/core_ext/load_error.rb`. diff --git a/guides/source/active_support_instrumentation.md b/guides/source/active_support_instrumentation.md index 6c77a40d42..121cdc0199 100644 --- a/guides/source/active_support_instrumentation.md +++ b/guides/source/active_support_instrumentation.md @@ -457,6 +457,7 @@ Most times you only care about the data itself. Here is a shortcut to just get t ActiveSupport::Notifications.subscribe "process_action.action_controller" do |*args| data = args.extract_options! data # { extra: :information } +end ``` You may also subscribe to events matching a regular expression. This enables you to subscribe to diff --git a/guides/source/asset_pipeline.md b/guides/source/asset_pipeline.md index 5bb895cb78..52fc9726d9 100644 --- a/guides/source/asset_pipeline.md +++ b/guides/source/asset_pipeline.md @@ -56,11 +56,11 @@ the comment operator on that line to later enable the asset pipeline: To set asset compression methods, set the appropriate configuration options in `production.rb` - `config.assets.css_compressor` for your CSS and -`config.assets.js_compressor` for your Javascript: +`config.assets.js_compressor` for your JavaScript: ```ruby config.assets.css_compressor = :yui -config.assets.js_compressor = :uglify +config.assets.js_compressor = :uglifier ``` NOTE: The `sass-rails` gem is automatically used for CSS compression if included @@ -245,7 +245,7 @@ When a file is referenced from a manifest or a helper, Sprockets searches the three default asset locations for it. The default locations are: the `images`, `javascripts` and `stylesheets` -directories under the `apps/assets` folder, but these subdirectories +directories under the `app/assets` folder, but these subdirectories are not special - any path under `assets/*` will be searched. For example, these files: @@ -581,23 +581,8 @@ runtime. To disable this behavior you can set: config.assets.raise_runtime_errors = false ``` -When `raise_runtime_errors` is set to `false` sprockets will not check that dependencies of assets are declared properly. Here is a scenario where you must tell the asset pipeline about a dependency: - -If you have `application.css.erb` that references `logo.png` like this: - -```css -#logo { background: url(<%= asset_data_uri 'logo.png' %>) } -``` - -Then you must declare that `logo.png` is a dependency of `application.css.erb`, so when the image gets re-compiled, the css file does as well. You can do this using the `//= depend_on_asset` declaration: - -```css -//= depend_on_asset "logo.png" -#logo { background: url(<%= asset_data_uri 'logo.png' %>) } -``` - -Without this declaration you may experience strange behavior when pushing to production that is difficult to debug. When you have `raise_runtime_errors` set to `true`, dependencies will be checked at runtime so you can ensure that all dependencies are met. - +When this option is true asset pipeline will check if all the assets loaded in your application +are included in the `config.assets.precompile` list. ### Turning Debugging Off @@ -724,17 +709,17 @@ JS/CSS is excluded, as well as raw JS/CSS files; for example, `.coffee` and `.scss` files are **not** automatically included as they compile to JS/CSS. If you have other manifests or individual stylesheets and JavaScript files to -include, you can add them to the `precompile` array in `config/application.rb`: +include, you can add them to the `precompile` array in `config/initializers/assets.rb`: ```ruby -config.assets.precompile += ['admin.js', 'admin.css', 'swfObject.js'] +Rails.application.config.assets.precompile += ['admin.js', 'admin.css', 'swfObject.js'] ``` Or, you can opt to precompile all assets with something like this: ```ruby -# config/application.rb -config.assets.precompile << Proc.new do |path| +# config/initializers/assets.rb +Rails.application.config.assets.precompile << Proc.new do |path| if path =~ /\.(css|js)\z/ full_path = Rails.application.assets.resolve(path).to_path app_assets_path = Rails.root.join('app', 'assets').to_path @@ -781,7 +766,7 @@ exception indicating the name of the missing file(s). #### Far-future Expires Header -Precompiled assets exist on the filesystem and are served directly by your web +Precompiled assets exist on the file system and are served directly by your web server. They do not have far-future headers by default, so to get the benefit of fingerprinting you'll have to update your server configuration to add those headers. @@ -943,7 +928,7 @@ gem. ```ruby config.assets.css_compressor = :yui ``` -The other option for compressing CSS if you have the sass-rails gem installed is +The other option for compressing CSS if you have the sass-rails gem installed is ```ruby config.assets.css_compressor = :sass @@ -1018,7 +1003,7 @@ The X-Sendfile header is a directive to the web server to ignore the response from the application, and instead serve a specified file from disk. This option is off by default, but can be enabled if your server supports it. When enabled, this passes responsibility for serving the file to the web server, which is -faster. Have a look at [send_file](http://api.rubyonrails.org/classes/ActionController/DataStreaming.html#method-i-send_file) +faster. Have a look at [send_file](http://api.rubyonrails.org/classes/ActionController/DataStreaming.html#method-i-send_file) on how to use this feature. Apache and nginx support this option, which can be enabled in @@ -1056,6 +1041,14 @@ cache store. config.assets.cache_store = :memory_store, { size: 32.megabytes } ``` +To disable the assets cache store: + +```ruby +config.assets.configure do |env| + env.cache = ActiveSupport::Cache.lookup_store(:null_store) +end +``` + Adding Assets to Your Gems -------------------------- diff --git a/guides/source/association_basics.md b/guides/source/association_basics.md index 5ec6ae0f21..df38bd7321 100644 --- a/guides/source/association_basics.md +++ b/guides/source/association_basics.md @@ -571,7 +571,7 @@ If you create an association some time after you build the underlying model, you 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. -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). +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: diff --git a/guides/source/caching_with_rails.md b/guides/source/caching_with_rails.md index 0d45e5fb28..b6423dd44e 100644 --- a/guides/source/caching_with_rails.md +++ b/guides/source/caching_with_rails.md @@ -30,13 +30,13 @@ config.action_controller.perform_caching = true Page caching is a Rails mechanism which allows the request for a generated page to be fulfilled by the webserver (i.e. Apache or nginx), without ever having to go through the Rails stack at all. Obviously, this is super-fast. Unfortunately, it can't be applied to every situation (such as pages that need authentication) and since the webserver is literally just serving a file from the filesystem, cache expiration is an issue that needs to be dealt with. -INFO: Page Caching has been removed from Rails 4. See the [actionpack-page_caching gem](https://github.com/rails/actionpack-page_caching). See [DHH's key-based cache expiration overview](http://37signals.com/svn/posts/3113-how-key-based-cache-expiration-works) for the newly-preferred method. +INFO: Page Caching has been removed from Rails 4. See the [actionpack-page_caching gem](https://github.com/rails/actionpack-page_caching). See [DHH's key-based cache expiration overview](http://signalvnoise.com/posts/3113-how-key-based-cache-expiration-works) for the newly-preferred method. ### Action Caching Page Caching cannot be used for actions that have before filters - for example, pages that require authentication. This is where Action Caching comes in. Action Caching works like Page Caching except the incoming web request hits the Rails stack so that before filters can be run on it before the cache is served. This allows authentication and other restrictions to be run while still serving the result of the output from a cached copy. -INFO: Action Caching has been removed from Rails 4. See the [actionpack-action_caching gem](https://github.com/rails/actionpack-action_caching). See [DHH's key-based cache expiration overview](http://37signals.com/svn/posts/3113-how-key-based-cache-expiration-works) for the newly-preferred method. +INFO: Action Caching has been removed from Rails 4. See the [actionpack-action_caching gem](https://github.com/rails/actionpack-action_caching). See [DHH's key-based cache expiration overview](http://signalvnoise.com/posts/3113-how-key-based-cache-expiration-works) for the newly-preferred method. ### Fragment Caching @@ -140,6 +140,26 @@ You can also combine the two schemes which is called "Russian Doll Caching": It's called "Russian Doll Caching" because it nests multiple fragments. The advantage is that if a single product is updated, all the other inner fragments can be reused when regenerating the outer fragment. +### Low-Level Caching + +Sometimes you need to cache a particular value or query result, instead of caching view fragments. Rails caching mechanism works great for storing __any__ kind of information. + +The most efficient way to implement low-level caching is using the `Rails.cache.fetch` method. This method does both reading and writing to the cache. When passed only a single argument, the key is fetched and value from the cache is returned. If a block is passed, the result of the block will be cached to the given key and the result is returned. + +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 + def competing_price + Rails.cache.fetch("#{cache_key}/competing_price", expires_in: 12.hours) do + Competitor::API.find_price(id) + end + end +end +``` + +NOTE: Notice that in this example we used `cache_key` method, so the resulting cache-key will be something like `products/233-20140225082222765838000/competing_price`. `cache_key` generates a string based on the model’s `id` and `updated_at` attributes. This is a common convention and has the benefit of invalidating the cache whenever the product is updated. In general, when you use low-level caching for instance level information, you need to generate a cache key. + ### SQL Caching Query caching is a Rails feature that caches the result set returned by each query so that if Rails encounters the same query again for that request, it will use the cached result set as opposed to running the query against the database again. diff --git a/guides/source/command_line.md b/guides/source/command_line.md index 3b80faec7f..756c8f8b51 100644 --- a/guides/source/command_line.md +++ b/guides/source/command_line.md @@ -254,7 +254,7 @@ $ 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 `rake db:migrate` command. We'll talk more about Rake in-depth in a little while. ```bash $ rake db:migrate @@ -411,7 +411,7 @@ The `doc:` namespace has the tools to generate documentation for your app, API d ### `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`, `.erb`, `.haml` and `.slim` for both default and custom annotations. +`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. ```bash $ rake notes @@ -425,6 +425,12 @@ app/models/school.rb: * [ 17] [FIXME] ``` +You can add support for new file extensions using `config.annotations.register_extensions` option, which receives a list of the extensions with its corresponding regex to match it up. + +```ruby +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. ```bash diff --git a/guides/source/configuring.md b/guides/source/configuring.md index 7b72e27b96..ae382fc54d 100644 --- a/guides/source/configuring.md +++ b/guides/source/configuring.md @@ -56,7 +56,7 @@ These configuration methods are to be called on a `Rails::Railtie` object, such end ``` -* `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 builtin in browsers using different domain aliases. Shorter version of `config.action_controller.asset_host`. +* `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. @@ -110,7 +110,7 @@ numbers. New applications filter out passwords by adding the following `config.f * `config.log_level` defines the verbosity of the Rails logger. This option defaults to `:debug` for all modes except production, where it defaults to `:info`. -* `config.log_tags` accepts a list of methods that respond to `request` object. 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.log_tags` accepts a list of methods that the `request` object responds to. 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`, with auto flushing off in production mode. @@ -118,7 +118,7 @@ numbers. New applications filter out passwords by adding the following `config.f * `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.secret_key_base` used for specifying a key which allows sessions for the application to be verified against a known secure key to prevent tampering. Applications get `config.secret_key_base` initialized to a random key in `config/initializers/secret_token.rb`. +* `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.serve_static_assets` configures Rails itself to serve static assets. Defaults to true, but in the production environment is turned off as the server software (e.g. Nginx or Apache) used to run the application should serve static assets instead. Unlike the default setting set this to true when running (absolutely not recommended!) or testing your app in production mode using WEBrick. Otherwise you won't be able use page caching and requests for files that exist regularly under the public directory will anyway hit your Rails app. @@ -274,7 +274,7 @@ All these configuration options are delegated to the `I18n` library. * `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` for Rails, although Active Record defaults to `:local` when used outside of Rails. +* `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. @@ -580,13 +580,13 @@ The only way to explicitly not use the connection information in `ENV['DATABASE_ ``` $ cat config/database.yml development: - url: sqlite3://localhost/NOT_my_database + url: sqlite3:NOT_my_database $ echo $DATABASE_URL postgresql://localhost/my_database $ rails runner 'puts ActiveRecord::Base.connections' -{"development"=>{"adapter"=>"sqlite3", "host"=>"localhost", "database"=>"NOT_my_database"}} +{"development"=>{"adapter"=>"sqlite3", "database"=>"NOT_my_database"}} ``` Here the connection information in `ENV['DATABASE_URL']` is ignored, note the different adapter and database name. @@ -644,11 +644,9 @@ development: encoding: unicode database: blog_development pool: 5 - username: blog - password: ``` -Prepared Statements can be disabled thus: +Prepared Statements are enabled by default on PostgreSQL. You can be disable prepared statements by setting `prepared_statements` to `false`: ```yaml production: @@ -656,6 +654,16 @@ production: prepared_statements: false ``` +If enabled, Active Record will create up to `1000` prepared statements per database connection by default. To modify this behavior you can set `statement_limit` to a different value: + +``` +production: + adapter: postgresql + statement_limit: 200 +``` + +The more prepared statements in use: the more memory your database will require. If your PostgreSQL database is hitting memory limits, try lowering `statement_limit` or disabling prepared statements. + #### Configuring an SQLite3 Database for JRuby Platform If you choose to use SQLite3 and are using JRuby, your `config/database.yml` will look a little different. Here's the development section: @@ -939,4 +947,4 @@ ActiveRecord::ConnectionTimeoutError - could not obtain a database connection wi If you get the above error, you might want to increase the size of connection pool by incrementing the `pool` option in `database.yml` -NOTE. As Rails is multi-threaded by default, there could be a chance that several threads may be accessing multiple connections simultaneously. So depending on your current request load, you could very well have multiple threads contending for a limited amount of connections. +NOTE. If you are running in a multi-threaded environment, there could be a chance that several threads may be accessing multiple connections simultaneously. So depending on your current request load, you could very well have multiple threads contending for a limited amount of connections. diff --git a/guides/source/contributing_to_ruby_on_rails.md b/guides/source/contributing_to_ruby_on_rails.md index 36e3862c6b..28e1172274 100644 --- a/guides/source/contributing_to_ruby_on_rails.md +++ b/guides/source/contributing_to_ruby_on_rails.md @@ -24,9 +24,9 @@ NOTE: Bugs in the most recent released version of Ruby on Rails are likely to ge ### Creating a Bug Report -If you've found a problem in Ruby on Rails which is not a security risk, do a search in GitHub under [Issues](https://github.com/rails/rails/issues) in case it was already reported. If you find no issue addressing it you can [add a new one](https://github.com/rails/rails/issues/new). (See the next section for reporting security issues.) +If you've found a problem in Ruby on Rails which is not a security risk, do a search in GitHub under [Issues](https://github.com/rails/rails/issues) in case it has already been reported. If you do not find any issue addressing it you may proceed to [open a new one](https://github.com/rails/rails/issues/new). (See the next section for reporting security issues.) -At the minimum, your issue report needs a title and descriptive text. But that's only a minimum. You should include as much relevant information as possible. You need at least to post the code sample that has the issue. Even better is to include a unit test that shows how the expected behavior is not occurring. Your goal should be to make it easy for yourself - and others - to replicate the bug and figure out a fix. +Your issue report should contain a title and a clear description of the issue at the bare minimum. You should include as much relevant information as possible and should at least post a code sample that demonstrates the issue. It would be even better if you could include a unit test that shows how the expected behavior is not occurring. Your goal should be to make it easy for yourself - and others - to replicate the bug and figure out a fix. Then, don't get your hopes up! Unless you have a "Code Red, Mission Critical, the World is Coming to an End" kind of bug, you're creating this issue report in the hope that others with the same problem will be able to collaborate with you on solving it. Do not expect that the issue report will automatically see any activity or that others will jump to fix it. Creating an issue like this is mostly to help yourself start on the path of fixing the problem and for others to confirm it with an "I'm having this problem too" comment. @@ -50,7 +50,7 @@ Please don't put "feature request" items into GitHub Issues. If there's a new feature that you want to see added to Ruby on Rails, you'll need to write the code yourself - or convince someone else to partner with you to write the code. Later in this guide you'll find detailed instructions for proposing a patch to -Ruby on Rails. If you enter a wishlist item in GitHub Issues with no code, you +Ruby on Rails. If you enter a wish list item in GitHub Issues with no code, you can expect it to be marked "invalid" as soon as it's reviewed. Sometimes, the line between 'bug' and 'feature' is a hard one to draw. @@ -69,89 +69,6 @@ won't be accepted." But it's the proper place to discuss new ideas. GitHub Issues are not a particularly good venue for the sometimes long and involved discussions new features require. -Setting Up a Development Environment ------------------------------------- - -To move on from submitting bugs to helping resolve existing issues or contributing your own code to Ruby on Rails, you _must_ be able to run its test suite. In this section of the guide you'll learn how to set up the tests on your own computer. - -### The Easy Way - -The easiest and recommended way to get a development environment ready to hack is to use the [Rails development box](https://github.com/rails/rails-dev-box). - -### The Hard Way - -In case you can't use the Rails development box, see section above, check [this other guide](development_dependencies_install.html). - - -Running an Application Against Your Local Branch ------------------------------------------------- - -The `--dev` flag of `rails new` generates an application that uses your local -branch: - -```bash -$ cd rails -$ bundle exec rails new ~/my-test-app --dev -``` - -The application generated in `~/my-test-app` runs against your local branch -and in particular sees any modifications upon server reboot. - - -Testing Active Record ---------------------- - -This is how you run the Active Record test suite only for SQLite3: - -```bash -$ cd activerecord -$ 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 -``` - -Finally, - -```bash -$ bundle exec rake test -``` - -will now run the four of them in turn. - -You can also run any single test separately: - -```bash -$ ARCONN=sqlite3 ruby -Itest test/cases/associations/has_many_associations_test.rb -``` - -You can invoke `test_jdbcmysql`, `test_jdbcsqlite3` or `test_jdbcpostgresql` also. See the file `activerecord/RUNNING_UNIT_TESTS.rdoc` for information on running more targeted database tests, or the file `ci/travis.rb` for the test suite run by the continuous integration server. - -### Warnings - -The test suite runs with warnings enabled. Ideally, Ruby on Rails should issue no warnings, but there may be a few, as well as some from third-party libraries. Please ignore (or fix!) them, if any, and submit patches that do not issue new warnings. - -If you are sure about what you are doing and would like to have a more clear output, there's a way to override the flag: - -```bash -$ RUBYOPT=-W0 bundle exec rake test -``` - -### Older Versions of Ruby on Rails - -If you want to add a fix to older versions of Ruby on Rails, you'll need to set up and switch to your own local tracking branch. Here is an example to switch to the 3-0-stable branch: - -```bash -$ git branch --track 3-0-stable origin/3-0-stable -$ git checkout 3-0-stable -``` - -TIP: You may want to [put your Git branch name in your shell prompt](http://qugstart.com/blog/git-and-svn/add-colored-git-branch-name-to-your-shell-prompt/) to make it easier to remember which version of the code you're working with. Helping to Resolve Existing Issues ---------------------------------- @@ -227,9 +144,21 @@ WARNING: Docrails has a very strict policy: no code can be touched whatsoever, n Contributing to the Rails Code ------------------------------ -### Clone the Rails Repository +### Setting Up a Development Environment ### + +To move on from submitting bugs to helping resolve existing issues or contributing your own code to Ruby on Rails, you _must_ be able to run its test suite. In this section of the guide you'll learn how to setup the tests on your own computer. + +#### The Easy Way + +The easiest and recommended way to get a development environment ready to hack is to use the [Rails development box](https://github.com/rails/rails-dev-box). + +#### The Hard Way + +In case you can't use the Rails development box, see [this other guide](development_dependencies_install.html). + +### Clone the Rails Repository ### -The first thing you need to do to be able to contribute code is to clone the repository: +To be able to contribute code, you need to clone the Rails repository: ```bash $ git clone git://github.com/rails/rails.git @@ -244,29 +173,31 @@ $ git checkout -b my_new_branch It doesn't matter much what name you use, because this branch will only exist on your local computer and your personal repository on GitHub. It won't be part of the Rails Git repository. -### Write Your Code +### Running an Application Against Your Local Branch ### + +In case you need a dummy Rails app to test changes, the `--dev` flag of `rails new` generates an application that uses your local branch: + +```bash +$ cd rails +$ bundle exec rails new ~/my-test-app --dev +``` + +The application generated in `~/my-test-app` runs against your local branch +and in particular sees any modifications upon server reboot. + +### Write Your Code ### -Now get busy and add or edit code. You're on your branch now, so you can write whatever you want (you can check to make sure you're on the right branch with `git branch -a`). But if you're planning to submit your change back for inclusion in Rails, keep a few things in mind: +Now get busy and add/edit code. You're on your branch now, so you can write whatever you want (you can check to make sure you're on the right branch with `git branch -a`). But if you're planning to submit your change back for inclusion in Rails, keep a few things in mind: * Get the code right. * Use Rails idioms and helpers. * Include tests that fail without your code, and pass with it. * Update the (surrounding) documentation, examples elsewhere, and the guides: whatever is affected by your contribution. -It is not customary in Rails to run the full test suite before pushing -changes. The railties test suite in particular takes a long time, and even -more if the source code is mounted in `/vagrant` as happens in the recommended -workflow with the [rails-dev-box](https://github.com/rails/rails-dev-box). - -As a compromise, test what your code obviously affects, and if the change is -not in railties, run the whole test suite of the affected component. If all -tests are passing, that's enough to propose your contribution. We have -[Travis CI](https://travis-ci.org/rails/rails) as a safety net for catching -unexpected breakages elsewhere. TIP: Changes that are cosmetic in nature and do not add anything substantial to the stability, functionality, or testability of Rails will generally not be accepted. -### Follow the Coding Conventions +#### Follow the Coding Conventions Rails follows a simple set of coding style conventions: @@ -284,13 +215,90 @@ Rails follows a simple set of coding style conventions: The above are guidelines - please use your best judgment in using them. -### Updating the CHANGELOG +### Running Tests ### +It is not customary in Rails to run the full test suite before pushing +changes. The railties test suite in particular takes a long time, and even +more if the source code is mounted in `/vagrant` as happens in the recommended +workflow with the [rails-dev-box](https://github.com/rails/rails-dev-box). + +As a compromise, test what your code obviously affects, and if the change is +not in railties, run the whole test suite of the affected component. If all +tests are passing, that's enough to propose your contribution. We have +[Travis CI](https://travis-ci.org/rails/rails) as a safety net for catching +unexpected breakages elsewhere. + +#### Entire Rails: +To run all the tests, do: +```bash +$ cd rails +$ bundle exec rake test +``` +#### Particular component of Rails +To run tests only for particular component(ActionPack, ActiveRecord, etc.). For +example, to run `ActionMailer` tests you can: + +```bash +$ cd actionmailer +$ bundle exec rake test +``` + +##### Testing Active Record + +This is how you run the Active Record test suite only for SQLite3: + +```bash +$ cd activerecord +$ 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 +``` + +Finally, + +```bash +$ bundle exec rake test +``` + +will now run the four of them in turn. + +You can also run any single test separately: + +```bash +$ ARCONN=sqlite3 ruby -Itest test/cases/associations/has_many_associations_test.rb +``` + +You can invoke `test_jdbcmysql`, `test_jdbcsqlite3` or `test_jdbcpostgresql` also. See the file `activerecord/RUNNING_UNIT_TESTS.rdoc` for information on running more targeted database tests, or the file `ci/travis.rb` for the test suite run by the continuous integration server. + +#### Single Test separately +to run just one test. For example, to run `LayoutMailerTest` you can: + +```bash +$ cd actionmailer +$ ruby -w -Ilib:test test/mail_layout_test.rb +``` + +### Warnings ### + +The test suite runs with warnings enabled. Ideally, Ruby on Rails should issue no warnings, but there may be a few, as well as some from third-party libraries. Please ignore (or fix!) them, if any, and submit patches that do not issue new warnings. + +If you are sure about what you are doing and would like to have a more clear output, there's a way to override the flag: + +```bash +$ RUBYOPT=-W0 bundle exec rake test +``` +### Updating the CHANGELOG ### The CHANGELOG is an important part of every release. It keeps the list of changes for every Rails version. You should add an entry to the CHANGELOG of the framework that you modified if you're adding or removing a feature, committing a bug fix or adding deprecation notices. Refactorings and documentation changes generally should not go to the CHANGELOG. -A CHANGELOG entry should summarize what was changed and should end with author's name and it should go on top of a CHANGELOG. You can use multiple lines if you need more space and you can attach code examples indented with 4 spaces. If a change is related to a specific issue, you should attach issue's number. Here is an example CHANGELOG entry: +A CHANGELOG entry should summarize what was changed and should end with author's name and it should go on top of a CHANGELOG. You can use multiple lines if you need more space and you can attach code examples indented with 4 spaces. If a change is related to a specific issue, you should attach the issue's number. Here is an example CHANGELOG entry: ``` * Summary of a change that briefly describes what was changed. You can use multiple @@ -309,17 +317,17 @@ A CHANGELOG entry should summarize what was changed and should end with author's Your name can be added directly after the last word if you don't provide any code examples or don't need multiple paragraphs. Otherwise, it's best to make as a new paragraph. -### Sanity Check +### Sanity Check ### You should not be the only person who looks at the code before you submit it. If you know someone else who uses Rails, try asking them if they'll check out your work. If you don't know anyone else using Rails, try hopping into the IRC -room or posting about your idea to the rails-core mailing list. Doing this in -private before you push a patch out publicly is the “smoke test” for a patch: -if you can’t convince one other developer of the beauty of your code, you’re +room or posting about your idea to the rails-core mailing list. Doing this in +private before you push a patch out publicly is the "smoke test" for a patch: +if you can't convince one other developer of the beauty of your code, you’re unlikely to convince the core team either. -### Commit Your Changes +### Commit Your Changes ### When you're happy with the code on your computer, you need to commit the changes to Git: @@ -359,7 +367,7 @@ You can also add bullet points: TIP. Please squash your commits into a single commit when appropriate. This simplifies future cherry picks, and also keeps the git log clean. -### Update Your Branch +### Update Your Branch ### It's pretty likely that other changes to master have happened while you were working. Go get them: @@ -377,7 +385,7 @@ $ git rebase master No conflicts? Tests still pass? Change still seems reasonable to you? Then move on. -### Fork +### Fork ### Navigate to the Rails [GitHub repository](https://github.com/rails/rails) and press "Fork" in the upper right hand corner. @@ -467,11 +475,11 @@ the same way that you appreciate feedback on your patches. ### Iterate as Necessary -It's entirely possible that the feedback you get will suggest changes. Don't get discouraged: the whole point of contributing to an active open source project is to tap into community knowledge. If people are encouraging you to tweak your code, then it's worth making the tweaks and resubmitting. If the feedback is that your code doesn't belong in the core, you might still think about releasing it as a gem. +It's entirely possible that the feedback you get will suggest changes. Don't get discouraged: the whole point of contributing to an active open source project is to tap into the knowledge of the community. If people are encouraging you to tweak your code, then it's worth making the tweaks and resubmitting. If the feedback is that your code doesn't belong in the core, you might still think about releasing it as a gem. #### Squashing commits -One of the things that we may ask you to do is "squash your commits," which +One of the things that we may ask you to do is to "squash your commits", which will combine all of your commits into a single commit. We prefer pull requests that are a single commit. This makes it easier to backport changes to stable branches, squashing makes it easier to revert bad commits, and the git history @@ -507,7 +515,19 @@ $ git push origin my_pull_request -f You should be able to refresh the pull request on GitHub and see that it has been updated. -### Backporting + +### Older Versions of Ruby on Rails ### + +If you want to add a fix to older versions of Ruby on Rails, you'll need to set up and switch to your own local tracking branch. Here is an example to switch to the 3-0-stable branch: + +```bash +$ git branch --track 3-0-stable origin/3-0-stable +$ git checkout 3-0-stable +``` + +TIP: You may want to [put your Git branch name in your shell prompt](http://qugstart.com/blog/git-and-svn/add-colored-git-branch-name-to-your-shell-prompt/) to make it easier to remember which version of the code you're working with. + +#### Backporting Changes that are merged into master are intended for the next major release of Rails. Sometimes, it might be beneficial for your changes to propagate back to the maintenance releases for older stable branches. Generally, security fixes and bug fixes are good candidates for a backport, while new features and patches that introduce a change in behavior will not be accepted. When in doubt, it is best to consult a Rails team member before backporting your changes to avoid wasted effort. diff --git a/guides/source/credits.html.erb b/guides/source/credits.html.erb index 7c6858fa2c..8767fbecce 100644 --- a/guides/source/credits.html.erb +++ b/guides/source/credits.html.erb @@ -64,7 +64,7 @@ Oscar Del Ben is a software engineer at <a href="http://www.wildfireapp.com/">Wi <% end %> <%= author('Pratik Naik', 'lifo') do %> - Pratik Naik is a Ruby on Rails developer at <a href="http://www.37signals.com">37signals</a> and also a member of the <a href="http://rubyonrails.org/core">Rails core team</a>. He maintains a blog at <a href="http://m.onkey.org">has_many :bugs, :through => :rails</a> and has a semi-active <a href="http://twitter.com/lifo">twitter account</a>. + Pratik Naik is a Ruby on Rails developer at <a href="https://basecamp.com/">Basecamp</a> and also a member of the <a href="http://rubyonrails.org/core">Rails core team</a>. He maintains a blog at <a href="http://m.onkey.org">has_many :bugs, :through => :rails</a> and has a semi-active <a href="http://twitter.com/lifo">twitter account</a>. <% end %> <%= author('Emilio Tagua', 'miloops') do %> diff --git a/guides/source/debugging_rails_applications.md b/guides/source/debugging_rails_applications.md index 226137c89a..b067d9efb7 100644 --- a/guides/source/debugging_rails_applications.md +++ b/guides/source/debugging_rails_applications.md @@ -123,7 +123,7 @@ config.logger = Logger.new(STDOUT) config.logger = Log4r::Logger.new("Application Log") ``` -TIP: By default, each log is created under `Rails.root/log/` and the log file name is `environment_name.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. ### Log Levels @@ -210,7 +210,7 @@ logger.tagged("BCX") { logger.tagged("Jason") { logger.info "Stuff" } } # Logs " ``` ### Impact of Logs on Performance -Logging will always have a small impact on performance of your rails app, +Logging will always have a small impact on performance of your rails app, particularly when logging to disk.However, there are a few subtleties: Using the `:debug` level will have a greater performance penalty than `:fatal`, @@ -224,446 +224,576 @@ Another potential pitfall is that if you have many calls to `Logger` like this logger.debug "Person attributes hash: #{@person.attributes.inspect}" ``` -In the above example, There will be a performance impact even if the allowed -output level doesn't include debug. The reason is that Ruby has to evaluate -these strings, which includes instantiating the somewhat heavy `String` object +In the above example, There will be a performance impact even if the allowed +output level doesn't include debug. The reason is that Ruby has to evaluate +these strings, which includes instantiating the somewhat heavy `String` object and interpolating the variables, and which takes time. -Therefore, it's recommended to pass blocks to the logger methods, as these are -only evaluated if the output level is the same or included in the allowed level +Therefore, it's recommended to pass blocks to the logger methods, as these are +only evaluated if the output level is the same or included in the allowed level (i.e. lazy loading). The same code rewritten would be: ```ruby logger.debug {"Person attributes hash: #{@person.attributes.inspect}"} ``` -The contents of the block, and therefore the string interpolation, is only -evaluated if debug is enabled. This performance savings is only really +The contents of the block, and therefore the string interpolation, is only +evaluated if debug is enabled. This performance savings is only really noticeable with large amounts of logging, but it's a good practice to employ. -Debugging with the `debugger` gem +Debugging with the `byebug` gem --------------------------------- -When your code is behaving in unexpected ways, you can try printing to logs or the console to diagnose the problem. Unfortunately, there are times when this sort of error tracking is not effective in finding the root cause of a problem. When you actually need to journey into your running source code, the debugger is your best companion. +When your code is behaving in unexpected ways, you can try printing to logs or +the console to diagnose the problem. Unfortunately, there are times when this +sort of error tracking is not effective in finding the root cause of a problem. +When you actually need to journey into your running source code, the debugger +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 deeper into Rails code. +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 deeper into +Rails code. ### Setup -You can use the `debugger` gem to set breakpoints and step through live code in Rails. To install it, just run: +You can use the `byebug` gem to set breakpoints and step through live code in +Rails. To install it, just run: ```bash -$ gem install debugger +$ gem install byebug ``` -Rails has had built-in support for debugging since Rails 2.0. Inside any Rails application you can invoke the debugger by calling the `debugger` method. +Inside any Rails application you can then invoke the debugger by calling the +`byebug` method. Here's an example: ```ruby class PeopleController < ApplicationController def new - debugger + byebug @person = Person.new end end ``` -If you see this message in the console or logs: +### The Shell + +As soon as your application calls the `byebug` method, the debugger will be +started in a debugger shell inside the terminal window where you launched your +application server, and you will be placed at the debugger's prompt `(byebug)`. +Before the prompt, the code around the line that is about to be run will be +displayed and the current line will be marked by '=>'. Like this: ``` -***** Debugger requested, but was not available: Start server with --debugger to enable ***** +[1, 10] in /PathTo/project/app/controllers/posts_controller.rb + 3: + 4: # GET /posts + 5: # GET /posts.json + 6: def index + 7: byebug +=> 8: @posts = Post.find_recent + 9: + 10: respond_to do |format| + 11: format.html # index.html.erb + 12: format.json { render json: @posts } + +(byebug) ``` -Make sure you have started your web server with the option `--debugger`: +If you got there by a browser request, the browser tab containing the request +will be hung until the debugger has finished and the trace has finished +processing the entire request. + +For example: ```bash -$ rails server --debugger => Booting WEBrick -=> Rails 4.0.0 application starting on http://0.0.0.0:3000 -=> Debugger enabled -... -``` +=> Rails 4.1.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.1.1 (2014-02-24) [i686-linux] +[2014-04-11 13:11:47] INFO WEBrick::HTTPServer#start: pid=6370 port=3000 -TIP: In development mode, you can dynamically `require \'debugger\'` instead of restarting the server, even if it was started without `--debugger`. -### The Shell +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 PostsController#index as HTML -As soon as your application calls the `debugger` method, the debugger will be started in a debugger shell inside the terminal window where you launched your application server, and you will be placed at the debugger's prompt `(rdb:n)`. The _n_ is the thread number. The prompt will also show you the next line of code that is waiting to run. +[3, 12] in /PathTo/project/app/controllers/posts_controller.rb + 3: + 4: # GET /posts + 5: # GET /posts.json + 6: def index + 7: byebug +=> 8: @posts = Post.find_recent + 9: + 10: respond_to do |format| + 11: format.html # index.html.erb + 12: format.json { render json: @posts } -If you got there by a browser request, the browser tab containing the request will be hung until the debugger has finished and the trace has finished processing the entire request. +(byebug) +``` -For example: +Now it's time to explore and dig into your application. A good place to start is +by asking the debugger for help. Type: `help` -```bash -@posts = Post.all -(rdb:7) ``` +(byebug) help -Now it's time to explore and dig into your application. A good place to start is by asking the debugger for help. Type: `help` +byebug 2.7.0 -``` -(rdb:7) help -ruby-debug help v0.10.2 Type 'help <command-name>' for help on a specific command Available commands: -backtrace delete enable help next quit show trace -break disable eval info p reload source undisplay -catch display exit irb pp restart step up -condition down finish list ps save thread var -continue edit frame method putl set tmate where +backtrace delete enable help list pry next restart source up +break disable eval info method ps save step var +catch display exit interrupt next putl set thread +condition down finish irb p quit show trace +continue edit frame kill pp reload skip undisplay ``` -TIP: To view the help menu for any command use `help <command-name>` at the debugger prompt. For example: _`help var`_ - -The next command to learn is one of the most useful: `list`. You can abbreviate any debugging command by supplying just enough letters to distinguish them from other commands, so you can also use `l` for the `list` command. +TIP: To view the help menu for any command use `help <command-name>` at the +debugger prompt. For example: _`help list`_. You can abbreviate any debugging +command by supplying just enough letters to distinguish them from other +commands, so you can also use `l` for the `list` command, for example. -This command shows you where you are in the code by printing 10 lines centered around the current line; the current line in this particular case is line 6 and is marked by `=>`. +To see the previous ten lines you should type `list-` (or `l-`) ``` -(rdb:7) list +(byebug) l- + [1, 10] in /PathTo/project/app/controllers/posts_controller.rb 1 class PostsController < ApplicationController - 2 # GET /posts - 3 # GET /posts.json - 4 def index - 5 debugger -=> 6 @posts = Post.all - 7 - 8 respond_to do |format| - 9 format.html # index.html.erb - 10 format.json { render json: @posts } -``` + 2 before_action :set_post, only: [:show, :edit, :update, :destroy] + 3 + 4 # GET /posts + 5 # GET /posts.json + 6 def index + 7 byebug + 8 @posts = Post.find_recent + 9 + 10 respond_to do |format| -If you repeat the `list` command, this time using just `l`, the next ten lines of the file will be printed out. - -``` -(rdb:7) l -[11, 20] in /PathTo/project/app/controllers/posts_controller.rb - 11 end - 12 end - 13 - 14 # GET /posts/1 - 15 # GET /posts/1.json - 16 def show - 17 @post = Post.find(params[:id]) - 18 - 19 respond_to do |format| - 20 format.html # show.html.erb ``` -And so on until the end of the current file. When the end of file is reached, the `list` command will start again from the beginning of the file and continue again up to the end, treating the file as a circular buffer. +This way you can move inside the file, being able to see the code above and over +the line where you added the `byebug` call. Finally, to see where you are in +the code again you can type `list=` -On the other hand, to see the previous ten lines you should type `list-` (or `l-`) - -``` -(rdb:7) l- -[1, 10] in /PathTo/project/app/controllers/posts_controller.rb - 1 class PostsController < ApplicationController - 2 # GET /posts - 3 # GET /posts.json - 4 def index - 5 debugger - 6 @posts = Post.all - 7 - 8 respond_to do |format| - 9 format.html # index.html.erb - 10 format.json { render json: @posts } ``` +(byebug) list= -This way you can move inside the file, being able to see the code above and over the line you added the `debugger`. -Finally, to see where you are in the code again you can type `list=` +[3, 12] in /PathTo/project/app/controllers/posts_controller.rb + 3: + 4: # GET /posts + 5: # GET /posts.json + 6: def index + 7: byebug +=> 8: @posts = Post.find_recent + 9: + 10: respond_to do |format| + 11: format.html # index.html.erb + 12: format.json { render json: @posts } -``` -(rdb:7) list= -[1, 10] in /PathTo/project/app/controllers/posts_controller.rb - 1 class PostsController < ApplicationController - 2 # GET /posts - 3 # GET /posts.json - 4 def index - 5 debugger -=> 6 @posts = Post.all - 7 - 8 respond_to do |format| - 9 format.html # index.html.erb - 10 format.json { render json: @posts } +(byebug) ``` ### The Context -When you start debugging your application, you will be placed in different contexts as you go through the different parts of the stack. - -The debugger creates a context when a stopping point or an event is reached. The context has information about the suspended program which enables a debugger to inspect the frame stack, evaluate variables from the perspective of the debugged program, and contains information about the place where the debugged program is stopped. - -At any time you can call the `backtrace` command (or its alias `where`) to print the backtrace of the application. This can be very helpful to know how you got where you are. If you ever wondered about how you got somewhere in your code, then `backtrace` will supply the answer. - -``` -(rdb:5) where - #0 PostsController.index - at line /PathTo/project/app/controllers/posts_controller.rb:6 - #1 Kernel.send - at line /PathTo/project/vendor/rails/actionpack/lib/action_controller/base.rb:1175 - #2 ActionController::Base.perform_action_without_filters - at line /PathTo/project/vendor/rails/actionpack/lib/action_controller/base.rb:1175 - #3 ActionController::Filters::InstanceMethods.call_filters(chain#ActionController::Fil...,...) - at line /PathTo/project/vendor/rails/actionpack/lib/action_controller/filters.rb:617 +When you start debugging your application, you will be placed in different +contexts as you go through the different parts of the stack. + +The debugger creates a context when a stopping point or an event is reached. The +context has information about the suspended program which enables the debugger +to inspect the frame stack, evaluate variables from the perspective of the +debugged program, and contains information about the place where the debugged +program is stopped. + +At any time you can call the `backtrace` command (or its alias `where`) to print +the backtrace of the application. This can be very helpful to know how you got +where you are. If you ever wondered about how you got somewhere in your code, +then `backtrace` will supply the answer. + +``` +(byebug) where +--> #0 PostsController.index + at /PathTo/project/test_app/app/controllers/posts_controller.rb:8 + #1 ActionController::ImplicitRender.send_action(method#String, *args#Array) + at /PathToGems/actionpack-4.1.0/lib/action_controller/metal/implicit_render.rb:4 + #2 AbstractController::Base.process_action(action#NilClass, *args#Array) + at /PathToGems/actionpack-4.1.0/lib/abstract_controller/base.rb:189 + #3 ActionController::Rendering.process_action(action#NilClass, *args#NilClass) + at /PathToGems/actionpack-4.1.0/lib/action_controller/metal/rendering.rb:10 ... ``` -You move anywhere you want in this trace (thus changing the context) by using the `frame _n_` command, where _n_ is the specified frame number. +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 +the specified frame number. If you do that, `byebug` will display your new +context. ``` -(rdb:5) frame 2 -#2 ActionController::Base.perform_action_without_filters - at line /PathTo/project/vendor/rails/actionpack/lib/action_controller/base.rb:1175 +(byebug) frame 2 + +[184, 193] in /PathToGems/actionpack-4.1.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, + +(byebug) ``` -The available variables are the same as if you were running the code line by line. After all, that's what debugging is. +The available variables are the same as if you were running the code line by +line. After all, that's what debugging is. -Moving up and down the stack frame: You can 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]` (`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. ### Threads -The debugger can list, stop, resume and switch between running threads by using the command `thread` (or the abbreviated `th`). This command has a handful of options: +The debugger can list, stop, resume and switch between running threads by using +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 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_. -This command is very helpful, among other occasions, when you are debugging concurrent threads and need to verify that there are no race conditions in your code. +This command is very helpful, among other occasions, when you are debugging +concurrent threads and need to verify that there are no race conditions in your +code. ### Inspecting Variables -Any expression can be evaluated in the current context. To evaluate an expression, just type it! - -This example shows how you can print the instance_variables defined within the current context: - -``` -@posts = Post.all -(rdb:11) instance_variables -["@_response", "@action_name", "@url", "@_session", "@_cookies", "@performed_render", "@_flash", "@template", "@_params", "@before_filter_chain_aborted", "@request_origin", "@_headers", "@performed_redirect", "@_request"] -``` - -As you may have figured out, all of the variables that you can access from a controller are displayed. This list is dynamically updated as you execute code. For example, run the next line using `next` (you'll learn more about this command later in this guide). - -``` -(rdb:11) next -Processing PostsController#index (for 127.0.0.1 at 2008-09-04 19:51:34) [GET] - Session ID: BAh7BiIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNoSGFzaHsABjoKQHVzZWR7AA==--b16e91b992453a8cc201694d660147bba8b0fd0e - Parameters: {"action"=>"index", "controller"=>"posts"} -/PathToProject/posts_controller.rb:8 -respond_to do |format| +Any expression can be evaluated in the current context. To evaluate an +expression, just type it! + +This example shows how you can print the instance variables defined within the +current context: + +``` +[3, 12] in /PathTo/project/app/controllers/posts_controller.rb + 3: + 4: # GET /posts + 5: # GET /posts.json + 6: def index + 7: byebug +=> 8: @posts = Post.find_recent + 9: + 10: respond_to do |format| + 11: format.html # index.html.erb + 12: format.json { render json: @posts } + +(byebug) instance_variables +[:@_action_has_layout, :@_routes, :@_headers, :@_status, :@_request, + :@_response, :@_env, :@_prefixes, :@_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 +controller are displayed. This list is dynamically updated as you execute code. +For example, run the next line using `next` (you'll learn more about this +command later in this guide). + +``` +(byebug) next +[5, 14] in /PathTo/project/app/controllers/posts_controller.rb + 5 # GET /posts.json + 6 def index + 7 byebug + 8 @posts = Post.find_recent + 9 +=> 10 respond_to do |format| + 11 format.html # index.html.erb + 12 format.json { render json: @posts } + 13 end + 14 end + 15 +(byebug) ``` And then ask again for the instance_variables: ``` -(rdb:11) instance_variables.include? "@posts" +(byebug) instance_variables.include? "@posts" true ``` -Now `@posts` is included in the instance variables, because the line defining it was executed. +Now `@posts` 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 way an irb session will be started within the context you invoked it. But be warned: this is an experimental feature. +TIP: You can also step into **irb** mode with the command `irb` (of course!). +This way an irb session will be started within the context you invoked it. But +be warned: this is an experimental feature. -The `var` method is the most convenient way to show variables and their values: +The `var` method is the most convenient way to show variables and their values. +Let's let `byebug` to help us with it. ``` -var -(rdb:1) v[ar] const <object> show constants of object -(rdb:1) v[ar] g[lobal] show global variables -(rdb:1) v[ar] i[nstance] <object> show instance variables of object -(rdb:1) v[ar] l[ocal] show local variables +(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 ``` -This is a great way to inspect the values of the current context variables. For example: +This is a great way to inspect the values of the current context variables. For +example, to check that we have no local variables currently defined. ``` -(rdb:9) var local - __dbg_verbose_save => false +(byebug) var local +(byebug) ``` You can also inspect for an object method this way: ``` -(rdb:9) var instance Post.new -@attributes = {"updated_at"=>nil, "body"=>nil, "title"=>nil, "published"=>nil, "created_at"... +(byebug) var instance Post.new +@_start_transaction_state = {} +@aggregation_cache = {} +@association_cache = {} +@attributes = {"id"=>nil, "created_at"=>nil, "updated_at"=>nil} @attributes_cache = {} -@new_record = true +@changed_attributes = 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. +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 tracking the values of a variable while the execution goes on. +You can use also `display` to start watching variables. This is a good way of +tracking the values of a variable while the execution goes on. ``` -(rdb:1) display @recent_comments -1: @recent_comments = +(byebug) display @posts +1: @posts = nil ``` -The variables inside the displaying list will be printed with their values after you move in the stack. To stop displaying a variable use `undisplay _n_` where _n_ is the variable number (1 in the last example). +The variables inside the displaying list will be printed with their values after +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 -Now you should know where you are in the running trace and be able to print the available variables. But lets continue and move on with the application execution. +Now you should know where you are in the running trace and be able to print the +available variables. But lets 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. +Use `step` (abbreviated `s`) to continue running your program until the next +logical stopping point and return control to the debugger. -TIP: You can also use `step+ n` and `step- n` to move forward or backward `n` steps respectively. +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. -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. As with step, you may use plus sign to move _n_ steps. +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. +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. -For example, consider this block of code with an included `debugger` statement: +For example, consider the following situation: ```ruby -class Author < ActiveRecord::Base - has_one :editorial - has_many :comments +Started GET "/" for 127.0.0.1 at 2014-04-11 13:39:23 +0200 +Processing by PostsController#index as HTML - def find_recent_comments(limit = 10) - debugger - @recent_comments ||= comments.where("created_at > ?", 1.week.ago).limit(limit) - end -end +[1, 8] in /home/davidr/Proyectos/test_app/app/models/post.rb + 1: class Post < 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 + +(byebug) ``` -TIP: You can use the debugger while using `rails console`. Just remember to `require "debugger"` before calling the `debugger` method. +If we use `next`, we want go deep inside method calls. Instead, byebug will go +to the next line within the same context. In this case, this is the last line of +the method, so `byebug` will jump to next next line of the previous frame. ``` -$ rails console -Loading development environment (Rails 4.0.0) ->> require "debugger" -=> [] ->> author = Author.first -=> #<Author id: 1, first_name: "Bob", last_name: "Smith", created_at: "2008-07-31 12:46:10", updated_at: "2008-07-31 12:46:10"> ->> author.find_recent_comments -/PathTo/project/app/models/author.rb:11 -) -``` +(byebug) next +Next went up a frame because previous frame finished -With the code stopped, take a look around: +[4, 13] in /PathTo/project/test_app/app/controllers/posts_controller.rb + 4: # GET /posts + 5: # GET /posts.json + 6: def index + 7: @posts = Post.find_recent + 8: +=> 9: respond_to do |format| + 10: format.html # index.html.erb + 11: format.json { render json: @posts } + 12: end + 13: end -``` -(rdb:1) list -[2, 9] in /PathTo/project/app/models/author.rb - 2 has_one :editorial - 3 has_many :comments - 4 - 5 def find_recent_comments(limit = 10) - 6 debugger -=> 7 @recent_comments ||= comments.where("created_at > ?", 1.week.ago).limit(limit) - 8 end - 9 end +(byebug) ``` -You are at the end of the line, but... was this line executed? You can inspect the instance variables. +If we use `step` in the same situation, we will literally go the next ruby +instruction to be executed. In this case, the activesupport's `week` method. ``` -(rdb:1) var instance -@attributes = {"updated_at"=>"2008-07-31 12:46:10", "id"=>"1", "first_name"=>"Bob", "las... -@attributes_cache = {} -``` +(byebug) step -`@recent_comments` hasn't been defined yet, so it's clear that this line hasn't been executed yet. Use the `next` command to move on in the code: +[50, 59] in /PathToGems/activesupport-4.1.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 +(byebug) ``` -(rdb:1) next -/PathTo/project/app/models/author.rb:12 -@recent_comments -(rdb:1) var instance -@attributes = {"updated_at"=>"2008-07-31 12:46:10", "id"=>"1", "first_name"=>"Bob", "las... -@attributes_cache = {} -@comments = [] -@recent_comments = [] -``` - -Now you can see that the `@comments` relationship was loaded and @recent_comments defined because the line was executed. -If you want to go deeper into the stack trace you can move single `steps`, through your calling methods and into Rails code. This is one of the best ways to find bugs in your code, or perhaps in Ruby or Rails. +This is one of the best ways to find bugs in your code, or perhaps in Ruby on +Rails. ### Breakpoints -A breakpoint makes your application stop whenever a certain point in the program is reached. The debugger shell is invoked in that line. +A breakpoint makes your application stop whenever a certain point in the program +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: +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 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. +* `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 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. + + +For example, in the previous situation ``` -(rdb:5) break 10 -Breakpoint 1 file /PathTo/project/vendor/rails/actionpack/lib/action_controller/filters.rb, line 10 +[4, 13] in /PathTo/project/app/controllers/posts_controller.rb + 4: # GET /posts + 5: # GET /posts.json + 6: def index + 7: @posts = Post.find_recent + 8: +=> 9: respond_to do |format| + 10: format.html # index.html.erb + 11: format.json { render json: @posts } + 12: end + 13: end + +(byebug) break 11 +Created breakpoint 1 at /PathTo/project/app/controllers/posts_controller.rb:11 + ``` -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 _n_` or `info break _n_` to list breakpoints. If you +supply a number, it lists that breakpoint. Otherwise it lists all breakpoints. ``` -(rdb:5) info breakpoints +(byebug) info breakpoints Num Enb What - 1 y at filters.rb:10 +1 y at /PathTo/project/app/controllers/posts_controller.rb:11 ``` -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.. +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. ``` -(rdb:5) delete 1 -(rdb:5) info breakpoints +(byebug) delete 1 +(byebug) info breakpoints No breakpoints. ``` You can also enable or disable breakpoints: -* `enable breakpoints`: allow a list _breakpoints_ or all of them if no list is specified, to stop your program. This is the default state when you create a breakpoint. +* `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 +breakpoint. * `disable breakpoints`: the _breakpoints_ will have no effect on your program. ### Catching Exceptions -The command `catch exception-name` (or just `cat exception-name`) can be used to intercept an exception of type _exception-name_ when there would otherwise be is no handler for it. +The command `catch exception-name` (or just `cat exception-name`) can be used to +intercept an exception of type _exception-name_ when there would otherwise be no +handler for it. To list all active catchpoints use `catch`. ### Resuming Execution -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. +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. ### 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. -* `tmate _n_` (abbreviated `tm`): open the current file in TextMate. It uses n-th frame if _n_ is specified. +* `edit [file:line]`: edit _file_ using the editor specified by the EDITOR +environment variable. A specific _line_ can also be given. ### Quitting -To exit the debugger, use the `quit` command (abbreviated `q`), or its alias `exit`. +To exit the debugger, use the `quit` command (abbreviated `q`), or its alias +`exit`. -A simple quit tries to terminate all threads in effect. Therefore your server will be stopped and you will have to start it again. +A simple quit tries to terminate all threads in effect. Therefore your server +will be stopped and you will have to start it again. ### Settings -The `debugger` gem can automatically show the code you're stepping through and reload it when you change it in an editor. Here are a few of the available options: - -* `set reload`: Reload source code when changed. -* `set autolist`: Execute `list` command on every breakpoint. -* `set listsize _n_`: Set number of source lines to list by default to _n_. -* `set forcestep`: Make sure the `next` and `step` commands always move to a new line +`byebug` has a few available options to tweak its behaviour: -You can see the full list by using `help set`. Use `help set _subcommand_` to learn about a particular `set` command. +* `set autoreload`: Reload source code when changed (default: true). +* `set autolist`: Execute `list` command on every breakpoint (default: true). +* `set listsize _n_`: Set number of source lines to list by default to _n_ +(default: 10) +* `set forcestep`: Make sure the `next` and `step` commands always move to a new +line. -TIP: You can save these settings in an `.rdebugrc` file in your home directory. The debugger reads these global settings when it starts. +You can see the full list by using `help set`. Use `help set _subcommand_` to +learn about a particular `set` command. -Here's a good start for an `.rdebugrc`: +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 autolist set forcestep set listsize 25 ``` @@ -671,35 +801,59 @@ set listsize 25 Debugging Memory Leaks ---------------------- -A Ruby application (on Rails or not), can leak memory - either in the Ruby code or at the C code level. +A Ruby application (on Rails or not), can leak memory - either in the Ruby code +or at the C code level. -In this section, you will learn how to find and fix such leaks by using tool such as Valgrind. +In this section, you will learn how to find and fix such leaks by using tool +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 a Linux-only 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 extension in the interpreter calls `malloc()` but doesn't properly call `free()`, this memory won't be available until the app terminates. +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 +extension in the interpreter calls `malloc()` but doesn't properly call +`free()`, this memory won't be available until the app terminates. -For further information on how to install Valgrind and use with Ruby, refer to [Valgrind and Ruby](http://blog.evanweaver.com/articles/2008/02/05/valgrind-and-ruby/) by Evan Weaver. +For further information on how to install Valgrind and use with Ruby, refer to +[Valgrind and Ruby](http://blog.evanweaver.com/articles/2008/02/05/valgrind-and-ruby/) +by Evan Weaver. Plugins for Debugging --------------------- -There are some Rails plugins to help you to find errors and debug your application. Here is a list of useful plugins for debugging: - -* [Footnotes](https://github.com/josevalim/rails-footnotes) Every Rails page has footnotes that give request information and link back to your source via TextMate. -* [Query Trace](https://github.com/ntalbott/query_trace/tree/master) Adds query origin tracing to your logs. -* [Query Reviewer](https://github.com/nesquena/query_reviewer) This rails plugin not only runs "EXPLAIN" before each of your select queries in development, but provides a small DIV in the rendered output of each page with the summary of warnings for each query that it analyzed. -* [Exception Notifier](https://github.com/smartinez87/exception_notification/tree/master) Provides a mailer object and a default set of templates for sending email notifications when errors occur in a Rails application. -* [Better Errors](https://github.com/charliesome/better_errors) Replaces the standard Rails error page with a new one containing more contextual information, like source code and variable inspection. -* [RailsPanel](https://github.com/dejan/rails_panel) Chrome extension for Rails development that will end your tailing of development.log. Have all information about your Rails app requests in the browser - in the Developer Tools panel. Provides insight to db/rendering/total times, parameter list, rendered views and more. +There are some Rails plugins to help you to find errors and debug your +application. Here is a list of useful plugins for debugging: + +* [Footnotes](https://github.com/josevalim/rails-footnotes) Every Rails page has +footnotes that give request information and link back to your source via +TextMate. +* [Query Trace](https://github.com/ntalbott/query_trace/tree/master) Adds query +origin tracing to your logs. +* [Query Reviewer](https://github.com/nesquena/query_reviewer) This rails plugin +not only runs "EXPLAIN" before each of your select queries in development, but +provides a small DIV in the rendered output of each page with the summary of +warnings for each query that it analyzed. +* [Exception Notifier](https://github.com/smartinez87/exception_notification/tree/master) +Provides a mailer object and a default set of templates for sending email +notifications when errors occur in a Rails application. +* [Better Errors](https://github.com/charliesome/better_errors) Replaces the +standard Rails error page with a new one containing more contextual information, +like source code and variable inspection. +* [RailsPanel](https://github.com/dejan/rails_panel) Chrome extension for Rails +development that will end your tailing of development.log. Have all information +about your Rails app requests in the browser - in the Developer Tools panel. +Provides insight to db/rendering/total times, parameter list, rendered views and +more. References ---------- * [ruby-debug Homepage](http://bashdb.sourceforge.net/ruby-debug/home-page.html) * [debugger Homepage](https://github.com/cldwalker/debugger) +* [byebug Homepage](https://github.com/deivid-rodriguez/byebug) * [Article: Debugging a Rails application with ruby-debug](http://www.sitepoint.com/debug-rails-app-ruby-debug/) * [Ryan Bates' debugging ruby (revised) screencast](http://railscasts.com/episodes/54-debugging-ruby-revised) * [Ryan Bates' stack trace screencast](http://railscasts.com/episodes/24-the-stack-trace) diff --git a/guides/source/development_dependencies_install.md b/guides/source/development_dependencies_install.md index 4ee43b6a97..b0e070120d 100644 --- a/guides/source/development_dependencies_install.md +++ b/guides/source/development_dependencies_install.md @@ -117,7 +117,7 @@ This command will install all dependencies except the MySQL and PostgreSQL Ruby NOTE: If you would like to run the tests that use memcached, you need to ensure that you have it installed and running. -You can use homebrew to install memcached on OSX: +You can use [Homebrew](http://brew.sh/) to install memcached on OSX: ```bash $ brew install memcached @@ -210,6 +210,14 @@ FreeBSD users will have to run the following: # pkg_add -r postgresql92-client postgresql92-server ``` +You can use [Homebrew](http://brew.sh/) to install MySQL and PostgreSQL on OSX: + +```bash +$ brew install mysql +$ brew install postgresql +``` +Follow instructions given by [Homebrew](http://brew.sh/) to start these. + Or install them through ports (they are located under the `databases` folder). If you run into troubles during the installation of MySQL, please see [the MySQL documentation](http://dev.mysql.com/doc/refman/5.1/en/freebsd-installation.html). @@ -245,10 +253,15 @@ $ bundle exec rake mysql:build_databases ``` PostgreSQL's authentication works differently. A simple way to set up the development environment for example is to run with your development account +This is not needed when installed via [Homebrew](http://brew.sh). ```bash $ sudo -u postgres createuser --superuser $USER ``` +And for OS X (when installed via [Homebrew](http://brew.sh)) +```bash +$ createuser --superuser $USER +``` and then create the test databases with diff --git a/guides/source/documents.yaml b/guides/source/documents.yaml index e4653b47fc..a160c462b2 100644 --- a/guides/source/documents.yaml +++ b/guides/source/documents.yaml @@ -167,7 +167,6 @@ - name: Ruby on Rails 4.1 Release Notes url: 4_1_release_notes.html - work_in_progress: true description: Release notes for Rails 4.1. - name: Ruby on Rails 4.0 Release Notes diff --git a/guides/source/engines.md b/guides/source/engines.md index bbd63bb892..8f9ba0995f 100644 --- a/guides/source/engines.md +++ b/guides/source/engines.md @@ -1052,6 +1052,16 @@ This tells the application that you still want to perform a `GET` request to the `index` action of this controller, but you want to use the engine's route to get there, rather than the application's one. +Another way to do this is to assign the `@routes` instance variable to `Engine.routes` in your test setup: + +```ruby +setup do + @routes = Engine.routes +end +``` + +This will also ensure url helpers for the engine will work as expected in your tests. + Improving engine functionality ------------------------------ diff --git a/guides/source/form_helpers.md b/guides/source/form_helpers.md index 455dc7bebe..027b6303fc 100644 --- a/guides/source/form_helpers.md +++ b/guides/source/form_helpers.md @@ -1,16 +1,16 @@ Form Helpers ============ -Forms in web applications are an essential interface for user input. However, form markup can quickly become tedious to write and maintain because of form control naming and their numerous attributes. Rails does away with these complexities by providing view helpers for generating form markup. However, since they have different use-cases, developers are required to know all the differences between similar helper methods before putting them to use. +Forms in web applications are an essential interface for user input. However, form markup can quickly become tedious to write and maintain because of the need to handle form control naming and its numerous attributes. Rails does away with this complexity by providing view helpers for generating form markup. However, since these helpers have different use cases, developers need to know the differences between the helper methods before putting them to use. After reading this guide, you will know: * How to create search forms and similar kind of generic forms not representing any specific model in your application. -* How to make model-centric forms for creation and editing of specific database records. +* How to make model-centric forms for creating and editing specific database records. * How to generate select boxes from multiple types of data. -* The date and time helpers Rails provides. +* What date and time helpers Rails provides. * What makes a file upload form different. -* Some cases of building forms to external resources. +* How to post forms to external resources and specify setting an `authenticity_token`. * How to build complex forms. -------------------------------------------------------------------------------- @@ -146,7 +146,7 @@ Output: <label for="age_adult">I'm over 21</label> ``` -As with `check_box_tag`, the second parameter to `radio_button_tag` is the value of the input. Because these two radio buttons share the same name (age) the user will only be able to select one, and `params[:age]` will contain either "child" or "adult". +As with `check_box_tag`, the second parameter to `radio_button_tag` is the value of the input. Because these two radio buttons share the same name (`age`), the user will only be able to select one of them, and `params[:age]` will contain either "child" or "adult". NOTE: Always use labels for checkbox and radio buttons. They associate text with a specific option and, by expanding the clickable region, @@ -442,7 +442,12 @@ WARNING: when `:include_blank` or `:prompt` are not present, `:include_blank` is You can add arbitrary attributes to the options using hashes: ```html+erb -<%= options_for_select([['Lisbon', 1, {'data-size' => '2.8 million'}], ['Madrid', 2, {'data-size' => '3.2 million'}]], 2) %> +<%= options_for_select( + [ + ['Lisbon', 1, { 'data-size' => '2.8 million' }], + ['Madrid', 2, { 'data-size' => '3.2 million' }] + ], 2 +) %> output: @@ -474,6 +479,16 @@ As with other helpers, if you were to use the `select` helper on a form builder <%= f.select(:city_id, ...) %> ``` +You can also pass a block to `select` helper: + +```erb +<%= f.select(:city_id) do %> + <% [['Lisbon', 1], ['Madrid', 2]].each do |c| -%> + <%= content_tag(:option, c.first, value: c.last) %> + <% end %> +<% end %> +``` + WARNING: If you are using `select` (or similar helpers such as `collection_select`, `select_tag`) to set a `belongs_to` association you must pass the name of the foreign key (in the example above `city_id`), not the name of association itself. If you specify `city` instead of `city_id` Active Record will raise an error along the lines of ` ActiveRecord::AssociationTypeMismatch: City(#17815740) expected, got String(#1138750) ` when you pass the `params` hash to `Person.new` or `update`. Another way of looking at this is that form helpers only edit attributes. You should also be aware of the potential security ramifications of allowing users to edit foreign keys directly. ### Option Tags from a Collection of Arbitrary Objects @@ -809,21 +824,21 @@ As a shortcut you can append [] to the name and omit the `:index` option. This i produces exactly the same output as the previous example. -Forms to external resources +Forms to External Resources --------------------------- -If you need to post some data to an external resource it is still great to build your form using rails form helpers. But sometimes you need to set an `authenticity_token` for this resource. You can do it by passing an `authenticity_token: 'your_external_token'` parameter to the `form_tag` options: +Rails' form helpers can also be used to build a form for posting data to an external resource. However, at times it can be necessary to set an `authenticity_token` for the resource; this can be done by passing an `authenticity_token: 'your_external_token'` parameter to the `form_tag` options: ```erb -<%= form_tag 'http://farfar.away/form', authenticity_token: 'external_token') do %> +<%= form_tag 'http://farfar.away/form', authenticity_token: 'external_token' do %> Form contents <% end %> ``` -Sometimes when you submit data to an external resource, like payment gateway, fields you can use in your form are limited by an external API. So you may want not to generate an `authenticity_token` hidden field at all. For doing this just pass `false` to the `:authenticity_token` option: +Sometimes when submitting data to an external resource, like a payment gateway, the fields that can be used in the form are limited by an external API and it may be undesirable to generate an `authenticity_token`. To not send a token, simply pass `false` to the `:authenticity_token` option: ```erb -<%= form_tag 'http://farfar.away/form', authenticity_token: false) do %> +<%= form_tag 'http://farfar.away/form', authenticity_token: false do %> Form contents <% end %> ``` @@ -998,4 +1013,4 @@ As a convenience you can instead pass the symbol `:all_blank` which will create ### Adding Fields on the Fly -Rather than rendering multiple sets of fields ahead of time you may wish to add them only when a user clicks on an 'Add new address' button. Rails does not provide any builtin support for this. When generating new sets of fields you must ensure the key of the associated array is unique - the current JavaScript date (milliseconds after the epoch) is a common choice. +Rather than rendering multiple sets of fields ahead of time you may wish to add them only when a user clicks on an 'Add new address' button. Rails does not provide any built-in support for this. When generating new sets of fields you must ensure the key of the associated array is unique - the current JavaScript date (milliseconds after the epoch) is a common choice. diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md index a16b9ac8da..8966eef76a 100644 --- a/guides/source/getting_started.md +++ b/guides/source/getting_started.md @@ -57,9 +57,9 @@ learned elsewhere, you may have a less happy experience. The Rails philosophy includes two major guiding principles: -* **Don't Repeat Yourself:** DRY is a principle of software development which +* **Don't Repeat Yourself:** DRY is a principle of software development which states that "Every piece of knowledge must have a single, unambiguous, authoritative - representation within a system." By not writing the same information over and over + representation within a system." By not writing the same information over and over again, our code is more maintainable, more extensible, and less buggy. * **Convention Over Configuration:** Rails has opinions about the best way to do many things in a web application, and defaults to this set of conventions, rather than @@ -99,7 +99,7 @@ ruby 2.0.0p353 ``` If you don't have Ruby installed have a look at -[ruby-lang.org](https://www.ruby-lang.org/en/downloads/) for possible ways to +[ruby-lang.org](https://www.ruby-lang.org/en/installation/) for possible ways to install Ruby on your platform. Many popular UNIX-like OSes ship with an acceptable version of SQLite3. Windows @@ -206,7 +206,7 @@ This will fire up WEBrick, a web server distributed with Ruby 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: -![Welcome aboard screenshot](images/getting_started/rails_welcome.jpg) +![Welcome aboard screenshot](images/getting_started/rails_welcome.png) TIP: To stop the web server, hit Ctrl+C in the terminal window where it's running. To verify the server has stopped you should see your command prompt @@ -344,7 +344,7 @@ resource. Here's what `config/routes.rb` should look like after the _article resource_ is declared. ```ruby -Blog::Application.routes.draw do +Rails.application.routes.draw do resources :articles @@ -612,7 +612,7 @@ def create end ``` -The `render` method here is taking a very simple hash with a key of `text` and +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 @@ -749,10 +749,33 @@ article. Try it! You should get an error that looks like this: Rails has several security features that help you write secure applications, and you're running into one of them now. This one is called -`strong_parameters`, which requires us to tell Rails exactly which parameters -we want to accept in our controllers. In this case, we want to allow the -`title` and `text` parameters, so change your `create` controller action to -look like this: +`[strong_parameters](http://guides.rubyonrails.org/action_controller_overview.html#strong-parameters)`, +which requires us to tell Rails exactly which parameters are allowed into +our controller actions. + +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 be 'mass assigned' into your model and then into the +database along with the good stuff - potentially breaking your application +or worse. + +We have to whitelist our controller parameters to prevent wrongful +mass assignment. In this case, we want to both allow and require the +`title` and `text` parameters for valid use of `create`. The syntax for +this introduces `require` and `permit`. The change will involve one line: + +```ruby + @article = Article.new(params.require(:article).permit(:title, :text)) +``` + +This is often factored out into its own method so it can be reused by +multiple actions in the same controller, for example `create` and `update`. +Above and beyond mass assignment issues, the method is often made +`private` to make sure it can't be called outside its intended context. +Here is the result: ```ruby def create @@ -768,13 +791,7 @@ private end ``` -See the `permit`? It allows us to accept both `title` and `text` in this -action. - -TIP: Note that `def article_params` is private. This new approach prevents an -attacker from setting the model's attributes by manipulating the hash passed to -the model. -For more information, refer to +TIP: For more information, refer to the reference above and [this blog article about Strong Parameters](http://weblog.rubyonrails.org/2012/3/21/strong-parameters/). ### Showing Articles @@ -846,7 +863,7 @@ def index end ``` -And then finally, add view for this action, located at +And then finally, add the view for this action, located at `app/views/articles/index.html.erb`: ```html+erb @@ -900,7 +917,7 @@ Also add a link in `app/views/articles/new.html.erb`, underneath the form, to go back to the `index` action: ```erb -<%= form_for :article do |f| %> +<%= form_for :article, url: articles_path do |f| %> ... <% end %> @@ -1011,17 +1028,21 @@ something went wrong. To do that, you'll modify ```html+erb <%= form_for :article, url: articles_path do |f| %> + <% if @article.errors.any? %> - <div id="error_explanation"> - <h2><%= pluralize(@article.errors.count, "error") %> prohibited - this article from being saved:</h2> - <ul> - <% @article.errors.full_messages.each do |msg| %> - <li><%= msg %></li> - <% end %> - </ul> - </div> + <div id="error_explanation"> + <h2> + <%= pluralize(@article.errors.count, "error") %> prohibited + this article from being saved: + </h2> + <ul> + <% @article.errors.full_messages.each do |msg| %> + <li><%= msg %></li> + <% end %> + </ul> + </div> <% end %> + <p> <%= f.label :title %><br> <%= f.text_field :title %> @@ -1035,6 +1056,7 @@ something went wrong. To do that, you'll modify <p> <%= f.submit %> </p> + <% end %> <%= link_to 'Back', articles_path %> @@ -1083,17 +1105,21 @@ it look as follows: <h1>Editing article</h1> <%= form_for :article, url: article_path(@article), method: :patch do |f| %> + <% if @article.errors.any? %> - <div id="error_explanation"> - <h2><%= pluralize(@article.errors.count, "error") %> prohibited - this article from being saved:</h2> - <ul> - <% @article.errors.full_messages.each do |msg| %> - <li><%= msg %></li> - <% end %> - </ul> - </div> + <div id="error_explanation"> + <h2> + <%= pluralize(@article.errors.count, "error") %> prohibited + this article from being saved: + </h2> + <ul> + <% @article.errors.full_messages.each do |msg| %> + <li><%= msg %></li> + <% end %> + </ul> + </div> <% end %> + <p> <%= f.label :title %><br> <%= f.text_field :title %> @@ -1107,6 +1133,7 @@ it look as follows: <p> <%= f.submit %> </p> + <% end %> <%= link_to 'Back', articles_path %> @@ -1119,10 +1146,10 @@ The `method: :patch` option tells Rails that we want this form to be submitted via the `PATCH` HTTP method which is the HTTP method you're expected to use to **update** resources according to the REST protocol. -The first parameter of the `form_tag` can be an object, say, `@article` which would +The first parameter of `form_for` can be an object, say, `@article` which would cause the helper to fill in the form with the fields of the object. Passing in a -symbol (`:article`) with the same name as the instance variable (`@article`) also -automagically leads to the same behavior. This is what is happening here. More details +symbol (`:article`) with the same name as the instance variable (`@article`) also +automagically leads to the same behavior. This is what is happening here. More details can be found in [form_for documentation](http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-form_for). Next we need to create the `update` action in @@ -1170,14 +1197,14 @@ it appear next to the "Show" link: <th colspan="2"></th> </tr> -<% @articles.each do |article| %> - <tr> - <td><%= article.title %></td> - <td><%= article.text %></td> - <td><%= link_to 'Show', article_path(article) %></td> - <td><%= link_to 'Edit', edit_article_path(article) %></td> - </tr> -<% end %> + <% @articles.each do |article| %> + <tr> + <td><%= article.title %></td> + <td><%= article.text %></td> + <td><%= link_to 'Show', article_path(article) %></td> + <td><%= link_to 'Edit', edit_article_path(article) %></td> + </tr> + <% end %> </table> ``` @@ -1211,17 +1238,21 @@ content: ```html+erb <%= form_for @article do |f| %> + <% if @article.errors.any? %> - <div id="error_explanation"> - <h2><%= pluralize(@article.errors.count, "error") %> prohibited - this article from being saved:</h2> - <ul> - <% @article.errors.full_messages.each do |msg| %> - <li><%= msg %></li> - <% end %> - </ul> - </div> + <div id="error_explanation"> + <h2> + <%= pluralize(@article.errors.count, "error") %> prohibited + this article from being saved: + </h2> + <ul> + <% @article.errors.full_messages.each do |msg| %> + <li><%= msg %></li> + <% end %> + </ul> + </div> <% end %> + <p> <%= f.label :title %><br> <%= f.text_field :title %> @@ -1235,6 +1266,7 @@ content: <p> <%= f.submit %> </p> + <% end %> ``` @@ -1316,16 +1348,17 @@ together. <th colspan="3"></th> </tr> -<% @articles.each do |article| %> - <tr> - <td><%= article.title %></td> - <td><%= article.text %></td> - <td><%= link_to 'Show', article_path(article) %></td> - <td><%= link_to 'Edit', edit_article_path(article) %></td> - <td><%= link_to 'Destroy', article_path(article), - method: :delete, data: { confirm: 'Are you sure?' } %></td> - </tr> -<% end %> + <% @articles.each do |article| %> + <tr> + <td><%= article.title %></td> + <td><%= article.text %></td> + <td><%= link_to 'Show', article_path(article) %></td> + <td><%= link_to 'Edit', edit_article_path(article) %></td> + <td><%= link_to 'Destroy', article_path(article), + method: :delete, + data: { confirm: 'Are you sure?' } %></td> + </tr> + <% end %> </table> ``` @@ -1396,7 +1429,7 @@ class CreateComments < ActiveRecord::Migration t.text :body # this line adds an integer column called `article_id`. - t.references :article, index: true + t.references :article, index: true t.timestamps end @@ -1535,8 +1568,8 @@ So first, we'll wire up the Article show template </p> <% end %> -<%= link_to 'Back', articles_path %> -| <%= link_to 'Edit', edit_article_path(@article) %> +<%= link_to 'Back', articles_path %> | +<%= link_to 'Edit', edit_article_path(@article) %> ``` This adds a form on the `Article` show page that creates a new comment by @@ -1806,7 +1839,7 @@ database and send us back to the show action for the article. ### Deleting Associated Objects -If you delete an article then its associated comments will also need to be +If you delete an article, its associated comments will also need to be deleted. Otherwise they would simply occupy space in the database. Rails allows you to use the `dependent` option of an association to achieve this. Modify the Article model, `app/models/article.rb`, as follows: @@ -1824,21 +1857,21 @@ Security ### Basic Authentication -If you were to publish your blog online, anybody would be able to add, edit and +If you were to publish your blog online, anyone would be able to add, edit and delete articles or delete comments. Rails provides a very simple HTTP authentication system that will work nicely in this situation. -In the `ArticlesController` we need to have a way to block access to the various -actions if the person is not authenticated, here we can use the Rails -`http_basic_authenticate_with` method, allowing access to the requested +In the `ArticlesController` we need to have a way to block access to the +various actions if the person is not authenticated. Here we can use the Rails +`http_basic_authenticate_with` method, which allows access to the requested action if that method allows it. To use the authentication system, we specify it at the top of our -`ArticlesController`, in this case, we want the user to be authenticated on -every action, except for `index` and `show`, so we write that in -`app/controllers/articles_controller.rb`: +`ArticlesController` in `app/controllers/articles_controller.rb`. In our case, +we want the user to be authenticated on every action except `index` and `show`, +so we write that: ```ruby class ArticlesController < ApplicationController diff --git a/guides/source/i18n.md b/guides/source/i18n.md index d72717fa3b..c1b575c7b7 100644 --- a/guides/source/i18n.md +++ b/guides/source/i18n.md @@ -92,7 +92,7 @@ Rails adds all `.rb` and `.yml` files from the `config/locales` directory to you The default `en.yml` locale in this directory contains a sample pair of translation strings: -```ruby +```yaml en: hello: "Hello world" ``` @@ -137,7 +137,7 @@ If you want to translate your Rails application to a **single language other tha However, you would probably like to **provide support for more locales** in your application. In such case, you need to set and pass the locale between requests. -WARNING: You may be tempted to store the chosen locale in a _session_ or a <em>cookie</em>, however **do not do this**. The locale should be transparent and a part of the URL. This way you won't break people's basic assumptions about the web itself: if you send a URL to a friend, they should see the same page and content as you. A fancy word for this would be that you're being [<em>RESTful</em>](http://en.wikipedia.org/wiki/Representational_State_Transfer). Read more about the RESTful approach in [Stefan Tilkov's articles](http://www.infoq.com/articles/rest-introduction). Sometimes there are exceptions to this rule and those are discussed below. +WARNING: You may be tempted to store the chosen locale in a _session_ or a <em>cookie</em>. However, **do not do this**. The locale should be transparent and a part of the URL. This way you won't break people's basic assumptions about the web itself: if you send a URL to a friend, they should see the same page and content as you. A fancy word for this would be that you're being [<em>RESTful</em>](http://en.wikipedia.org/wiki/Representational_State_Transfer). Read more about the RESTful approach in [Stefan Tilkov's articles](http://www.infoq.com/articles/rest-introduction). Sometimes there are exceptions to this rule and those are discussed below. The _setting part_ is easy. You can set the locale in a `before_action` in the `ApplicationController` like this: @@ -179,7 +179,7 @@ end # in your /etc/hosts file to try this out locally def extract_locale_from_tld parsed_locale = request.host.split('.').last - I18n.available_locales.include?(parsed_locale.to_sym) ? parsed_locale : nil + I18n.available_locales.map(&:to_s).include?(parsed_locale) ? parsed_locale : nil end ``` @@ -192,7 +192,7 @@ We can also set the locale from the _subdomain_ in a very similar way: # in your /etc/hosts file to try this out locally def extract_locale_from_subdomain parsed_locale = request.subdomains.first - I18n.available_locales.include?(parsed_locale.to_sym) ? parsed_locale : nil + I18n.available_locales.map(&:to_s).include?(parsed_locale) ? parsed_locale : nil end ``` @@ -212,17 +212,16 @@ The most usual way of setting (and passing) the locale would be to include it in This approach has almost the same set of advantages as setting the locale from the domain name: namely that it's RESTful and in accord with the rest of the World Wide Web. It does require a little bit more work to implement, though. -Getting the locale from `params` and setting it accordingly is not hard; including it in every URL and thus **passing it through the requests** is. To include an explicit option in every URL (e.g. `link_to( books_url(locale: I18n.locale))`) would be tedious and probably impossible, of course. +Getting the locale from `params` and setting it accordingly is not hard; including it in every URL and thus **passing it through the requests** is. To include an explicit option in every URL, e.g. `link_to(books_url(locale: I18n.locale))`, would be tedious and probably impossible, of course. -Rails contains infrastructure for "centralizing dynamic decisions about the URLs" in its [`ApplicationController#default_url_options`](http://api.rubyonrails.org/classes/ActionController/Base.html#M000515), which is useful precisely in this scenario: it enables us to set "defaults" for [`url_for`](http://api.rubyonrails.org/classes/ActionController/Base.html#M000503) and helper methods dependent on it (by implementing/overriding this method). +Rails contains infrastructure for "centralizing dynamic decisions about the URLs" in its [`ApplicationController#default_url_options`](http://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Base.html#method-i-default_url_options), which is useful precisely in this scenario: it enables us to set "defaults" for [`url_for`](http://api.rubyonrails.org/classes/ActionDispatch/Routing/UrlFor.html#method-i-url_for) and helper methods dependent on it (by implementing/overriding this method). We can include something like this in our `ApplicationController` then: ```ruby # app/controllers/application_controller.rb -def default_url_options(options={}) - logger.debug "default_url_options is passed options: #{options.inspect}\n" - { locale: I18n.locale } +def default_url_options(options = {}) + { locale: I18n.locale }.merge options end ``` @@ -310,7 +309,7 @@ You most probably have something like this in one of your applications: ```ruby # config/routes.rb -Yourapp::Application.routes.draw do +Rails.application.routes.draw do root to: "home#index" end ``` @@ -370,7 +369,7 @@ NOTE: Rails adds a `t` (`translate`) helper method to your views so that you do So let's add the missing translations into the dictionary files (i.e. do the "localization" part): -```ruby +```yaml # config/locales/en.yml en: hello_world: Hello world! @@ -422,7 +421,7 @@ OK! Now let's add a timestamp to the view, so we can demo the **date/time locali And in our pirate translations file let's add a time format (it's already there in Rails' defaults for English): -```ruby +```yaml # config/locales/pirate.yml pirate: time: @@ -681,62 +680,13 @@ NOTE: Automatic conversion to HTML safe translate text is only available from th ![i18n demo html safe](images/i18n/demo_html_safe.png) -How to Store your Custom Translations -------------------------------------- - -The Simple backend shipped with Active Support allows you to store translations in both plain Ruby and YAML format.[^2] - -For example a Ruby Hash providing translations can look like this: - -```ruby -{ - pt: { - foo: { - bar: "baz" - } - } -} -``` - -The equivalent YAML file would look like this: - -```ruby -pt: - foo: - bar: baz -``` - -As you see, in both cases the top level key is the locale. `:foo` is a namespace key and `:bar` is the key for the translation "baz". - -Here is a "real" example from the Active Support `en.yml` translations YAML file: - -```ruby -en: - date: - formats: - default: "%Y-%m-%d" - short: "%b %d" - long: "%B %d, %Y" -``` - -So, all of the following equivalent lookups will return the `:short` date format `"%b %d"`: - -```ruby -I18n.t 'date.formats.short' -I18n.t 'formats.short', scope: :date -I18n.t :short, scope: 'date.formats' -I18n.t :short, scope: [:date, :formats] -``` - -Generally we recommend using YAML as a format for storing translations. There are cases, though, where you want to store Ruby lambdas as part of your locale data, e.g. for special date formats. - ### Translations for Active Record Models You can use the methods `Model.model_name.human` and `Model.human_attribute_name(attribute)` to transparently look up translations for your model and attribute names. For example when you add the following translations: -```ruby +```yaml en: activerecord: models: @@ -751,7 +701,7 @@ Then `User.model_name.human` will return "Dude" and `User.human_attribute_name(" You can also set a plural form for model names, adding as following: -```ruby +```yaml en: activerecord: models: @@ -921,6 +871,55 @@ Rails uses fixed strings and other localizations, such as format strings and oth * `Array#to_sentence` uses format settings as given in the [support.array](https://github.com/rails/rails/blob/master/activesupport/lib/active_support/locale/en.yml#L33) scope. +How to Store your Custom Translations +------------------------------------- + +The Simple backend shipped with Active Support allows you to store translations in both plain Ruby and YAML format.[^2] + +For example a Ruby Hash providing translations can look like this: + +```yaml +{ + pt: { + foo: { + bar: "baz" + } + } +} +``` + +The equivalent YAML file would look like this: + +```yaml +pt: + foo: + bar: baz +``` + +As you see, in both cases the top level key is the locale. `:foo` is a namespace key and `:bar` is the key for the translation "baz". + +Here is a "real" example from the Active Support `en.yml` translations YAML file: + +```yaml +en: + date: + formats: + default: "%Y-%m-%d" + short: "%b %d" + long: "%B %d, %Y" +``` + +So, all of the following equivalent lookups will return the `:short` date format `"%b %d"`: + +```ruby +I18n.t 'date.formats.short' +I18n.t 'formats.short', scope: :date +I18n.t :short, scope: 'date.formats' +I18n.t :short, scope: [:date, :formats] +``` + +Generally we recommend using YAML as a format for storing translations. There are cases, though, where you want to store Ruby lambdas as part of your locale data, e.g. for special date formats. + Customize your I18n Setup ------------------------- diff --git a/guides/source/initialization.md b/guides/source/initialization.md index ec3cec5c6f..00b2761716 100644 --- a/guides/source/initialization.md +++ b/guides/source/initialization.md @@ -166,6 +166,7 @@ is called. COMMAND_WHITELIST = %(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 @@ -178,8 +179,7 @@ With the `server` command, Rails will further run the following code: ```ruby def set_application_directory! - Dir.chdir(File.expand_path('../../', APP_PATH)) unless - File.exist?(File.expand_path("config.ru")) + Dir.chdir(File.expand_path('../../', APP_PATH)) unless File.exist?(File.expand_path("config.ru")) end def server @@ -187,6 +187,8 @@ def server require_command!("server") Rails::Server.new.tap do |server| + # We need to require application after the server sets environment, + # otherwise the --environment option given to the server won't propagate. require APP_PATH Dir.chdir(Rails.application.root) server.start @@ -207,6 +209,7 @@ sets up the `Rails::Server` class. require 'fileutils' require 'optparse' require 'action_dispatch' +require 'rails' module Rails class Server < ::Rack::Server @@ -273,7 +276,7 @@ def parse_options(args) # http://www.meb.uni-bonn.de/docs/cgi/cl.html args.clear if ENV.include?("REQUEST_METHOD") - options.merge! opt_parser.parse! args + options.merge! opt_parser.parse!(args) options[:config] = ::File.expand_path(options[:config]) ENV["RACK_ENV"] = options[:environment] options @@ -284,13 +287,16 @@ With the `default_options` set to this: ```ruby def default_options + environment = ENV['RACK_ENV'] || 'development' + default_host = environment == 'development' ? 'localhost' : '0.0.0.0' + { - environment: ENV['RACK_ENV'] || "development", - pid: nil, - Port: 9292, - Host: "0.0.0.0", - AccessLog: [], - config: "config.ru" + :environment => environment, + :pid => nil, + :Port => 9292, + :Host => default_host, + :AccessLog => [], + :config => "config.ru" } end ``` @@ -348,6 +354,7 @@ private def print_boot_information ... puts "=> Run `rails server -h` for more startup options" + ... puts "=> Ctrl-C to shutdown server" unless options[:daemonize] end @@ -434,7 +441,11 @@ The `app` method here is defined like so: ```ruby def app - @app ||= begin + @app ||= options[:builder] ? build_app_from_string : build_app_and_options_from_config +end +... +private + def build_app_and_options_from_config if !::File.exist? options[:config] abort "configuration #{options[:config]} not found" end @@ -443,7 +454,10 @@ def app self.options.merge! options app end -end + + def build_app_from_string + Rack::Builder.new_from_string(self.options[:builder]) + end ``` The `options[:config]` value defaults to `config.ru` which contains this: @@ -459,8 +473,14 @@ run <%= app_const %> The `Rack::Builder.parse_file` method here takes the content from this `config.ru` file and parses it using this code: ```ruby -app = eval "Rack::Builder.new {( " + cfgfile + "\n )}.to_app", - TOPLEVEL_BINDING, config +app = new_from_string cfgfile, config + +... + +def self.new_from_string(builder_script, file="(rackup)") + eval "Rack::Builder.new {\n" + builder_script + "\n}.to_app", + TOPLEVEL_BINDING, file, 0 +end ``` The `initialize` method of `Rack::Builder` will take the block here and execute it within an instance of `Rack::Builder`. This is where the majority of the initialization process of Rails happens. The `require` line for `config/environment.rb` in `config.ru` is the first to run: @@ -473,11 +493,22 @@ require ::File.expand_path('../config/environment', __FILE__) This file is the common file required by `config.ru` (`rails server`) and Passenger. This is where these two ways to run the server meet; everything before this point has been Rack and Rails setup. -This file begins with requiring `config/application.rb`. +This file begins with requiring `config/application.rb`: + +```ruby +require File.expand_path('../application', __FILE__) +``` ### `config/application.rb` -This file requires `config/boot.rb`, but only if it hasn't been required before, which would be the case in `rails server` but **wouldn't** be the case with Passenger. +This file requires `config/boot.rb`: + +```ruby +require File.expand_path('../boot', __FILE__) +``` + +But only if it hasn't been required before, which would be the case in `rails server` +but **wouldn't** be the case with Passenger. Then the fun begins! @@ -498,11 +529,12 @@ This file is responsible for requiring all the individual frameworks of Rails: require "rails" %w( - active_record - action_controller - action_mailer - rails/test_unit - sprockets + active_record + action_controller + action_view + action_mailer + rails/test_unit + sprockets ).each do |framework| begin require "#{framework}/railtie" @@ -526,7 +558,7 @@ The rest of `config/application.rb` defines the configuration for the initialized. When `config/application.rb` has finished loading Rails and defined the application namespace, we go back to `config/environment.rb`, where the application is initialized. For example, if the application was called -`Blog`, here we would find `Blog::Application.initialize!`, which is +`Blog`, here we would find `Rails.application.initialize!`, which is defined in `rails/application.rb` ### `railties/lib/rails/application.rb` @@ -555,7 +587,7 @@ def run_initializers(group=:default, *args) end ``` -The run_initializers code itself is tricky. What Rails is doing here is +The `run_initializers` code itself is tricky. What Rails is doing here is traversing all the class ancestors looking for those that respond to an `initializers` method. It then sorts the ancestors by name, and runs them. For example, the `Engine` class will make all the engines available by @@ -568,7 +600,7 @@ initializers (like building the middleware stack) are run last. The `railtie` initializers are the initializers which have been defined on the `Rails::Application` itself and are run between the `bootstrap` and `finishers`. -After this is done we go back to `Rack::Server` +After this is done we go back to `Rack::Server`. ### Rack: lib/rack/server.rb @@ -576,7 +608,11 @@ Last time we left when the `app` method was being defined: ```ruby def app - @app ||= begin + @app ||= options[:builder] ? build_app_from_string : build_app_and_options_from_config +end +... +private + def build_app_and_options_from_config if !::File.exist? options[:config] abort "configuration #{options[:config]} not found" end @@ -585,7 +621,10 @@ def app self.options.merge! options app end -end + + def build_app_from_string + Rack::Builder.new_from_string(self.options[:builder]) + end ``` At this point `app` is the Rails app itself (a middleware), and what @@ -603,7 +642,7 @@ def build_app(app) end ``` -Remember, `build_app` was called (by wrapped_app) in the last line of `Server#start`. +Remember, `build_app` was called (by `wrapped_app`) in the last line of `Server#start`. Here's how it looked like when we left: ```ruby @@ -611,40 +650,50 @@ server.run wrapped_app, options, &blk ``` At this point, the implementation of `server.run` will depend on the -server you're using. For example, if you were using Mongrel, here's what +server you're using. For example, if you were using Puma, here's what the `run` method would look like: ```ruby -def self.run(app, options={}) - server = ::Mongrel::HttpServer.new( - options[:Host] || '0.0.0.0', - options[:Port] || 8080, - options[:num_processors] || 950, - options[:throttle] || 0, - options[:timeout] || 60) - # Acts like Rack::URLMap, utilizing Mongrel's own path finding methods. - # Use is similar to #run, replacing the app argument with a hash of - # { path=>app, ... } or an instance of Rack::URLMap. - if options[:map] - if app.is_a? Hash - app.each do |path, appl| - path = '/'+path unless path[0] == ?/ - server.register(path, Rack::Handler::Mongrel.new(appl)) - end - elsif app.is_a? URLMap - app.instance_variable_get(:@mapping).each do |(host, path, appl)| - next if !host.nil? && !options[:Host].nil? && options[:Host] != host - path = '/'+path unless path[0] == ?/ - server.register(path, Rack::Handler::Mongrel.new(appl)) - end - else - raise ArgumentError, "first argument should be a Hash or URLMap" - end - else - server.register('/', Rack::Handler::Mongrel.new(app)) +... +DEFAULT_OPTIONS = { + :Host => '0.0.0.0', + :Port => 8080, + :Threads => '0:16', + :Verbose => false +} + +def self.run(app, options = {}) + options = DEFAULT_OPTIONS.merge(options) + + if options[:Verbose] + app = Rack::CommonLogger.new(app, STDOUT) end + + if options[:environment] + ENV['RACK_ENV'] = options[:environment].to_s + end + + server = ::Puma::Server.new(app) + min, max = options[:Threads].split(':', 2) + + puts "Puma #{::Puma::Const::PUMA_VERSION} starting..." + puts "* Min threads: #{min}, max threads: #{max}" + puts "* Environment: #{ENV['RACK_ENV']}" + puts "* Listening on tcp://#{options[:Host]}:#{options[:Port]}" + + server.add_tcp_listener options[:Host], options[:Port] + server.min_threads = min + server.max_threads = max yield server if block_given? - server.run.join + + begin + server.run.join + rescue Interrupt + puts "* Gracefully stopping, waiting for requests to finish" + server.stop(true) + puts "* Goodbye!" + end + end ``` @@ -654,4 +703,4 @@ the last piece of our journey in the Rails initialization process. This high level overview will help you understand when your code is executed and how, and overall become a better Rails developer. If you still want to know more, the Rails source code itself is probably the -best place to go next. +best place to go next.
\ No newline at end of file diff --git a/guides/source/layouts_and_rendering.md b/guides/source/layouts_and_rendering.md index 66ed6f2e08..bd33c5a146 100644 --- a/guides/source/layouts_and_rendering.md +++ b/guides/source/layouts_and_rendering.md @@ -304,10 +304,13 @@ type, by using the `:body` option to `render`: render body: "raw" ``` -TIP: This option should be used only if you explicitly want the content type to -be unset. Using `:plain` or `:html` might be more appropriate in most of the +TIP: This option should be used only if you don't care about the content type of +the response. Using `:plain` or `:html` might be more appropriate in most of the time. +NOTE: Unless overriden, your response returned from this render option will be +`text/html`, as that is the default content type of Action Dispatch response. + #### Options for `render` Calls to the `render` method generally accept four options: diff --git a/guides/source/maintenance_policy.md b/guides/source/maintenance_policy.md index 93729c6f72..8f119f36aa 100644 --- a/guides/source/maintenance_policy.md +++ b/guides/source/maintenance_policy.md @@ -20,7 +20,7 @@ Only the latest release series will receive bug fixes. When enough bugs are fixed and its deemed worthy to release a new gem, this is the branch it happens from. -**Currently included series:** 4.0.z +**Currently included series:** 4.1.z, 4.0.z Security Issues --------------- @@ -35,7 +35,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.0.z, 3.2.z +**Currently included series:** 4.1.z, 4.0.z Severe Security Issues ---------------------- @@ -44,7 +44,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.0.z, 3.2.z +**Currently included series:** 4.1.z, 4.0.z, 3.2.z Unsupported Release Series -------------------------- diff --git a/guides/source/migrations.md b/guides/source/migrations.md index 64c4e1e07e..c61ccfe94a 100644 --- a/guides/source/migrations.md +++ b/guides/source/migrations.md @@ -18,9 +18,10 @@ After reading this guide, you will know: Migration Overview ------------------ -Migrations are a convenient way to alter your database schema over time in a -consistent and easy way. They use a Ruby DSL so that you don't have to write -SQL by hand, allowing your schema and changes to be database independent. +Migrations are a convenient way to +[alter your database schema over time](http://en.wikipedia.org/wiki/Schema_migration) +in a consistent and easy way. They use a Ruby DSL so that you don't have to +write SQL by hand, allowing your schema and changes to be database independent. You can think of each migration as being a new 'version' of the database. A schema starts off with nothing in it, and each migration modifies it to add or @@ -494,6 +495,7 @@ class ExampleMigration < ActiveRecord::Migration add_column :users, :home_page_url, :string rename_column :users, :email, :email_address end +end ``` Using `reversible` will ensure that the instructions are executed in the @@ -818,159 +820,6 @@ The `revert` method can be helpful when writing a new migration to undo previous migrations in whole or in part (see [Reverting Previous Migrations](#reverting-previous-migrations) above). -Using Models in Your Migrations -------------------------------- - -When creating or updating data in a migration it is often tempting to use one -of your models. After all, they exist to provide easy access to the underlying -data. This can be done, but some caution should be observed. - -For example, problems occur when the model uses database columns which are (1) -not currently in the database and (2) will be created by this or a subsequent -migration. - -Consider this example, where Alice and Bob are working on the same code base -which contains a `Product` model: - -Bob goes on vacation. - -Alice creates a migration for the `products` table which adds a new column and -initializes it: - -```ruby -# db/migrate/20100513121110_add_flag_to_product.rb - -class AddFlagToProduct < ActiveRecord::Migration - def change - add_column :products, :flag, :boolean - reversible do |dir| - dir.up { Product.update_all flag: false } - end - end -end -``` - -She also adds a validation to the `Product` model for the new column: - -```ruby -# app/models/product.rb - -class Product < ActiveRecord::Base - validates :flag, inclusion: { in: [true, false] } -end -``` - -Alice adds a second migration which adds another column to the `products` -table and initializes it: - -```ruby -# db/migrate/20100515121110_add_fuzz_to_product.rb - -class AddFuzzToProduct < ActiveRecord::Migration - def change - add_column :products, :fuzz, :string - reversible do |dir| - dir.up { Product.update_all fuzz: 'fuzzy' } - end - end -end -``` - -She also adds a validation to the `Product` model for the new column: - -```ruby -# app/models/product.rb - -class Product < ActiveRecord::Base - validates :flag, inclusion: { in: [true, false] } - validates :fuzz, presence: true -end -``` - -Both migrations work for Alice. - -Bob comes back from vacation and: - -* Updates the source - which contains both migrations and the latest version - of the Product model. -* Runs outstanding migrations with `rake db:migrate`, which - includes the one that updates the `Product` model. - -The migration crashes because when the model attempts to save, it tries to -validate the second added column, which is not in the database when the _first_ -migration runs: - -``` -rake aborted! -An error has occurred, this and all later migrations canceled: - -undefined method `fuzz' for #<Product:0x000001049b14a0> -``` - -A fix for this is to create a local model within the migration. This keeps -Rails from running the validations, so that the migrations run to completion. - -When using a local model, it's a good idea to call -`Product.reset_column_information` to refresh the Active Record cache for the -`Product` model prior to updating data in the database. - -If Alice had done this instead, there would have been no problem: - -```ruby -# db/migrate/20100513121110_add_flag_to_product.rb - -class AddFlagToProduct < ActiveRecord::Migration - class Product < ActiveRecord::Base - end - - def change - add_column :products, :flag, :boolean - Product.reset_column_information - reversible do |dir| - dir.up { Product.update_all flag: false } - end - end -end -``` - -```ruby -# db/migrate/20100515121110_add_fuzz_to_product.rb - -class AddFuzzToProduct < ActiveRecord::Migration - class Product < ActiveRecord::Base - end - - def change - add_column :products, :fuzz, :string - Product.reset_column_information - reversible do |dir| - dir.up { Product.update_all fuzz: 'fuzzy' } - end - end -end -``` - -There are other ways in which the above example could have gone badly. - -For example, imagine that Alice creates a migration that selectively -updates the `description` field on certain products. She runs the -migration, commits the code, and then begins working on the next feature, -which is to add a new column `fuzz` to the products table. - -She creates two migrations for this new feature, one which adds the new -column, and a second which selectively updates the `fuzz` column based on -other product attributes. - -These migrations run just fine, but when Bob comes back from his vacation -and calls `rake db:migrate` to run all the outstanding migrations, he gets a -subtle bug: The descriptions have defaults, and the `fuzz` column is present, -but `fuzz` is `nil` on all products. - -The solution is again to use `Product.reset_column_information` before -referencing the Product model in a migration, ensuring the Active Record's -knowledge of the table structure is current before manipulating data in those -records. - Schema Dumping and You ---------------------- diff --git a/guides/source/nested_model_forms.md b/guides/source/nested_model_forms.md index 855fab18e3..4f0634d955 100644 --- a/guides/source/nested_model_forms.md +++ b/guides/source/nested_model_forms.md @@ -17,9 +17,9 @@ Model setup To be able to use the nested model functionality in your forms, the model will need to support some basic operations. -First of all, it needs to define a writer method for the attribute that corresponds to the association you are building a nested model form for. The `fields_for` form helper will look for this method to decide whether or not a nested model form should be build. +First of all, it needs to define a writer method for the attribute that corresponds to the association you are building a nested model form for. The `fields_for` form helper will look for this method to decide whether or not a nested model form should be built. -If the associated object is an array a form builder will be yielded for each object, else only a single form builder will be yielded. +If the associated object is an array, a form builder will be yielded for each object, else only a single form builder will be yielded. Consider a Person model with an associated Address. When asked to yield a nested FormBuilder for the `:address` attribute, the `fields_for` form helper will look for a method on the Person instance named `address_attributes=`. @@ -220,6 +220,6 @@ As you can see it has generated 2 `project name` inputs, one for each new `proje You can basically see the `projects_attributes` hash as an array of attribute hashes, one for each model instance. -NOTE: The reason that `fields_for` constructed a form which would result in a hash instead of an array is that it won't work for any forms nested deeper than one level deep. +NOTE: The reason that `fields_for` constructed a hash instead of an array is that it won't work for any form nested deeper than one level deep. TIP: You _can_ however pass an array to the writer method generated by `accepts_nested_attributes_for` if you're using plain Ruby or some other API access. See (TODO) for more info and example. diff --git a/guides/source/plugins.md b/guides/source/plugins.md index 720ca5d117..fe4215839f 100644 --- a/guides/source/plugins.md +++ b/guides/source/plugins.md @@ -92,12 +92,12 @@ Run `rake` to run the test. This test should fail because we haven't implemented Great - now you are ready to start development. -In `lib/yaffle.rb`, add `require "yaffle/core_ext"`: +In `lib/yaffle.rb`, add `require 'yaffle/core_ext'`: ```ruby # yaffle/lib/yaffle.rb -require "yaffle/core_ext" +require 'yaffle/core_ext' module Yaffle end @@ -149,7 +149,7 @@ end ```ruby # yaffle/lib/yaffle.rb -require "yaffle/core_ext" +require 'yaffle/core_ext' require 'yaffle/acts_as_yaffle' module Yaffle diff --git a/guides/source/rails_on_rack.md b/guides/source/rails_on_rack.md index 9c92cf3aea..b1b4c8fa4e 100644 --- a/guides/source/rails_on_rack.md +++ b/guides/source/rails_on_rack.md @@ -27,10 +27,9 @@ Rails on Rack ### Rails Application's Rack Object -`ApplicationName::Application` is the primary Rack application object of a Rails +`Rails.application` is the primary Rack application object of a Rails application. Any Rack compliant web server should be using -`ApplicationName::Application` object to serve a Rails -application. `Rails.application` refers to the same application object. +`Rails.application` object to serve a Rails application. ### `rails server` @@ -141,7 +140,7 @@ use ActionDispatch::ParamsParser use Rack::Head use Rack::ConditionalGet use Rack::ETag -run MyApp::Application.routes +run Rails.application.routes ``` The default middlewares shown here (and some others) are each summarized in the [Internal Middlewares](#internal-middleware-stack) section, below. @@ -201,7 +200,7 @@ use ActionDispatch::Static use #<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x00000001c304c8> use Rack::Runtime ... -run Blog::Application.routes +run Rails.application.routes ``` If you want to remove session related middleware, do the following: diff --git a/guides/source/routing.md b/guides/source/routing.md index 9c495bf09d..0783bce442 100644 --- a/guides/source/routing.md +++ b/guides/source/routing.md @@ -352,15 +352,15 @@ end The comments resource here will have the following routes generated for it: -| HTTP Verb | Path | Controller#Action | Named Helper | -| --------- | -------------------------------------- | ----------------- | ------------------- | -| GET | /posts/:post_id/comments(.:format) | comments#index | post_comments | -| POST | /posts/:post_id/comments(.:format) | comments#create | post_comments | -| GET | /posts/:post_id/comments/new(.:format) | comments#new | new_post_comment | -| GET | /sekret/comments/:id/edit(.:format) | comments#edit | edit_comment | -| GET | /sekret/comments/:id(.:format) | comments#show | comment | -| PATCH/PUT | /sekret/comments/:id(.:format) | comments#update | comment | -| DELETE | /sekret/comments/:id(.:format) | comments#destroy | comment | +| HTTP Verb | Path | Controller#Action | Named Helper | +| --------- | -------------------------------------- | ----------------- | --------------------- | +| GET | /posts/:post_id/comments(.:format) | comments#index | post_comments_path | +| POST | /posts/:post_id/comments(.:format) | comments#create | post_comments_path | +| GET | /posts/:post_id/comments/new(.:format) | comments#new | new_post_comment_path | +| GET | /sekret/comments/:id/edit(.:format) | comments#edit | edit_comment_path | +| GET | /sekret/comments/:id(.:format) | comments#show | comment_path | +| PATCH/PUT | /sekret/comments/:id(.:format) | comments#update | comment_path | +| DELETE | /sekret/comments/:id(.:format) | comments#destroy | comment_path | The `:shallow_prefix` option adds the specified parameter to the named helpers: @@ -374,15 +374,15 @@ end The comments resource here will have the following routes generated for it: -| HTTP Verb | Path | Controller#Action | Named Helper | -| --------- | -------------------------------------- | ----------------- | ------------------- | -| GET | /posts/:post_id/comments(.:format) | comments#index | post_comments | -| POST | /posts/:post_id/comments(.:format) | comments#create | post_comments | -| GET | /posts/:post_id/comments/new(.:format) | comments#new | new_post_comment | -| GET | /comments/:id/edit(.:format) | comments#edit | edit_sekret_comment | -| GET | /comments/:id(.:format) | comments#show | sekret_comment | -| PATCH/PUT | /comments/:id(.:format) | comments#update | sekret_comment | -| DELETE | /comments/:id(.:format) | comments#destroy | sekret_comment | +| HTTP Verb | Path | Controller#Action | Named Helper | +| --------- | -------------------------------------- | ----------------- | ------------------------ | +| GET | /posts/:post_id/comments(.:format) | comments#index | post_comments_path | +| POST | /posts/:post_id/comments(.:format) | comments#create | post_comments_path | +| GET | /posts/:post_id/comments/new(.:format) | comments#new | new_post_comment_path | +| GET | /comments/:id/edit(.:format) | comments#edit | edit_sekret_comment_path | +| GET | /comments/:id(.:format) | comments#show | sekret_comment_path | +| PATCH/PUT | /comments/:id(.:format) | comments#update | sekret_comment_path | +| DELETE | /comments/:id(.:format) | comments#destroy | sekret_comment_path | ### Routing concerns @@ -694,6 +694,8 @@ namespace :admin do end ``` +NOTE: Request constraints work by calling a method on the <a href="action_controller_overview.html#the-request-object">Request object</a> 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. + ### 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: @@ -709,7 +711,7 @@ class BlacklistConstraint end end -TwitterClone::Application.routes.draw do +Rails.application.routes.draw do get '*path', to: 'blacklist#index', constraints: BlacklistConstraint.new end @@ -718,7 +720,7 @@ end You can also specify constraints as a lambda: ```ruby -TwitterClone::Application.routes.draw do +Rails.application.routes.draw do get '*path', to: 'blacklist#index', constraints: lambda { |request| Blacklist.retrieve_ips.include?(request.remote_ip) } end diff --git a/guides/source/security.md b/guides/source/security.md index ece431dae7..0d347c9e4b 100644 --- a/guides/source/security.md +++ b/guides/source/security.md @@ -60,7 +60,7 @@ Many web applications have an authentication system: a user provides a user name 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. This is one more reason not to work from a coffee shop. 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 @@ -95,9 +95,16 @@ Rails 2 introduced a new default session storage, CookieStore. CookieStore saves 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_. -`config.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 `config.secret_key_base` initialized to a random key in `config/initializers/secret_token.rb`, e.g.: +`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.: - YourApp::Application.config.secret_key_base = '49d3f3de9ed86c74b94ad6bd0...' + development: + secret_key_base: a75d... + + test: + secret_key_base: 492f... + + production: + secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> Older versions of Rails use CookieStore, which uses `secret_token` instead of `secret_key_base` that is used by EncryptedCookieStore. Read the upgrade documentation for more information. @@ -144,7 +151,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 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_. 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. @@ -232,24 +239,23 @@ Or the attacker places the code into the onmouseover event handler of an image: There are many other possibilities, like using a `<script>` tag to make a cross-site request to a URL with a JSONP or JavaScript response. The response is executable code that the attacker can find a way to run, possibly extracting sensitive data. To protect against this data leakage, we disallow cross-site `<script>` tags. Only Ajax requests may have JavaScript responses since XmlHttpRequest is subject to the browser Same-Origin policy - meaning only your site can initiate the request. -To protect against all other forged requests, we introduce a _required security token_ that our site knows but other sites don't know. We include the security token in requests and verify it on the server. This is a one-liner in your application controller: +To protect against all other forged requests, we introduce a _required security token_ that our site knows but other sites don't know. We include the security token in requests and verify it on the server. This is a one-liner in your application controller, and is the default for newly created rails applications: ```ruby -protect_from_forgery +protect_from_forgery with: :exception ``` -This will automatically include a security token in all forms and Ajax requests generated by Rails. If the security token doesn't match what was expected, the session will be reset. +This will automatically include a security token in all forms and Ajax requests generated by Rails. If the security token doesn't match what was expected, an exception will be thrown. It is common to use persistent cookies to store user information, with `cookies.permanent` for example. In this case, the cookies will not be cleared and the out of the box CSRF protection will not be effective. If you are using a different cookie store than the session for this information, you must handle what to do with it yourself: ```ruby -def handle_unverified_request - super - sign_out_user # Example method that will destroy the user cookies. +rescue_from ActionController::InvalidAuthenticityToken do |exception| + sign_out_user # Example method that will destroy the user cookies end ``` -The above method can be placed in the `ApplicationController` and will be called when a CSRF token is not present on a non-GET request. +The above method can be placed in the `ApplicationController` and will be called when a CSRF token is not present or is incorrect on a non-GET request. Note that _cross-site scripting (XSS) vulnerabilities bypass all CSRF protections_. XSS gives the attacker access to all elements on a page, so they can read the CSRF security token from a form or directly submit the form. Read <a href="#cross-site-scripting-xss">more about XSS</a> later. @@ -307,7 +313,7 @@ def sanitize_filename(filename) end ``` -A significant disadvantage of synchronous processing of file uploads (as the attachment\_fu plugin may do with images), is its _vulnerability to denial-of-service attacks_. An attacker can synchronously start image file uploads from many computers which increases the server load and may eventually crash or stall the server. +A significant disadvantage of synchronous processing of file uploads (as the attachment_fu plugin may do with images), is its _vulnerability to denial-of-service attacks_. An attacker can synchronously start image file uploads from many computers which increases the server load and may eventually crash or stall the server. The solution to this is best to _process media files asynchronously_: Save the media file and schedule a processing request in the database. A second process will handle the processing of the file in the background. @@ -996,7 +1002,7 @@ _'1; mode=block' in Rails by default_ - use XSS Auditor and block page if XSS at * X-Content-Type-Options _'nosniff' in Rails by default_ - stops the browser from guessing the MIME type of a file. * X-Content-Security-Policy -[A powerful mechanism for controlling which sites certain content types can be loaded from](http://dvcs.w3.org/hg/content-security-policy/raw-file/tip/csp-specification.dev.html) +[A powerful mechanism for controlling which sites certain content types can be loaded from](http://w3c.github.io/webappsec/specs/content-security-policy/csp-specification.dev.html) * Access-Control-Allow-Origin Used to control which sites are allowed to bypass same origin policies and send cross-origin requests. * Strict-Transport-Security @@ -1005,7 +1011,7 @@ Used to control which sites are allowed to bypass same origin policies and send Environmental Security ---------------------- -It is beyond the scope of this guide to inform you on how to secure your application code and environments. However, please secure your database configuration, e.g. `config/database.yml`, and your server-side secret, e.g. stored in `config/initializers/secret_token.rb`. You may want to further restrict access, using environment-specific versions of these files and any others that may contain sensitive information. +It is beyond the scope of this guide to inform you on how to secure your application code and environments. However, please secure your database configuration, e.g. `config/database.yml`, and your server-side secret, e.g. stored in `config/secrets.yml`. You may want to further restrict access, using environment-specific versions of these files and any others that may contain sensitive information. Additional Resources -------------------- diff --git a/guides/source/testing.md b/guides/source/testing.md index aa37115d14..36d37f3af0 100644 --- a/guides/source/testing.md +++ b/guides/source/testing.md @@ -796,7 +796,7 @@ when you initiate a Rails project. Brief Note About `MiniTest` ----------------------------- -Ruby ships with a boat load of libraries. Ruby 1.8 provides `Test::Unit`, a framework for unit testing in Ruby. All the basic assertions discussed above are actually defined in `Test::Unit::Assertions`. The class `ActiveSupport::TestCase` which we have been using in our unit and functional tests extends `Test::Unit::TestCase`, allowing +Ruby ships with a vast Standard Library for all common use-cases including testing. Ruby 1.8 provided `Test::Unit`, a framework for unit testing in Ruby. All the basic assertions discussed above are actually defined in `Test::Unit::Assertions`. The class `ActiveSupport::TestCase` which we have been using in our unit and functional tests extends `Test::Unit::TestCase`, allowing us to use all of the basic assertions in our tests. Ruby 1.9 introduced `MiniTest`, an updated version of `Test::Unit` which provides a backwards compatible API for `Test::Unit`. You could also use `MiniTest` in Ruby 1.8 by installing the `minitest` gem. diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md index da124e21a4..da161f84c9 100644 --- a/guides/source/upgrading_ruby_on_rails.md +++ b/guides/source/upgrading_ruby_on_rails.md @@ -25,8 +25,6 @@ TIP: Ruby 1.8.7 p248 and p249 have marshaling bugs that crash Rails. Ruby Enterp Upgrading from Rails 4.0 to Rails 4.1 ------------------------------------- -NOTE: This section is a work in progress. - ### CSRF protection from remote `<script>` tags Or, "whaaat my tests are failing!!!?" @@ -79,12 +77,15 @@ secrets, you need to: secret_key_base: production: - secret_key_base: + secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> ``` -2. Copy the existing `secret_key_base` from the `secret_token.rb` initializer to - `secrets.yml` under the `production` section. - +2. Use your existing `secret_key_base` from the `secret_token.rb` initializer to + set the SECRET_KEY_BASE environment variable for whichever users run the Rails + app in production mode. Alternately, you can simply copy the existing + `secret_key_base` from the `secret_token.rb` initializer to `secrets.yml` + under the `production` section, replacing '<%= ENV["SECRET_KEY_BASE"] %>'. + 3. Remove the `secret_token.rb` initializer. 4. Use `rake secret` to generate new keys for the `development` and `test` sections. @@ -104,13 +105,57 @@ Applications created before Rails 4.1 uses `Marshal` to serialize cookie values the signed and encrypted cookie jars. If you want to use the new `JSON`-based format in your application, you can add an initializer file with the following content: - ```ruby - Rails.application.config.cookies_serializer :hybrid - ``` +```ruby +Rails.application.config.action_dispatch.cookies_serializer = :hybrid +``` This would transparently migrate your existing `Marshal`-serialized cookies into the new `JSON`-based format. +When using the `:json` or `:hybrid` serializer, you should beware that not all +Ruby objects can be serialized as JSON. For example, `Date` and `Time` objects +will be serialized as strings, and `Hash`es will have their keys stringified. + +```ruby +class CookiesController < ApplicationController + def set_cookie + cookies.encrypted[:expiration_date] = Date.tomorrow # => Thu, 20 Mar 2014 + redirect_to action: 'read_cookie' + end + + def read_cookie + cookies.encrypted[:expiration_date] # => "2014-03-20" + end +end +``` + +It's advisable that you only store simple data (strings and numbers) in cookies. +If you have to store complex objects, you would need to handle the conversion +manually when reading the values on subsequent requests. + +If you use the cookie session store, this would apply to the `session` and +`flash` hash as well. + +### Flash structure changes + +Flash message keys are +[normalized to strings](https://github.com/rails/rails/commit/a668beffd64106a1e1fedb71cc25eaaa11baf0c1). They +can still be accessed using either symbols or strings. Lopping through the flash +will always yield string keys: + +```ruby +flash["string"] = "a string" +flash[:symbol] = "a symbol" + +# Rails < 4.1 +flash.keys # => ["string", :symbol] + +# Rails >= 4.1 +flash.keys # => ["string", "symbol"] +``` + +Make sure you are comparing Flash message keys against strings. + ### Changes in JSON handling There are a few major changes related to JSON handling in Rails 4.1. @@ -419,7 +464,7 @@ being used, you can update your form to use the `PUT` method instead: <%= form_for [ :update_name, @user ], method: :put do |f| %> ``` -For more on PATCH and why this change was made, see [this post](http://weblog.rubyonrails.org/2012/2/26/edge-rails-patch-is-the-new-primary-http-method-for-updates/) +For more on PATCH and why this change was made, see [this post](http://weblog.rubyonrails.org/2012/2/25/edge-rails-patch-is-the-new-primary-http-method-for-updates/) on the Rails blog. #### A note about media types diff --git a/guides/source/working_with_javascript_in_rails.md b/guides/source/working_with_javascript_in_rails.md index a8695ec034..aba3c9ed61 100644 --- a/guides/source/working_with_javascript_in_rails.md +++ b/guides/source/working_with_javascript_in_rails.md @@ -111,7 +111,9 @@ paintIt = (element, backgroundColor, textColor) -> element.style.color = textColor $ -> - $("a[data-background-color]").click -> + $("a[data-background-color]").click (e) -> + e.preventDefault() + backgroundColor = $(this).data("background-color") textColor = $(this).data("text-color") paintIt(this, backgroundColor, textColor) |