rails 4.1.16 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (143) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +12 -10
  3. data/guides/CHANGELOG.md +15 -100
  4. data/guides/Rakefile +5 -3
  5. data/guides/assets/javascripts/guides.js +6 -0
  6. data/guides/assets/stylesheets/main.css +4 -1
  7. data/guides/bug_report_templates/action_controller_master.rb +1 -0
  8. data/guides/rails_guides/helpers.rb +1 -1
  9. data/guides/rails_guides/levenshtein.rb +29 -21
  10. data/guides/rails_guides/markdown/renderer.rb +1 -1
  11. data/guides/rails_guides/markdown.rb +11 -7
  12. data/guides/rails_guides.rb +2 -2
  13. data/guides/source/2_2_release_notes.md +1 -1
  14. data/guides/source/2_3_release_notes.md +4 -4
  15. data/guides/source/3_0_release_notes.md +8 -8
  16. data/guides/source/3_1_release_notes.md +6 -3
  17. data/guides/source/3_2_release_notes.md +6 -3
  18. data/guides/source/4_0_release_notes.md +6 -3
  19. data/guides/source/4_1_release_notes.md +5 -6
  20. data/guides/source/4_2_release_notes.md +850 -0
  21. data/guides/source/_license.html.erb +1 -1
  22. data/guides/source/_welcome.html.erb +2 -8
  23. data/guides/source/action_controller_overview.md +81 -7
  24. data/guides/source/action_mailer_basics.md +91 -28
  25. data/guides/source/action_view_overview.md +148 -130
  26. data/guides/source/active_job_basics.md +318 -0
  27. data/guides/source/active_model_basics.md +371 -17
  28. data/guides/source/active_record_basics.md +19 -18
  29. data/guides/source/active_record_callbacks.md +12 -9
  30. data/guides/source/{migrations.md → active_record_migrations.md} +95 -220
  31. data/guides/source/active_record_postgresql.md +433 -0
  32. data/guides/source/active_record_querying.md +263 -265
  33. data/guides/source/active_record_validations.md +20 -11
  34. data/guides/source/active_support_core_extensions.md +159 -72
  35. data/guides/source/active_support_instrumentation.md +10 -7
  36. data/guides/source/api_documentation_guidelines.md +62 -16
  37. data/guides/source/asset_pipeline.md +258 -63
  38. data/guides/source/association_basics.md +81 -74
  39. data/guides/source/caching_with_rails.md +32 -7
  40. data/guides/source/command_line.md +52 -30
  41. data/guides/source/configuring.md +132 -29
  42. data/guides/source/constant_autoloading_and_reloading.md +1297 -0
  43. data/guides/source/contributing_to_ruby_on_rails.md +192 -112
  44. data/guides/source/credits.html.erb +2 -2
  45. data/guides/source/debugging_rails_applications.md +440 -286
  46. data/guides/source/development_dependencies_install.md +47 -36
  47. data/guides/source/documents.yaml +19 -7
  48. data/guides/source/engines.md +182 -182
  49. data/guides/source/form_helpers.md +79 -56
  50. data/guides/source/generators.md +24 -11
  51. data/guides/source/getting_started.md +337 -198
  52. data/guides/source/i18n.md +108 -65
  53. data/guides/source/index.html.erb +1 -0
  54. data/guides/source/initialization.md +108 -61
  55. data/guides/source/layout.html.erb +1 -4
  56. data/guides/source/layouts_and_rendering.md +27 -25
  57. data/guides/source/maintenance_policy.md +6 -3
  58. data/guides/source/nested_model_forms.md +7 -4
  59. data/guides/source/plugins.md +27 -27
  60. data/guides/source/rails_application_templates.md +21 -3
  61. data/guides/source/rails_on_rack.md +8 -4
  62. data/guides/source/routing.md +98 -72
  63. data/guides/source/ruby_on_rails_guides_guidelines.md +11 -12
  64. data/guides/source/security.md +38 -32
  65. data/guides/source/testing.md +188 -117
  66. data/guides/source/upgrading_ruby_on_rails.md +254 -28
  67. data/guides/source/working_with_javascript_in_rails.md +18 -16
  68. data/guides/w3c_validator.rb +2 -0
  69. metadata +40 -96
  70. data/guides/bug_report_templates/generic_gem.rb +0 -15
  71. data/guides/bug_report_templates/generic_master.rb +0 -26
  72. data/guides/code/getting_started/Gemfile +0 -40
  73. data/guides/code/getting_started/Gemfile.lock +0 -125
  74. data/guides/code/getting_started/README.rdoc +0 -28
  75. data/guides/code/getting_started/Rakefile +0 -6
  76. data/guides/code/getting_started/app/assets/javascripts/application.js +0 -15
  77. data/guides/code/getting_started/app/assets/javascripts/comments.js.coffee +0 -3
  78. data/guides/code/getting_started/app/assets/javascripts/posts.js.coffee +0 -3
  79. data/guides/code/getting_started/app/assets/javascripts/welcome.js.coffee +0 -3
  80. data/guides/code/getting_started/app/assets/stylesheets/application.css +0 -13
  81. data/guides/code/getting_started/app/assets/stylesheets/comments.css.scss +0 -3
  82. data/guides/code/getting_started/app/assets/stylesheets/posts.css.scss +0 -3
  83. data/guides/code/getting_started/app/assets/stylesheets/welcome.css.scss +0 -3
  84. data/guides/code/getting_started/app/controllers/application_controller.rb +0 -5
  85. data/guides/code/getting_started/app/controllers/comments_controller.rb +0 -23
  86. data/guides/code/getting_started/app/controllers/posts_controller.rb +0 -53
  87. data/guides/code/getting_started/app/controllers/welcome_controller.rb +0 -4
  88. data/guides/code/getting_started/app/helpers/application_helper.rb +0 -2
  89. data/guides/code/getting_started/app/helpers/comments_helper.rb +0 -2
  90. data/guides/code/getting_started/app/helpers/posts_helper.rb +0 -2
  91. data/guides/code/getting_started/app/helpers/welcome_helper.rb +0 -2
  92. data/guides/code/getting_started/app/models/comment.rb +0 -3
  93. data/guides/code/getting_started/app/models/post.rb +0 -7
  94. data/guides/code/getting_started/app/views/comments/_comment.html.erb +0 -15
  95. data/guides/code/getting_started/app/views/comments/_form.html.erb +0 -13
  96. data/guides/code/getting_started/app/views/layouts/application.html.erb +0 -14
  97. data/guides/code/getting_started/app/views/posts/_form.html.erb +0 -27
  98. data/guides/code/getting_started/app/views/posts/edit.html.erb +0 -5
  99. data/guides/code/getting_started/app/views/posts/index.html.erb +0 -21
  100. data/guides/code/getting_started/app/views/posts/new.html.erb +0 -5
  101. data/guides/code/getting_started/app/views/posts/show.html.erb +0 -18
  102. data/guides/code/getting_started/app/views/welcome/index.html.erb +0 -4
  103. data/guides/code/getting_started/bin/bundle +0 -4
  104. data/guides/code/getting_started/bin/rails +0 -4
  105. data/guides/code/getting_started/bin/rake +0 -4
  106. data/guides/code/getting_started/config/application.rb +0 -18
  107. data/guides/code/getting_started/config/boot.rb +0 -4
  108. data/guides/code/getting_started/config/database.yml +0 -25
  109. data/guides/code/getting_started/config/environment.rb +0 -5
  110. data/guides/code/getting_started/config/environments/development.rb +0 -30
  111. data/guides/code/getting_started/config/environments/production.rb +0 -80
  112. data/guides/code/getting_started/config/environments/test.rb +0 -36
  113. data/guides/code/getting_started/config/initializers/backtrace_silencers.rb +0 -7
  114. data/guides/code/getting_started/config/initializers/filter_parameter_logging.rb +0 -4
  115. data/guides/code/getting_started/config/initializers/inflections.rb +0 -16
  116. data/guides/code/getting_started/config/initializers/locale.rb +0 -9
  117. data/guides/code/getting_started/config/initializers/mime_types.rb +0 -5
  118. data/guides/code/getting_started/config/initializers/secret_token.rb +0 -12
  119. data/guides/code/getting_started/config/initializers/session_store.rb +0 -3
  120. data/guides/code/getting_started/config/initializers/wrap_parameters.rb +0 -14
  121. data/guides/code/getting_started/config/locales/en.yml +0 -23
  122. data/guides/code/getting_started/config/routes.rb +0 -7
  123. data/guides/code/getting_started/config.ru +0 -4
  124. data/guides/code/getting_started/db/migrate/20130122042648_create_posts.rb +0 -10
  125. data/guides/code/getting_started/db/migrate/20130122045842_create_comments.rb +0 -11
  126. data/guides/code/getting_started/db/schema.rb +0 -33
  127. data/guides/code/getting_started/db/seeds.rb +0 -7
  128. data/guides/code/getting_started/public/404.html +0 -60
  129. data/guides/code/getting_started/public/422.html +0 -60
  130. data/guides/code/getting_started/public/500.html +0 -59
  131. data/guides/code/getting_started/public/favicon.ico +0 -0
  132. data/guides/code/getting_started/public/robots.txt +0 -5
  133. data/guides/code/getting_started/test/controllers/comments_controller_test.rb +0 -7
  134. data/guides/code/getting_started/test/controllers/posts_controller_test.rb +0 -7
  135. data/guides/code/getting_started/test/controllers/welcome_controller_test.rb +0 -9
  136. data/guides/code/getting_started/test/fixtures/comments.yml +0 -11
  137. data/guides/code/getting_started/test/fixtures/posts.yml +0 -9
  138. data/guides/code/getting_started/test/helpers/comments_helper_test.rb +0 -4
  139. data/guides/code/getting_started/test/helpers/posts_helper_test.rb +0 -4
  140. data/guides/code/getting_started/test/helpers/welcome_helper_test.rb +0 -4
  141. data/guides/code/getting_started/test/models/comment_test.rb +0 -7
  142. data/guides/code/getting_started/test/models/post_test.rb +0 -7
  143. data/guides/code/getting_started/test/test_helper.rb +0 -12
