rails 4.1.16 → 4.2.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (141) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -3
  3. data/guides/CHANGELOG.md +13 -102
  4. data/guides/Rakefile +2 -2
  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_gem.rb +2 -2
  8. data/guides/bug_report_templates/action_controller_master.rb +5 -2
  9. data/guides/bug_report_templates/active_record_master.rb +2 -0
  10. data/guides/rails_guides.rb +2 -2
  11. data/guides/rails_guides/helpers.rb +1 -1
  12. data/guides/rails_guides/levenshtein.rb +29 -21
  13. data/guides/rails_guides/markdown.rb +6 -7
  14. data/guides/rails_guides/markdown/renderer.rb +1 -1
  15. data/guides/source/2_3_release_notes.md +3 -3
  16. data/guides/source/3_0_release_notes.md +4 -4
  17. data/guides/source/3_1_release_notes.md +2 -2
  18. data/guides/source/3_2_release_notes.md +2 -2
  19. data/guides/source/4_1_release_notes.md +8 -9
  20. data/guides/source/4_2_release_notes.md +572 -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 +79 -7
  24. data/guides/source/action_mailer_basics.md +36 -11
  25. data/guides/source/action_view_overview.md +138 -119
  26. data/guides/source/active_job_basics.md +253 -0
  27. data/guides/source/active_model_basics.md +23 -0
  28. data/guides/source/active_record_basics.md +16 -15
  29. data/guides/source/active_record_callbacks.md +12 -9
  30. data/guides/source/{migrations.md → active_record_migrations.md} +90 -217
  31. data/guides/source/active_record_postgresql.md +437 -0
  32. data/guides/source/active_record_querying.md +261 -261
  33. data/guides/source/active_record_validations.md +7 -7
  34. data/guides/source/active_support_core_extensions.md +105 -44
  35. data/guides/source/active_support_instrumentation.md +3 -2
  36. data/guides/source/api_documentation_guidelines.md +62 -16
  37. data/guides/source/asset_pipeline.md +58 -46
  38. data/guides/source/association_basics.md +47 -38
  39. data/guides/source/caching_with_rails.md +31 -6
  40. data/guides/source/command_line.md +56 -25
  41. data/guides/source/configuring.md +98 -19
  42. data/guides/source/contributing_to_ruby_on_rails.md +174 -111
  43. data/guides/source/credits.html.erb +1 -1
  44. data/guides/source/debugging_rails_applications.md +438 -284
  45. data/guides/source/development_dependencies_install.md +17 -4
  46. data/guides/source/documents.yaml +11 -7
  47. data/guides/source/engines.md +192 -203
  48. data/guides/source/form_helpers.md +54 -45
  49. data/guides/source/generators.md +20 -11
  50. data/guides/source/getting_started.md +330 -191
  51. data/guides/source/i18n.md +92 -62
  52. data/guides/source/index.html.erb +1 -0
  53. data/guides/source/initialization.md +108 -59
  54. data/guides/source/layout.html.erb +1 -4
  55. data/guides/source/layouts_and_rendering.md +24 -23
  56. data/guides/source/nested_model_forms.md +3 -3
  57. data/guides/source/plugins.md +26 -26
  58. data/guides/source/rails_application_templates.md +21 -3
  59. data/guides/source/rails_on_rack.md +1 -1
  60. data/guides/source/routing.md +97 -71
  61. data/guides/source/ruby_on_rails_guides_guidelines.md +10 -12
  62. data/guides/source/security.md +39 -33
  63. data/guides/source/testing.md +111 -108
  64. data/guides/source/upgrading_ruby_on_rails.md +131 -14
  65. data/guides/source/working_with_javascript_in_rails.md +18 -16
  66. data/guides/w3c_validator.rb +2 -0
  67. metadata +37 -94
  68. data/guides/bug_report_templates/generic_gem.rb +0 -15
  69. data/guides/bug_report_templates/generic_master.rb +0 -26
  70. data/guides/code/getting_started/Gemfile +0 -40
  71. data/guides/code/getting_started/Gemfile.lock +0 -125
  72. data/guides/code/getting_started/README.rdoc +0 -28
  73. data/guides/code/getting_started/Rakefile +0 -6
  74. data/guides/code/getting_started/app/assets/javascripts/application.js +0 -15
  75. data/guides/code/getting_started/app/assets/javascripts/comments.js.coffee +0 -3
  76. data/guides/code/getting_started/app/assets/javascripts/posts.js.coffee +0 -3
  77. data/guides/code/getting_started/app/assets/javascripts/welcome.js.coffee +0 -3
  78. data/guides/code/getting_started/app/assets/stylesheets/application.css +0 -13
  79. data/guides/code/getting_started/app/assets/stylesheets/comments.css.scss +0 -3
  80. data/guides/code/getting_started/app/assets/stylesheets/posts.css.scss +0 -3
  81. data/guides/code/getting_started/app/assets/stylesheets/welcome.css.scss +0 -3
  82. data/guides/code/getting_started/app/controllers/application_controller.rb +0 -5
  83. data/guides/code/getting_started/app/controllers/comments_controller.rb +0 -23
  84. data/guides/code/getting_started/app/controllers/posts_controller.rb +0 -53
  85. data/guides/code/getting_started/app/controllers/welcome_controller.rb +0 -4
  86. data/guides/code/getting_started/app/helpers/application_helper.rb +0 -2
  87. data/guides/code/getting_started/app/helpers/comments_helper.rb +0 -2
  88. data/guides/code/getting_started/app/helpers/posts_helper.rb +0 -2
  89. data/guides/code/getting_started/app/helpers/welcome_helper.rb +0 -2
  90. data/guides/code/getting_started/app/models/comment.rb +0 -3
  91. data/guides/code/getting_started/app/models/post.rb +0 -7
  92. data/guides/code/getting_started/app/views/comments/_comment.html.erb +0 -15
  93. data/guides/code/getting_started/app/views/comments/_form.html.erb +0 -13
  94. data/guides/code/getting_started/app/views/layouts/application.html.erb +0 -14
  95. data/guides/code/getting_started/app/views/posts/_form.html.erb +0 -27
  96. data/guides/code/getting_started/app/views/posts/edit.html.erb +0 -5
  97. data/guides/code/getting_started/app/views/posts/index.html.erb +0 -21
  98. data/guides/code/getting_started/app/views/posts/new.html.erb +0 -5
  99. data/guides/code/getting_started/app/views/posts/show.html.erb +0 -18
  100. data/guides/code/getting_started/app/views/welcome/index.html.erb +0 -4
  101. data/guides/code/getting_started/bin/bundle +0 -4
  102. data/guides/code/getting_started/bin/rails +0 -4
  103. data/guides/code/getting_started/bin/rake +0 -4
  104. data/guides/code/getting_started/config.ru +0 -4
  105. data/guides/code/getting_started/config/application.rb +0 -18
  106. data/guides/code/getting_started/config/boot.rb +0 -4
  107. data/guides/code/getting_started/config/database.yml +0 -25
  108. data/guides/code/getting_started/config/environment.rb +0 -5
  109. data/guides/code/getting_started/config/environments/development.rb +0 -30
  110. data/guides/code/getting_started/config/environments/production.rb +0 -80
  111. data/guides/code/getting_started/config/environments/test.rb +0 -36
  112. data/guides/code/getting_started/config/initializers/backtrace_silencers.rb +0 -7
  113. data/guides/code/getting_started/config/initializers/filter_parameter_logging.rb +0 -4
  114. data/guides/code/getting_started/config/initializers/inflections.rb +0 -16
  115. data/guides/code/getting_started/config/initializers/locale.rb +0 -9
  116. data/guides/code/getting_started/config/initializers/mime_types.rb +0 -5
  117. data/guides/code/getting_started/config/initializers/secret_token.rb +0 -12
  118. data/guides/code/getting_started/config/initializers/session_store.rb +0 -3
  119. data/guides/code/getting_started/config/initializers/wrap_parameters.rb +0 -14
  120. data/guides/code/getting_started/config/locales/en.yml +0 -23
  121. data/guides/code/getting_started/config/routes.rb +0 -7
  122. data/guides/code/getting_started/db/migrate/20130122042648_create_posts.rb +0 -10
  123. data/guides/code/getting_started/db/migrate/20130122045842_create_comments.rb +0 -11
  124. data/guides/code/getting_started/db/schema.rb +0 -33
  125. data/guides/code/getting_started/db/seeds.rb +0 -7
  126. data/guides/code/getting_started/public/404.html +0 -60
  127. data/guides/code/getting_started/public/422.html +0 -60
  128. data/guides/code/getting_started/public/500.html +0 -59
  129. data/guides/code/getting_started/public/favicon.ico +0 -0
  130. data/guides/code/getting_started/public/robots.txt +0 -5
  131. data/guides/code/getting_started/test/controllers/comments_controller_test.rb +0 -7
  132. data/guides/code/getting_started/test/controllers/posts_controller_test.rb +0 -7
  133. data/guides/code/getting_started/test/controllers/welcome_controller_test.rb +0 -9
  134. data/guides/code/getting_started/test/fixtures/comments.yml +0 -11
  135. data/guides/code/getting_started/test/fixtures/posts.yml +0 -9
  136. data/guides/code/getting_started/test/helpers/comments_helper_test.rb +0 -4
  137. data/guides/code/getting_started/test/helpers/posts_helper_test.rb +0 -4
  138. data/guides/code/getting_started/test/helpers/welcome_helper_test.rb +0 -4
  139. data/guides/code/getting_started/test/models/comment_test.rb +0 -7
  140. data/guides/code/getting_started/test/models/post_test.rb +0 -7
  141. data/guides/code/getting_started/test/test_helper.rb +0 -12
