rails 4.0.13 → 4.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rails might be problematic. Click here for more details.

Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +20 -15
  3. data/guides/CHANGELOG.md +5 -74
  4. data/guides/assets/images/edge_badge.png +0 -0
  5. data/guides/assets/images/feature_tile.gif +0 -0
  6. data/guides/assets/images/footer_tile.gif +0 -0
  7. data/guides/assets/images/fxn.png +0 -0
  8. data/guides/assets/images/getting_started/challenge.png +0 -0
  9. data/guides/assets/images/getting_started/forbidden_attributes_for_new_post.png +0 -0
  10. data/guides/assets/images/getting_started/new_post.png +0 -0
  11. data/guides/assets/images/getting_started/routing_error_no_controller.png +0 -0
  12. data/guides/assets/images/getting_started/routing_error_no_route_matches.png +0 -0
  13. data/guides/assets/images/getting_started/template_is_missing_posts_new.png +0 -0
  14. data/guides/assets/images/getting_started/unknown_action_create_for_posts.png +0 -0
  15. data/guides/assets/images/getting_started/unknown_action_new_for_posts.png +0 -0
  16. data/guides/assets/images/header_tile.gif +0 -0
  17. data/guides/assets/images/icons/README +1 -1
  18. data/guides/assets/images/icons/callouts/11.png +0 -0
  19. data/guides/assets/images/icons/callouts/12.png +0 -0
  20. data/guides/assets/images/icons/callouts/13.png +0 -0
  21. data/guides/assets/images/icons/callouts/15.png +0 -0
  22. data/guides/assets/images/icons/caution.png +0 -0
  23. data/guides/assets/images/icons/example.png +0 -0
  24. data/guides/assets/images/radar.png +0 -0
  25. data/guides/assets/images/rails4_features.png +0 -0
  26. data/guides/assets/images/rails_guides_kindle_cover.jpg +0 -0
  27. data/guides/assets/images/vijaydev.jpg +0 -0
  28. data/guides/assets/javascripts/guides.js +30 -34
  29. data/guides/assets/stylesheets/main.css +2 -1
  30. data/guides/assets/stylesheets/print.css +1 -1
  31. data/guides/bug_report_templates/action_controller_gem.rb +2 -0
  32. data/guides/bug_report_templates/action_controller_master.rb +2 -0
  33. data/guides/bug_report_templates/active_record_gem.rb +1 -1
  34. data/guides/bug_report_templates/active_record_master.rb +2 -1
  35. data/guides/code/getting_started/Gemfile +1 -1
  36. data/guides/code/getting_started/app/assets/javascripts/application.js +1 -2
  37. data/guides/code/getting_started/config/environments/development.rb +1 -1
  38. data/guides/code/getting_started/public/404.html +2 -0
  39. data/guides/code/getting_started/public/422.html +2 -0
  40. data/guides/code/getting_started/public/500.html +2 -0
  41. data/guides/rails_guides/helpers.rb +1 -1
  42. data/guides/source/2_2_release_notes.md +2 -2
  43. data/guides/source/2_3_release_notes.md +8 -8
  44. data/guides/source/3_0_release_notes.md +1 -2
  45. data/guides/source/3_1_release_notes.md +1 -1
  46. data/guides/source/3_2_release_notes.md +12 -12
  47. data/guides/source/4_0_release_notes.md +79 -46
  48. data/guides/source/4_1_release_notes.md +601 -0
  49. data/guides/source/_welcome.html.erb +1 -1
  50. data/guides/source/action_controller_overview.md +117 -31
  51. data/guides/source/action_mailer_basics.md +19 -19
  52. data/guides/source/action_view_overview.md +131 -12
  53. data/guides/source/active_model_basics.md +6 -6
  54. data/guides/source/active_record_basics.md +15 -15
  55. data/guides/source/active_record_callbacks.md +18 -16
  56. data/guides/source/active_record_querying.md +67 -39
  57. data/guides/source/active_record_validations.md +31 -31
  58. data/guides/source/active_support_core_extensions.md +63 -74
  59. data/guides/source/active_support_instrumentation.md +13 -4
  60. data/guides/source/api_documentation_guidelines.md +19 -5
  61. data/guides/source/asset_pipeline.md +544 -249
  62. data/guides/source/association_basics.md +81 -22
  63. data/guides/source/caching_with_rails.md +15 -6
  64. data/guides/source/command_line.md +28 -19
  65. data/guides/source/configuring.md +98 -50
  66. data/guides/source/contributing_to_ruby_on_rails.md +11 -11
  67. data/guides/source/credits.html.erb +2 -2
  68. data/guides/source/debugging_rails_applications.md +36 -5
  69. data/guides/source/development_dependencies_install.md +89 -8
  70. data/guides/source/documents.yaml +7 -1
  71. data/guides/source/engines.md +648 -224
  72. data/guides/source/form_helpers.md +56 -45
  73. data/guides/source/generators.md +7 -3
  74. data/guides/source/getting_started.md +379 -164
  75. data/guides/source/i18n.md +59 -23
  76. data/guides/source/index.html.erb +1 -1
  77. data/guides/source/initialization.md +153 -56
  78. data/guides/source/kindle/toc.html.erb +1 -1
  79. data/guides/source/layout.html.erb +3 -3
  80. data/guides/source/layouts_and_rendering.md +12 -11
  81. data/guides/source/maintenance_policy.md +4 -23
  82. data/guides/source/migrations.md +41 -37
  83. data/guides/source/nested_model_forms.md +3 -3
  84. data/guides/source/plugins.md +27 -23
  85. data/guides/source/rails_application_templates.md +25 -6
  86. data/guides/source/rails_on_rack.md +35 -51
  87. data/guides/source/routing.md +108 -99
  88. data/guides/source/ruby_on_rails_guides_guidelines.md +2 -2
  89. data/guides/source/security.md +33 -31
  90. data/guides/source/testing.md +37 -34
  91. data/guides/source/upgrading_ruby_on_rails.md +335 -16
  92. data/guides/source/working_with_javascript_in_rails.md +18 -10
  93. metadata +66 -39
  94. data/guides/assets/images/jaimeiniesta.jpg +0 -0
  95. data/guides/source/kindle/KINDLE.md +0 -26