@@ -28,7 +28,7 @@ After reading this guide, you will know:
28
28
 
29
29
  --------------------------------------------------------------------------------
30
30
 
31
- NOTE: The Ruby I18n framework provides you with all necessary means for internationalization/localization of your Rails application. You may, however, use any of various plugins and extensions available, which add additional functionality or features. See the Ruby [I18n Wiki](http://ruby-i18n.org/wiki) for more information.
31
+ NOTE: The Ruby I18n framework provides you with all necessary means for internationalization/localization of your Rails application. You may, also use various gems available to add additional functionality or features. See the [rails-i18n gem](https://github.com/svenfuchs/rails-i18n) for more information.
32
32
 
33
33
  How I18n in Ruby on Rails Works
34
34
  -------------------------------
@@ -92,7 +92,7 @@ Rails adds all `.rb` and `.yml` files from the `config/locales` directory to you
92
92
 
93
93
  The default `en.yml` locale in this directory contains a sample pair of translation strings:
94
94
 
95
- ```ruby
95
+ ```yaml
96
96
  en:
97
97
  hello: "Hello world"
98
98
  ```
@@ -101,13 +101,13 @@ This means, that in the `:en` locale, the key _hello_ will map to the _Hello wor
101
101
 
102
102
  The I18n library will use **English** as a **default locale**, i.e. if you don't set a different locale, `:en` will be used for looking up translations.
103
103
 
104
- NOTE: The i18n library takes a **pragmatic approach** to locale keys (after [some discussion](http://groups.google.com/group/rails-i18n/browse_thread/thread/14dede2c7dbe9470/80eec34395f64f3c?hl=en)), including only the _locale_ ("language") part, like `:en`, `:pl`, not the _region_ part, like `:en-US` or `:en-GB`, which are traditionally used for separating "languages" and "regional setting" or "dialects". Many international applications use only the "language" element of a locale such as `:cs`, `:th` or `:es` (for Czech, Thai and Spanish). However, there are also regional differences within different language groups that may be important. For instance, in the `:en-US` locale you would have $ as a currency symbol, while in `:en-GB`, you would have £. Nothing stops you from separating regional and other settings in this way: you just have to provide full "English - United Kingdom" locale in a `:en-GB` dictionary. Various [Rails I18n plugins](http://rails-i18n.org/wiki) such as [Globalize3](https://github.com/globalize/globalize) may help you implement it.
104
+ NOTE: The i18n library takes a **pragmatic approach** to locale keys (after [some discussion](http://groups.google.com/group/rails-i18n/browse_thread/thread/14dede2c7dbe9470/80eec34395f64f3c?hl=en)), including only the _locale_ ("language") part, like `:en`, `:pl`, not the _region_ part, like `:en-US` or `:en-GB`, which are traditionally used for separating "languages" and "regional setting" or "dialects". Many international applications use only the "language" element of a locale such as `:cs`, `:th` or `:es` (for Czech, Thai and Spanish). However, there are also regional differences within different language groups that may be important. For instance, in the `:en-US` locale you would have $ as a currency symbol, while in `:en-GB`, you would have £. Nothing stops you from separating regional and other settings in this way: you just have to provide full "English - United Kingdom" locale in a `:en-GB` dictionary. Few gems such as [Globalize3](https://github.com/globalize/globalize) may help you implement it.
105
105
 
106
106
  The **translations load path** (`I18n.load_path`) is just a Ruby Array of paths to your translation files that will be loaded automatically and available in your application. You can pick whatever directory and translation file naming scheme makes sense for you.
107
107
 
108
108
  NOTE: The backend will lazy-load these translations when a translation is looked up for the first time. This makes it possible to just swap the backend with something else even after translations have already been announced.
109
109
 
110
- The default `application.rb` files has instructions on how to add locales from another directory and how to set a different default locale. Just uncomment and edit the specific lines.
110
+ The default `application.rb` file has instructions on how to add locales from another directory and how to set a different default locale. Just uncomment and edit the specific lines.
111
111
 
112
112
  ```ruby
113
113
  # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
@@ -137,7 +137,7 @@ If you want to translate your Rails application to a **single language other tha
137
137
 
138
138
  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.
139
139
 
140
- 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.
140
+ WARNING: You may be tempted to store the chosen locale in a _session_ or a *cookie*. 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 [*RESTful*](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.
141
141
 
142
142
  The _setting part_ is easy. You can set the locale in a `before_action` in the `ApplicationController` like this:
143
143
 
@@ -212,17 +212,16 @@ The most usual way of setting (and passing) the locale would be to include it in
212
212
 
213
213
  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.
214
214
 
215
- 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.
215
+ 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.
216
216
 
217
- 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).
217
+ 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).
218
218
 
219
219
  We can include something like this in our `ApplicationController` then:
220
220
 
221
221
  ```ruby
222
222
  # app/controllers/application_controller.rb
223
- def default_url_options(options={})
224
- logger.debug "default_url_options is passed options: #{options.inspect}\n"
225
- { locale: I18n.locale }
223
+ def default_url_options(options = {})
224
+ { locale: I18n.locale }.merge options
226
225
  end
227
226
  ```
228
227
 
@@ -263,7 +262,7 @@ get '/:locale' => 'dashboard#index'
263
262
 
264
263
  Do take special care about the **order of your routes**, so this route declaration does not "eat" other ones. (You may want to add it directly before the `root :to` declaration.)
265
264
 
266
- NOTE: Have a look at two plugins which simplify work with routes in this way: Sven Fuchs's [routing_filter](https://github.com/svenfuchs/routing-filter/tree/master) and Raul Murciano's [translate_routes](https://github.com/raul/translate_routes/tree/master).
265
+ NOTE: Have a look at various gems which simplify working with routes: [routing_filter](https://github.com/svenfuchs/routing-filter/tree/master), [rails-translate-routes](https://github.com/francesc/rails-translate-routes), [route_translator](https://github.com/enriclluelles/route_translator).
267
266
 
268
267
  ### Setting the Locale from the Client Supplied Information
269
268
 
@@ -289,7 +288,7 @@ private
289
288
  end
290
289
  ```
291
290
 
292
- Of course, in a production environment you would need much more robust code, and could use a plugin such as Iain Hecker's [http_accept_language](https://github.com/iain/http_accept_language/tree/master) or even Rack middleware such as Ryan Tomayko's [locale](https://github.com/rack/rack-contrib/blob/master/lib/rack/contrib/locale.rb).
291
+ Of course, in a production environment you would need much more robust code, and could use a gem such as Iain Hecker's [http_accept_language](https://github.com/iain/http_accept_language/tree/master) or even Rack middleware such as Ryan Tomayko's [locale](https://github.com/rack/rack-contrib/blob/master/lib/rack/contrib/locale.rb).
293
292
 
294
293
  #### Using GeoIP (or Similar) Database
295
294
 
@@ -370,7 +369,7 @@ NOTE: Rails adds a `t` (`translate`) helper method to your views so that you do
370
369
 
371
370
  So let's add the missing translations into the dictionary files (i.e. do the "localization" part):
372
371
 
373
- ```ruby
372
+ ```yaml
374
373
  # config/locales/en.yml
375
374
  en:
376
375
  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
422
421
 
423
422
  And in our pirate translations file let's add a time format (it's already there in Rails' defaults for English):
424
423
 
425
- ```ruby
424
+ ```yaml
426
425
  # config/locales/pirate.yml
427
426
  pirate:
428
427
  time:
@@ -485,8 +484,6 @@ NOTE: The default locale loading mechanism in Rails does not load locale files i
485
484
 
486
485
  ```
487
486
 
488
- Do check the [Rails i18n Wiki](http://rails-i18n.org/wiki) for list of tools available for managing translations.
489
-
490
487
  Overview of the I18n API Features
491
488
  ---------------------------------
492
489
 
@@ -677,58 +674,25 @@ en:
677
674
  <div><%= t('title.html') %></div>
678
675
  ```
679
676
 
680
- NOTE: Automatic conversion to HTML safe translate text is only available from the `translate` view helper method.
681
-
682
- ![i18n demo html safe](images/i18n/demo_html_safe.png)
683
-
684
- How to Store your Custom Translations
685
- -------------------------------------
686
-
687
- The Simple backend shipped with Active Support allows you to store translations in both plain Ruby and YAML format.[^2]
688
-
689
- For example a Ruby Hash providing translations can look like this:
677
+ Interpolation escapes as needed though. For example, given:
690
678
 
691
- ```ruby
692
- {
693
- pt: {
694
- foo: {
695
- bar: "baz"
696
- }
697
- }
698
- }
699
- ```
700
-
701
- The equivalent YAML file would look like this:
702
-
703
- ```ruby
704
- pt:
705
- foo:
706
- bar: baz
679
+ ```yaml
680
+ en:
681
+ welcome_html: "<b>Welcome %{username}!</b>"
707
682
  ```
708
683
 
709
- 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".
710
-
711
- Here is a "real" example from the Active Support `en.yml` translations YAML file:
684
+ you can safely pass the username as set by the user:
712
685
 
713
- ```ruby
714
- en:
715
- date:
716
- formats:
717
- default: "%Y-%m-%d"
718
- short: "%b %d"
719
- long: "%B %d, %Y"
686
+ ```erb
687
+ <%# This is safe, it is going to be escaped if needed. %>
688
+ <%= t('welcome_html', username: @current_user.username %>
720
689
  ```
721
690
 
722
- So, all of the following equivalent lookups will return the `:short` date format `"%b %d"`:
691
+ Safe strings on the other hand are interpolated verbatim.
723
692
 
724
- ```ruby
725
- I18n.t 'date.formats.short'
726
- I18n.t 'formats.short', scope: :date
727
- I18n.t :short, scope: 'date.formats'
728
- I18n.t :short, scope: [:date, :formats]
729
- ```
693
+ NOTE: Automatic conversion to HTML safe translate text is only available from the `translate` view helper method.
730
694
 
731
- 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.
695
+ ![i18n demo html safe](images/i18n/demo_html_safe.png)
732
696
 
733
697
  ### Translations for Active Record Models
734
698
 
@@ -736,7 +700,7 @@ You can use the methods `Model.model_name.human` and `Model.human_attribute_name
736
700
 
737
701
  For example when you add the following translations:
738
702
 
739
- ```ruby
703
+ ```yaml
740
704
  en:
741
705
  activerecord:
742
706
  models:
@@ -751,7 +715,7 @@ Then `User.model_name.human` will return "Dude" and `User.human_attribute_name("
751
715
 
752
716
  You can also set a plural form for model names, adding as following:
753
717
 
754
- ```ruby
718
+ ```yaml
755
719
  en:
756
720
  activerecord:
757
721
  models:
@@ -762,6 +726,19 @@ en:
762
726
 
763
727
  Then `User.model_name.human(count: 2)` will return "Dudes". With `count: 1` or without params will return "Dude".
764
728
 
729
+ In the event you need to access nested attributes within a given model, you should nest these under `model/attribute` at the model level of your translation file:
730
+
731
+ ```yaml
732
+ en:
733
+ activerecord:
734
+ attributes:
735
+ user/gender:
736
+ female: "Female"
737
+ male: "Male"
738
+ ```
739
+
740
+ Then `User.human_attribute_name("gender.female")` will return "Female".
741
+
765
742
  #### Error Message Scopes
766
743
 
767
744
  Active Record validation error messages can also be translated easily. Active Record gives you a couple of namespaces where you can place your message translations in order to provide different messages and translation for certain models, attributes, and/or validations. It also transparently takes single table inheritance into account.
@@ -897,6 +874,24 @@ en:
897
874
  subject: "Welcome to Rails Guides!"
898
875
  ```
899
876
 
877
+ To send parameters to interpolation use the `default_i18n_subject` method on the mailer.
878
+
879
+ ```ruby
880
+ # user_mailer.rb
881
+ class UserMailer < ActionMailer::Base
882
+ def welcome(user)
883
+ mail(to: user.email, subject: default_i18n_subject(user: user.name))
884
+ end
885
+ end
886
+ ```
887
+
888
+ ```yaml
889
+ en:
890
+ user_mailer:
891
+ welcome:
892
+ subject: "%{user}, welcome to Rails Guides!"
893
+ ```
894
+
900
895
  ### Overview of Other Built-In Methods that Provide I18n Support
901
896
 
902
897
  Rails uses fixed strings and other localizations, such as format strings and other format information in a couple of helpers. Here's a brief overview.
@@ -921,6 +916,55 @@ Rails uses fixed strings and other localizations, such as format strings and oth
921
916
 
922
917
  * `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.
923
918
 
919
+ How to Store your Custom Translations
920
+ -------------------------------------
921
+
922
+ The Simple backend shipped with Active Support allows you to store translations in both plain Ruby and YAML format.[^2]
923
+
924
+ For example a Ruby Hash providing translations can look like this:
925
+
926
+ ```yaml
927
+ {
928
+ pt: {
929
+ foo: {
930
+ bar: "baz"
931
+ }
932
+ }
933
+ }
934
+ ```
935
+
936
+ The equivalent YAML file would look like this:
937
+
938
+ ```yaml
939
+ pt:
940
+ foo:
941
+ bar: baz
942
+ ```
943
+
944
+ 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".
945
+
946
+ Here is a "real" example from the Active Support `en.yml` translations YAML file:
947
+
948
+ ```yaml
949
+ en:
950
+ date:
951
+ formats:
952
+ default: "%Y-%m-%d"
953
+ short: "%b %d"
954
+ long: "%B %d, %Y"
955
+ ```
956
+
957
+ So, all of the following equivalent lookups will return the `:short` date format `"%b %d"`:
958
+
959
+ ```ruby
960
+ I18n.t 'date.formats.short'
961
+ I18n.t 'formats.short', scope: :date
962
+ I18n.t :short, scope: 'date.formats'
963
+ I18n.t :short, scope: [:date, :formats]
964
+ ```
965
+
966
+ 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.
967
+
924
968
  Customize your I18n Setup
925
969
  -------------------------
926
970
 
@@ -1006,9 +1050,9 @@ If you find anything missing or wrong in this guide, please file a ticket on our
1006
1050
  Contributing to Rails I18n
1007
1051
  --------------------------
1008
1052
 
1009
- I18n support in Ruby on Rails was introduced in the release 2.2 and is still evolving. The project follows the good Ruby on Rails development tradition of evolving solutions in plugins and real applications first, and only then cherry-picking the best-of-breed of most widely useful features for inclusion in the core.
1053
+ I18n support in Ruby on Rails was introduced in the release 2.2 and is still evolving. The project follows the good Ruby on Rails development tradition of evolving solutions in gems and real applications first, and only then cherry-picking the best-of-breed of most widely useful features for inclusion in the core.
1010
1054
 
1011
- Thus we encourage everybody to experiment with new ideas and features in plugins or other libraries and make them available to the community. (Don't forget to announce your work on our [mailing list](http://groups.google.com/group/rails-i18n!))
1055
+ Thus we encourage everybody to experiment with new ideas and features in gems or other libraries and make them available to the community. (Don't forget to announce your work on our [mailing list](http://groups.google.com/group/rails-i18n!))
1012
1056
 
1013
1057
  If you find your own locale (language) missing from our [example translations data](https://github.com/svenfuchs/rails-i18n/tree/master/rails/locale) repository for Ruby on Rails, please [_fork_](https://github.com/guides/fork-a-project-and-submit-your-modifications) the repository, add your data and send a [pull request](https://github.com/guides/pull-requests).
1014
1058
 
@@ -1016,7 +1060,6 @@ If you find your own locale (language) missing from our [example translations da
1016
1060
  Resources
1017
1061
  ---------
1018
1062
 
1019
- * [rails-i18n.org](http://rails-i18n.org) - Homepage of the rails-i18n project. You can find lots of useful resources on the [wiki](http://rails-i18n.org/wiki).
1020
1063
  * [Google group: rails-i18n](http://groups.google.com/group/rails-i18n) - The project's mailing list.
1021
1064
  * [GitHub: rails-i18n](https://github.com/svenfuchs/rails-i18n/tree/master) - Code repository for the rails-i18n project. Most importantly you can find lots of [example translations](https://github.com/svenfuchs/rails-i18n/tree/master/rails/locale) for Rails that should work for your application in most cases.
1022
1065
  * [GitHub: i18n](https://github.com/svenfuchs/i18n/tree/master) - Code repository for the i18n gem.
@@ -9,6 +9,7 @@ Ruby on Rails Guides
9
9
  <% content_for :index_section do %>
10
10
  <div id="subCol">
11
11
  <dl>
12
+ <dt></dt>
12
13
  <dd class="kindle">Rails Guides are also available for <%= link_to 'Kindle', @mobi %>.</dd>
13
14
  <dd class="work-in-progress">Guides marked with this icon are currently being worked on and will not be available in the Guides Index menu. While still useful, they may contain incomplete information and even errors. You can help by reviewing them and posting your comments and corrections.</dd>
14
15
  </dl>
@@ -98,9 +98,9 @@ configure the load path for your Gemfile's dependencies.
98
98
 
99
99
  A standard Rails application depends on several gems, specifically:
100
100
 
101
- * abstract
102
101
  * actionmailer
103
102
  * actionpack
103
+ * actionview
104
104
  * activemodel
105
105
  * activerecord
106
106
  * activesupport
@@ -111,7 +111,6 @@ A standard Rails application depends on several gems, specifically:
111
111
  * i18n
112
112
  * mail
113
113
  * mime-types
114
- * polyglot
115
114
  * rack
116
115
  * rack-cache
117
116
  * rack-mount
@@ -119,9 +118,8 @@ A standard Rails application depends on several gems, specifically:
119
118
  * rails
120
119
  * railties
121
120
  * rake
122
- * sqlite3-ruby
121
+ * sqlite3
123
122
  * thor
124
- * treetop
125
123
  * tzinfo
126
124
 
127
125
  ### `rails/commands.rb`
@@ -166,6 +164,7 @@ is called.
166
164
  COMMAND_WHITELIST = %(plugin generate destroy console server dbconsole application runner new version help)
167
165
 
168
166
  def run_command!(command)
167
+ command = parse_command(command)
169
168
  if COMMAND_WHITELIST.include?(command)
170
169
  send(command)
171
170
  else
@@ -178,8 +177,7 @@ With the `server` command, Rails will further run the following code:
178
177
 
179
178
  ```ruby
180
179
  def set_application_directory!
181
- Dir.chdir(File.expand_path('../../', APP_PATH)) unless
182
- File.exist?(File.expand_path("config.ru"))
180
+ Dir.chdir(File.expand_path('../../', APP_PATH)) unless File.exist?(File.expand_path("config.ru"))
183
181
  end
184
182
 
185
183
  def server
@@ -187,6 +185,8 @@ def server
187
185
  require_command!("server")
188
186
 
189
187
  Rails::Server.new.tap do |server|
188
+ # We need to require application after the server sets environment,
189
+ # otherwise the --environment option given to the server won't propagate.
190
190
  require APP_PATH
191
191
  Dir.chdir(Rails.application.root)
192
192
  server.start
@@ -207,6 +207,7 @@ sets up the `Rails::Server` class.
207
207
  require 'fileutils'
208
208
  require 'optparse'
209
209
  require 'action_dispatch'
210
+ require 'rails'
210
211
 
211
212
  module Rails
212
213
  class Server < ::Rack::Server
@@ -273,7 +274,7 @@ def parse_options(args)
273
274
  # http://www.meb.uni-bonn.de/docs/cgi/cl.html
274
275
  args.clear if ENV.include?("REQUEST_METHOD")
275
276
 
276
- options.merge! opt_parser.parse! args
277
+ options.merge! opt_parser.parse!(args)
277
278
  options[:config] = ::File.expand_path(options[:config])
278
279
  ENV["RACK_ENV"] = options[:environment]
279
280
  options
@@ -284,18 +285,21 @@ With the `default_options` set to this:
284
285
 
285
286
  ```ruby
286
287
  def default_options
288
+ environment = ENV['RACK_ENV'] || 'development'
289
+ default_host = environment == 'development' ? 'localhost' : '0.0.0.0'
290
+
287
291
  {
288
- environment: ENV['RACK_ENV'] || "development",
289
- pid: nil,
290
- Port: 9292,
291
- Host: "0.0.0.0",
292
- AccessLog: [],
293
- config: "config.ru"
292
+ :environment => environment,
293
+ :pid => nil,
294
+ :Port => 9292,
295
+ :Host => default_host,
296
+ :AccessLog => [],
297
+ :config => "config.ru"
294
298
  }
295
299
  end
296
300
  ```
297
301
 
298
- There is no `REQUEST_METHOD` key in `ENV` so we can skip over that line. The next line merges in the options from `opt_parser` which is defined plainly in `Rack::Server`
302
+ There is no `REQUEST_METHOD` key in `ENV` so we can skip over that line. The next line merges in the options from `opt_parser` which is defined plainly in `Rack::Server`:
299
303
 
300
304
  ```ruby
301
305
  def opt_parser
@@ -348,6 +352,7 @@ private
348
352
  def print_boot_information
349
353
  ...
350
354
  puts "=> Run `rails server -h` for more startup options"
355
+ ...
351
356
  puts "=> Ctrl-C to shutdown server" unless options[:daemonize]
352
357
  end
353
358
 
@@ -434,7 +439,11 @@ The `app` method here is defined like so:
434
439
 
435
440
  ```ruby
436
441
  def app
437
- @app ||= begin
442
+ @app ||= options[:builder] ? build_app_from_string : build_app_and_options_from_config
443
+ end
444
+ ...
445
+ private
446
+ def build_app_and_options_from_config
438
447
  if !::File.exist? options[:config]
439
448
  abort "configuration #{options[:config]} not found"
440
449
  end
@@ -443,7 +452,10 @@ def app
443
452
  self.options.merge! options
444
453
  app
445
454
  end
446
- end
455
+
456
+ def build_app_from_string
457
+ Rack::Builder.new_from_string(self.options[:builder])
458
+ end
447
459
  ```
448
460
 
449
461
  The `options[:config]` value defaults to `config.ru` which contains this:
@@ -459,8 +471,14 @@ run <%= app_const %>
459
471
  The `Rack::Builder.parse_file` method here takes the content from this `config.ru` file and parses it using this code:
460
472
 
461
473
  ```ruby
462
- app = eval "Rack::Builder.new {( " + cfgfile + "\n )}.to_app",
463
- TOPLEVEL_BINDING, config
474
+ app = new_from_string cfgfile, config
475
+
476
+ ...
477
+
478
+ def self.new_from_string(builder_script, file="(rackup)")
479
+ eval "Rack::Builder.new {\n" + builder_script + "\n}.to_app",
480
+ TOPLEVEL_BINDING, file, 0
481
+ end
464
482
  ```
465
483
 
466
484
  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 +491,22 @@ require ::File.expand_path('../config/environment', __FILE__)
473
491
 
474
492
  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.
475
493
 
476
- This file begins with requiring `config/application.rb`.
494
+ This file begins with requiring `config/application.rb`:
495
+
496
+ ```ruby
497
+ require File.expand_path('../application', __FILE__)
498
+ ```
477
499
 
478
500
  ### `config/application.rb`
479
501
 
480
- 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.
502
+ This file requires `config/boot.rb`:
503
+
504
+ ```ruby
505
+ require File.expand_path('../boot', __FILE__)
506
+ ```
507
+
508
+ But only if it hasn't been required before, which would be the case in `rails server`
509
+ but **wouldn't** be the case with Passenger.
481
510
 
482
511
  Then the fun begins!
483
512
 
@@ -498,11 +527,12 @@ This file is responsible for requiring all the individual frameworks of Rails:
498
527
  require "rails"
499
528
 
500
529
  %w(
501
- active_record
502
- action_controller
503
- action_mailer
504
- rails/test_unit
505
- sprockets
530
+ active_record
531
+ action_controller
532
+ action_view
533
+ action_mailer
534
+ rails/test_unit
535
+ sprockets
506
536
  ).each do |framework|
507
537
  begin
508
538
  require "#{framework}/railtie"
@@ -527,7 +557,7 @@ initialized. When `config/application.rb` has finished loading Rails and defined
527
557
  the application namespace, we go back to `config/environment.rb`,
528
558
  where the application is initialized. For example, if the application was called
529
559
  `Blog`, here we would find `Rails.application.initialize!`, which is
530
- defined in `rails/application.rb`
560
+ defined in `rails/application.rb`.
531
561
 
532
562
  ### `railties/lib/rails/application.rb`
533
563
 
@@ -543,7 +573,7 @@ end
543
573
  ```
544
574
 
545
575
  As you can see, you can only initialize an app once. The initializers are run through
546
- the `run_initializers` method which is defined in `railties/lib/rails/initializable.rb`
576
+ the `run_initializers` method which is defined in `railties/lib/rails/initializable.rb`:
547
577
 
548
578
  ```ruby
549
579
  def run_initializers(group=:default, *args)
@@ -555,7 +585,7 @@ def run_initializers(group=:default, *args)
555
585
  end
556
586
  ```
557
587
 
558
- The run_initializers code itself is tricky. What Rails is doing here is
588
+ The `run_initializers` code itself is tricky. What Rails is doing here is
559
589
  traversing all the class ancestors looking for those that respond to an
560
590
  `initializers` method. It then sorts the ancestors by name, and runs them.
561
591
  For example, the `Engine` class will make all the engines available by
@@ -568,7 +598,7 @@ initializers (like building the middleware stack) are run last. The `railtie`
568
598
  initializers are the initializers which have been defined on the `Rails::Application`
569
599
  itself and are run between the `bootstrap` and `finishers`.
570
600
 
571
- After this is done we go back to `Rack::Server`
601
+ After this is done we go back to `Rack::Server`.
572
602
 
573
603
  ### Rack: lib/rack/server.rb
574
604
 
@@ -576,7 +606,11 @@ Last time we left when the `app` method was being defined:
576
606
 
577
607
  ```ruby
578
608
  def app
579
- @app ||= begin
609
+ @app ||= options[:builder] ? build_app_from_string : build_app_and_options_from_config
610
+ end
611
+ ...
612
+ private
613
+ def build_app_and_options_from_config
580
614
  if !::File.exist? options[:config]
581
615
  abort "configuration #{options[:config]} not found"
582
616
  end
@@ -585,7 +619,10 @@ def app
585
619
  self.options.merge! options
586
620
  app
587
621
  end
588
- end
622
+
623
+ def build_app_from_string
624
+ Rack::Builder.new_from_string(self.options[:builder])
625
+ end
589
626
  ```
590
627
 
591
628
  At this point `app` is the Rails app itself (a middleware), and what
@@ -603,7 +640,7 @@ def build_app(app)
603
640
  end
604
641
  ```
605
642
 
606
- Remember, `build_app` was called (by wrapped_app) in the last line of `Server#start`.
643
+ Remember, `build_app` was called (by `wrapped_app`) in the last line of `Server#start`.
607
644
  Here's how it looked like when we left:
608
645
 
609
646
  ```ruby
@@ -611,40 +648,50 @@ server.run wrapped_app, options, &blk
611
648
  ```
612
649
 
613
650
  At this point, the implementation of `server.run` will depend on the
614
- server you're using. For example, if you were using Mongrel, here's what
651
+ server you're using. For example, if you were using Puma, here's what
615
652
  the `run` method would look like:
616
653
 
617
654
  ```ruby
618
- def self.run(app, options={})
619
- server = ::Mongrel::HttpServer.new(
620
- options[:Host] || '0.0.0.0',
621
- options[:Port] || 8080,
622
- options[:num_processors] || 950,
623
- options[:throttle] || 0,
624
- options[:timeout] || 60)
625
- # Acts like Rack::URLMap, utilizing Mongrel's own path finding methods.
626
- # Use is similar to #run, replacing the app argument with a hash of
627
- # { path=>app, ... } or an instance of Rack::URLMap.
628
- if options[:map]
629
- if app.is_a? Hash
630
- app.each do |path, appl|
631
- path = '/'+path unless path[0] == ?/
632
- server.register(path, Rack::Handler::Mongrel.new(appl))
633
- end
634
- elsif app.is_a? URLMap
635
- app.instance_variable_get(:@mapping).each do |(host, path, appl)|
636
- next if !host.nil? && !options[:Host].nil? && options[:Host] != host
637
- path = '/'+path unless path[0] == ?/
638
- server.register(path, Rack::Handler::Mongrel.new(appl))
639
- end
640
- else
641
- raise ArgumentError, "first argument should be a Hash or URLMap"
642
- end
643
- else
644
- server.register('/', Rack::Handler::Mongrel.new(app))
655
+ ...
656
+ DEFAULT_OPTIONS = {
657
+ :Host => '0.0.0.0',
658
+ :Port => 8080,
659
+ :Threads => '0:16',
660
+ :Verbose => false
661
+ }
662
+
663
+ def self.run(app, options = {})
664
+ options = DEFAULT_OPTIONS.merge(options)
665
+
666
+ if options[:Verbose]
667
+ app = Rack::CommonLogger.new(app, STDOUT)
645
668
  end
669
+
670
+ if options[:environment]
671
+ ENV['RACK_ENV'] = options[:environment].to_s
672
+ end
673
+
674
+ server = ::Puma::Server.new(app)
675
+ min, max = options[:Threads].split(':', 2)
676
+
677
+ puts "Puma #{::Puma::Const::PUMA_VERSION} starting..."
678
+ puts "* Min threads: #{min}, max threads: #{max}"
679
+ puts "* Environment: #{ENV['RACK_ENV']}"
680
+ puts "* Listening on tcp://#{options[:Host]}:#{options[:Port]}"
681
+
682
+ server.add_tcp_listener options[:Host], options[:Port]
683
+ server.min_threads = min
684
+ server.max_threads = max
646
685
  yield server if block_given?
647
- server.run.join
686
+
687
+ begin
688
+ server.run.join
689
+ rescue Interrupt
690
+ puts "* Gracefully stopping, waiting for requests to finish"
691
+ server.stop(true)
692
+ puts "* Goodbye!"
693
+ end
694
+
648
695
  end
649
696
  ```
650
697