@@ -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
  ```
@@ -107,7 +107,7 @@ The **translations load path** (`I18n.load_path`) is just a Ruby Array of paths
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 two plugins which simplify working 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).
267
266
 
268
267
  ### Setting the Locale from the Client Supplied Information
269
268
 
@@ -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:
@@ -681,62 +680,13 @@ NOTE: Automatic conversion to HTML safe translate text is only available from th
681
680
 
682
681
  ![i18n demo html safe](images/i18n/demo_html_safe.png)
683
682
 
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:
690
-
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
707
- ```
708
-
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:
712
-
713
- ```ruby
714
- en:
715
- date:
716
- formats:
717
- default: "%Y-%m-%d"
718
- short: "%b %d"
719
- long: "%B %d, %Y"
720
- ```
721
-
722
- So, all of the following equivalent lookups will return the `:short` date format `"%b %d"`:
723
-
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
- ```
730
-
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.
732
-
733
683
  ### Translations for Active Record Models
734
684
 
735
685
  You can use the methods `Model.model_name.human` and `Model.human_attribute_name(attribute)` to transparently look up translations for your model and attribute names.
736
686
 
737
687
  For example when you add the following translations:
738
688
 
739
- ```ruby
689
+ ```yaml
740
690
  en:
741
691
  activerecord:
742
692
  models:
@@ -751,7 +701,7 @@ Then `User.model_name.human` will return "Dude" and `User.human_attribute_name("
751
701
 
752
702
  You can also set a plural form for model names, adding as following:
753
703
 
754
- ```ruby
704
+ ```yaml
755
705
  en:
756
706
  activerecord:
757
707
  models:
@@ -762,6 +712,19 @@ en:
762
712
 
763
713
  Then `User.model_name.human(count: 2)` will return "Dudes". With `count: 1` or without params will return "Dude".
764
714
 
715
+ 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:
716
+
717
+ ```yaml
718
+ en:
719
+ activerecord:
720
+ attributes:
721
+ user/gender:
722
+ female: "Female"
723
+ male: "Male"
724
+ ```
725
+
726
+ Then `User.human_attribute_name("gender.female")` will return "Female".
727
+
765
728
  #### Error Message Scopes
766
729
 
767
730
  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 +860,24 @@ en:
897
860
  subject: "Welcome to Rails Guides!"
898
861
  ```
899
862
 
863
+ To send parameters to interpolation use the `default_i18n_subject` method on the mailer.
864
+
865
+ ```ruby
866
+ # user_mailer.rb
867
+ class UserMailer < ActionMailer::Base
868
+ def welcome(user)
869
+ mail(to: user.email, subject: default_i18n_subject(user: user.name))
870
+ end
871
+ end
872
+ ```
873
+
874
+ ```yaml
875
+ en:
876
+ user_mailer:
877
+ welcome:
878
+ subject: "%{user}, welcome to Rails Guides!"
879
+ ```
880
+
900
881
  ### Overview of Other Built-In Methods that Provide I18n Support
901
882
 
902
883
  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 +902,55 @@ Rails uses fixed strings and other localizations, such as format strings and oth
921
902
 
922
903
  * `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
904
 
905
+ How to Store your Custom Translations
906
+ -------------------------------------
907
+
908
+ The Simple backend shipped with Active Support allows you to store translations in both plain Ruby and YAML format.[^2]
909
+
910
+ For example a Ruby Hash providing translations can look like this:
911
+
912
+ ```yaml
913
+ {
914
+ pt: {
915
+ foo: {
916
+ bar: "baz"
917
+ }
918
+ }
919
+ }
920
+ ```
921
+
922
+ The equivalent YAML file would look like this:
923
+
924
+ ```yaml
925
+ pt:
926
+ foo:
927
+ bar: baz
928
+ ```
929
+
930
+ 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".
931
+
932
+ Here is a "real" example from the Active Support `en.yml` translations YAML file:
933
+
934
+ ```yaml
935
+ en:
936
+ date:
937
+ formats:
938
+ default: "%Y-%m-%d"
939
+ short: "%b %d"
940
+ long: "%B %d, %Y"
941
+ ```
942
+
943
+ So, all of the following equivalent lookups will return the `:short` date format `"%b %d"`:
944
+
945
+ ```ruby
946
+ I18n.t 'date.formats.short'
947
+ I18n.t 'formats.short', scope: :date
948
+ I18n.t :short, scope: 'date.formats'
949
+ I18n.t :short, scope: [:date, :formats]
950
+ ```
951
+
952
+ 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.
953
+
924
954
  Customize your I18n Setup
925
955
  -------------------------
926
956
 
@@ -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
@@ -119,7 +119,7 @@ A standard Rails application depends on several gems, specifically:
119
119
  * rails
120
120
  * railties
121
121
  * rake
122
- * sqlite3-ruby
122
+ * sqlite3
123
123
  * thor
124
124
  * treetop
125
125
  * tzinfo
@@ -166,6 +166,7 @@ is called.
166
166
  COMMAND_WHITELIST = %(plugin generate destroy console server dbconsole application runner new version help)
167
167
 
168
168
  def run_command!(command)
169
+ command = parse_command(command)
169
170
  if COMMAND_WHITELIST.include?(command)
170
171
  send(command)
171
172
  else
@@ -178,8 +179,7 @@ With the `server` command, Rails will further run the following code:
178
179
 
179
180
  ```ruby
180
181
  def set_application_directory!
181
- Dir.chdir(File.expand_path('../../', APP_PATH)) unless
182
- File.exist?(File.expand_path("config.ru"))
182
+ Dir.chdir(File.expand_path('../../', APP_PATH)) unless File.exist?(File.expand_path("config.ru"))
183
183
  end
184
184
 
185
185
  def server
@@ -187,6 +187,8 @@ def server
187
187
  require_command!("server")
188
188
 
189
189
  Rails::Server.new.tap do |server|
190
+ # We need to require application after the server sets environment,
191
+ # otherwise the --environment option given to the server won't propagate.
190
192
  require APP_PATH
191
193
  Dir.chdir(Rails.application.root)
192
194
  server.start
@@ -207,6 +209,7 @@ sets up the `Rails::Server` class.
207
209
  require 'fileutils'
208
210
  require 'optparse'
209
211
  require 'action_dispatch'
212
+ require 'rails'
210
213
 
211
214
  module Rails
212
215
  class Server < ::Rack::Server
@@ -273,7 +276,7 @@ def parse_options(args)
273
276
  # http://www.meb.uni-bonn.de/docs/cgi/cl.html
274
277
  args.clear if ENV.include?("REQUEST_METHOD")
275
278
 
276
- options.merge! opt_parser.parse! args
279
+ options.merge! opt_parser.parse!(args)
277
280
  options[:config] = ::File.expand_path(options[:config])
278
281
  ENV["RACK_ENV"] = options[:environment]
279
282
  options
@@ -284,18 +287,21 @@ With the `default_options` set to this:
284
287
 
285
288
  ```ruby
286
289
  def default_options
290
+ environment = ENV['RACK_ENV'] || 'development'
291
+ default_host = environment == 'development' ? 'localhost' : '0.0.0.0'
292
+
287
293
  {
288
- environment: ENV['RACK_ENV'] || "development",
289
- pid: nil,
290
- Port: 9292,
291
- Host: "0.0.0.0",
292
- AccessLog: [],
293
- config: "config.ru"
294
+ :environment => environment,
295
+ :pid => nil,
296
+ :Port => 9292,
297
+ :Host => default_host,
298
+ :AccessLog => [],
299
+ :config => "config.ru"
294
300
  }
295
301
  end
296
302
  ```
297
303
 
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`
304
+ 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
305
 
300
306
  ```ruby
301
307
  def opt_parser
@@ -348,6 +354,7 @@ private
348
354
  def print_boot_information
349
355
  ...
350
356
  puts "=> Run `rails server -h` for more startup options"
357
+ ...
351
358
  puts "=> Ctrl-C to shutdown server" unless options[:daemonize]
352
359
  end
353
360
 
@@ -434,7 +441,11 @@ The `app` method here is defined like so:
434
441
 
435
442
  ```ruby
436
443
  def app
437
- @app ||= begin
444
+ @app ||= options[:builder] ? build_app_from_string : build_app_and_options_from_config
445
+ end
446
+ ...
447
+ private
448
+ def build_app_and_options_from_config
438
449
  if !::File.exist? options[:config]
439
450
  abort "configuration #{options[:config]} not found"
440
451
  end
@@ -443,7 +454,10 @@ def app
443
454
  self.options.merge! options
444
455
  app
445
456
  end
446
- end
457
+
458
+ def build_app_from_string
459
+ Rack::Builder.new_from_string(self.options[:builder])
460
+ end
447
461
  ```
448
462
 
449
463
  The `options[:config]` value defaults to `config.ru` which contains this:
@@ -459,8 +473,14 @@ run <%= app_const %>
459
473
  The `Rack::Builder.parse_file` method here takes the content from this `config.ru` file and parses it using this code:
460
474
 
461
475
  ```ruby
462
- app = eval "Rack::Builder.new {( " + cfgfile + "\n )}.to_app",
463
- TOPLEVEL_BINDING, config
476
+ app = new_from_string cfgfile, config
477
+
478
+ ...
479
+
480
+ def self.new_from_string(builder_script, file="(rackup)")
481
+ eval "Rack::Builder.new {\n" + builder_script + "\n}.to_app",
482
+ TOPLEVEL_BINDING, file, 0
483
+ end
464
484
  ```
465
485
 
466
486
  The `initialize` method of `Rack::Builder` will take the block here and execute it within an instance of `Rack::Builder`. This is where the majority of the initialization process of Rails happens. The `require` line for `config/environment.rb` in `config.ru` is the first to run:
@@ -473,11 +493,22 @@ require ::File.expand_path('../config/environment', __FILE__)
473
493
 
474
494
  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
495
 
476
- This file begins with requiring `config/application.rb`.
496
+ This file begins with requiring `config/application.rb`:
497
+
498
+ ```ruby
499
+ require File.expand_path('../application', __FILE__)
500
+ ```
477
501
 
478
502
  ### `config/application.rb`
479
503
 
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.
504
+ This file requires `config/boot.rb`:
505
+
506
+ ```ruby
507
+ require File.expand_path('../boot', __FILE__)
508
+ ```
509
+
510
+ But only if it hasn't been required before, which would be the case in `rails server`
511
+ but **wouldn't** be the case with Passenger.
481
512
 
482
513
  Then the fun begins!
483
514
 
@@ -498,11 +529,12 @@ This file is responsible for requiring all the individual frameworks of Rails:
498
529
  require "rails"
499
530
 
500
531
  %w(
501
- active_record
502
- action_controller
503
- action_mailer
504
- rails/test_unit
505
- sprockets
532
+ active_record
533
+ action_controller
534
+ action_view
535
+ action_mailer
536
+ rails/test_unit
537
+ sprockets
506
538
  ).each do |framework|
507
539
  begin
508
540
  require "#{framework}/railtie"
@@ -527,7 +559,7 @@ initialized. When `config/application.rb` has finished loading Rails and defined
527
559
  the application namespace, we go back to `config/environment.rb`,
528
560
  where the application is initialized. For example, if the application was called
529
561
  `Blog`, here we would find `Rails.application.initialize!`, which is
530
- defined in `rails/application.rb`
562
+ defined in `rails/application.rb`.
531
563
 
532
564
  ### `railties/lib/rails/application.rb`
533
565
 
@@ -543,7 +575,7 @@ end
543
575
  ```
544
576
 
545
577
  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`
578
+ the `run_initializers` method which is defined in `railties/lib/rails/initializable.rb`:
547
579
 
548
580
  ```ruby
549
581
  def run_initializers(group=:default, *args)
@@ -555,7 +587,7 @@ def run_initializers(group=:default, *args)
555
587
  end
556
588
  ```
557
589
 
558
- The run_initializers code itself is tricky. What Rails is doing here is
590
+ The `run_initializers` code itself is tricky. What Rails is doing here is
559
591
  traversing all the class ancestors looking for those that respond to an
560
592
  `initializers` method. It then sorts the ancestors by name, and runs them.
561
593
  For example, the `Engine` class will make all the engines available by
@@ -568,7 +600,7 @@ initializers (like building the middleware stack) are run last. The `railtie`
568
600
  initializers are the initializers which have been defined on the `Rails::Application`
569
601
  itself and are run between the `bootstrap` and `finishers`.
570
602
 
571
- After this is done we go back to `Rack::Server`
603
+ After this is done we go back to `Rack::Server`.
572
604
 
573
605
  ### Rack: lib/rack/server.rb
574
606
 
@@ -576,7 +608,11 @@ Last time we left when the `app` method was being defined:
576
608
 
577
609
  ```ruby
578
610
  def app
579
- @app ||= begin
611
+ @app ||= options[:builder] ? build_app_from_string : build_app_and_options_from_config
612
+ end
613
+ ...
614
+ private
615
+ def build_app_and_options_from_config
580
616
  if !::File.exist? options[:config]
581
617
  abort "configuration #{options[:config]} not found"
582
618
  end
@@ -585,7 +621,10 @@ def app
585
621
  self.options.merge! options
586
622
  app
587
623
  end
588
- end
624
+
625
+ def build_app_from_string
626
+ Rack::Builder.new_from_string(self.options[:builder])
627
+ end
589
628
  ```
590
629
 
591
630
  At this point `app` is the Rails app itself (a middleware), and what
@@ -603,7 +642,7 @@ def build_app(app)
603
642
  end
604
643
  ```
605
644
 
606
- Remember, `build_app` was called (by wrapped_app) in the last line of `Server#start`.
645
+ Remember, `build_app` was called (by `wrapped_app`) in the last line of `Server#start`.
607
646
  Here's how it looked like when we left:
608
647
 
609
648
  ```ruby
@@ -611,40 +650,50 @@ server.run wrapped_app, options, &blk
611
650
  ```
612
651
 
613
652
  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
653
+ server you're using. For example, if you were using Puma, here's what
615
654
  the `run` method would look like:
616
655
 
617
656
  ```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))
657
+ ...
658
+ DEFAULT_OPTIONS = {
659
+ :Host => '0.0.0.0',
660
+ :Port => 8080,
661
+ :Threads => '0:16',
662
+ :Verbose => false
663
+ }
664
+
665
+ def self.run(app, options = {})
666
+ options = DEFAULT_OPTIONS.merge(options)
667
+
668
+ if options[:Verbose]
669
+ app = Rack::CommonLogger.new(app, STDOUT)
645
670
  end
671
+
672
+ if options[:environment]
673
+ ENV['RACK_ENV'] = options[:environment].to_s
674
+ end
675
+
676
+ server = ::Puma::Server.new(app)
677
+ min, max = options[:Threads].split(':', 2)
678
+
679
+ puts "Puma #{::Puma::Const::PUMA_VERSION} starting..."
680
+ puts "* Min threads: #{min}, max threads: #{max}"
681
+ puts "* Environment: #{ENV['RACK_ENV']}"
682
+ puts "* Listening on tcp://#{options[:Host]}:#{options[:Port]}"
683
+
684
+ server.add_tcp_listener options[:Host], options[:Port]
685
+ server.min_threads = min
686
+ server.max_threads = max
646
687
  yield server if block_given?
647
- server.run.join
688
+
689
+ begin
690
+ server.run.join
691
+ rescue Interrupt
692
+ puts "* Gracefully stopping, waiting for requests to finish"
693
+ server.stop(true)
694
+ puts "* Goodbye!"
695
+ end
696
+
648
697
  end
649
698
  ```
650
699