rails 4.0.0 → 4.2.11.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (190) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +30 -23
  3. data/guides/CHANGELOG.md +108 -6
  4. data/guides/Rakefile +21 -6
  5. data/guides/assets/images/akshaysurve.jpg +0 -0
  6. data/guides/assets/images/edge_badge.png +0 -0
  7. data/guides/assets/images/feature_tile.gif +0 -0
  8. data/guides/assets/images/footer_tile.gif +0 -0
  9. data/guides/assets/images/fxn.png +0 -0
  10. data/guides/assets/images/getting_started/article_with_comments.png +0 -0
  11. data/guides/assets/images/getting_started/challenge.png +0 -0
  12. data/guides/assets/images/getting_started/confirm_dialog.png +0 -0
  13. data/guides/assets/images/getting_started/forbidden_attributes_for_new_article.png +0 -0
  14. data/guides/assets/images/getting_started/form_with_errors.png +0 -0
  15. data/guides/assets/images/getting_started/index_action_with_edit_link.png +0 -0
  16. data/guides/assets/images/getting_started/new_article.png +0 -0
  17. data/guides/assets/images/getting_started/rails_welcome.png +0 -0
  18. data/guides/assets/images/getting_started/routing_error_no_controller.png +0 -0
  19. data/guides/assets/images/getting_started/routing_error_no_route_matches.png +0 -0
  20. data/guides/assets/images/getting_started/show_action_for_articles.png +0 -0
  21. data/guides/assets/images/getting_started/template_is_missing_articles_new.png +0 -0
  22. data/guides/assets/images/getting_started/unknown_action_create_for_articles.png +0 -0
  23. data/guides/assets/images/getting_started/unknown_action_new_for_articles.png +0 -0
  24. data/guides/assets/images/header_tile.gif +0 -0
  25. data/guides/assets/images/icons/README +1 -1
  26. data/guides/assets/images/icons/callouts/11.png +0 -0
  27. data/guides/assets/images/icons/callouts/12.png +0 -0
  28. data/guides/assets/images/icons/callouts/13.png +0 -0
  29. data/guides/assets/images/icons/callouts/15.png +0 -0
  30. data/guides/assets/images/icons/caution.png +0 -0
  31. data/guides/assets/images/icons/example.png +0 -0
  32. data/guides/assets/images/radar.png +0 -0
  33. data/guides/assets/images/rails4_features.png +0 -0
  34. data/guides/assets/images/rails_guides_kindle_cover.jpg +0 -0
  35. data/guides/assets/images/vijaydev.jpg +0 -0
  36. data/guides/assets/javascripts/guides.js +36 -34
  37. data/guides/assets/stylesheets/main.css +6 -2
  38. data/guides/assets/stylesheets/print.css +1 -1
  39. data/guides/bug_report_templates/action_controller_gem.rb +47 -0
  40. data/guides/bug_report_templates/action_controller_master.rb +54 -0
  41. data/guides/bug_report_templates/active_record_gem.rb +5 -2
  42. data/guides/bug_report_templates/active_record_master.rb +3 -2
  43. data/guides/bug_report_templates/generic_gem.rb +15 -0
  44. data/guides/bug_report_templates/generic_master.rb +26 -0
  45. data/guides/rails_guides.rb +23 -4
  46. data/guides/rails_guides/generator.rb +1 -1
  47. data/guides/rails_guides/helpers.rb +4 -2
  48. data/guides/rails_guides/levenshtein.rb +27 -21
  49. data/guides/rails_guides/markdown.rb +11 -7
  50. data/guides/rails_guides/markdown/renderer.rb +1 -1
  51. data/guides/source/2_2_release_notes.md +3 -3
  52. data/guides/source/2_3_release_notes.md +12 -12
  53. data/guides/source/3_0_release_notes.md +10 -13
  54. data/guides/source/3_1_release_notes.md +7 -4
  55. data/guides/source/3_2_release_notes.md +17 -14
  56. data/guides/source/4_0_release_notes.md +110 -54
  57. data/guides/source/4_1_release_notes.md +730 -0
  58. data/guides/source/4_2_release_notes.md +877 -0
  59. data/guides/source/_license.html.erb +1 -1
  60. data/guides/source/_welcome.html.erb +6 -2
  61. data/guides/source/action_controller_overview.md +223 -57
  62. data/guides/source/action_mailer_basics.md +129 -76
  63. data/guides/source/action_view_overview.md +247 -246
  64. data/guides/source/active_job_basics.md +339 -0
  65. data/guides/source/active_model_basics.md +374 -20
  66. data/guides/source/active_record_basics.md +46 -45
  67. data/guides/source/active_record_callbacks.md +83 -28
  68. data/guides/source/{migrations.md → active_record_migrations.md} +191 -275
  69. data/guides/source/active_record_postgresql.md +433 -0
  70. data/guides/source/active_record_querying.md +382 -300
  71. data/guides/source/active_record_validations.md +64 -55
  72. data/guides/source/active_support_core_extensions.md +229 -187
  73. data/guides/source/active_support_instrumentation.md +23 -22
  74. data/guides/source/api_documentation_guidelines.md +167 -15
  75. data/guides/source/asset_pipeline.md +768 -294
  76. data/guides/source/association_basics.md +188 -96
  77. data/guides/source/autoloading_and_reloading_constants.md +1311 -0
  78. data/guides/source/caching_with_rails.md +45 -11
  79. data/guides/source/command_line.md +96 -65
  80. data/guides/source/configuring.md +404 -70
  81. data/guides/source/contributing_to_ruby_on_rails.md +270 -130
  82. data/guides/source/credits.html.erb +7 -3
  83. data/guides/source/debugging_rails_applications.md +471 -284
  84. data/guides/source/development_dependencies_install.md +115 -21
  85. data/guides/source/documents.yaml +31 -9
  86. data/guides/source/engines.md +737 -291
  87. data/guides/source/form_helpers.md +137 -89
  88. data/guides/source/generators.md +60 -28
  89. data/guides/source/getting_started.md +1007 -596
  90. data/guides/source/i18n.md +178 -96
  91. data/guides/source/index.html.erb +2 -1
  92. data/guides/source/initialization.md +248 -104
  93. data/guides/source/kindle/toc.html.erb +1 -1
  94. data/guides/source/layout.html.erb +14 -22
  95. data/guides/source/layouts_and_rendering.md +78 -46
  96. data/guides/source/maintenance_policy.md +78 -0
  97. data/guides/source/nested_model_forms.md +10 -7
  98. data/guides/source/plugins.md +66 -57
  99. data/guides/source/rails_application_templates.md +49 -12
  100. data/guides/source/rails_on_rack.md +50 -60
  101. data/guides/source/routing.md +190 -139
  102. data/guides/source/ruby_on_rails_guides_guidelines.md +12 -13
  103. data/guides/source/security.md +134 -83
  104. data/guides/source/testing.md +322 -200
  105. data/guides/source/upgrading_ruby_on_rails.md +834 -37
  106. data/guides/source/working_with_javascript_in_rails.md +36 -26
  107. data/guides/w3c_validator.rb +2 -0
  108. metadata +93 -116
  109. data/guides/assets/images/getting_started/forbidden_attributes_for_new_post.png +0 -0
  110. data/guides/assets/images/getting_started/new_post.png +0 -0
  111. data/guides/assets/images/getting_started/post_with_comments.png +0 -0
  112. data/guides/assets/images/getting_started/show_action_for_posts.png +0 -0
  113. data/guides/assets/images/getting_started/template_is_missing_posts_new.png +0 -0
  114. data/guides/assets/images/getting_started/undefined_method_post_path.png +0 -0
  115. data/guides/assets/images/getting_started/unknown_action_create_for_posts.png +0 -0
  116. data/guides/assets/images/getting_started/unknown_action_new_for_posts.png +0 -0
  117. data/guides/assets/images/jaimeiniesta.jpg +0 -0
  118. data/guides/code/getting_started/Gemfile +0 -43
  119. data/guides/code/getting_started/Gemfile.lock +0 -150
  120. data/guides/code/getting_started/README.rdoc +0 -28
  121. data/guides/code/getting_started/Rakefile +0 -6
  122. data/guides/code/getting_started/app/assets/javascripts/application.js +0 -16
  123. data/guides/code/getting_started/app/assets/javascripts/comments.js.coffee +0 -3
  124. data/guides/code/getting_started/app/assets/javascripts/posts.js.coffee +0 -3
  125. data/guides/code/getting_started/app/assets/javascripts/welcome.js.coffee +0 -3
  126. data/guides/code/getting_started/app/assets/stylesheets/application.css +0 -13
  127. data/guides/code/getting_started/app/assets/stylesheets/comments.css.scss +0 -3
  128. data/guides/code/getting_started/app/assets/stylesheets/posts.css.scss +0 -3
  129. data/guides/code/getting_started/app/assets/stylesheets/welcome.css.scss +0 -3
  130. data/guides/code/getting_started/app/controllers/application_controller.rb +0 -5
  131. data/guides/code/getting_started/app/controllers/comments_controller.rb +0 -17
  132. data/guides/code/getting_started/app/controllers/posts_controller.rb +0 -47
  133. data/guides/code/getting_started/app/controllers/welcome_controller.rb +0 -4
  134. data/guides/code/getting_started/app/helpers/application_helper.rb +0 -2
  135. data/guides/code/getting_started/app/helpers/comments_helper.rb +0 -2
  136. data/guides/code/getting_started/app/helpers/posts_helper.rb +0 -2
  137. data/guides/code/getting_started/app/helpers/welcome_helper.rb +0 -2
  138. data/guides/code/getting_started/app/models/comment.rb +0 -3
  139. data/guides/code/getting_started/app/models/post.rb +0 -7
  140. data/guides/code/getting_started/app/views/comments/_comment.html.erb +0 -15
  141. data/guides/code/getting_started/app/views/comments/_form.html.erb +0 -13
  142. data/guides/code/getting_started/app/views/layouts/application.html.erb +0 -14
  143. data/guides/code/getting_started/app/views/posts/_form.html.erb +0 -27
  144. data/guides/code/getting_started/app/views/posts/edit.html.erb +0 -5
  145. data/guides/code/getting_started/app/views/posts/index.html.erb +0 -21
  146. data/guides/code/getting_started/app/views/posts/new.html.erb +0 -5
  147. data/guides/code/getting_started/app/views/posts/show.html.erb +0 -18
  148. data/guides/code/getting_started/app/views/welcome/index.html.erb +0 -3
  149. data/guides/code/getting_started/bin/bundle +0 -4
  150. data/guides/code/getting_started/bin/rails +0 -4
  151. data/guides/code/getting_started/bin/rake +0 -4
  152. data/guides/code/getting_started/config.ru +0 -4
  153. data/guides/code/getting_started/config/application.rb +0 -18
  154. data/guides/code/getting_started/config/boot.rb +0 -4
  155. data/guides/code/getting_started/config/database.yml +0 -25
  156. data/guides/code/getting_started/config/environment.rb +0 -5
  157. data/guides/code/getting_started/config/environments/development.rb +0 -30
  158. data/guides/code/getting_started/config/environments/production.rb +0 -80
  159. data/guides/code/getting_started/config/environments/test.rb +0 -36
  160. data/guides/code/getting_started/config/initializers/backtrace_silencers.rb +0 -7
  161. data/guides/code/getting_started/config/initializers/filter_parameter_logging.rb +0 -4
  162. data/guides/code/getting_started/config/initializers/inflections.rb +0 -16
  163. data/guides/code/getting_started/config/initializers/locale.rb +0 -9
  164. data/guides/code/getting_started/config/initializers/mime_types.rb +0 -5
  165. data/guides/code/getting_started/config/initializers/secret_token.rb +0 -12
  166. data/guides/code/getting_started/config/initializers/session_store.rb +0 -3
  167. data/guides/code/getting_started/config/initializers/wrap_parameters.rb +0 -14
  168. data/guides/code/getting_started/config/locales/en.yml +0 -23
  169. data/guides/code/getting_started/config/routes.rb +0 -7
  170. data/guides/code/getting_started/db/migrate/20130122042648_create_posts.rb +0 -10
  171. data/guides/code/getting_started/db/migrate/20130122045842_create_comments.rb +0 -11
  172. data/guides/code/getting_started/db/schema.rb +0 -33
  173. data/guides/code/getting_started/db/seeds.rb +0 -7
  174. data/guides/code/getting_started/public/404.html +0 -58
  175. data/guides/code/getting_started/public/422.html +0 -58
  176. data/guides/code/getting_started/public/500.html +0 -57
  177. data/guides/code/getting_started/public/favicon.ico +0 -0
  178. data/guides/code/getting_started/public/robots.txt +0 -5
  179. data/guides/code/getting_started/test/controllers/comments_controller_test.rb +0 -7
  180. data/guides/code/getting_started/test/controllers/posts_controller_test.rb +0 -7
  181. data/guides/code/getting_started/test/controllers/welcome_controller_test.rb +0 -9
  182. data/guides/code/getting_started/test/fixtures/comments.yml +0 -11
  183. data/guides/code/getting_started/test/fixtures/posts.yml +0 -9
  184. data/guides/code/getting_started/test/helpers/comments_helper_test.rb +0 -4
  185. data/guides/code/getting_started/test/helpers/posts_helper_test.rb +0 -4
  186. data/guides/code/getting_started/test/helpers/welcome_helper_test.rb +0 -4
  187. data/guides/code/getting_started/test/models/comment_test.rb +0 -7
  188. data/guides/code/getting_started/test/models/post_test.rb +0 -7
  189. data/guides/code/getting_started/test/test_helper.rb +0 -15
  190. data/guides/source/kindle/KINDLE.md +0 -26