@@ -13,17 +13,22 @@ So, in the process of _internationalizing_ your Rails application you have to:
13
13
 
14
14
  In the process of _localizing_ your application you'll probably want to do the following three things:
15
15
 
16
- * Replace or supplement Rails' default locale e.g. date and time formats, month names, Active Record model names, etc.
17
- * Abstract strings in your application into keyed dictionaries e.g. flash messages, static text in your views, etc.
16
+ * Replace or supplement Rails' default locale - e.g. date and time formats, month names, Active Record model names, etc.
17
+ * Abstract strings in your application into keyed dictionaries - e.g. flash messages, static text in your views, etc.
18
18
  * Store the resulting dictionaries somewhere.
19
19
 
20
20
  This guide will walk you through the I18n API and contains a tutorial on how to internationalize a Rails application from the start.
21
21
 
22
22
  After reading this guide, you will know:
23
23
 
24
+ * How I18n works in Ruby on Rails
25
+ * How to correctly use I18n into a RESTful application in various ways
26
+ * How to use I18n to translate ActiveRecord errors or ActionMailer E-mail subjects
27
+ * Some other tools to go further with the translation process of your application
28
+
24
29
  --------------------------------------------------------------------------------
25
30
 
26
- 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 Rails [I18n Wiki](http://rails-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, 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.
27
32
 
28
33
  How I18n in Ruby on Rails Works
29
34
  -------------------------------
@@ -33,13 +38,13 @@ Internationalization is a complex problem. Natural languages differ in so many w
33
38
  * providing support for English and similar languages out of the box
34
39
  * making it easy to customize and extend everything for other languages
35
40
 
36
- As part of this solution, **every static string in the Rails framework** e.g. Active Record validation messages, time and date formats **has been internationalized**, so _localization_ of a Rails application means "over-riding" these defaults.
41
+ As part of this solution, **every static string in the Rails framework** - e.g. Active Record validation messages, time and date formats - **has been internationalized**, so _localization_ of a Rails application means "over-riding" these defaults.
37
42
 
38
43
  ### The Overall Architecture of the Library
39
44
 
40
45
  Thus, the Ruby I18n gem is split into two parts:
41
46
 
42
- * The public API of the i18n framework a Ruby module with public methods that define how the library works
47
+ * The public API of the i18n framework - a Ruby module with public methods that define how the library works
43
48
  * A default backend (which is intentionally named _Simple_ backend) that implements these methods
44
49
 
45
50
  As a user you should always only access the public methods on the I18n module, but it is useful to know about the capabilities of the backend.
@@ -174,7 +179,7 @@ end
174
179
  # in your /etc/hosts file to try this out locally
175
180
  def extract_locale_from_tld
176
181
  parsed_locale = request.host.split('.').last
177
- I18n.available_locales.map(&:to_s).include?(parsed_locale) ? parsed_locale : nil
182
+ I18n.available_locales.include?(parsed_locale.to_sym) ? parsed_locale : nil
178
183
  end
179
184
  ```
180
185
 
@@ -187,7 +192,7 @@ We can also set the locale from the _subdomain_ in a very similar way:
187
192
  # in your /etc/hosts file to try this out locally
188
193
  def extract_locale_from_subdomain
189
194
  parsed_locale = request.subdomains.first
190
- I18n.available_locales.map(&:to_s).include?(parsed_locale) ? parsed_locale : nil
195
+ I18n.available_locales.include?(parsed_locale.to_sym) ? parsed_locale : nil
191
196
  end
192
197
  ```
193
198
 
@@ -262,7 +267,7 @@ NOTE: Have a look at two plugins which simplify work with routes in this way: Sv
262
267
 
263
268
  ### Setting the Locale from the Client Supplied Information
264
269
 
265
- In specific cases, it would make sense to set the locale from client-supplied information, i.e. not from the URL. This information may come for example from the users' preferred language (set in their browser), can be based on the users' geographical location inferred from their IP, or users can provide it simply by choosing the locale in your application interface and saving it to their profile. This approach is more suitable for web-based applications or services, not for websites see the box about _sessions_, _cookies_ and RESTful architecture above.
270
+ In specific cases, it would make sense to set the locale from client-supplied information, i.e. not from the URL. This information may come for example from the users' preferred language (set in their browser), can be based on the users' geographical location inferred from their IP, or users can provide it simply by choosing the locale in your application interface and saving it to their profile. This approach is more suitable for web-based applications or services, not for websites - see the box about _sessions_, _cookies_ and RESTful architecture above.
266
271
 
267
272
 
268
273
  #### Using `Accept-Language`
@@ -277,21 +282,22 @@ def set_locale
277
282
  I18n.locale = extract_locale_from_accept_language_header
278
283
  logger.debug "* Locale set to '#{I18n.locale}'"
279
284
  end
285
+
280
286
  private
281
- def extract_locale_from_accept_language_header
282
- request.env['HTTP_ACCEPT_LANGUAGE'].scan(/^[a-z]{2}/).first
283
- end
287
+ def extract_locale_from_accept_language_header
288
+ request.env['HTTP_ACCEPT_LANGUAGE'].scan(/^[a-z]{2}/).first
289
+ end
284
290
  ```
285
291
 
286
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).
287
293
 
288
294
  #### Using GeoIP (or Similar) Database
289
295
 
290
- Another way of choosing the locale from client information would be to use a database for mapping the client IP to the region, such as [GeoIP Lite Country](http://www.maxmind.com/app/geolitecountry). The mechanics of the code would be very similar to the code above you would need to query the database for the user's IP, and look up your preferred locale for the country/region/city returned.
296
+ Another way of choosing the locale from client information would be to use a database for mapping the client IP to the region, such as [GeoIP Lite Country](http://www.maxmind.com/app/geolitecountry). The mechanics of the code would be very similar to the code above - you would need to query the database for the user's IP, and look up your preferred locale for the country/region/city returned.
291
297
 
292
298
  #### User Profile
293
299
 
294
- You can also provide users of your application with means to set (and possibly over-ride) the locale in your application interface, as well. Again, mechanics for this approach would be very similar to the code above you'd probably let users choose a locale from a dropdown list and save it to their profile in the database. Then you'd set the locale to this value.
300
+ You can also provide users of your application with means to set (and possibly over-ride) the locale in your application interface, as well. Again, mechanics for this approach would be very similar to the code above - you'd probably let users choose a locale from a dropdown list and save it to their profile in the database. Then you'd set the locale to this value.
295
301
 
296
302
  Internationalizing your Application
297
303
  -----------------------------------
@@ -309,6 +315,17 @@ Yourapp::Application.routes.draw do
309
315
  end
310
316
  ```
311
317
 
318
+ ```ruby
319
+ # app/controllers/application_controller.rb
320
+ class ApplicationController < ActionController::Base
321
+ before_action :set_locale
322
+
323
+ def set_locale
324
+ I18n.locale = params[:locale] || I18n.default_locale
325
+ end
326
+ end
327
+ ```
328
+
312
329
  ```ruby
313
330
  # app/controllers/home_controller.rb
314
331
  class HomeController < ApplicationController
@@ -394,7 +411,7 @@ en:
394
411
 
395
412
  ### Adding Date/Time Formats
396
413
 
397
- OK! Now let's add a timestamp to the view, so we can demo the **date/time localization** feature as well. To localize the time format you pass the Time object to `I18n.l` or (preferably) use Rails' `#l` helper. You can pick a format by passing the `:format` option by default the `:default` format is used.
414
+ OK! Now let's add a timestamp to the view, so we can demo the **date/time localization** feature as well. To localize the time format you pass the Time object to `I18n.l` or (preferably) use Rails' `#l` helper. You can pick a format by passing the `:format` option - by default the `:default` format is used.
398
415
 
399
416
  ```erb
400
417
  # app/views/home/index.html.erb
@@ -475,12 +492,14 @@ Overview of the I18n API Features
475
492
 
476
493
  You should have good understanding of using the i18n library now, knowing all necessary aspects of internationalizing a basic Rails application. In the following chapters, we'll cover it's features in more depth.
477
494
 
495
+ These chapters will show examples using both the `I18n.translate` method as well as the [`translate` view helper method](http://api.rubyonrails.org/classes/ActionView/Helpers/TranslationHelper.html#method-i-translate) (noting the additional feature provide by the view helper method).
496
+
478
497
  Covered are features like these:
479
498
 
480
499
  * looking up translations
481
500
  * interpolating data into translations
482
501
  * pluralizing translations
483
- * using safe HTML translations
502
+ * using safe HTML translations (view helper method only)
484
503
  * localizing dates, numbers, currency, etc.
485
504
 
486
505
  ### Looking up Translations
@@ -494,7 +513,7 @@ I18n.t :message
494
513
  I18n.t 'message'
495
514
  ```
496
515
 
497
- The `translate` method also takes a `:scope` option which can contain one or more additional keys that will be used to specify a namespace or scope for a translation key:
516
+ The `translate` method also takes a `:scope` option which can contain one or more additional keys that will be used to specify a "namespace" or scope for a translation key:
498
517
 
499
518
  ```ruby
500
519
  I18n.t :record_invalid, scope: [:activerecord, :errors, :messages]
@@ -568,6 +587,8 @@ you can look up the `books.index.title` value **inside** `app/views/books/index.
568
587
  <%= t '.title' %>
569
588
  ```
570
589
 
590
+ NOTE: Automatic translation scoping by partial is only available from the `translate` view helper method.
591
+
571
592
  ### Interpolation
572
593
 
573
594
  In many cases you want to abstract your translations so that **variables can be interpolated into the translation**. For this reason the I18n API provides an interpolation feature.
@@ -656,6 +677,8 @@ en:
656
677
  <div><%= t('title.html') %></div>
657
678
  ```
658
679
 
680
+ NOTE: Automatic conversion to HTML safe translate text is only available from the `translate` view helper method.
681
+
659
682
  ![i18n demo html safe](images/i18n/demo_html_safe.png)
660
683
 
661
684
  How to Store your Custom Translations
@@ -726,6 +749,19 @@ en:
726
749
 
727
750
  Then `User.model_name.human` will return "Dude" and `User.human_attribute_name("login")` will return "Handle".
728
751
 
752
+ You can also set a plural form for model names, adding as following:
753
+
754
+ ```ruby
755
+ en:
756
+ activerecord:
757
+ models:
758
+ user:
759
+ one: Dude
760
+ other: Dudes
761
+ ```
762
+
763
+ Then `User.model_name.human(count: 2)` will return "Dudes". With `count: 1` or without params will return "Dude".
764
+
729
765
  #### Error Message Scopes
730
766
 
731
767
  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.
@@ -867,15 +903,15 @@ Rails uses fixed strings and other localizations, such as format strings and oth
867
903
 
868
904
  #### Action View Helper Methods
869
905
 
870
- * `distance_of_time_in_words` translates and pluralizes its result and interpolates the number of seconds, minutes, hours, and so on. See [datetime.distance_in_words](https://github.com/rails/rails/blob/master/actionpack/lib/action_view/locale/en.yml#L51) translations.
906
+ * `distance_of_time_in_words` translates and pluralizes its result and interpolates the number of seconds, minutes, hours, and so on. See [datetime.distance_in_words](https://github.com/rails/rails/blob/master/actionview/lib/action_view/locale/en.yml#L4) translations.
871
907
 
872
- * `datetime_select` and `select_month` use translated month names for populating the resulting select tag. See [date.month_names](https://github.com/rails/rails/blob/master/activesupport/lib/active_support/locale/en.yml#L15) for translations. `datetime_select` also looks up the order option from [date.order](https://github.com/rails/rails/blob/master/activesupport/lib/active_support/locale/en.yml#L18) (unless you pass the option explicitly). All date selection helpers translate the prompt using the translations in the [datetime.prompts](https://github.com/rails/rails/blob/master/actionpack/lib/action_view/locale/en.yml#L83) scope if applicable.
908
+ * `datetime_select` and `select_month` use translated month names for populating the resulting select tag. See [date.month_names](https://github.com/rails/rails/blob/master/activesupport/lib/active_support/locale/en.yml#L15) for translations. `datetime_select` also looks up the order option from [date.order](https://github.com/rails/rails/blob/master/activesupport/lib/active_support/locale/en.yml#L18) (unless you pass the option explicitly). All date selection helpers translate the prompt using the translations in the [datetime.prompts](https://github.com/rails/rails/blob/master/actionview/lib/action_view/locale/en.yml#L39) scope if applicable.
873
909
 
874
- * The `number_to_currency`, `number_with_precision`, `number_to_percentage`, `number_with_delimiter`, and `number_to_human_size` helpers use the number format settings located in the [number](https://github.com/rails/rails/blob/master/actionpack/lib/action_view/locale/en.yml#L2) scope.
910
+ * The `number_to_currency`, `number_with_precision`, `number_to_percentage`, `number_with_delimiter`, and `number_to_human_size` helpers use the number format settings located in the [number](https://github.com/rails/rails/blob/master/activesupport/lib/active_support/locale/en.yml#L37) scope.
875
911
 
876
912
  #### Active Model Methods
877
913
 
878
- * `model_name.human` and `human_attribute_name` use translations for model names and attribute names if available in the [activerecord.models](https://github.com/rails/rails/blob/master/activerecord/lib/active_record/locale/en.yml#L29) scope. They also support translations for inherited class names (e.g. for use with STI) as explained above in "Error message scopes".
914
+ * `model_name.human` and `human_attribute_name` use translations for model names and attribute names if available in the [activerecord.models](https://github.com/rails/rails/blob/master/activerecord/lib/active_record/locale/en.yml#L36) scope. They also support translations for inherited class names (e.g. for use with STI) as explained above in "Error message scopes".
879
915
 
880
916
  * `ActiveModel::Errors#generate_message` (which is used by Active Model validations but may also be used manually) uses `model_name.human` and `human_attribute_name` (see above). It also translates the error message and supports translations for inherited class names as explained above in "Error message scopes".
881
917
 
@@ -883,7 +919,7 @@ Rails uses fixed strings and other localizations, such as format strings and oth
883
919
 
884
920
  #### Active Support Methods
885
921
 
886
- * `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#L30) scope.
922
+ * `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.
887
923
 
888
924
  Customize your I18n Setup
889
925
  -------------------------
@@ -917,7 +953,7 @@ ReservedInterpolationKey # the translation contains a reserved interpolation
917
953
  UnknownFileType # the backend does not know how to handle a file type that was added to I18n.load_path
918
954
  ```
919
955
 
920
- The I18n API will catch all of these exceptions when they are thrown in the backend and pass them to the default_exception_handler method. This method will re-raise all exceptions except for `MissingTranslationData` exceptions. When a `MissingTranslationData` exception has been caught, it will return the exceptions error message string containing the missing key/scope.
956
+ The I18n API will catch all of these exceptions when they are thrown in the backend and pass them to the default_exception_handler method. This method will re-raise all exceptions except for `MissingTranslationData` exceptions. When a `MissingTranslationData` exception has been caught, it will return the exception's error message string containing the missing key/scope.
921
957
 
922
958
  The reason for this is that during development you'd usually want your views to still render even though a translation is missing.
923
959
 
@@ -1000,7 +1036,7 @@ If you found this guide useful, please consider recommending its authors on [wor
1000
1036
  Footnotes
1001
1037
  ---------
1002
1038
 
1003
- [^1]: Or, to quote [Wikipedia](http://en.wikipedia.org/wiki/Internationalization_and_localization:) _"Internationalization is the process of designing a software application so that it can be adapted to various languages and regions without engineering changes. Localization is the process of adapting software for a specific region or language by adding locale-specific components and translating text."_
1039
+ [^1]: Or, to quote [Wikipedia](http://en.wikipedia.org/wiki/Internationalization_and_localization): _"Internationalization is the process of designing a software application so that it can be adapted to various languages and regions without engineering changes. Localization is the process of adapting software for a specific region or language by adding locale-specific components and translating text."_
1004
1040
 
1005
1041
  [^2]: Other backends might allow or require to use other formats, e.g. a GetText backend might allow to read GetText files.
1006
1042
 
@@ -19,7 +19,7 @@ Ruby on Rails Guides
19
19
  <h3><%= section['name'] %></h3>
20
20
  <dl>
21
21
  <% section['documents'].each do |document| %>
22
- <%= guide(document['name'], document['url'], :work_in_progress => document['work_in_progress']) do %>
22
+ <%= guide(document['name'], document['url'], work_in_progress: document['work_in_progress']) do %>
23
23
  <p><%= document['description'] %></p>
24
24
  <% end %>
25
25
  <% end %>
@@ -7,14 +7,17 @@ as of Rails 4. It is an extremely in-depth guide and recommended for advanced Ra
7
7
  After reading this guide, you will know:
8
8
 
9
9
  * How to use `rails server`.
10
+ * The timeline of Rails' initialization sequence.
11
+ * Where different files are required by the boot sequence.
12
+ * How the Rails::Server interface is defined and used.
10
13
 
11
14
  --------------------------------------------------------------------------------
12
15
 
13
16
  This guide goes through every method call that is
14
17
  required to boot up the Ruby on Rails stack for a default Rails 4
15
18
  application, explaining each part in detail along the way. For this
16
- guide, we will be focusing on what happens when you execute +rails
17
- server+ to boot your app.
19
+ guide, we will be focusing on what happens when you execute `rails server`
20
+ to boot your app.
18
21
 
19
22
  NOTE: Paths in this guide are relative to Rails or a Rails application unless otherwise specified.
20
23
 
@@ -26,9 +29,42 @@ quickly.
26
29
  Launch!
27
30
  -------
28
31
 
29
- Now we finally boot and initialize the app. It all starts with your app's
30
- `bin/rails` executable. A Rails application is usually started by running
31
- `rails console` or `rails server`.
32
+ Let's start to boot and initialize the app. A Rails application is usually
33
+ started by running `rails console` or `rails server`.
34
+
35
+ ### `railties/bin/rails`
36
+
37
+ The `rails` in the command `rails server` is a ruby executable in your load
38
+ path. This executable contains the following lines:
39
+
40
+ ```ruby
41
+ version = ">= 0"
42
+ load Gem.bin_path('railties', 'rails', version)
43
+ ```
44
+
45
+ If you try out this command in a Rails console, you would see that this loads
46
+ `railties/bin/rails`. A part of the file `railties/bin/rails.rb` has the
47
+ following code:
48
+
49
+ ```ruby
50
+ require "rails/cli"
51
+ ```
52
+
53
+ The file `railties/lib/rails/cli` in turn calls
54
+ `Rails::AppRailsLoader.exec_app_rails`.
55
+
56
+ ### `railties/lib/rails/app_rails_loader.rb`
57
+
58
+ The primary goal of the function `exec_app_rails` is to execute your app's
59
+ `bin/rails`. If the current directory does not have a `bin/rails`, it will
60
+ navigate upwards until it finds a `bin/rails` executable. Thus one can invoke a
61
+ `rails` command from anywhere inside a rails application.
62
+
63
+ For `rails server` the equivalent of the following command is executed:
64
+
65
+ ```bash
66
+ $ exec ruby bin/rails server
67
+ ```
32
68
 
33
69
  ### `bin/rails`
34
70
 
@@ -36,8 +72,8 @@ This file is as follows:
36
72
 
37
73
  ```ruby
38
74
  #!/usr/bin/env ruby
39
- APP_PATH = File.expand_path('../../config/application', __FILE__)
40
- require File.expand_path('../../config/boot', __FILE__)
75
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
76
+ require_relative '../config/boot'
41
77
  require 'rails/commands'
42
78
  ```
43
79
 
@@ -57,7 +93,8 @@ require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
57
93
  In a standard Rails application, there's a `Gemfile` which declares all
58
94
  dependencies of the application. `config/boot.rb` sets
59
95
  `ENV['BUNDLE_GEMFILE']` to the location of this file. If the Gemfile
60
- exists, `bundler/setup` is then required.
96
+ exists, then `bundler/setup` is required. The require is used by Bundler to
97
+ configure the load path for your Gemfile's dependencies.
61
98
 
62
99
  A standard Rails application depends on several gems, specifically:
63
100
 
@@ -89,7 +126,9 @@ A standard Rails application depends on several gems, specifically:
89
126
 
90
127
  ### `rails/commands.rb`
91
128
 
92
- Once `config/boot.rb` has finished, the next file that is required is `rails/commands` which will execute a command based on the arguments passed in. In this case, the `ARGV` array simply contains `server` which is extracted into the `command` variable using these lines:
129
+ Once `config/boot.rb` has finished, the next file that is required is
130
+ `rails/commands`, which helps in expanding aliases. In the current case, the
131
+ `ARGV` array simply contains `server` which will be passed over:
93
132
 
94
133
  ```ruby
95
134
  ARGV << '--help' if ARGV.empty?
@@ -105,31 +144,64 @@ aliases = {
105
144
 
106
145
  command = ARGV.shift
107
146
  command = aliases[command] || command
147
+
148
+ require 'rails/commands/commands_tasks'
149
+
150
+ Rails::CommandsTasks.new(ARGV).run_command!(command)
108
151
  ```
109
152
 
110
153
  TIP: As you can see, an empty ARGV list will make Rails show the help
111
154
  snippet.
112
155
 
113
- If we used `s` rather than `server`, Rails will use the `aliases` defined in the file and match them to their respective commands. With the `server` command, Rails will run this code:
156
+ If we had used `s` rather than `server`, Rails would have used the `aliases`
157
+ defined here to find the matching command.
158
+
159
+ ### `rails/commands/command_tasks.rb`
160
+
161
+ When one types an incorrect rails command, the `run_command` is responsible for
162
+ throwing an error message. If the command is valid, a method of the same name
163
+ is called.
164
+
165
+ ```ruby
166
+ COMMAND_WHITELIST = %(plugin generate destroy console server dbconsole application runner new version help)
167
+
168
+ def run_command!(command)
169
+ if COMMAND_WHITELIST.include?(command)
170
+ send(command)
171
+ else
172
+ write_error_message(command)
173
+ end
174
+ end
175
+ ```
176
+
177
+ With the `server` command, Rails will further run the following code:
114
178
 
115
179
  ```ruby
116
- when 'server'
117
- # Change to the application's path if there is no config.ru file in current dir.
118
- # This allows us to run `rails server` from other directories, but still get
119
- # the main config.ru and properly set the tmp directory.
120
- Dir.chdir(File.expand_path('../../', APP_PATH)) unless File.exist?(File.expand_path("config.ru"))
180
+ def set_application_directory!
181
+ Dir.chdir(File.expand_path('../../', APP_PATH)) unless
182
+ File.exist?(File.expand_path("config.ru"))
183
+ end
184
+
185
+ def server
186
+ set_application_directory!
187
+ require_command!("server")
121
188
 
122
- require 'rails/commands/server'
123
189
  Rails::Server.new.tap do |server|
124
- # We need to require application after the server sets environment,
125
- # otherwise the --environment option given to the server won't propagate.
126
190
  require APP_PATH
127
191
  Dir.chdir(Rails.application.root)
128
192
  server.start
129
193
  end
194
+ end
195
+
196
+ def require_command!(command)
197
+ require "rails/commands/#{command}"
198
+ end
130
199
  ```
131
200
 
132
- This file will change into the Rails root directory (a path two directories up from `APP_PATH` which points at `config/application.rb`), but only if the `config.ru` file isn't found. This then requires `rails/commands/server` which sets up the `Rails::Server` class.
201
+ This file will change into the Rails root directory (a path two directories up
202
+ from `APP_PATH` which points at `config/application.rb`), but only if the
203
+ `config.ru` file isn't found. This then requires `rails/commands/server` which
204
+ sets up the `Rails::Server` class.
133
205
 
134
206
  ```ruby
135
207
  require 'fileutils'
@@ -213,12 +285,12 @@ With the `default_options` set to this:
213
285
  ```ruby
214
286
  def default_options
215
287
  {
216
- :environment => ENV['RACK_ENV'] || "development",
217
- :pid => nil,
218
- :Port => 9292,
219
- :Host => "0.0.0.0",
220
- :AccessLog => [],
221
- :config => "config.ru"
288
+ environment: ENV['RACK_ENV'] || "development",
289
+ pid: nil,
290
+ Port: 9292,
291
+ Host: "0.0.0.0",
292
+ AccessLog: [],
293
+ config: "config.ru"
222
294
  }
223
295
  end
224
296
  ```
@@ -251,43 +323,49 @@ set earlier) is required.
251
323
 
252
324
  ### `config/application`
253
325
 
254
- When `require APP_PATH` is executed, `config/application.rb` is loaded.
255
- This file exists in your app and it's free for you to change based
256
- on your needs.
326
+ When `require APP_PATH` is executed, `config/application.rb` is loaded (recall
327
+ that `APP_PATH` is defined in `bin/rails`). This file exists in your application
328
+ and it's free for you to change based on your needs.
257
329
 
258
330
  ### `Rails::Server#start`
259
331
 
260
- After `config/application` is loaded, `server.start` is called. This method is defined like this:
332
+ After `config/application` is loaded, `server.start` is called. This method is
333
+ defined like this:
261
334
 
262
335
  ```ruby
263
336
  def start
264
- url = "#{options[:SSLEnable] ? 'https' : 'http'}://#{options[:Host]}:#{options[:Port]}"
265
- puts "=> Booting #{ActiveSupport::Inflector.demodulize(server)}"
266
- puts "=> Rails #{Rails.version} application starting in #{Rails.env} on #{url}"
267
- puts "=> Run `rails server -h` for more startup options"
337
+ print_boot_information
268
338
  trap(:INT) { exit }
269
- puts "=> Ctrl-C to shutdown server" unless options[:daemonize]
339
+ create_tmp_directories
340
+ log_to_stdout if options[:log_stdout]
341
+
342
+ super
343
+ ...
344
+ end
270
345
 
271
- #Create required tmp directories if not found
272
- %w(cache pids sessions sockets).each do |dir_to_make|
273
- FileUtils.mkdir_p(Rails.root.join('tmp', dir_to_make))
346
+ private
347
+
348
+ def print_boot_information
349
+ ...
350
+ puts "=> Run `rails server -h` for more startup options"
351
+ puts "=> Ctrl-C to shutdown server" unless options[:daemonize]
352
+ end
353
+
354
+ def create_tmp_directories
355
+ %w(cache pids sessions sockets).each do |dir_to_make|
356
+ FileUtils.mkdir_p(File.join(Rails.root, 'tmp', dir_to_make))
357
+ end
274
358
  end
275
359
 
276
- unless options[:daemonize]
360
+ def log_to_stdout
277
361
  wrapped_app # touch the app so the logger is set up
278
362
 
279
363
  console = ActiveSupport::Logger.new($stdout)
280
364
  console.formatter = Rails.logger.formatter
365
+ console.level = Rails.logger.level
281
366
 
282
367
  Rails.logger.extend(ActiveSupport::Logger.broadcast(console))
283
368
  end
284
-
285
- super
286
- ensure
287
- # The '-h' option calls exit before @options is set.
288
- # If we call 'options' with it unset, we get double help banners.
289
- puts 'Exiting' unless @options && options[:daemonize]
290
- end
291
369
  ```
292
370
 
293
371
  This is where the first output of the Rails initialization happens. This
@@ -346,7 +424,7 @@ end
346
424
 
347
425
  The interesting part for a Rails app is the last line, `server.run`. Here we encounter the `wrapped_app` method again, which this time
348
426
  we're going to explore more (even though it was executed before, and
349
- thus memorized by now).
427
+ thus memoized by now).
350
428
 
351
429
  ```ruby
352
430
  @wrapped_app ||= build_app app
@@ -373,7 +451,7 @@ The `options[:config]` value defaults to `config.ru` which contains this:
373
451
  ```ruby
374
452
  # This file is used by Rack-based servers to start the application.
375
453
 
376
- require ::File.expand_path('../config/environment', __FILE__)
454
+ require ::File.expand_path('../config/environment', __FILE__)
377
455
  run <%= app_const %>
378
456
  ```
379
457
 
@@ -388,7 +466,7 @@ app = eval "Rack::Builder.new {( " + cfgfile + "\n )}.to_app",
388
466
  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:
389
467
 
390
468
  ```ruby
391
- require ::File.expand_path('../config/environment', __FILE__)
469
+ require ::File.expand_path('../config/environment', __FILE__)
392
470
  ```
393
471
 
394
472
  ### `config/environment.rb`
@@ -443,7 +521,9 @@ I18n and Rails configuration are all being defined here.
443
521
 
444
522
  ### Back to `config/environment.rb`
445
523
 
446
- When `config/application.rb` has finished loading Rails, and defined
524
+ The rest of `config/application.rb` defines the configuration for the
525
+ `Rails::Application` which will be used once the application is fully
526
+ initialized. When `config/application.rb` has finished loading Rails and defined
447
527
  the application namespace, we go back to `config/environment.rb`,
448
528
  where the application is initialized. For example, if the application was called
449
529
  `Blog`, here we would find `Blog::Application.initialize!`, which is
@@ -462,14 +542,31 @@ def initialize!(group=:default) #:nodoc:
462
542
  end
463
543
  ```
464
544
 
465
- As you can see, you can only initialize an app once. This is also where the initializers are run.
545
+ 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`
547
+
548
+ ```ruby
549
+ def run_initializers(group=:default, *args)
550
+ return if instance_variable_defined?(:@ran)
551
+ initializers.tsort_each do |initializer|
552
+ initializer.run(*args) if initializer.belongs_to?(group)
553
+ end
554
+ @ran = true
555
+ end
556
+ ```
466
557
 
467
- TODO: review this
558
+ The run_initializers code itself is tricky. What Rails is doing here is
559
+ traversing all the class ancestors looking for those that respond to an
560
+ `initializers` method. It then sorts the ancestors by name, and runs them.
561
+ For example, the `Engine` class will make all the engines available by
562
+ providing an `initializers` method on them.
468
563
 
469
- The initializers code itself is tricky. What Rails is doing here is it
470
- traverses all the class ancestors looking for an `initializers` method,
471
- sorting them and running them. For example, the `Engine` class will make
472
- all the engines available by providing the `initializers` method.
564
+ The `Rails::Application` class, as defined in `railties/lib/rails/application.rb`
565
+ defines `bootstrap`, `railtie`, and `finisher` initializers. The `bootstrap` initializers
566
+ prepare the application (like initializing the logger) while the `finisher`
567
+ initializers (like building the middleware stack) are run last. The `railtie`
568
+ initializers are the initializers which have been defined on the `Rails::Application`
569
+ itself and are run between the `bootstrap` and `finishers`.
473
570
 
474
571
  After this is done we go back to `Rack::Server`
475
572
 
@@ -546,7 +643,7 @@ def self.run(app, options={})
546
643
  else
547
644
  server.register('/', Rack::Handler::Mongrel.new(app))
548
645
  end
549
- yield server if block_given?
646
+ yield server if block_given?
550
647
  server.run.join
551
648
  end
552
649
  ```