@@ -1,2 +1,2 @@
1
- <p>This work is licensed under a <a href="http://creativecommons.org/licenses/by-sa/3.0/">Creative Commons Attribution-Share Alike 3.0</a> License</p>
1
+ <p>This work is licensed under a <a href="https://creativecommons.org/licenses/by-sa/4.0/">Creative Commons Attribution-ShareAlike 4.0 International</a> License</p>
2
2
  <p>"Rails", "Ruby on Rails", and the Rails logo are trademarks of David Heinemeier Hansson. All rights reserved.</p>
@@ -10,10 +10,14 @@
10
10
  </p>
11
11
  <% else %>
12
12
  <p>
13
- These are the new guides for Rails 3.2 based on <a href="https://github.com/rails/rails/tree/<%= @version %>"><%= @version %></a>.
13
+ These are the new guides for Rails 4.2 based on <a href="https://github.com/rails/rails/tree/<%= @version %>"><%= @version %></a>.
14
14
  These guides are designed to make you immediately productive with Rails, and to help you understand how all of the pieces fit together.
15
15
  </p>
16
16
  <% end %>
17
17
  <p>
18
- The guides for Rails 2.3.x are available at <a href="http://guides.rubyonrails.org/v2.3.11/">http://guides.rubyonrails.org/v2.3.11/</a>.
18
+ The guides for earlier releases:
19
+ <a href="http://guides.rubyonrails.org/v4.1/">Rails 4.1</a>,
20
+ <a href="http://guides.rubyonrails.org/v4.0/">Rails 4.0</a>,
21
+ <a href="http://guides.rubyonrails.org/v3.2/">Rails 3.2</a>, and
22
+ <a href="http://guides.rubyonrails.org/v2.3/">Rails 2.3</a>.
19
23
  </p>
@@ -34,7 +34,7 @@ The naming convention of controllers in Rails favors pluralization of the last w
34
34
 
35
35
  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.
36
36
 
37
- NOTE: The controller naming convention differs from the naming convention of models, which expected to be named in singular form.
37
+ NOTE: The controller naming convention differs from the naming convention of models, which are expected to be named in singular form.
38
38
 
39
39
 
40
40
  Methods and Actions
@@ -112,6 +112,10 @@ NOTE: The actual URL in this example will be encoded as "/clients?ids%5b%5d=1&id
112
112
 
113
113
  The value of `params[:ids]` will now be `["1", "2", "3"]`. Note that parameter values are always strings; Rails makes no attempt to guess or cast the type.
114
114
 
115
+ NOTE: Values such as `[]`, `[nil]` or `[nil, nil, ...]` in `params` are replaced
116
+ with `nil` for security reasons by default. See [Security Guide](security.html#unsafe-query-generation)
117
+ for more information.
118
+
115
119
  To send a hash you include the key name inside the brackets:
116
120
 
117
121
  ```html
@@ -129,7 +133,7 @@ Note that the `params` hash is actually an instance of `ActiveSupport::HashWithI
129
133
 
130
134
  ### JSON parameters
131
135
 
132
- If you're writing a web service application, you might find yourself more comfortable accepting parameters in JSON format. Rails will automatically convert your parameters into the `params` hash, which you can access as you would normally.
136
+ If you're writing a web service application, you might find yourself more comfortable accepting parameters in JSON format. If the "Content-Type" header of your request is set to "application/json", Rails will automatically convert your parameters into the `params` hash, which you can access as you would normally.
133
137
 
134
138
  So for example, if you are sending this JSON content:
135
139
 
@@ -160,7 +164,7 @@ NOTE: Support for parsing XML parameters has been extracted into a gem named `ac
160
164
  The `params` hash will always contain the `:controller` and `:action` keys, but you should use the methods `controller_name` and `action_name` instead to access these values. Any other parameters defined by the routing, such as `:id` will also be available. As an example, consider a listing of clients where the list can show either active or inactive clients. We can add a route which captures the `:status` parameter in a "pretty" URL:
161
165
 
162
166
  ```ruby
163
- match '/clients/:status' => 'clients#index', foo: 'bar'
167
+ get '/clients/:status' => 'clients#index', foo: 'bar'
164
168
  ```
165
169
 
166
170
  In this case, when a user opens the URL `/clients/active`, `params[:status]` will be set to "active". When this route is used, `params[:foo]` will also be set to "bar" just like it was passed in the query string. In the same way `params[:action]` will contain "index".
@@ -209,7 +213,7 @@ class PeopleController < ActionController::Base
209
213
  # Request reply.
210
214
  def update
211
215
  person = current_account.people.find(params[:id])
212
- person.update_attributes!(person_params)
216
+ person.update!(person_params)
213
217
  redirect_to person
214
218
  end
215
219
 
@@ -256,8 +260,8 @@ used:
256
260
  params.require(:log_entry).permit!
257
261
  ```
258
262
 
259
- This will mark the `:log_entry` parameters hash and any subhash of it
260
- permitted. Extreme care should be taken when using `permit!` as it
263
+ This will mark the `:log_entry` parameters hash and any sub-hash of it
264
+ permitted. Extreme care should be taken when using `permit!` as it
261
265
  will allow all current and future model attributes to be
262
266
  mass-assigned.
263
267
 
@@ -321,16 +325,16 @@ in mind. It is not meant as a silver bullet to handle all your
321
325
  whitelisting problems. However you can easily mix the API with your
322
326
  own code to adapt to your situation.
323
327
 
324
- Imagine a scenario where you want to whitelist an attribute
325
- containing a hash with any keys. Using strong parameters you can't
326
- allow a hash with any keys but you can use a simple assignment to get
327
- the job done:
328
+ Imagine a scenario where you have parameters representing a product
329
+ name and a hash of arbitrary data associated with that product, and
330
+ you want to whitelist the product name attribute but also the whole
331
+ data hash. The strong parameters API doesn't let you directly
332
+ whitelist the whole of a nested hash with any keys, but you can use
333
+ the keys of your nested hash to declare what to whitelist:
328
334
 
329
335
  ```ruby
330
336
  def product_params
331
- params.require(:product).permit(:name).tap do |whitelisted|
332
- whitelisted[:data] = params[:product][:data]
333
- end
337
+ params.require(:product).permit(:name, data: params[:product][:data].try(:keys))
334
338
  end
335
339
  ```
336
340
 
@@ -346,11 +350,11 @@ Your application has a session for each user in which you can store small amount
346
350
 
347
351
  All session stores use a cookie to store a unique ID for each session (you must use a cookie, Rails will not allow you to pass the session ID in the URL as this is less secure).
348
352
 
349
- For most stores, this ID is used to look up the session data on the server, e.g. in a database table. There is one exception, and that is the default and recommended session store - the CookieStore - which stores all session data in the cookie itself (the ID is still available to you if you need it). This has the advantage of being very lightweight and it requires zero setup in a new application in order to use the session. The cookie data is cryptographically signed to make it tamper-proof, but it is not encrypted, so anyone with access to it can read its contents but not edit it (Rails will not accept it if it has been edited).
353
+ For most stores, this ID is used to look up the session data on the server, e.g. in a database table. There is one exception, and that is the default and recommended session store - the CookieStore - which stores all session data in the cookie itself (the ID is still available to you if you need it). This has the advantage of being very lightweight and it requires zero setup in a new application in order to use the session. The cookie data is cryptographically signed to make it tamper-proof. And it is also encrypted so anyone with access to it can't read its contents. (Rails will not accept it if it has been edited).
350
354
 
351
- The CookieStore can store around 4kB of data much less than the others but this is usually enough. Storing large amounts of data in the session is discouraged no matter which session store your application uses. You should especially avoid storing complex objects (anything other than basic Ruby objects, the most common example being model instances) in the session, as the server might not be able to reassemble them between requests, which will result in an error.
355
+ The CookieStore can store around 4kB of data - much less than the others - but this is usually enough. Storing large amounts of data in the session is discouraged no matter which session store your application uses. You should especially avoid storing complex objects (anything other than basic Ruby objects, the most common example being model instances) in the session, as the server might not be able to reassemble them between requests, which will result in an error.
352
356
 
353
- If your user sessions don't store critical data or don't need to be around for long periods (for instance if you just use the flash for messaging), you can consider using ActionDispatch::Session::CacheStore. This will store sessions using the cache implementation you have configured for your application. The advantage of this is that you can use your existing cache infrastructure for storing sessions without requiring any additional setup or administration. The downside, of course, is that the sessions will be ephemeral and could disappear at any time.
357
+ If your user sessions don't store critical data or don't need to be around for long periods (for instance if you just use the flash for messaging), you can consider using `ActionDispatch::Session::CacheStore`. This will store sessions using the cache implementation you have configured for your application. The advantage of this is that you can use your existing cache infrastructure for storing sessions without requiring any additional setup or administration. The downside, of course, is that the sessions will be ephemeral and could disappear at any time.
354
358
 
355
359
  Read more about session storage in the [Security Guide](security.html).
356
360
 
@@ -360,33 +364,48 @@ If you need a different session storage mechanism, you can change it in the `con
360
364
  # Use the database for sessions instead of the cookie-based default,
361
365
  # which shouldn't be used to store highly confidential information
362
366
  # (create the session table with "rails g active_record:session_migration")
363
- # YourApp::Application.config.session_store :active_record_store
367
+ # Rails.application.config.session_store :active_record_store
364
368
  ```
365
369
 
366
370
  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`:
367
371
 
368
372
  ```ruby
369
373
  # Be sure to restart your server when you modify this file.
370
- YourApp::Application.config.session_store :cookie_store, key: '_your_app_session'
374
+ Rails.application.config.session_store :cookie_store, key: '_your_app_session'
371
375
  ```
372
376
 
373
377
  You can also pass a `:domain` key and specify the domain name for the cookie:
374
378
 
375
379
  ```ruby
376
380
  # Be sure to restart your server when you modify this file.
377
- YourApp::Application.config.session_store :cookie_store, key: '_your_app_session', domain: ".example.com"
381
+ Rails.application.config.session_store :cookie_store, key: '_your_app_session', domain: ".example.com"
378
382
  ```
379
383
 
380
- 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`
384
+ Rails sets up (for the CookieStore) a secret key used for signing the session data. This can be changed in `config/secrets.yml`
381
385
 
382
386
  ```ruby
383
387
  # Be sure to restart your server when you modify this file.
384
388
 
385
- # Your secret key for verifying the integrity of signed cookies.
389
+ # Your secret key is used for verifying the integrity of signed cookies.
386
390
  # If you change this key, all old signed cookies will become invalid!
391
+
387
392
  # Make sure the secret is at least 30 characters and all random,
388
393
  # no regular words or you'll be exposed to dictionary attacks.
389
- YourApp::Application.config.secret_key_base = '49d3f3de9ed86c74b94ad6bd0...'
394
+ # You can use `rake secret` to generate a secure secret key.
395
+
396
+ # Make sure the secrets in this file are kept private
397
+ # if you're sharing your code publicly.
398
+
399
+ development:
400
+ secret_key_base: a75d...
401
+
402
+ test:
403
+ secret_key_base: 492f...
404
+
405
+ # Do not keep production secrets in the repository,
406
+ # instead read values from the environment.
407
+ production:
408
+ secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
390
409
  ```
391
410
 
392
411
  NOTE: Changing the secret when using the `CookieStore` will invalidate all existing sessions.
@@ -410,7 +429,7 @@ class ApplicationController < ActionController::Base
410
429
  # logging out removes it.
411
430
  def current_user
412
431
  @_current_user ||= session[:current_user_id] &&
413
- User.find_by_id(session[:current_user_id])
432
+ User.find_by(id: session[:current_user_id])
414
433
  end
415
434
  end
416
435
  ```
@@ -538,7 +557,7 @@ end
538
557
  Cookies
539
558
  -------
540
559
 
541
- Your application can store small amounts of data on the client called cookies that will be persisted across requests and even sessions. Rails provides easy access to cookies via the `cookies` method, which much like the `session` works like a hash:
560
+ Your application can store small amounts of data on the client - called cookies - that will be persisted across requests and even sessions. Rails provides easy access to cookies via the `cookies` method, which - much like the `session` - works like a hash:
542
561
 
543
562
  ```ruby
544
563
  class CommentsController < ApplicationController
@@ -568,10 +587,66 @@ end
568
587
 
569
588
  Note that while for session values you set the key to `nil`, to delete a cookie value you should use `cookies.delete(:key)`.
570
589
 
571
- Rendering xml and json data
590
+ Rails also provides a signed cookie jar and an encrypted cookie jar for storing
591
+ sensitive data. The signed cookie jar appends a cryptographic signature on the
592
+ cookie values to protect their integrity. The encrypted cookie jar encrypts the
593
+ values in addition to signing them, so that they cannot be read by the end user.
594
+ Refer to the [API documentation](http://api.rubyonrails.org/classes/ActionDispatch/Cookies.html)
595
+ for more details.
596
+
597
+ These special cookie jars use a serializer to serialize the assigned values into
598
+ strings and deserializes them into Ruby objects on read.
599
+
600
+ You can specify what serializer to use:
601
+
602
+ ```ruby
603
+ Rails.application.config.action_dispatch.cookies_serializer = :json
604
+ ```
605
+
606
+ The default serializer for new applications is `:json`. For compatibility with
607
+ old applications with existing cookies, `:marshal` is used when `serializer`
608
+ option is not specified.
609
+
610
+ You may also set this option to `:hybrid`, in which case Rails would transparently
611
+ deserialize existing (`Marshal`-serialized) cookies on read and re-write them in
612
+ the `JSON` format. This is useful for migrating existing applications to the
613
+ `:json` serializer.
614
+
615
+ It is also possible to pass a custom serializer that responds to `load` and
616
+ `dump`:
617
+
618
+ ```ruby
619
+ Rails.application.config.action_dispatch.cookies_serializer = MyCustomSerializer
620
+ ```
621
+
622
+ When using the `:json` or `:hybrid` serializer, you should beware that not all
623
+ Ruby objects can be serialized as JSON. For example, `Date` and `Time` objects
624
+ will be serialized as strings, and `Hash`es will have their keys stringified.
625
+
626
+ ```ruby
627
+ class CookiesController < ApplicationController
628
+ def set_cookie
629
+ cookies.encrypted[:expiration_date] = Date.tomorrow # => Thu, 20 Mar 2014
630
+ redirect_to action: 'read_cookie'
631
+ end
632
+
633
+ def read_cookie
634
+ cookies.encrypted[:expiration_date] # => "2014-03-20"
635
+ end
636
+ end
637
+ ```
638
+
639
+ It's advisable that you only store simple data (strings and numbers) in cookies.
640
+ If you have to store complex objects, you would need to handle the conversion
641
+ manually when reading the values on subsequent requests.
642
+
643
+ If you use the cookie session store, this would apply to the `session` and
644
+ `flash` hash as well.
645
+
646
+ Rendering XML and JSON data
572
647
  ---------------------------
573
648
 
574
- ActionController makes it extremely easy to render `xml` or `json` data. If you've generated a controller using scaffolding, it would look something like this:
649
+ ActionController makes it extremely easy to render `XML` or `JSON` data. If you've generated a controller using scaffolding, it would look something like this:
575
650
 
576
651
  ```ruby
577
652
  class UsersController < ApplicationController
@@ -660,19 +735,22 @@ You can choose not to yield and build the response yourself, in which case the a
660
735
 
661
736
  While the most common way to use filters is by creating private methods and using *_action to add them, there are two other ways to do the same thing.
662
737
 
663
- The first is to use a block directly with the *_action methods. The block receives the controller as an argument, and the `require_login` filter from above could be rewritten to use a block:
738
+ The first is to use a block directly with the *\_action methods. The block receives the controller as an argument, and the `require_login` filter from above could be rewritten to use a block:
664
739
 
665
740
  ```ruby
666
741
  class ApplicationController < ActionController::Base
667
742
  before_action do |controller|
668
- redirect_to new_login_url unless controller.send(:logged_in?)
743
+ unless controller.send(:logged_in?)
744
+ flash[:error] = "You must be logged in to access this section"
745
+ redirect_to new_login_url
746
+ end
669
747
  end
670
748
  end
671
749
  ```
672
750
 
673
751
  Note that the filter in this case uses `send` because the `logged_in?` method is private and the filter is not run in the scope of the controller. This is not the recommended way to implement this particular filter, but in more simple cases it might be useful.
674
752
 
675
- The second way is to use a class (actually, any object that responds to the right methods will do) to handle the filtering. This is useful in cases that are more complex and can not be implemented in a readable and reusable way using the two other methods. As an example, you could rewrite the login filter again to use a class:
753
+ The second way is to use a class (actually, any object that responds to the right methods will do) to handle the filtering. This is useful in cases that are more complex and cannot be implemented in a readable and reusable way using the two other methods. As an example, you could rewrite the login filter again to use a class:
676
754
 
677
755
  ```ruby
678
756
  class ApplicationController < ActionController::Base
@@ -680,16 +758,16 @@ class ApplicationController < ActionController::Base
680
758
  end
681
759
 
682
760
  class LoginFilter
683
- def self.filter(controller)
761
+ def self.before(controller)
684
762
  unless controller.send(:logged_in?)
685
- controller.flash[:error] = "You must be logged in"
763
+ controller.flash[:error] = "You must be logged in to access this section"
686
764
  controller.redirect_to controller.new_login_url
687
765
  end
688
766
  end
689
767
  end
690
768
  ```
691
769
 
692
- Again, this is not an ideal example for this filter, because it's not run in the scope of the controller but gets the controller passed as an argument. The filter class has a class method `filter` which gets run before or after the action, depending on if it's a before or after filter. Classes used as around filters can also use the same `filter` method, which will get run in the same way. The method must `yield` to execute the action. Alternatively, it can have both a `before` and an `after` method that are run before and after the action.
770
+ Again, this is not an ideal example for this filter, because it's not run in the scope of the controller but gets the controller passed as an argument. The filter class must implement a method with the same name as the filter, so for the `before_action` filter the class must implement a `before` method, and so on. The `around` method must `yield` to execute the action.
693
771
 
694
772
  Request Forgery Protection
695
773
  --------------------------
@@ -794,7 +872,7 @@ class AdminsController < ApplicationController
794
872
  end
795
873
  ```
796
874
 
797
- With this in place, you can create namespaced controllers that inherit from `AdminController`. The filter will thus be run for all actions in those controllers, protecting them with HTTP basic authentication.
875
+ With this in place, you can create namespaced controllers that inherit from `AdminsController`. The filter will thus be run for all actions in those controllers, protecting them with HTTP basic authentication.
798
876
 
799
877
  ### HTTP Digest Authentication
800
878
 
@@ -808,11 +886,11 @@ class AdminsController < ApplicationController
808
886
 
809
887
  private
810
888
 
811
- def authenticate
812
- authenticate_or_request_with_http_digest do |username|
813
- USERS[username]
889
+ def authenticate
890
+ authenticate_or_request_with_http_digest do |username|
891
+ USERS[username]
892
+ end
814
893
  end
815
- end
816
894
  end
817
895
  ```
818
896
 
@@ -839,13 +917,13 @@ class ClientsController < ApplicationController
839
917
 
840
918
  private
841
919
 
842
- def generate_pdf(client)
843
- Prawn::Document.new do
844
- text client.name, align: :center
845
- text "Address: #{client.address}"
846
- text "Email: #{client.email}"
847
- end.render
848
- end
920
+ def generate_pdf(client)
921
+ Prawn::Document.new do
922
+ text client.name, align: :center
923
+ text "Address: #{client.address}"
924
+ text "Email: #{client.email}"
925
+ end.render
926
+ end
849
927
  end
850
928
  ```
851
929
 
@@ -907,6 +985,92 @@ Now the user can request to get a PDF version of a client just by adding ".pdf"
907
985
  GET /clients/1.pdf
908
986
  ```
909
987
 
988
+ ### Live Streaming of Arbitrary Data
989
+
990
+ Rails allows you to stream more than just files. In fact, you can stream anything
991
+ you would like in a response object. The `ActionController::Live` module allows
992
+ you to create a persistent connection with a browser. Using this module, you will
993
+ be able to send arbitrary data to the browser at specific points in time.
994
+
995
+ #### Incorporating Live Streaming
996
+
997
+ Including `ActionController::Live` inside of your controller class will provide
998
+ all actions inside of the controller the ability to stream data. You can mix in
999
+ the module like so:
1000
+
1001
+ ```ruby
1002
+ class MyController < ActionController::Base
1003
+ include ActionController::Live
1004
+
1005
+ def stream
1006
+ response.headers['Content-Type'] = 'text/event-stream'
1007
+ 100.times {
1008
+ response.stream.write "hello world\n"
1009
+ sleep 1
1010
+ }
1011
+ ensure
1012
+ response.stream.close
1013
+ end
1014
+ end
1015
+ ```
1016
+
1017
+ The above code will keep a persistent connection with the browser and send 100
1018
+ messages of `"hello world\n"`, each one second apart.
1019
+
1020
+ There are a couple of things to notice in the above example. We need to make
1021
+ sure to close the response stream. Forgetting to close the stream will leave
1022
+ the socket open forever. We also have to set the content type to `text/event-stream`
1023
+ before we write to the response stream. This is because headers cannot be written
1024
+ after the response has been committed (when `response.committed` returns a truthy
1025
+ value), which occurs when you `write` or `commit` the response stream.
1026
+
1027
+ #### Example Usage
1028
+
1029
+ Let's suppose that you were making a Karaoke machine and a user wants to get the
1030
+ lyrics for a particular song. Each `Song` has a particular number of lines and
1031
+ each line takes time `num_beats` to finish singing.
1032
+
1033
+ If we wanted to return the lyrics in Karaoke fashion (only sending the line when
1034
+ the singer has finished the previous line), then we could use `ActionController::Live`
1035
+ as follows:
1036
+
1037
+ ```ruby
1038
+ class LyricsController < ActionController::Base
1039
+ include ActionController::Live
1040
+
1041
+ def show
1042
+ response.headers['Content-Type'] = 'text/event-stream'
1043
+ song = Song.find(params[:id])
1044
+
1045
+ song.each do |line|
1046
+ response.stream.write line.lyrics
1047
+ sleep line.num_beats
1048
+ end
1049
+ ensure
1050
+ response.stream.close
1051
+ end
1052
+ end
1053
+ ```
1054
+
1055
+ The above code sends the next line only after the singer has completed the previous
1056
+ line.
1057
+
1058
+ #### Streaming Considerations
1059
+
1060
+ Streaming arbitrary data is an extremely powerful tool. As shown in the previous
1061
+ examples, you can choose when and what to send across a response stream. However,
1062
+ you should also note the following things:
1063
+
1064
+ * Each response stream creates a new thread and copies over the thread local
1065
+ variables from the original thread. Having too many thread local variables can
1066
+ negatively impact performance. Similarly, a large number of threads can also
1067
+ hinder performance.
1068
+ * Failing to close the response stream will leave the corresponding socket open
1069
+ forever. Make sure to call `close` whenever you are using a response stream.
1070
+ * WEBrick servers buffer all responses, and so including `ActionController::Live`
1071
+ will not work. You must use a web server which does not automatically buffer
1072
+ responses.
1073
+
910
1074
  Log Filtering
911
1075
  -------------
912
1076
 
@@ -914,7 +1078,7 @@ Rails keeps a log file for each environment in the `log` folder. These are extre
914
1078
 
915
1079
  ### Parameters Filtering
916
1080
 
917
- You can filter certain request parameters from your log files by appending them to `config.filter_parameters` in the application configuration. These parameters will be marked [FILTERED] in the log.
1081
+ You can filter out sensitive request parameters from your log files by appending them to `config.filter_parameters` in the application configuration. These parameters will be marked [FILTERED] in the log.
918
1082
 
919
1083
  ```ruby
920
1084
  config.filter_parameters << :password
@@ -922,7 +1086,7 @@ config.filter_parameters << :password
922
1086
 
923
1087
  ### Redirects Filtering
924
1088
 
925
- Sometimes it's desirable to filter out from log files some sensible locations your application is redirecting to.
1089
+ Sometimes it's desirable to filter out from log files some sensitive locations your application is redirecting to.
926
1090
  You can do that by using the `config.filter_redirect` configuration option:
927
1091
 
928
1092
  ```ruby
@@ -962,9 +1126,9 @@ class ApplicationController < ActionController::Base
962
1126
 
963
1127
  private
964
1128
 
965
- def record_not_found
966
- render text: "404 Not Found", status: 404
967
- end
1129
+ def record_not_found
1130
+ render plain: "404 Not Found", status: 404
1131
+ end
968
1132
  end
969
1133
  ```
970
1134
 
@@ -976,10 +1140,10 @@ class ApplicationController < ActionController::Base
976
1140
 
977
1141
  private
978
1142
 
979
- def user_not_authorized
980
- flash[:error] = "You don't have access to this section."
981
- redirect_to :back
982
- end
1143
+ def user_not_authorized
1144
+ flash[:error] = "You don't have access to this section."
1145
+ redirect_to :back
1146
+ end
983
1147
  end
984
1148
 
985
1149
  class ClientsController < ApplicationController
@@ -993,13 +1157,15 @@ class ClientsController < ApplicationController
993
1157
 
994
1158
  private
995
1159
 
996
- # If the user is not authorized, just throw the exception.
997
- def check_authorization
998
- raise User::NotAuthorized unless current_user.admin?
999
- end
1160
+ # If the user is not authorized, just throw the exception.
1161
+ def check_authorization
1162
+ raise User::NotAuthorized unless current_user.admin?
1163
+ end
1000
1164
  end
1001
1165
  ```
1002
1166
 
1167
+ WARNING: You shouldn't do `rescue_from Exception` or `rescue_from StandardError` unless you have a particular reason as it will cause serious side-effects (e.g. you won't be able to see exception details and tracebacks during development).
1168
+
1003
1169
  NOTE: Certain exceptions are only rescuable from the `ApplicationController` class, as they are raised before the controller gets initialized and the action gets executed. See Pratik Naik's [article](http://m.onkey.org/2008/7/20/rescue-from-dispatching) on the subject for more information.
1004
1170
 
1005
1171
  Force HTTPS protocol