aboutsummaryrefslogtreecommitdiffstats
path: root/guides
diff options
context:
space:
mode:
Diffstat (limited to 'guides')
-rw-r--r--guides/Rakefile78
-rw-r--r--guides/assets/images/belongs_to.pngbin34017 -> 26076 bytes
-rw-r--r--guides/assets/images/book_icon.gifbin337 -> 329 bytes
-rw-r--r--guides/assets/images/challenge.pngbin54134 -> 33373 bytes
-rw-r--r--guides/assets/images/chapters_icon.gifbin628 -> 620 bytes
-rw-r--r--guides/assets/images/check_bullet.gifbin384 -> 376 bytes
-rw-r--r--guides/assets/images/credits_pic_blank.gifbin613 -> 597 bytes
-rw-r--r--guides/assets/images/csrf.pngbin41996 -> 32179 bytes
-rw-r--r--guides/assets/images/customized_error_messages.pngbin5055 -> 2561 bytes
-rw-r--r--guides/assets/images/edge_badge.pngbin7945 -> 5964 bytes
-rw-r--r--guides/assets/images/error_messages.pngbin14645 -> 10964 bytes
-rw-r--r--guides/assets/images/getting_started/confirm_dialog.pngbin36070 -> 29542 bytes
-rw-r--r--guides/assets/images/getting_started/form_with_errors.pngbin20820 -> 14031 bytes
-rw-r--r--guides/assets/images/getting_started/index_action_with_edit_link.pngbin15547 -> 9772 bytes
-rw-r--r--guides/assets/images/getting_started/new_post.pngbin14334 -> 5888 bytes
-rw-r--r--guides/assets/images/getting_started/post_with_comments.pngbin31630 -> 18496 bytes
-rw-r--r--guides/assets/images/getting_started/routing_error_no_controller.pngbin15744 -> 6268 bytes
-rw-r--r--guides/assets/images/getting_started/routing_error_no_route_matches.pngbin16065 -> 6508 bytes
-rw-r--r--guides/assets/images/getting_started/show_action_for_posts.pngbin6885 -> 2991 bytes
-rw-r--r--guides/assets/images/getting_started/template_is_missing_posts_new.pngbin15168 -> 5851 bytes
-rw-r--r--guides/assets/images/getting_started/undefined_method_post_path.pngbin15254 -> 9217 bytes
-rw-r--r--guides/assets/images/getting_started/unknown_action_create_for_posts.pngbin12652 -> 4146 bytes
-rw-r--r--guides/assets/images/getting_started/unknown_action_new_for_posts.pngbin12756 -> 4208 bytes
-rw-r--r--guides/assets/images/grey_bullet.gifbin45 -> 37 bytes
-rw-r--r--guides/assets/images/habtm.pngbin63801 -> 49332 bytes
-rw-r--r--guides/assets/images/has_many.pngbin38582 -> 28988 bytes
-rw-r--r--guides/assets/images/has_many_through.pngbin100220 -> 79428 bytes
-rw-r--r--guides/assets/images/has_one.pngbin39022 -> 29072 bytes
-rw-r--r--guides/assets/images/has_one_through.pngbin92594 -> 72434 bytes
-rw-r--r--guides/assets/images/header_backdrop.pngbin882 -> 224 bytes
-rw-r--r--guides/assets/images/i18n/demo_html_safe.pngbin11946 -> 10073 bytes
-rw-r--r--guides/assets/images/i18n/demo_localized_pirate.pngbin15027 -> 11485 bytes
-rw-r--r--guides/assets/images/i18n/demo_translated_en.pngbin12057 -> 9325 bytes
-rw-r--r--guides/assets/images/i18n/demo_translated_pirate.pngbin13392 -> 10202 bytes
-rw-r--r--guides/assets/images/i18n/demo_translation_missing.pngbin13143 -> 10260 bytes
-rw-r--r--guides/assets/images/i18n/demo_untranslated.pngbin11925 -> 9224 bytes
-rw-r--r--guides/assets/images/icons/callouts/1.pngbin329 -> 147 bytes
-rw-r--r--guides/assets/images/icons/callouts/10.pngbin361 -> 183 bytes
-rw-r--r--guides/assets/images/icons/callouts/11.pngbin565 -> 290 bytes
-rw-r--r--guides/assets/images/icons/callouts/12.pngbin617 -> 322 bytes
-rw-r--r--guides/assets/images/icons/callouts/13.pngbin623 -> 328 bytes
-rw-r--r--guides/assets/images/icons/callouts/14.pngbin411 -> 246 bytes
-rw-r--r--guides/assets/images/icons/callouts/15.pngbin640 -> 340 bytes
-rw-r--r--guides/assets/images/icons/callouts/2.pngbin353 -> 168 bytes
-rw-r--r--guides/assets/images/icons/callouts/3.pngbin350 -> 170 bytes
-rw-r--r--guides/assets/images/icons/callouts/4.pngbin345 -> 165 bytes
-rw-r--r--guides/assets/images/icons/callouts/5.pngbin348 -> 169 bytes
-rw-r--r--guides/assets/images/icons/callouts/6.pngbin355 -> 176 bytes
-rw-r--r--guides/assets/images/icons/callouts/7.pngbin344 -> 160 bytes
-rw-r--r--guides/assets/images/icons/callouts/8.pngbin357 -> 176 bytes
-rw-r--r--guides/assets/images/icons/callouts/9.pngbin357 -> 177 bytes
-rw-r--r--guides/assets/images/icons/caution.pngbin2554 -> 2300 bytes
-rw-r--r--guides/assets/images/icons/example.pngbin2354 -> 2079 bytes
-rw-r--r--guides/assets/images/icons/home.pngbin1340 -> 1163 bytes
-rw-r--r--guides/assets/images/icons/important.pngbin2657 -> 2451 bytes
-rw-r--r--guides/assets/images/icons/next.pngbin1302 -> 1146 bytes
-rw-r--r--guides/assets/images/icons/note.pngbin2730 -> 2155 bytes
-rw-r--r--guides/assets/images/icons/prev.pngbin1348 -> 1126 bytes
-rw-r--r--guides/assets/images/icons/tip.pngbin2602 -> 2248 bytes
-rw-r--r--guides/assets/images/icons/up.pngbin1320 -> 1133 bytes
-rw-r--r--guides/assets/images/icons/warning.pngbin2828 -> 2616 bytes
-rw-r--r--guides/assets/images/nav_arrow.gifbin427 -> 419 bytes
-rw-r--r--guides/assets/images/oscardelben.jpgbin0 -> 6299 bytes
-rw-r--r--guides/assets/images/polymorphic.pngbin85248 -> 66415 bytes
-rw-r--r--guides/assets/images/rails_guides_logo.gifbin5114 -> 5106 bytes
-rw-r--r--guides/assets/images/rails_welcome.pngbin121314 -> 71979 bytes
-rw-r--r--guides/assets/images/session_fixation.pngbin47860 -> 38451 bytes
-rw-r--r--guides/assets/images/tab_grey.gifbin4924 -> 4684 bytes
-rw-r--r--guides/assets/images/tab_info.gifbin4762 -> 4522 bytes
-rw-r--r--guides/assets/images/tab_note.gifbin4807 -> 4566 bytes
-rw-r--r--guides/assets/images/tab_red.gifbin4753 -> 4507 bytes
-rw-r--r--guides/assets/images/tab_yellow.gifbin4759 -> 4519 bytes
-rw-r--r--guides/assets/images/tab_yellow.pngbin1611 -> 1441 bytes
-rw-r--r--guides/assets/images/validation_error_messages.pngbin1107 -> 583 bytes
-rw-r--r--guides/rails_guides/generator.rb9
-rw-r--r--guides/source/action_view_overview.textile66
-rw-r--r--guides/source/active_record_querying.textile48
-rw-r--r--guides/source/active_support_core_extensions.textile131
-rw-r--r--guides/source/active_support_instrumentation.textile4
-rw-r--r--guides/source/command_line.textile198
-rw-r--r--guides/source/configuring.textile2
-rw-r--r--guides/source/contributing_to_ruby_on_rails.textile97
-rw-r--r--guides/source/credits.html.erb4
-rw-r--r--guides/source/debugging_rails_applications.textile2
-rw-r--r--guides/source/engines.textile8
-rw-r--r--guides/source/form_helpers.textile14
-rw-r--r--guides/source/getting_started.textile58
-rw-r--r--guides/source/initialization.textile263
-rw-r--r--guides/source/migrations.textile3
-rw-r--r--guides/source/rails_on_rack.textile66
-rw-r--r--guides/source/routing.textile10
-rw-r--r--guides/source/ruby_on_rails_guides_guidelines.textile24
-rw-r--r--guides/source/security.textile79
-rw-r--r--guides/source/upgrading_ruby_on_rails.textile20
94 files changed, 839 insertions, 345 deletions
diff --git a/guides/Rakefile b/guides/Rakefile
index ad4ff91fe6..d005a12936 100644
--- a/guides/Rakefile
+++ b/guides/Rakefile
@@ -1,11 +1,71 @@
-desc 'Generate guides (for authors), use ONLY=foo to process just "foo.textile"'
-task :generate_guides do
- ENV["WARN_BROKEN_LINKS"] = "1" # authors can't disable this
- ruby "rails_guides.rb"
-end
+namespace :guides do
+
+ desc 'Generate guides (for authors), use ONLY=foo to process just "foo.textile"'
+ task :generate => 'generate:html'
+
+ namespace :generate do
+
+ desc "Generate HTML guides"
+ task :html do
+ ENV["WARN_BROKEN_LINKS"] = "1" # authors can't disable this
+ ruby "rails_guides.rb"
+ end
+
+ desc "Generate .mobi file. The kindlegen executable must be in your PATH. You can get it for free from http://www.amazon.com/kindlepublishing"
+ task :kindle do
+ ENV['KINDLE'] = '1'
+ Rake::Task['guides:generate:html'].invoke
+ end
+ end
+
+ # Validate guides -------------------------------------------------------------------------
+ desc 'Validate guides, use ONLY=foo to process just "foo.html"'
+ task :validate do
+ ruby "w3c_validator.rb"
+ end
+
+ desc "Show help"
+ task :help do
+ puts <<-help
+
+Guides are taken from the source directory, and the resulting HTML goes into the
+output directory. Assets are stored under files, and copied to output/files as
+part of the generation process.
+
+All this process is handled via rake tasks, here's a full list of them:
-# Validate guides -------------------------------------------------------------------------
-desc 'Validate guides, use ONLY=foo to process just "foo.html"'
-task :validate_guides do
- ruby "w3c_validator.rb"
+#{%x[rake -T]}
+Some arguments may be passed via environment variables:
+
+ WARNINGS=1
+ Internal links (anchors) are checked, also detects duplicated IDs.
+
+ ALL=1
+ Force generation of all guides.
+
+ ONLY=name
+ Useful if you want to generate only one or a set of guides.
+
+ Generate only association_basics.html:
+ ONLY=assoc
+
+ Separate many using commas:
+ ONLY=assoc,migrations
+
+ GUIDES_LANGUAGE
+ Use it when you want to generate translated guides in
+ source/<GUIDES_LANGUAGE> folder (such as source/es)
+
+ EDGE=1
+ Indicate generated guides should be marked as edge.
+
+Examples:
+ $ rake guides:generate ALL=1
+ $ rake guides:generate EDGE=1
+ $ rake guides:generate:kindle EDGE=1
+ $ rake guides:generate GUIDES_LANGUAGE=es
+ help
+ end
end
+
+task :default => 'guides:help'
diff --git a/guides/assets/images/belongs_to.png b/guides/assets/images/belongs_to.png
index 44243edbca..43c963ffa8 100644
--- a/guides/assets/images/belongs_to.png
+++ b/guides/assets/images/belongs_to.png
Binary files differ
diff --git a/guides/assets/images/book_icon.gif b/guides/assets/images/book_icon.gif
index c81d5db520..efc5e06880 100644
--- a/guides/assets/images/book_icon.gif
+++ b/guides/assets/images/book_icon.gif
Binary files differ
diff --git a/guides/assets/images/challenge.png b/guides/assets/images/challenge.png
index d163748640..30be3d7028 100644
--- a/guides/assets/images/challenge.png
+++ b/guides/assets/images/challenge.png
Binary files differ
diff --git a/guides/assets/images/chapters_icon.gif b/guides/assets/images/chapters_icon.gif
index 06fb415f4a..a61c28c02d 100644
--- a/guides/assets/images/chapters_icon.gif
+++ b/guides/assets/images/chapters_icon.gif
Binary files differ
diff --git a/guides/assets/images/check_bullet.gif b/guides/assets/images/check_bullet.gif
index 1fcfeba250..bd54ef64c9 100644
--- a/guides/assets/images/check_bullet.gif
+++ b/guides/assets/images/check_bullet.gif
Binary files differ
diff --git a/guides/assets/images/credits_pic_blank.gif b/guides/assets/images/credits_pic_blank.gif
index f6f654fc65..a6b335d0c9 100644
--- a/guides/assets/images/credits_pic_blank.gif
+++ b/guides/assets/images/credits_pic_blank.gif
Binary files differ
diff --git a/guides/assets/images/csrf.png b/guides/assets/images/csrf.png
index ab73baafe8..a8123d47c3 100644
--- a/guides/assets/images/csrf.png
+++ b/guides/assets/images/csrf.png
Binary files differ
diff --git a/guides/assets/images/customized_error_messages.png b/guides/assets/images/customized_error_messages.png
index fa676991e3..fcf47b4be0 100644
--- a/guides/assets/images/customized_error_messages.png
+++ b/guides/assets/images/customized_error_messages.png
Binary files differ
diff --git a/guides/assets/images/edge_badge.png b/guides/assets/images/edge_badge.png
index cddd46c4b8..a35dc9f8ee 100644
--- a/guides/assets/images/edge_badge.png
+++ b/guides/assets/images/edge_badge.png
Binary files differ
diff --git a/guides/assets/images/error_messages.png b/guides/assets/images/error_messages.png
index 428892194a..1189e486d4 100644
--- a/guides/assets/images/error_messages.png
+++ b/guides/assets/images/error_messages.png
Binary files differ
diff --git a/guides/assets/images/getting_started/confirm_dialog.png b/guides/assets/images/getting_started/confirm_dialog.png
index a26c09ef2d..1a13eddd91 100644
--- a/guides/assets/images/getting_started/confirm_dialog.png
+++ b/guides/assets/images/getting_started/confirm_dialog.png
Binary files differ
diff --git a/guides/assets/images/getting_started/form_with_errors.png b/guides/assets/images/getting_started/form_with_errors.png
index badefe6ea6..6910e1647e 100644
--- a/guides/assets/images/getting_started/form_with_errors.png
+++ b/guides/assets/images/getting_started/form_with_errors.png
Binary files differ
diff --git a/guides/assets/images/getting_started/index_action_with_edit_link.png b/guides/assets/images/getting_started/index_action_with_edit_link.png
index 6e58a13756..bf23cba231 100644
--- a/guides/assets/images/getting_started/index_action_with_edit_link.png
+++ b/guides/assets/images/getting_started/index_action_with_edit_link.png
Binary files differ
diff --git a/guides/assets/images/getting_started/new_post.png b/guides/assets/images/getting_started/new_post.png
index dc9459032a..b573cb164c 100644
--- a/guides/assets/images/getting_started/new_post.png
+++ b/guides/assets/images/getting_started/new_post.png
Binary files differ
diff --git a/guides/assets/images/getting_started/post_with_comments.png b/guides/assets/images/getting_started/post_with_comments.png
index bd9b2e10f5..e13095ff8f 100644
--- a/guides/assets/images/getting_started/post_with_comments.png
+++ b/guides/assets/images/getting_started/post_with_comments.png
Binary files differ
diff --git a/guides/assets/images/getting_started/routing_error_no_controller.png b/guides/assets/images/getting_started/routing_error_no_controller.png
index 92a39efd78..407ea2ea06 100644
--- a/guides/assets/images/getting_started/routing_error_no_controller.png
+++ b/guides/assets/images/getting_started/routing_error_no_controller.png
Binary files differ
diff --git a/guides/assets/images/getting_started/routing_error_no_route_matches.png b/guides/assets/images/getting_started/routing_error_no_route_matches.png
index bc768a94a2..d461807c5d 100644
--- a/guides/assets/images/getting_started/routing_error_no_route_matches.png
+++ b/guides/assets/images/getting_started/routing_error_no_route_matches.png
Binary files differ
diff --git a/guides/assets/images/getting_started/show_action_for_posts.png b/guides/assets/images/getting_started/show_action_for_posts.png
index 5c8c4d8e5e..9467df6a07 100644
--- a/guides/assets/images/getting_started/show_action_for_posts.png
+++ b/guides/assets/images/getting_started/show_action_for_posts.png
Binary files differ
diff --git a/guides/assets/images/getting_started/template_is_missing_posts_new.png b/guides/assets/images/getting_started/template_is_missing_posts_new.png
index 9f070d59db..6860aaeca7 100644
--- a/guides/assets/images/getting_started/template_is_missing_posts_new.png
+++ b/guides/assets/images/getting_started/template_is_missing_posts_new.png
Binary files differ
diff --git a/guides/assets/images/getting_started/undefined_method_post_path.png b/guides/assets/images/getting_started/undefined_method_post_path.png
index f568bf315c..c29cb2f54f 100644
--- a/guides/assets/images/getting_started/undefined_method_post_path.png
+++ b/guides/assets/images/getting_started/undefined_method_post_path.png
Binary files differ
diff --git a/guides/assets/images/getting_started/unknown_action_create_for_posts.png b/guides/assets/images/getting_started/unknown_action_create_for_posts.png
index 03d92dfb7d..1eca14b988 100644
--- a/guides/assets/images/getting_started/unknown_action_create_for_posts.png
+++ b/guides/assets/images/getting_started/unknown_action_create_for_posts.png
Binary files differ
diff --git a/guides/assets/images/getting_started/unknown_action_new_for_posts.png b/guides/assets/images/getting_started/unknown_action_new_for_posts.png
index b63883d922..fd72586573 100644
--- a/guides/assets/images/getting_started/unknown_action_new_for_posts.png
+++ b/guides/assets/images/getting_started/unknown_action_new_for_posts.png
Binary files differ
diff --git a/guides/assets/images/grey_bullet.gif b/guides/assets/images/grey_bullet.gif
index e75e8e93a1..3c08b1571c 100644
--- a/guides/assets/images/grey_bullet.gif
+++ b/guides/assets/images/grey_bullet.gif
Binary files differ
diff --git a/guides/assets/images/habtm.png b/guides/assets/images/habtm.png
index fea78b0b5c..b062bc73fe 100644
--- a/guides/assets/images/habtm.png
+++ b/guides/assets/images/habtm.png
Binary files differ
diff --git a/guides/assets/images/has_many.png b/guides/assets/images/has_many.png
index 6cff58460d..e7589e3b75 100644
--- a/guides/assets/images/has_many.png
+++ b/guides/assets/images/has_many.png
Binary files differ
diff --git a/guides/assets/images/has_many_through.png b/guides/assets/images/has_many_through.png
index 85d7599925..858c898dc1 100644
--- a/guides/assets/images/has_many_through.png
+++ b/guides/assets/images/has_many_through.png
Binary files differ
diff --git a/guides/assets/images/has_one.png b/guides/assets/images/has_one.png
index a70ddaaa86..93faa05b07 100644
--- a/guides/assets/images/has_one.png
+++ b/guides/assets/images/has_one.png
Binary files differ
diff --git a/guides/assets/images/has_one_through.png b/guides/assets/images/has_one_through.png
index 89a7617a30..07dac1a27d 100644
--- a/guides/assets/images/has_one_through.png
+++ b/guides/assets/images/has_one_through.png
Binary files differ
diff --git a/guides/assets/images/header_backdrop.png b/guides/assets/images/header_backdrop.png
index ff2982175e..72b030478f 100644
--- a/guides/assets/images/header_backdrop.png
+++ b/guides/assets/images/header_backdrop.png
Binary files differ
diff --git a/guides/assets/images/i18n/demo_html_safe.png b/guides/assets/images/i18n/demo_html_safe.png
index f881f60dac..9afa8ebec1 100644
--- a/guides/assets/images/i18n/demo_html_safe.png
+++ b/guides/assets/images/i18n/demo_html_safe.png
Binary files differ
diff --git a/guides/assets/images/i18n/demo_localized_pirate.png b/guides/assets/images/i18n/demo_localized_pirate.png
index 9134709573..bf8d0b558c 100644
--- a/guides/assets/images/i18n/demo_localized_pirate.png
+++ b/guides/assets/images/i18n/demo_localized_pirate.png
Binary files differ
diff --git a/guides/assets/images/i18n/demo_translated_en.png b/guides/assets/images/i18n/demo_translated_en.png
index ecdd878d38..e887bfa306 100644
--- a/guides/assets/images/i18n/demo_translated_en.png
+++ b/guides/assets/images/i18n/demo_translated_en.png
Binary files differ
diff --git a/guides/assets/images/i18n/demo_translated_pirate.png b/guides/assets/images/i18n/demo_translated_pirate.png
index 41c580923a..aa5618a865 100644
--- a/guides/assets/images/i18n/demo_translated_pirate.png
+++ b/guides/assets/images/i18n/demo_translated_pirate.png
Binary files differ
diff --git a/guides/assets/images/i18n/demo_translation_missing.png b/guides/assets/images/i18n/demo_translation_missing.png
index af9e2d0427..867aa7c42d 100644
--- a/guides/assets/images/i18n/demo_translation_missing.png
+++ b/guides/assets/images/i18n/demo_translation_missing.png
Binary files differ
diff --git a/guides/assets/images/i18n/demo_untranslated.png b/guides/assets/images/i18n/demo_untranslated.png
index 3603f43463..2ea6404822 100644
--- a/guides/assets/images/i18n/demo_untranslated.png
+++ b/guides/assets/images/i18n/demo_untranslated.png
Binary files differ
diff --git a/guides/assets/images/icons/callouts/1.png b/guides/assets/images/icons/callouts/1.png
index 7d473430b7..c5d02adcf4 100644
--- a/guides/assets/images/icons/callouts/1.png
+++ b/guides/assets/images/icons/callouts/1.png
Binary files differ
diff --git a/guides/assets/images/icons/callouts/10.png b/guides/assets/images/icons/callouts/10.png
index 997bbc8246..fe89f9ef83 100644
--- a/guides/assets/images/icons/callouts/10.png
+++ b/guides/assets/images/icons/callouts/10.png
Binary files differ
diff --git a/guides/assets/images/icons/callouts/11.png b/guides/assets/images/icons/callouts/11.png
index ce47dac3f5..9244a1ac4b 100644
--- a/guides/assets/images/icons/callouts/11.png
+++ b/guides/assets/images/icons/callouts/11.png
Binary files differ
diff --git a/guides/assets/images/icons/callouts/12.png b/guides/assets/images/icons/callouts/12.png
index 31daf4e2f2..ae56459f4c 100644
--- a/guides/assets/images/icons/callouts/12.png
+++ b/guides/assets/images/icons/callouts/12.png
Binary files differ
diff --git a/guides/assets/images/icons/callouts/13.png b/guides/assets/images/icons/callouts/13.png
index 14021a89c2..1181f9f892 100644
--- a/guides/assets/images/icons/callouts/13.png
+++ b/guides/assets/images/icons/callouts/13.png
Binary files differ
diff --git a/guides/assets/images/icons/callouts/14.png b/guides/assets/images/icons/callouts/14.png
index 64014b75fe..4274e6580a 100644
--- a/guides/assets/images/icons/callouts/14.png
+++ b/guides/assets/images/icons/callouts/14.png
Binary files differ
diff --git a/guides/assets/images/icons/callouts/15.png b/guides/assets/images/icons/callouts/15.png
index 0d65765fcf..39304de94f 100644
--- a/guides/assets/images/icons/callouts/15.png
+++ b/guides/assets/images/icons/callouts/15.png
Binary files differ
diff --git a/guides/assets/images/icons/callouts/2.png b/guides/assets/images/icons/callouts/2.png
index 5d09341b2f..8c57970ba9 100644
--- a/guides/assets/images/icons/callouts/2.png
+++ b/guides/assets/images/icons/callouts/2.png
Binary files differ
diff --git a/guides/assets/images/icons/callouts/3.png b/guides/assets/images/icons/callouts/3.png
index ef7b700471..57a33d15b4 100644
--- a/guides/assets/images/icons/callouts/3.png
+++ b/guides/assets/images/icons/callouts/3.png
Binary files differ
diff --git a/guides/assets/images/icons/callouts/4.png b/guides/assets/images/icons/callouts/4.png
index adb8364eb5..f061ab02b8 100644
--- a/guides/assets/images/icons/callouts/4.png
+++ b/guides/assets/images/icons/callouts/4.png
Binary files differ
diff --git a/guides/assets/images/icons/callouts/5.png b/guides/assets/images/icons/callouts/5.png
index 4d7eb46002..b4de02da11 100644
--- a/guides/assets/images/icons/callouts/5.png
+++ b/guides/assets/images/icons/callouts/5.png
Binary files differ
diff --git a/guides/assets/images/icons/callouts/6.png b/guides/assets/images/icons/callouts/6.png
index 0ba694af6c..0e055eec1e 100644
--- a/guides/assets/images/icons/callouts/6.png
+++ b/guides/assets/images/icons/callouts/6.png
Binary files differ
diff --git a/guides/assets/images/icons/callouts/7.png b/guides/assets/images/icons/callouts/7.png
index 472e96f8ac..5ead87d040 100644
--- a/guides/assets/images/icons/callouts/7.png
+++ b/guides/assets/images/icons/callouts/7.png
Binary files differ
diff --git a/guides/assets/images/icons/callouts/8.png b/guides/assets/images/icons/callouts/8.png
index 5e60973c21..cb99545eb6 100644
--- a/guides/assets/images/icons/callouts/8.png
+++ b/guides/assets/images/icons/callouts/8.png
Binary files differ
diff --git a/guides/assets/images/icons/callouts/9.png b/guides/assets/images/icons/callouts/9.png
index a0676d26cc..0ac03602f6 100644
--- a/guides/assets/images/icons/callouts/9.png
+++ b/guides/assets/images/icons/callouts/9.png
Binary files differ
diff --git a/guides/assets/images/icons/caution.png b/guides/assets/images/icons/caution.png
index cb9d5ea0df..031e19c776 100644
--- a/guides/assets/images/icons/caution.png
+++ b/guides/assets/images/icons/caution.png
Binary files differ
diff --git a/guides/assets/images/icons/example.png b/guides/assets/images/icons/example.png
index bba1c0010d..1b0e482059 100644
--- a/guides/assets/images/icons/example.png
+++ b/guides/assets/images/icons/example.png
Binary files differ
diff --git a/guides/assets/images/icons/home.png b/guides/assets/images/icons/home.png
index 37a5231bac..24149d6e78 100644
--- a/guides/assets/images/icons/home.png
+++ b/guides/assets/images/icons/home.png
Binary files differ
diff --git a/guides/assets/images/icons/important.png b/guides/assets/images/icons/important.png
index 1096c23295..dafcf0f59e 100644
--- a/guides/assets/images/icons/important.png
+++ b/guides/assets/images/icons/important.png
Binary files differ
diff --git a/guides/assets/images/icons/next.png b/guides/assets/images/icons/next.png
index 64e126bdda..355b329f5a 100644
--- a/guides/assets/images/icons/next.png
+++ b/guides/assets/images/icons/next.png
Binary files differ
diff --git a/guides/assets/images/icons/note.png b/guides/assets/images/icons/note.png
index 841820f7c4..08d35a6f5c 100644
--- a/guides/assets/images/icons/note.png
+++ b/guides/assets/images/icons/note.png
Binary files differ
diff --git a/guides/assets/images/icons/prev.png b/guides/assets/images/icons/prev.png
index 3e8f12fe24..ea564c865e 100644
--- a/guides/assets/images/icons/prev.png
+++ b/guides/assets/images/icons/prev.png
Binary files differ
diff --git a/guides/assets/images/icons/tip.png b/guides/assets/images/icons/tip.png
index a3a029d898..d834e6d1bb 100644
--- a/guides/assets/images/icons/tip.png
+++ b/guides/assets/images/icons/tip.png
Binary files differ
diff --git a/guides/assets/images/icons/up.png b/guides/assets/images/icons/up.png
index 2db1ce62fa..379f0045af 100644
--- a/guides/assets/images/icons/up.png
+++ b/guides/assets/images/icons/up.png
Binary files differ
diff --git a/guides/assets/images/icons/warning.png b/guides/assets/images/icons/warning.png
index 0b0c419df2..72a8a5d873 100644
--- a/guides/assets/images/icons/warning.png
+++ b/guides/assets/images/icons/warning.png
Binary files differ
diff --git a/guides/assets/images/nav_arrow.gif b/guides/assets/images/nav_arrow.gif
index c4f57658d7..ff081819ad 100644
--- a/guides/assets/images/nav_arrow.gif
+++ b/guides/assets/images/nav_arrow.gif
Binary files differ
diff --git a/guides/assets/images/oscardelben.jpg b/guides/assets/images/oscardelben.jpg
new file mode 100644
index 0000000000..9f3f67c2c7
--- /dev/null
+++ b/guides/assets/images/oscardelben.jpg
Binary files differ
diff --git a/guides/assets/images/polymorphic.png b/guides/assets/images/polymorphic.png
index ff2fd9f76d..a3cbc4502a 100644
--- a/guides/assets/images/polymorphic.png
+++ b/guides/assets/images/polymorphic.png
Binary files differ
diff --git a/guides/assets/images/rails_guides_logo.gif b/guides/assets/images/rails_guides_logo.gif
index a24683a34e..9b0ad5af28 100644
--- a/guides/assets/images/rails_guides_logo.gif
+++ b/guides/assets/images/rails_guides_logo.gif
Binary files differ
diff --git a/guides/assets/images/rails_welcome.png b/guides/assets/images/rails_welcome.png
index f2aa210d19..8ad2d351de 100644
--- a/guides/assets/images/rails_welcome.png
+++ b/guides/assets/images/rails_welcome.png
Binary files differ
diff --git a/guides/assets/images/session_fixation.png b/guides/assets/images/session_fixation.png
index 6b084508db..ac3ab01614 100644
--- a/guides/assets/images/session_fixation.png
+++ b/guides/assets/images/session_fixation.png
Binary files differ
diff --git a/guides/assets/images/tab_grey.gif b/guides/assets/images/tab_grey.gif
index e9680b7136..995adb76cf 100644
--- a/guides/assets/images/tab_grey.gif
+++ b/guides/assets/images/tab_grey.gif
Binary files differ
diff --git a/guides/assets/images/tab_info.gif b/guides/assets/images/tab_info.gif
index 458fea9a61..e9dd164f18 100644
--- a/guides/assets/images/tab_info.gif
+++ b/guides/assets/images/tab_info.gif
Binary files differ
diff --git a/guides/assets/images/tab_note.gif b/guides/assets/images/tab_note.gif
index 1d5c171ed6..f9b546c6f8 100644
--- a/guides/assets/images/tab_note.gif
+++ b/guides/assets/images/tab_note.gif
Binary files differ
diff --git a/guides/assets/images/tab_red.gif b/guides/assets/images/tab_red.gif
index daf140b5a8..0613093ddc 100644
--- a/guides/assets/images/tab_red.gif
+++ b/guides/assets/images/tab_red.gif
Binary files differ
diff --git a/guides/assets/images/tab_yellow.gif b/guides/assets/images/tab_yellow.gif
index dc961c99dd..39a3c2dc6a 100644
--- a/guides/assets/images/tab_yellow.gif
+++ b/guides/assets/images/tab_yellow.gif
Binary files differ
diff --git a/guides/assets/images/tab_yellow.png b/guides/assets/images/tab_yellow.png
index cceea6581f..3ab1c56c4d 100644
--- a/guides/assets/images/tab_yellow.png
+++ b/guides/assets/images/tab_yellow.png
Binary files differ
diff --git a/guides/assets/images/validation_error_messages.png b/guides/assets/images/validation_error_messages.png
index 622d35da5d..30e4ca4a3d 100644
--- a/guides/assets/images/validation_error_messages.png
+++ b/guides/assets/images/validation_error_messages.png
Binary files differ
diff --git a/guides/rails_guides/generator.rb b/guides/rails_guides/generator.rb
index d6a98f9ac4..230bebf3bb 100644
--- a/guides/rails_guides/generator.rb
+++ b/guides/rails_guides/generator.rb
@@ -1,7 +1,7 @@
# ---------------------------------------------------------------------------
#
-# This script generates the guides. It can be invoked either directly or via the
-# generate_guides rake task within the railties directory.
+# This script generates the guides. It can be invoked via the
+# guides:generate rake task within the guides directory.
#
# Guides are taken from the source directory, and the resulting HTML goes into the
# output directory. Assets are stored under files, and copied to output/files as
@@ -47,11 +47,6 @@
# Set to "1" to indicate generated guides should be marked as edge. This
# inserts a badge and changes the preamble of the home page.
#
-# KINDLE
-# Set to "1" to generate the .mobi with all the guides. The kindlegen
-# executable must be in your PATH. You can get it for free from
-# http://www.amazon.com/kindlepublishing
-#
# ---------------------------------------------------------------------------
require 'set'
diff --git a/guides/source/action_view_overview.textile b/guides/source/action_view_overview.textile
index bde30ba21c..fdfa97effa 100644
--- a/guides/source/action_view_overview.textile
+++ b/guides/source/action_view_overview.textile
@@ -454,7 +454,7 @@ input("post", "title") # =>
h4. RecordTagHelper
-This module provides methods for generating a container tag, such as a +<div>+, for your record. This is the recommended way of creating a container for render your Active Record object, as it adds an appropriate class and id attributes to that container. You can then refer to those containers easily by following the convention, instead of having to think about which class or id attribute you should use.
+This module provides methods for generating container tags, such as +div+, for your record. This is the recommended way of creating a container for render your Active Record object, as it adds an appropriate class and id attributes to that container. You can then refer to those containers easily by following the convention, instead of having to think about which class or id attribute you should use.
h5. content_tag_for
@@ -542,28 +542,28 @@ image_tag("rails.png") # => <img src="http://assets.example.com/images/rails.png
h5. register_javascript_expansion
-Register one or more JavaScript files to be included when symbol is passed to javascript_include_tag. This method is typically intended to be called from plugin initialization to register JavaScript files that the plugin installed in +public/javascripts+.
+Register one or more JavaScript files to be included when symbol is passed to javascript_include_tag. This method is typically intended to be called from plugin initialization to register JavaScript files that the plugin installed in +vendor/assets/javascripts+.
<ruby>
ActionView::Helpers::AssetTagHelper.register_javascript_expansion :monkey => ["head", "body", "tail"]
javascript_include_tag :monkey # =>
- <script src="/javascripts/head.js"></script>
- <script src="/javascripts/body.js"></script>
- <script src="/javascripts/tail.js"></script>
+ <script src="/assets/head.js"></script>
+ <script src="/assets/body.js"></script>
+ <script src="/assets/tail.js"></script>
</ruby>
h5. register_stylesheet_expansion
-Register one or more stylesheet files to be included when symbol is passed to +stylesheet_link_tag+. This method is typically intended to be called from plugin initialization to register stylesheet files that the plugin installed in +public/stylesheets+.
+Register one or more stylesheet files to be included when symbol is passed to +stylesheet_link_tag+. This method is typically intended to be called from plugin initialization to register stylesheet files that the plugin installed in +vendor/assets/stylesheets+.
<ruby>
ActionView::Helpers::AssetTagHelper.register_stylesheet_expansion :monkey => ["head", "body", "tail"]
stylesheet_link_tag :monkey # =>
- <link href="/stylesheets/head.css" media="screen" rel="stylesheet" />
- <link href="/stylesheets/body.css" media="screen" rel="stylesheet" />
- <link href="/stylesheets/tail.css" media="screen" rel="stylesheet" />
+ <link href="/assets/head.css" media="screen" rel="stylesheet" />
+ <link href="/assets/body.css" media="screen" rel="stylesheet" />
+ <link href="/assets/tail.css" media="screen" rel="stylesheet" />
</ruby>
h5. auto_discovery_link_tag
@@ -577,44 +577,49 @@ auto_discovery_link_tag(:rss, "http://www.example.com/feed.rss", {:title => "RSS
h5. image_path
-Computes the path to an image asset in the +public/images+ directory. Full paths from the document root will be passed through. Used internally by +image_tag+ to build the image path.
+Computes the path to an image asset in the +app/assets/images+ directory. Full paths from the document root will be passed through. Used internally by +image_tag+ to build the image path.
<ruby>
-image_path("edit.png") # => /images/edit.png
+image_path("edit.png") # => /assets/edit.png
+</ruby>
+
+Fingerprint will be added to the filename if config.assets.digest is set to true.
+
+<ruby>
+image_path("edit.png") # => /assets/edit-2d1a2db63fc738690021fedb5a65b68e.png
</ruby>
h5. image_url
-Computes the url to an image asset in the +public/images+ directory. This will call +image_path+ internally and merge with your current host or your asset host.
+Computes the url to an image asset in the +app/asset/images+ directory. This will call +image_path+ internally and merge with your current host or your asset host.
<ruby>
-image_url("edit.png") # => http://www.example.com/images/edit.png
+image_url("edit.png") # => http://www.example.com/assets/edit.png
</ruby>
h5. image_tag
-Returns an html image tag for the source. The source can be a full path or a file that exists in your +public/images+ directory.
+Returns an html image tag for the source. The source can be a full path or a file that exists in your +app/assets/images+ directory.
<ruby>
-image_tag("icon.png") # => <img src="/images/icon.png" alt="Icon" />
+image_tag("icon.png") # => <img src="/assets/icon.png" alt="Icon" />
</ruby>
h5. javascript_include_tag
-Returns an html script tag for each of the sources provided. You can pass in the filename (+.js+ extension is optional) of JavaScript files that exist in your +public/javascripts+ directory for inclusion into the current page or you can pass the full path relative to your document root.
+Returns an html script tag for each of the sources provided. You can pass in the filename (+.js+ extension is optional) of JavaScript files that exist in your +app/assets/javascripts+ directory for inclusion into the current page or you can pass the full path relative to your document root.
<ruby>
-javascript_include_tag "common" # =>
- <script src="/javascripts/common.js"></script>
+javascript_include_tag "common" # => <script src="/assets/common.js"></script>
</ruby>
-If the application does not use the asset pipeline, to include the jQuery JavaScript library in your application, pass +:defaults+ as the source. When using +:defaults+, if an +application.js+ file exists in your +public/javascripts+ directory, it will be included as well.
+If the application does not use the asset pipeline, to include the jQuery JavaScript library in your application, pass +:defaults+ as the source. When using +:defaults+, if an +application.js+ file exists in your +app/assets/javascripts+ directory, it will be included as well.
<ruby>
javascript_include_tag :defaults
</ruby>
-You can also include all JavaScript files in the +public/javascripts+ directory using +:all+ as the source.
+You can also include all JavaScript files in the +app/assets/javascripts+ directory using +:all+ as the source.
<ruby>
javascript_include_tag :all
@@ -629,18 +634,18 @@ javascript_include_tag :all, :cache => true # =>
h5. javascript_path
-Computes the path to a JavaScript asset in the +public/javascripts+ directory. If the source filename has no extension, +.js+ will be appended. Full paths from the document root will be passed through. Used internally by +javascript_include_tag+ to build the script path.
+Computes the path to a JavaScript asset in the +app/assets/javascripts+ directory. If the source filename has no extension, +.js+ will be appended. Full paths from the document root will be passed through. Used internally by +javascript_include_tag+ to build the script path.
<ruby>
-javascript_path "common" # => /javascripts/common.js
+javascript_path "common" # => /assets/common.js
</ruby>
h5. javascript_url
-Computes the url to a JavaScript asset in the +public/javascripts+ directory. This will call +javascript_path+ internally and merge with your current host or your asset host.
+Computes the url to a JavaScript asset in the +app/assets/javascripts+ directory. This will call +javascript_path+ internally and merge with your current host or your asset host.
<ruby>
-javascript_url "common" # => http://www.example.com/javascripts/common.js
+javascript_url "common" # => http://www.example.com/assets/common.js
</ruby>
h5. stylesheet_link_tag
@@ -648,8 +653,7 @@ h5. stylesheet_link_tag
Returns a stylesheet link tag for the sources specified as arguments. If you don't specify an extension, +.css+ will be appended automatically.
<ruby>
-stylesheet_link_tag "application" # =>
- <link href="/stylesheets/application.css" media="screen" rel="stylesheet" />
+stylesheet_link_tag "application" # => <link href="/assets/application.css" media="screen" rel="stylesheet" />
</ruby>
You can also include all styles in the stylesheet directory using :all as the source:
@@ -662,23 +666,23 @@ You can also cache multiple stylesheets into one file, which requires less HTTP
<ruby>
stylesheet_link_tag :all, :cache => true
- <link href="/stylesheets/all.css" media="screen" rel="stylesheet" />
+# => <link href="/assets/all.css" media="screen" rel="stylesheet" />
</ruby>
h5. stylesheet_path
-Computes the path to a stylesheet asset in the +public/stylesheets+ directory. If the source filename has no extension, .css will be appended. Full paths from the document root will be passed through. Used internally by stylesheet_link_tag to build the stylesheet path.
+Computes the path to a stylesheet asset in the +app/assets/stylesheets+ directory. If the source filename has no extension, .css will be appended. Full paths from the document root will be passed through. Used internally by stylesheet_link_tag to build the stylesheet path.
<ruby>
-stylesheet_path "application" # => /stylesheets/application.css
+stylesheet_path "application" # => /assets/application.css
</ruby>
h5. stylesheet_url
-Computes the url to a stylesheet asset in the +public/stylesheets+ directory. This will call +stylesheet_path+ internally and merge with your current host or your asset host.
+Computes the url to a stylesheet asset in the +app/assets/stylesheets+ directory. This will call +stylesheet_path+ internally and merge with your current host or your asset host.
<ruby>
-stylesheet_url "application" # => http://www.example.com/stylesheets/application.css
+stylesheet_url "application" # => http://www.example.com/assets/application.css
</ruby>
h4. AtomFeedHelper
diff --git a/guides/source/active_record_querying.textile b/guides/source/active_record_querying.textile
index 294ef25b33..4b14671efc 100644
--- a/guides/source/active_record_querying.textile
+++ b/guides/source/active_record_querying.textile
@@ -259,6 +259,54 @@ SELECT * FROM clients WHERE (clients.id IN (1,10))
WARNING: <tt>Model.find(array_of_primary_key)</tt> will raise an +ActiveRecord::RecordNotFound+ exception unless a matching record is found for <strong>all</strong> of the supplied primary keys.
+h5. take
+
+<tt>Model.take(limit)</tt> retrieves the first number of records specified by +limit+ without any explicit ordering:
+
+<ruby>
+Client.take(2)
+# => [#<Client id: 1, first_name: "Lifo">,
+ #<Client id: 2, first_name: "Raf">]
+</ruby>
+
+The SQL equivalent of the above is:
+
+<sql>
+SELECT * FROM clients LIMIT 2
+</sql>
+
+h5. first
+
+<tt>Model.first(limit)</tt> finds the first number of records specified by +limit+ ordered by primary key:
+
+<ruby>
+Client.first(2)
+# => [#<Client id: 1, first_name: "Lifo">,
+ #<Client id: 2, first_name: "Raf">]
+</ruby>
+
+The SQL equivalent of the above is:
+
+<sql>
+SELECT * FROM clients LIMIT 2
+</sql>
+
+h5. last
+
+<tt>Model.last(limit)</tt> finds the number of records specified by +limit+ ordered by primary key in descending order:
+
+<ruby>
+Client.last(2)
+# => [#<Client id: 10, first_name: "Ryan">,
+ #<Client id: 9, first_name: "John">]
+</ruby>
+
+The SQL equivalent of the above is:
+
+<sql>
+SELECT * FROM clients ORDER By id DESC LIMIT 2
+</sql>
+
h4. Retrieving Multiple Objects in Batches
We often need to iterate over a large set of records, as when we send a newsletter to a large set of users, or when we export data.
diff --git a/guides/source/active_support_core_extensions.textile b/guides/source/active_support_core_extensions.textile
index 6443255f5d..2addc50d68 100644
--- a/guides/source/active_support_core_extensions.textile
+++ b/guides/source/active_support_core_extensions.textile
@@ -84,7 +84,7 @@ The following values are considered to be blank in a Rails application:
* any other object that responds to +empty?+ and it is empty.
-INFO: In Ruby 1.9 the predicate for strings uses the Unicode-aware character class <tt>[:space:]</tt>, so for example U+2029 (paragraph separator) is considered to be whitespace. In Ruby 1.8 whitespace is considered to be <tt>\s</tt> together with the ideographic space U+3000.
+INFO: The predicate for strings uses the Unicode-aware character class <tt>[:space:]</tt>, so for example U+2029 (paragraph separator) is considered to be whitespace.
WARNING: Note that numbers are not mentioned, in particular 0 and 0.0 are *not* blank.
@@ -1840,6 +1840,76 @@ date and time arithmetic.
NOTE: Defined in +active_support/core_ext/numeric/time.rb+.
+h4. Formatting
+
+Enables the formatting of numbers in a variety of ways.
+
+Produce a string representation of a number as a telephone number:
+<ruby>
+5551234.to_s(:phone) # => 555-1234
+1235551234.to_s(:phone) # => 123-555-1234
+1235551234.to_s(:phone, :area_code => true) # => (123) 555-1234
+1235551234.to_s(:phone, :delimiter => " ") # => 123 555 1234
+1235551234.to_s(:phone, :area_code => true, :extension => 555) # => (123) 555-1234 x 555
+1235551234.to_s(:phone, :country_code => 1) # => +1-123-555-1234
+</ruby>
+
+Produce a string representation of a number as currency:
+<ruby>
+1234567890.50.to_s(:currency) # => $1,234,567,890.50
+1234567890.506.to_s(:currency) # => $1,234,567,890.51
+1234567890.506.to_s(:currency, :precision => 3) # => $1,234,567,890.506
+</ruby>
+
+Produce a string representation of a number as a percentage:
+<ruby>
+100.to_s(:percentage) # => 100.000%
+100.to_s(:percentage, :precision => 0) # => 100%
+1000.to_s(:percentage, :delimiter => '.', :separator => ',') # => 1.000,000%
+302.24398923423.to_s(:percentage, :precision => 5) # => 302.24399%
+</ruby>
+
+Produce a string representation of a number in delimited form:
+<ruby>
+12345678.to_s(:delimited) # => 12,345,678
+12345678.05.to_s(:delimited) # => 12,345,678.05
+12345678.to_s(:delimited, :delimiter => ".") # => 12.345.678
+12345678.to_s(:delimited, :delimiter => ",") # => 12,345,678
+12345678.05.to_s(:delimited, :separator => " ") # => 12,345,678 05
+</ruby>
+
+Produce a string representation of a number rounded to a precision:
+<ruby>
+111.2345.to_s(:rounded) # => 111.235
+111.2345.to_s(:rounded, :precision => 2) # => 111.23
+13.to_s(:rounded, :precision => 5) # => 13.00000
+389.32314.to_s(:rounded, :precision => 0) # => 389
+111.2345.to_s(:rounded, :significant => true) # => 111
+</ruby>
+
+Produce a string representation of a number as a human-readable number of bytes:
+<ruby>
+123.to_s(:human_size) # => 123 Bytes
+1234.to_s(:human_size) # => 1.21 KB
+12345.to_s(:human_size) # => 12.1 KB
+1234567.to_s(:human_size) # => 1.18 MB
+1234567890.to_s(:human_size) # => 1.15 GB
+1234567890123.to_s(:human_size) # => 1.12 TB
+</ruby>
+
+Produce a string representation of a number in human-readable words:
+<ruby>
+123.to_s(:human) # => "123"
+1234.to_s(:human) # => "1.23 Thousand"
+12345.to_s(:human) # => "12.3 Thousand"
+1234567.to_s(:human) # => "1.23 Million"
+1234567890.to_s(:human) # => "1.23 Billion"
+1234567890123.to_s(:human) # => "1.23 Trillion"
+1234567890123456.to_s(:human) # => "1.23 Quadrillion"
+</ruby>
+
+NOTE: Defined in +active_support/core_ext/numeric/formatting.rb+.
+
h3. Extensions to +Integer+
h4. +multiple_of?+
@@ -2093,7 +2163,7 @@ h5. +to_formatted_s+
The method +to_formatted_s+ acts like +to_s+ by default.
-If the array contains items that respond to +id+, however, it may be passed the symbol <tt>:db</tt> as argument. That's typically used with collections of ARs, though technically any object in Ruby 1.8 responds to +id+ indeed. Returned strings are:
+If the array contains items that respond to +id+, however, it may be passed the symbol <tt>:db</tt> as argument. That's typically used with collections of ARs. Returned strings are:
<ruby>
[].to_formatted_s(:db) # => "null"
@@ -2549,6 +2619,45 @@ There's also the bang variant +except!+ that removes keys in the very receiver.
NOTE: Defined in +active_support/core_ext/hash/except.rb+.
+h5. +transform_keys+ and +transform_keys!+
+
+The method +transform_keys+ accepts a block and returns a hash that has applied the block operations to each of the keys in the receiver:
+
+<ruby>
+{nil => nil, 1 => 1, :a => :a}.transform_keys{ |key| key.to_s.upcase }
+# => {"" => nil, "A" => :a, "1" => 1}
+</ruby>
+
+The result in case of collision is undefined:
+
+<ruby>
+{"a" => 1, :a => 2}.transform_keys{ |key| key.to_s.upcase }
+# => {"A" => 2}, in my test, can't rely on this result though
+</ruby>
+
+This method may be useful for example to build specialized conversions. For instance +stringify_keys+ and +symbolize_keys+ use +transform_keys+ to perform their key conversions:
+
+<ruby>
+def stringify_keys
+ transform_keys{ |key| key.to_s }
+end
+...
+def symbolize_keys
+ transform_keys{ |key| key.to_sym rescue key }
+end
+</ruby>
+
+There's also the bang variant +transform_keys!+ that applies the block operations to keys in the very receiver.
+
+Besides that, one can use +deep_transform_keys+ and +deep_transform_keys!+ to perform the block operation on all the keys in the given hash and all the hashes nested into it. An example of the result is:
+
+<ruby>
+{nil => nil, 1 => 1, :nested => {:a => 3, 5 => 5}}.deep_transform_keys{ |key| key.to_s.upcase }
+# => {""=>nil, "1"=>1, "NESTED"=>{"A"=>3, "5"=>5}}
+</ruby>
+
+NOTE: Defined in +active_support/core_ext/hash/keys.rb+.
+
h5. +stringify_keys+ and +stringify_keys!+
The method +stringify_keys+ returns a hash that has a stringified version of the keys in the receiver. It does so by sending +to_s+ to them:
@@ -2579,6 +2688,13 @@ The second line can safely access the "type" key, and let the user to pass eithe
There's also the bang variant +stringify_keys!+ that stringifies keys in the very receiver.
+Besides that, one can use +deep_stringify_keys+ and +deep_stringify_keys!+ to stringify all the keys in the given hash and all the hashes nested into it. An example of the result is:
+
+<ruby>
+{nil => nil, 1 => 1, :nested => {:a => 3, 5 => 5}}.deep_stringify_keys
+# => {""=>nil, "1"=>1, "nested"=>{"a"=>3, "5"=>5}}
+</ruby>
+
NOTE: Defined in +active_support/core_ext/hash/keys.rb+.
h5. +symbolize_keys+ and +symbolize_keys!+
@@ -2613,6 +2729,13 @@ The second line can safely access the +:params+ key, and let the user to pass ei
There's also the bang variant +symbolize_keys!+ that symbolizes keys in the very receiver.
+Besides that, one can use +deep_symbolize_keys+ and +deep_symbolize_keys!+ to symbolize all the keys in the given hash and all the hashes nested into it. An example of the result is:
+
+<ruby>
+{nil => nil, 1 => 1, "nested" => {"a" => 3, 5 => 5}}.deep_symbolize_keys
+# => {nil=>nil, 1=>1, :nested=>{:a=>3, 5=>5}}
+</ruby>
+
NOTE: Defined in +active_support/core_ext/hash/keys.rb+.
h5. +to_options+ and +to_options!+
@@ -2869,8 +2992,6 @@ d.prev_year # => Sun, 28 Feb 1999
d.next_year # => Wed, 28 Feb 2001
</ruby>
-Active Support defines these methods as well for Ruby 1.8.
-
+prev_year+ is aliased to +last_year+.
h6. +prev_month+, +next_month+
@@ -2892,8 +3013,6 @@ Date.new(2000, 5, 31).next_month # => Fri, 30 Jun 2000
Date.new(2000, 1, 31).next_month # => Tue, 29 Feb 2000
</ruby>
-Active Support defines these methods as well for Ruby 1.8.
-
+prev_month+ is aliased to +last_month+.
h6. +beginning_of_week+, +end_of_week+
diff --git a/guides/source/active_support_instrumentation.textile b/guides/source/active_support_instrumentation.textile
index 430549fba4..dcdd9d14f5 100644
--- a/guides/source/active_support_instrumentation.textile
+++ b/guides/source/active_support_instrumentation.textile
@@ -15,7 +15,7 @@ h3. Introduction to instrumentation
The instrumentation API provided by ActiveSupport allows developers to provide hooks which other developers may hook into. There are several of these within the Rails framework, as described below in <TODO: link to section detailing each hook point>. With this API, developers can choose to be notified when certain events occur inside their application or another piece of Ruby code.
-For example, there is a hook provided within Active Record that is called every time Active Record uses a SQL query on a database. This hook could be *subscribed* to, and used to track the number of queries during a certain action. There's another hook around the processing of an action of a controller. This could be used, for instance, to track how long a specific action has taken.
+For example, there is a hook provided within Active Record that is called every time Active Record uses an SQL query on a database. This hook could be *subscribed* to, and used to track the number of queries during a certain action. There's another hook around the processing of an action of a controller. This could be used, for instance, to track how long a specific action has taken.
You are even able to create your own events inside your application which you can later subscribe to.
@@ -377,7 +377,7 @@ listen to any notification.
The block receives the following arguments:
# The name of the event
-# Time when is started
+# Time when it started
# Time when it finished
# An unique ID for this event
# The payload (described in previous sections)
diff --git a/guides/source/command_line.textile b/guides/source/command_line.textile
index b656a0857a..19e42cea93 100644
--- a/guides/source/command_line.textile
+++ b/guides/source/command_line.textile
@@ -31,20 +31,21 @@ h4. +rails new+
The first thing we'll want to do is create a new Rails application by running the +rails new+ command after installing Rails.
-TIP: You can install the rails gem by typing +gem install rails+, if you don't have it already.
+INFO: You can install the rails gem by typing +gem install rails+, if you don't have it already.
<shell>
$ rails new commandsapp
create
create README.rdoc
- create .gitignore
create Rakefile
create config.ru
+ create .gitignore
create Gemfile
create app
...
create tmp/cache
- create tmp/pids
+ ...
+ run bundle install
</shell>
Rails will set you up with what seems like a huge amount of stuff for such a tiny command! You've got the entire Rails directory structure now with all the code you need to run our simple application right out of the box.
@@ -61,17 +62,17 @@ With no further work, +rails server+ will run our new shiny Rails app:
$ cd commandsapp
$ rails server
=> Booting WEBrick
-=> Rails 3.1.0 application starting in development on http://0.0.0.0:3000
+=> Rails 3.2.3 application starting in development on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
-[2010-04-18 03:20:33] INFO WEBrick 1.3.1
-[2010-04-18 03:20:33] INFO ruby 1.8.7 (2010-01-10) [x86_64-linux]
-[2010-04-18 03:20:33] INFO WEBrick::HTTPServer#start: pid=26086 port=3000
+[2012-05-28 00:39:41] INFO WEBrick 1.3.1
+[2012-05-28 00:39:41] INFO ruby 1.9.2 (2011-02-18) [x86_64-darwin11.2.0]
+[2012-05-28 00:39:41] INFO WEBrick::HTTPServer#start: pid=69680 port=3000
</shell>
With just three commands we whipped up a Rails server listening on port 3000. Go to your browser and open "http://localhost:3000":http://localhost:3000, you will see a basic Rails app running.
-You can also use the alias "s" to start the server: <tt>rails s</tt>.
+INFO: You can also use the alias "s" to start the server: <tt>rails s</tt>.
The server can be run on a different port using the +-p+ option. The default development environment can be changed using +-e+.
@@ -85,7 +86,7 @@ h4. +rails generate+
The +rails generate+ command uses templates to create a whole lot of things. Running +rails generate+ by itself gives a list of available generators:
-You can also use the alias "g" to invoke the generator command: <tt>rails g</tt>.
+INFO: You can also use the alias "g" to invoke the generator command: <tt>rails g</tt>.
<shell>
$ rails generate
@@ -97,6 +98,7 @@ Usage: rails generate GENERATOR [args] [options]
Please choose a generator below.
Rails:
+ assets
controller
generator
...
@@ -118,23 +120,22 @@ Usage: rails generate controller NAME [action action] [options]
...
...
+Description:
+ ...
+
+ To create a controller within a module, specify the controller name as a
+ path like 'parent_module/controller_name'.
+
+ ...
+
Example:
- rails generate controller CreditCard open debit credit close
+ `rails generate controller CreditCard open debit credit close`
Credit card controller with URLs like /credit_card/debit.
- Controller: app/controllers/credit_card_controller.rb
- Views: app/views/credit_card/debit.html.erb [...]
- Helper: app/helpers/credit_card_helper.rb
- Test: test/functional/credit_card_controller_test.rb
-
-Modules Example:
- rails generate controller 'admin/credit_card' suspend late_fee
-
- Credit card admin controller with URLs like /admin/credit_card/suspend.
- Controller: app/controllers/admin/credit_card_controller.rb
- Views: app/views/admin/credit_card/debit.html.erb [...]
- Helper: app/helpers/admin/credit_card_helper.rb
- Test: test/functional/admin/credit_card_controller_test.rb
+ Controller: app/controllers/credit_card_controller.rb
+ Functional Test: test/functional/credit_card_controller_test.rb
+ Views: app/views/credit_card/debit.html.erb [...]
+ Helper: app/helpers/credit_card_helper.rb
</shell>
The controller generator is expecting parameters in the form of +generate controller ControllerName action1 action2+. Let's make a +Greetings+ controller with an action of *hello*, which will say something nice to us.
@@ -153,10 +154,10 @@ $ rails generate controller Greetings hello
invoke test_unit
create test/unit/helpers/greetings_helper_test.rb
invoke assets
- create app/assets/javascripts/greetings.js
- invoke css
- create app/assets/stylesheets/greetings.css
-
+ invoke coffee
+ create app/assets/javascripts/greetings.js.coffee
+ invoke scss
+ create app/assets/stylesheets/greetings.css.scss
</shell>
What all did this generate? It made sure a bunch of directories were in our application, and created a controller file, a view file, a functional test file, a helper for the view, a javascript file and a stylesheet file.
@@ -193,21 +194,19 @@ Rails comes with a generator for data models too.
<shell>
$ rails generate model
-Usage: rails generate model NAME [field:type field:type] [options]
+Usage:
+ rails generate model NAME [field[:type][:index] field[:type][:index]] [options]
...
-Examples:
- rails generate model account
-
- Model: app/models/account.rb
- Test: test/unit/account_test.rb
- Fixtures: test/fixtures/accounts.yml
- Migration: db/migrate/XXX_add_accounts.rb
+ActiveRecord options:
+ [--migration] # Indicates when to generate migration
+ # Default: true
- rails generate model post title:string body:text published:boolean
+...
- Creates a Post model with a string title, text body, and published flag.
+Description:
+ Create rails files for model generator.
</shell>
NOTE: For a list of available field types, refer to the "API documentation":http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html#method-i-column for the column method for the +TableDefinition+ class.
@@ -218,46 +217,47 @@ We will set up a simple resource called "HighScore" that will keep track of our
<shell>
$ rails generate scaffold HighScore game:string score:integer
- exists app/models/
- exists app/controllers/
- exists app/helpers/
- create app/views/high_scores
- create app/views/layouts/
- exists test/functional/
- create test/unit/
- create app/assets/stylesheets/
- create app/views/high_scores/index.html.erb
- create app/views/high_scores/show.html.erb
- create app/views/high_scores/new.html.erb
- create app/views/high_scores/edit.html.erb
- create app/views/layouts/high_scores.html.erb
- create app/assets/stylesheets/scaffold.css.scss
- create app/controllers/high_scores_controller.rb
- create test/functional/high_scores_controller_test.rb
- create app/helpers/high_scores_helper.rb
- route resources :high_scores
-dependency model
- exists app/models/
- exists test/unit/
- create test/fixtures/
+ invoke active_record
+ create db/migrate/20120528060026_create_high_scores.rb
create app/models/high_score.rb
- create test/unit/high_score_test.rb
- create test/fixtures/high_scores.yml
- exists db/migrate
- create db/migrate/20100209025147_create_high_scores.rb
+ invoke test_unit
+ create test/unit/high_score_test.rb
+ create test/fixtures/high_scores.yml
+ route resources :high_scores
+ invoke scaffold_controller
+ create app/controllers/high_scores_controller.rb
+ invoke erb
+ create app/views/high_scores
+ create app/views/high_scores/index.html.erb
+ create app/views/high_scores/edit.html.erb
+ create app/views/high_scores/show.html.erb
+ create app/views/high_scores/new.html.erb
+ create app/views/high_scores/_form.html.erb
+ invoke test_unit
+ create test/functional/high_scores_controller_test.rb
+ invoke helper
+ create app/helpers/high_scores_helper.rb
+ invoke test_unit
+ create test/unit/helpers/high_scores_helper_test.rb
+ invoke assets
+ invoke coffee
+ create app/assets/javascripts/high_scores.js.coffee
+ invoke scss
+ create app/assets/stylesheets/high_scores.css.scss
+ invoke scss
+ create app/assets/stylesheets/scaffolds.css.scss
</shell>
The generator checks that there exist the directories for models, controllers, helpers, layouts, functional and unit tests, stylesheets, creates the views, controller, model and database migration for HighScore (creating the +high_scores+ table and fields), takes care of the route for the *resource*, and new tests for everything.
-The migration requires that we *migrate*, that is, run some Ruby code (living in that +20100209025147_create_high_scores.rb+) to modify the schema of our database. Which database? The sqlite3 database that Rails will create for you when we run the +rake db:migrate+ command. We'll talk more about Rake in-depth in a little while.
+The migration requires that we *migrate*, that is, run some Ruby code (living in that +20120528060026_create_high_scores.rb+) to modify the schema of our database. Which database? The sqlite3 database that Rails will create for you when we run the +rake db:migrate+ command. We'll talk more about Rake in-depth in a little while.
<shell>
$ rake db:migrate
-(in /home/foobar/commandsapp)
== CreateHighScores: migrating ===============================================
-- create_table(:high_scores)
- -> 0.0026s
-== CreateHighScores: migrated (0.0028s) ======================================
+ -> 0.0017s
+== CreateHighScores: migrated (0.0019s) ======================================
</shell>
INFO: Let's talk about unit tests. Unit tests are code that tests and makes assertions about code. In unit testing, we take a little part of code, say a method of a model, and test its inputs and outputs. Unit tests are your friend. The sooner you make peace with the fact that your quality of life will drastically increase when you unit test your code, the better. Seriously. We'll make one in a moment.
@@ -274,19 +274,19 @@ h4. +rails console+
The +console+ command lets you interact with your Rails application from the command line. On the underside, +rails console+ uses IRB, so if you've ever used it, you'll be right at home. This is useful for testing out quick ideas with code and changing data server-side without touching the website.
-You can also use the alias "c" to invoke the console: <tt>rails c</tt>.
+INFO: You can also use the alias "c" to invoke the console: <tt>rails c</tt>.
-You can specify the environment in which the +console+ command should operate using the +-e+ switch.
+You can specify the environment in which the +console+ command should operate.
<shell>
-$ rails console -e staging
+$ rails console staging
</shell>
If you wish to test out some code without changing any data, you can do that by invoking +rails console --sandbox+.
<shell>
$ rails console --sandbox
-Loading development environment in sandbox (Rails 3.1.0)
+Loading development environment in sandbox (Rails 3.2.3)
Any modifications you make will be rolled back on exit
irb(main):001:0>
</shell>
@@ -295,7 +295,7 @@ h4. +rails dbconsole+
+rails dbconsole+ figures out which database you're using and drops you into whichever command line interface you would use with it (and figures out the command line parameters to give to it, too!). It supports MySQL, PostgreSQL, SQLite and SQLite3.
-You can also use the alias "db" to invoke the dbconsole: <tt>rails db</tt>.
+INFO: You can also use the alias "db" to invoke the dbconsole: <tt>rails db</tt>.
h4. +rails runner+
@@ -305,7 +305,7 @@ h4. +rails runner+
$ rails runner "Model.long_running_method"
</shell>
-You can also use the alias "r" to invoke the runner: <tt>rails r</tt>.
+INFO: You can also use the alias "r" to invoke the runner: <tt>rails r</tt>.
You can specify the environment in which the +runner+ command should operate using the +-e+ switch.
@@ -317,31 +317,25 @@ h4. +rails destroy+
Think of +destroy+ as the opposite of +generate+. It'll figure out what generate did, and undo it.
-You can also use the alias "d" to invoke the destroy command: <tt>rails d</tt>.
+INFO: You can also use the alias "d" to invoke the destroy command: <tt>rails d</tt>.
<shell>
$ rails generate model Oops
- exists app/models/
- exists test/unit/
- exists test/fixtures/
- create app/models/oops.rb
- create test/unit/oops_test.rb
- create test/fixtures/oops.yml
- exists db/migrate
- create db/migrate/20081221040817_create_oops.rb
+ invoke active_record
+ create db/migrate/20120528062523_create_oops.rb
+ create app/models/oops.rb
+ invoke test_unit
+ create test/unit/oops_test.rb
+ create test/fixtures/oops.yml
+</shell>
+<shell>
$ rails destroy model Oops
- notempty db/migrate
- notempty db
- rm db/migrate/20081221040817_create_oops.rb
- rm test/fixtures/oops.yml
- rm test/unit/oops_test.rb
- rm app/models/oops.rb
- notempty test/fixtures
- notempty test
- notempty test/unit
- notempty test
- notempty app/models
- notempty app
+ invoke active_record
+ remove db/migrate/20120528062523_create_oops.rb
+ remove app/models/oops.rb
+ invoke test_unit
+ remove test/unit/oops_test.rb
+ remove test/fixtures/oops.yml
</shell>
h3. Rake
@@ -352,16 +346,16 @@ You can get a list of Rake tasks available to you, which will often depend on yo
<shell>
$ rake --tasks
-(in /home/foobar/commandsapp)
-rake db:abort_if_pending_migrations # Raises an error if there are pending migrations
-rake db:charset # Retrieves the charset for the current environment's database
-rake db:collation # Retrieves the collation for the current environment's database
-rake db:create # Create the database defined in config/database.yml for the current Rails.env
+rake about # List versions of all Rails frameworks and the environment
+rake assets:clean # Remove compiled assets
+rake assets:precompile # Compile all the assets named in config.assets.precompile
+rake db:create # Create the database from config/database.yml for the current Rails.env
...
+rake log:clear # Truncates all *.log files in log/ to zero bytes
+rake middleware # Prints out your Rack middleware stack
...
-rake tmp:pids:clear # Clears all files in tmp/pids
-rake tmp:sessions:clear # Clears all files in tmp/sessions
-rake tmp:sockets:clear # Clears all files in tmp/sockets
+rake tmp:clear # Clear session, cache, and socket files from tmp/ (narrow w/ tmp:sessions:clear, tmp:cache:clear, tmp:sockets:clear)
+rake tmp:create # Creates tmp directories for sessions, cache, sockets, and pids
</shell>
h4. +about+
diff --git a/guides/source/configuring.textile b/guides/source/configuring.textile
index f114075cae..af46538bf5 100644
--- a/guides/source/configuring.textile
+++ b/guides/source/configuring.textile
@@ -585,7 +585,7 @@ After loading the framework and any gems in your application, Rails turns to loa
NOTE: You can use subfolders to organize your initializers if you like, because Rails will look into the whole file hierarchy from the initializers folder on down.
-TIP: If you have any ordering dependency in your initializers, you can control the load order by naming. For example, +01_critical.rb+ will be loaded before +02_normal.rb+.
+TIP: If you have any ordering dependency in your initializers, you can control the load order through naming. Initializer files are loaded in alphabetical order by their path. For example, +01_critical.rb+ will be loaded before +02_normal.rb+.
h3. Initialization events
diff --git a/guides/source/contributing_to_ruby_on_rails.textile b/guides/source/contributing_to_ruby_on_rails.textile
index df475a2359..acf75d41cd 100644
--- a/guides/source/contributing_to_ruby_on_rails.textile
+++ b/guides/source/contributing_to_ruby_on_rails.textile
@@ -343,9 +343,39 @@ h4. Commit Your Changes
When you're happy with the code on your computer, you need to commit the changes to git:
<shell>
-$ git commit -a -m "Here is a commit message on what I changed in this commit"
+$ git commit -a
</shell>
+At this point, your editor should be fired up and you can write a message for this commit. Well formatted and descriptive commit messages are extremely helpful for the others, especially when figuring out why given change was made, so please take the time to write it.
+
+Good commit message should be formatted according to the following example:
+
+<plain>
+Short summary (ideally 50 characters or less)
+
+More detailed description, if necessary. It should be wrapped to 72
+characters. Try to be as descriptive as you can, even if you think that
+the commit content is obvious, it may not be obvious to others. You
+should add such description also if it's already present in bug tracker,
+it should not be necessary to visit a webpage to check the history.
+
+Description can have multiple paragraps and you can use code examples
+inside, just indent it with 4 spaces:
+
+ class PostsController
+ def index
+ respond_with Post.limit(10)
+ end
+ end
+
+You can also add bullet points:
+
+- you can use dashes or asterisks
+
+- also, try to indent next line of a point for readability, if it's too
+ long to fit in 72 characters
+</plain>
+
TIP. Please squash your commits into a single commit when appropriate. This simplifies future cherry picks, and also keeps the git log clean.
h4. Update Master
@@ -382,6 +412,42 @@ Push to your remote:
$ git push mine my_new_branch
</shell>
+You might have cloned your forked repository into your machine and might want to add the original Rails repository as a remote instead, if that's the case here's what you have to do.
+
+In the directory you cloned your fork:
+
+<shell>
+$ git remote add rails git://github.com/rails/rails.git
+</shell>
+
+Download new commits and branches from the official repository:
+
+<shell>
+$ git fetch rails
+</shell>
+
+Merge the new content:
+
+<shell>
+$ git checkout master
+$ git rebase rails/master
+</shell>
+
+Update your fork:
+
+<shell>
+$ git push origin master
+</shell>
+
+If you want to update another branches:
+
+<shell>
+$ git checkout branch_name
+$ git rebase rails/branch_name
+$ git push origin branch_name
+</shell>
+
+
h4. Issue a Pull Request
Navigate to the Rails repository you just pushed to (e.g. https://github.com/your-user-name/rails) and press "Pull Request" in the upper right hand corner.
@@ -400,6 +466,35 @@ h4. Iterate as Necessary
It’s entirely possible that the feedback you get will suggest changes. Don’t get discouraged: the whole point of contributing to an active open source project is to tap into community knowledge. If people are encouraging you to tweak your code, then it’s worth making the tweaks and resubmitting. If the feedback is that your code doesn’t belong in the core, you might still think about releasing it as a gem.
+h4. Backporting
+
+Changes that are merged into master are intended for the next major release of Rails. Sometimes, it might be beneficial for your changes to propagate back to the maintenance releases for older stable branches. Generally, security fixes and bug fixes are good candidates for a backport, while new features and patches that introduce a change in behavior will not be accepted. When in doubt, it is best to consult a rails team member before backporting your changes to avoid wasted effort.
+
+For simple fixes, the easiest way to backport your change is to "extract a diff from your changes in master and apply them to the target branch":http://ariejan.net/2009/10/26/how-to-create-and-apply-a-patch-with-git.
+
+First make sure your changes are the only difference between your current branch and master:
+
+<shell>
+$ git log master..HEAD
+</shell>
+
+Then extract the diff:
+
+<shell>
+$ git format-patch master --stdout > ~/my_changes.patch
+</shell>
+
+Switch over to the target branch and apply your changes:
+
+<shell>
+$ git checkout -b my_backport_branch 3-2-stable
+$ git apply ~/my_changes.patch
+</shell>
+
+This works well for simple changes. However, if your changes are complicated or if the code in master has deviated significantly from your target branch, it might require more work on your part. The difficulty of a backport varies greatly from case to case, and sometimes it is simply not worth the effort.
+
+Once you have resolved all conflicts and made sure all the tests are passing, push your changes and open a separate pull request for your backport. It is also worth noting that older branches might have a different set of build targets than master. When possible, it is best to first test your backport locally against the ruby versions listed in +.travis.yml+ before submitting your pull request.
+
And then ... think about your next contribution!
h3. Rails Contributors
diff --git a/guides/source/credits.html.erb b/guides/source/credits.html.erb
index da6bd6acdf..04deec6a11 100644
--- a/guides/source/credits.html.erb
+++ b/guides/source/credits.html.erb
@@ -31,6 +31,10 @@ Ruby on Rails Guides: Credits
Ryan Bigg works as a consultant at <a href="http://rubyx.com">RubyX</a> and has been working with Rails since 2006. He's co-authoring a book called <a href="http://manning.com/katz">Rails 3 in Action</a> and he's written many gems which can be seen on <a href="http://github.com/radar">his GitHub page</a> and he also tweets prolifically as <a href="http://twitter.com/ryanbigg">@ryanbigg</a>.
<% end %>
+<%= author('Oscar Del Ben', 'oscardelben', 'oscardelben.jpg') do %>
+Oscar Del Ben is a software engineer at <a href="http://www.wildfireapp.com/">Wildfire</a>. He's a regular open source contributor (<a href="https://github.com/oscardelben">Github account</a>) and tweets regularly at <a href="https://twitter.com/oscardelben">@oscardelben</a>.
+ <% end %>
+
<%= author('Frederick Cheung', 'fcheung') do %>
Frederick Cheung is Chief Wizard at Texperts where he has been using Rails since 2006. He is based in Cambridge (UK) and when not consuming fine ales he blogs at <a href="http://www.spacevatican.org">spacevatican.org</a>.
<% end %>
diff --git a/guides/source/debugging_rails_applications.textile b/guides/source/debugging_rails_applications.textile
index 45fa4ada78..0802a2db26 100644
--- a/guides/source/debugging_rails_applications.textile
+++ b/guides/source/debugging_rails_applications.textile
@@ -698,7 +698,7 @@ There are some Rails plugins to help you to find errors and debug your applicati
h3. References
-* "ruby-debug Homepage":http://www.datanoise.com/ruby-debug
+* "ruby-debug Homepage":http://bashdb.sourceforge.net/ruby-debug/home-page.html
* "debugger Homepage":http://github.com/cldwalker/debugger
* "Article: Debugging a Rails application with ruby-debug":http://www.sitepoint.com/article/debug-rails-app-ruby-debug/
* "ruby-debug Basics screencast":http://brian.maybeyoureinsane.net/blog/2007/05/07/ruby-debug-basics-screencast/
diff --git a/guides/source/engines.textile b/guides/source/engines.textile
index 880be57fb5..86e7254201 100644
--- a/guides/source/engines.textile
+++ b/guides/source/engines.textile
@@ -36,6 +36,12 @@ To generate an engine with Rails 3.1, you will need to run the plugin generator
$ rails plugin new blorgh --full --mountable
</shell>
+The full list of options for the plugin generator may be seen by typing:
+
+<shell>
+$ rails plugin --help
+</shell>
+
The +--full+ option tells the plugin generator that you want to create an engine (which is a mountable plugin, hence the option name), creating the basic directory structure of an engine by providing things such as the foundations of an +app+ folder, as well a +config/routes.rb+ file. This generator also provides a file at +lib/blorgh/engine.rb+ which is identical in function to an application's +config/application.rb+ file.
The +--mountable+ option tells the generator to mount the engine inside the dummy testing application located at +test/dummy+ inside the engine. It does this by placing this line in to the dummy application's +config/routes.rb+ file, located at +test/dummy/config/routes.rb+ inside the engine:
@@ -738,7 +744,7 @@ This tells sprockets to add you engine assets when +rake assets:precompile+ is r
You can define assets for precompilation in +engine.rb+
<ruby>
-initializer do |app|
+initializer "blorgh.assets.precompile" do |app|
app.config.assets.precompile += %w(admin.css admin.js)
end
</ruby>
diff --git a/guides/source/form_helpers.textile b/guides/source/form_helpers.textile
index 033b33ec3b..8106de6f9d 100644
--- a/guides/source/form_helpers.textile
+++ b/guides/source/form_helpers.textile
@@ -150,7 +150,7 @@ NOTE: Always use labels for checkbox and radio buttons. They associate text with
h4. Other Helpers of Interest
-Other form controls worth mentioning are textareas, password fields, hidden fields, search fields, telephone fields, date fields, time fields, URL fields and email fields:
+Other form controls worth mentioning are textareas, password fields, hidden fields, search fields, telephone fields, date fields, time fields, color fields, datetime fields, datetime-local fields, month fields, week fields, URL fields and email fields:
<erb>
<%= text_area_tag(:message, "Hi, nice site", :size => "24x6") %>
@@ -159,8 +159,13 @@ Other form controls worth mentioning are textareas, password fields, hidden fiel
<%= search_field(:user, :name) %>
<%= telephone_field(:user, :phone) %>
<%= date_field(:user, :born_on) %>
+<%= datetime_field(:user, :meeting_time) %>
+<%= datetime_local_field(:user, :graduation_day) %>
+<%= month_field(:user, :birthday_month) %>
+<%= week_field(:user, :birthday_week) %>
<%= url_field(:user, :homepage) %>
<%= email_field(:user, :address) %>
+<%= color_field(:user, :favorite_color) %>
<%= time_field(:task, :started_at) %>
</erb>
@@ -173,14 +178,19 @@ Output:
<input id="user_name" name="user[name]" type="search" />
<input id="user_phone" name="user[phone]" type="tel" />
<input id="user_born_on" name="user[born_on]" type="date" />
+<input id="user_meeting_time" name="user[meeting_time]" type="datetime" />
+<input id="user_graduation_day" name="user[graduation_day]" type="datetime-local" />
+<input id="user_birthday_month" name="user[birthday_month]" type="month" />
+<input id="user_birthday_week" name="user[birthday_week]" type="week" />
<input id="user_homepage" name="user[homepage]" type="url" />
<input id="user_address" name="user[address]" type="email" />
+<input id="user_favorite_color" name="user[favorite_color]" type="color" value="#000000" />
<input id="task_started_at" name="task[started_at]" type="time" />
</html>
Hidden inputs are not shown to the user but instead hold data like any textual input. Values inside them can be changed with JavaScript.
-IMPORTANT: The search, telephone, date, time, URL, and email inputs are HTML5 controls. If you require your app to have a consistent experience in older browsers, you will need an HTML5 polyfill (provided by CSS and/or JavaScript). There is definitely "no shortage of solutions for this":https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills, although a couple of popular tools at the moment are "Modernizr":http://www.modernizr.com/ and "yepnope":http://yepnopejs.com/, which provide a simple way to add functionality based on the presence of detected HTML5 features.
+IMPORTANT: The search, telephone, date, time, color, datetime, datetime-local, month, week, URL, and email inputs are HTML5 controls. If you require your app to have a consistent experience in older browsers, you will need an HTML5 polyfill (provided by CSS and/or JavaScript). There is definitely "no shortage of solutions for this":https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills, although a couple of popular tools at the moment are "Modernizr":http://www.modernizr.com/ and "yepnope":http://yepnopejs.com/, which provide a simple way to add functionality based on the presence of detected HTML5 features.
TIP: If you're using password input fields (for any purpose), you might want to configure your application to prevent those parameters from being logged. You can learn about this in the "Security Guide":security.html#logging.
diff --git a/guides/source/getting_started.textile b/guides/source/getting_started.textile
index 19bd106ff0..f25e0c0200 100644
--- a/guides/source/getting_started.textile
+++ b/guides/source/getting_started.textile
@@ -13,8 +13,6 @@ endprologue.
WARNING. This Guide is based on Rails 3.2. Some of the code shown here will not
work in earlier versions of Rails.
-WARNING: The Edge version of this guide is currently being re-worked. Please excuse us while we re-arrange the place.
-
h3. Guide Assumptions
This guide is designed for beginners who want to get started with a Rails
@@ -77,7 +75,7 @@ By following along with this guide, you'll create a Rails project called
(very) simple weblog. Before you can start building the application, you need to
make sure that you have Rails itself installed.
-TIP: The examples below use # and $ to denote terminal prompts. If you are using Windows, your prompt will look something like c:\source_code>
+TIP: The examples below use # and $ to denote superuser and regular user terminal prompts respectively in a UNIX-like OS. If you are using Windows, your prompt will look something like c:\source_code>
h4. Installing Rails
@@ -110,7 +108,7 @@ To use this generator, open a terminal, navigate to a directory where you have r
$ rails new blog
</shell>
-This will create a Rails application called Blog in a directory called blog.
+This will create a Rails application called Blog in a directory called blog and install the gem dependencies that are already mentioned in +Gemfile+ using +bundle install+.
TIP: You can see all of the command line options that the Rails
application builder accepts by running +rails new -h+.
@@ -140,7 +138,7 @@ application. Most of the work in this tutorial will happen in the +app/+ folder,
|README.rdoc|This is a brief instruction manual for your application. You should edit this file to tell others what your application does, how to set it up, and so on.|
|script/|Contains the rails script that starts your app and can contain other scripts you use to deploy or run your application.|
|test/|Unit tests, fixtures, and other test apparatus. These are covered in "Testing Rails Applications":testing.html|
-|tmp/|Temporary files|
+|tmp/|Temporary files (like cache, pid and session files)|
|vendor/|A place for all third-party code. In a typical Rails application, this includes Ruby Gems and the Rails source code (if you optionally install it into your project).|
h3. Hello, Rails!
@@ -179,7 +177,28 @@ To create a new controller, you will need to run the "controller" generator and
$ rails generate controller welcome index
</shell>
-Rails will create several files for you. Most important of these are of course the controller, located at +app/controllers/welcome_controller.rb+ and the view, located at +app/views/welcome/index.html.erb+.
+Rails will create several files and a route for you.
+
+<shell>
+create app/controllers/welcome_controller.rb
+ route get "welcome/index"
+invoke erb
+create app/views/welcome
+create app/views/welcome/index.html.erb
+invoke test_unit
+create test/functional/welcome_controller_test.rb
+invoke helper
+create app/helpers/welcome_helper.rb
+invoke test_unit
+create test/unit/helpers/welcome_helper_test.rb
+invoke assets
+invoke coffee
+create app/assets/javascripts/welcome.js.coffee
+invoke scss
+create app/assets/stylesheets/welcome.css.scss
+</shell>
+
+Most important of these are of course the controller, located at +app/controllers/welcome_controller.rb+ and the view, located at +app/views/welcome/index.html.erb+.
Open the +app/views/welcome/index.html.erb+ file in your text editor and edit it to contain a single line of code:
@@ -197,18 +216,27 @@ You need to do this because Rails will serve any static file in the +public+ dir
Next, you have to tell Rails where your actual home page is located.
-Open the file +config/routes.rb+ in your editor. This is your application's _routing file_ which holds entries in a special DSL (domain-specific language) that tells Rails how to connect incoming requests to controllers and actions. This file contains many sample routes on commented lines, and one of them actually shows you how to connect the root of your site to a specific controller and action. Find the line beginning with +root :to+ and uncomment it. It should look something like the following:
+Open the file +config/routes.rb+ in your editor.
<ruby>
Blog::Application.routes.draw do
-
- #...
+ get "welcome/index"
+
+ # The priority is based upon order of creation:
+ # first created -> highest priority.
+ # ...
# You can have the root of your site routed with "root"
# just remember to delete public/index.html.
- root :to => "welcome#index"
+ # root :to => "welcome#index"
+</ruby>
+
+This is your application's _routing file_ which holds entries in a special DSL (domain-specific language) that tells Rails how to connect incoming requests to controllers and actions. This file contains many sample routes on commented lines, and one of them actually shows you how to connect the root of your site to a specific controller and action. Find the line beginning with +root :to+ and uncomment it. It should look something like the following:
+
+<ruby>
+root :to => "welcome#index"
</ruby>
-The +root :to => "welcome#index"+ tells Rails to map requests to the root of the application to the welcome controller's index action. This was created earlier when you ran the controller generator (+rails generate controller welcome index+).
+The +root :to => "welcome#index"+ tells Rails to map requests to the root of the application to the welcome controller's index action and +get "welcome/index"+ tells Rails to map requests to "http://localhost:3000/welcome/index":http://localhost:3000/welcome/index to the welcome controller's index action. This was created earlier when you ran the controller generator (+rails generate controller welcome index+).
If you navigate to "http://localhost:3000":http://localhost:3000 in your browser, you'll see the +Hello, Rails!+ message you put into +app/views/welcome/index.html.erb+, indicating that this new route is indeed going to +WelcomeController+'s +index+ action and is rendering the view correctly.
@@ -502,7 +530,7 @@ database columns. In the first line we do just that (remember that
+params[:post]+ contains the attributes we're interested in). Then,
+@post.save+ is responsible for saving the model in the database.
Finally, we redirect the user to the +show+ action,
-wich we'll define later.
+which we'll define later.
TIP: As we'll see later, +@post.save+ returns a boolean indicating
wherever the model was saved or not.
@@ -612,7 +640,7 @@ The +link_to+ method is one of Rails' built-in view helpers. It creates a
hyperlink based on text to display and where to go - in this case, to the path
for posts.
-Let's add links to the other views as well, starting with adding this "New Post" link to +app/views/posts/index.html.erb+, placing it above the +<table>+ tag:
+Let's add links to the other views as well, starting with adding this "New Post" link to +app/views/posts/index.html.erb+, placing it above the +&lt;table&gt;+ tag:
<erb>
<%= link_to 'New post', :action => :new %>
@@ -678,7 +706,7 @@ end
This change will ensure that all changes made through HTML forms can edit the content of the text and title fields.
It will not be possible to define any other field value through forms. You can still define them by calling the `field=` method of course.
-Accessible attributes and the mass assignment probem is covered in details in the "Security guide":security.html#mass-assignment
+Accessible attributes and the mass assignment problem is covered in details in the "Security guide":security.html#mass-assignment
h4. Adding Some Validation
@@ -1131,7 +1159,7 @@ together.
Here we're using +link_to+ in a different way. We wrap the
+:action+ and +:id+ attributes in a hash so that we can pass those two keys in
first as one argument, and then the final two keys as another argument. The +:method+ and +:confirm+
-options are used as html5 attributes so that when the click is linked,
+options are used as HTML5 attributes so that when the link is clicked,
Rails will first show a confirm dialog to the user, and then submit the
link with method +delete+. This is done via the JavaScript file +jquery_ujs+
which is automatically included into your application's layout
diff --git a/guides/source/initialization.textile b/guides/source/initialization.textile
index 155a439e64..48d4373afe 100644
--- a/guides/source/initialization.textile
+++ b/guides/source/initialization.textile
@@ -1,13 +1,15 @@
h2. The Rails Initialization Process
-This guide explains the internals of the initialization process in Rails as of Rails 3.1. It is an extremely in-depth guide and recommended for advanced Rails developers.
+This guide explains the internals of the initialization process in Rails
+as of Rails 4. It is an extremely in-depth guide and recommended for advanced Rails developers.
* Using +rails server+
* Using Passenger
endprologue.
-This guide goes through every single file, class and method call that is required to boot up the Ruby on Rails stack for a default Rails 3.1 application, explaining each part in detail along the way. For this guide, we will be focusing on how the two most common methods (+rails server+ and Passenger) boot a Rails application.
+This guide goes through every single file, class and method call that is
+required to boot up the Ruby on Rails stack for a default Rails 4 application, explaining each part in detail along the way. For this guide, we will be focusing on how the two most common methods (+rails server+ and Passenger) boot a Rails application.
NOTE: Paths in this guide are relative to Rails or a Rails application unless otherwise specified.
@@ -22,16 +24,15 @@ The actual +rails+ command is kept in _bin/rails_:
<ruby>
#!/usr/bin/env ruby
-begin
- require "rails/cli"
-rescue LoadError
- railties_path = File.expand_path('../../railties/lib', __FILE__)
+if File.exists?(File.join(File.expand_path('../../..', __FILE__), '.git'))
+ railties_path = File.expand_path('../../lib', __FILE__)
$:.unshift(railties_path)
- require "rails/cli"
end
+require "rails/cli"
</ruby>
-This file will attempt to load +rails/cli+. If it cannot find it then +railties/lib+ is added to the load path (+$:+) before retrying.
+This file will first attempt to push the +railties/lib+ directory if
+present, and then require +rails/cli+.
h4. +railties/lib/rails/cli.rb+
@@ -46,7 +47,7 @@ require 'rails/script_rails_loader'
Rails::ScriptRailsLoader.exec_script_rails!
require 'rails/ruby_version_check'
-Signal.trap("INT") { puts; exit }
+Signal.trap("INT") { puts; exit(1) }
if ARGV.first == 'plugin'
ARGV.shift
@@ -120,6 +121,9 @@ exec RUBY, SCRIPT_RAILS, *ARGV if in_rails_application?
This is effectively the same as running +ruby script/rails [arguments]+, where +[arguments]+ at this point in time is simply "server".
+TIP: If you execute +script/rails+ directly from your Rails app you will
+avoid executing the code that we just described.
+
h4. +script/rails+
This file is as follows:
@@ -134,30 +138,30 @@ The +APP_PATH+ constant will be used later in +rails/commands+. The +config/boot
h4. +config/boot.rb+
-+config/boot.rb+ contains this:
++config/boot.rb+ contains:
<ruby>
# Set up gems listed in the Gemfile.
-gemfile = File.expand_path('../../Gemfile', __FILE__)
-begin
- ENV['BUNDLE_GEMFILE'] = gemfile
- require 'bundler'
- Bundler.setup
-rescue Bundler::GemNotFound => e
- STDERR.puts e.message
- STDERR.puts "Try running `bundle install`."
- exit!
-end if File.exist?(gemfile)
+ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
+
+require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
</ruby>
-In a standard Rails application, there's a +Gemfile+ which declares all dependencies of the application. +config/boot.rb+ sets +ENV["BUNDLE_GEMFILE"]+ to the location of this file, then requires Bundler and calls +Bundler.setup+ which adds the dependencies of the application (including all the Rails parts) to the load path, making them available for the application to load. The gems that a Rails 3.1 application depends on are as follows:
+In a standard Rails application, there's a +Gemfile+ which declares all
+dependencies of the application. +config/boot.rb+ sets
++ENV['BUNDLE_GEMFILE']+ to the location of this file. If the Gemfile
+exists, +bundler/setup+ is then required.
+
+The gems that a Rails 4 application depends on are as follows:
+
+TODO: change these when the Rails 4 release is near.
* abstract (1.0.0)
-* actionmailer (3.1.0.beta)
-* actionpack (3.1.0.beta)
-* activemodel (3.1.0.beta)
-* activerecord (3.1.0.beta)
-* activesupport (3.1.0.beta)
+* actionmailer (4.0.0.beta)
+* actionpack (4.0.0.beta)
+* activemodel (4.0.0.beta)
+* activerecord (4.0.0.beta)
+* activesupport (4.0.0.beta)
* arel (2.0.7)
* builder (3.0.0)
* bundler (1.0.6)
@@ -170,8 +174,8 @@ In a standard Rails application, there's a +Gemfile+ which declares all dependen
* rack-cache (0.5.3)
* rack-mount (0.6.13)
* rack-test (0.5.6)
-* rails (3.1.0.beta)
-* railties (3.1.0.beta)
+* rails (4.0.0.beta)
+* railties (4.0.0.beta)
* rake (0.8.7)
* sqlite3-ruby (1.3.2)
* thor (0.14.6)
@@ -183,8 +187,11 @@ h4. +rails/commands.rb+
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:
<ruby>
+ARGV << '--help' if ARGV.empty?
+
aliases = {
"g" => "generate",
+ "d" => "destroy",
"c" => "console",
"s" => "server",
"db" => "dbconsole",
@@ -195,6 +202,9 @@ command = ARGV.shift
command = aliases[command] || command
</ruby>
+TIP: As you can see, an empty ARGV list will make Rails show the help
+snippet.
+
If we used <tt>s</tt> 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:
<ruby>
@@ -361,8 +371,9 @@ This method is defined like this:
<ruby>
def start
+ url = "#{options[:SSLEnable] ? 'https' : 'http'}://#{options[:Host]}:#{options[:Port]}"
puts "=> Booting #{ActiveSupport::Inflector.demodulize(server)}"
- puts "=> Rails #{Rails.version} application starting in #{Rails.env} on http://#{options[:Host]}:#{options[:Port]}"
+ puts "=> Rails #{Rails.version} application starting in #{Rails.env} on #{url}"
puts "=> Call with -d to detach" unless options[:daemonize]
trap(:INT) { exit }
puts "=> Ctrl-C to shutdown server" unless options[:daemonize]
@@ -372,6 +383,15 @@ def start
FileUtils.mkdir_p(Rails.root.join('tmp', dir_to_make))
end
+ unless options[:daemonize]
+ wrapped_app # touch the app so the logger is set up
+
+ console = ActiveSupport::Logger.new($stdout)
+ console.formatter = Rails.logger.formatter
+
+ Rails.logger.extend(ActiveSupport::Logger.broadcast(console))
+ end
+
super
ensure
# The '-h' option calls exit before @options is set.
@@ -380,10 +400,18 @@ ensure
end
</ruby>
-This is where the first output of the Rails initialization happens. This method creates a trap for +INT+ signals, so if you +CTRL+C+ the server, it will exit the process. As we can see from the code here, it will create the +tmp/cache+, +tmp/pids+, +tmp/sessions+ and +tmp/sockets+ directories if they don't already exist prior to calling +super+. The +super+ method will call +Rack::Server.start+ which begins its definition like this:
+This is where the first output of the Rails initialization happens. This
+method creates a trap for +INT+ signals, so if you +CTRL-C+ the server,
+it will exit the process. As we can see from the code here, it will
+create the +tmp/cache+, +tmp/pids+, +tmp/sessions+ and +tmp/sockets+
+directories. It then calls +wrapped_app+ which is responsible for
+creating the Rack app, before creating and assignig an
+instance of +ActiveSupport::Logger+.
+
+The +super+ method will call +Rack::Server.start+ which begins its definition like this:
<ruby>
-def start
+def start &blk
if options[:warn]
$-w = true
end
@@ -403,22 +431,37 @@ def start
pp wrapped_app
pp app
end
-end
-</ruby>
-In a Rails application, these options are not set at all and therefore aren't used at all. The first line of code that's executed in this method is a call to this method:
+ check_pid! if options[:pid]
-<ruby>
-wrapped_app
+ # Touch the wrapped app, so that the config.ru is loaded before
+ # daemonization (i.e. before chdir, etc).
+ wrapped_app
+
+ daemonize_app if options[:daemonize]
+
+ write_pid if options[:pid]
+
+ trap(:INT) do
+ if server.respond_to?(:shutdown)
+ server.shutdown
+ else
+ exit
+ end
+ end
+
+ server.run wrapped_app, options, &blk
+end
</ruby>
-This method calls another method:
+The interesting part for a Rails app is the last line, +server.run+. Here we encounter the +wrapped_app+ method again, which this time
+we're going to explore more.
<ruby>
@wrapped_app ||= build_app app
</ruby>
-Then the +app+ method here is defined like so:
+The +app+ method here is defined like so:
<ruby>
def app
@@ -440,7 +483,7 @@ The +options[:config]+ value defaults to +config.ru+ which contains this:
# This file is used by Rack-based servers to start the application.
require ::File.expand_path('../config/environment', __FILE__)
-run YourApp::Application
+run <%= app_const %>
</ruby>
@@ -489,6 +532,7 @@ require "rails"
action_controller
action_mailer
rails/test_unit
+ sprockets/rails
).each do |framework|
begin
require "#{framework}/railtie"
@@ -501,13 +545,19 @@ First off the line is the +rails+ require itself.
h4. +railties/lib/rails.rb+
-This file is responsible for the initial definition of the +Rails+ module and, rather than defining the autoloads like +ActiveSupport+, +ActionDispatch+ and so on, it actually defines other functionality. Such as the +root+, +env+ and +application+ methods which are extremely useful in Rails 3 applications.
+This file is responsible for the initial definition of the +Rails+
+module and, rather than defining the autoloads like +ActiveSupport+,
++ActionDispatch+ and so on, it actually defines other functionality.
+Such as the +root+, +env+ and +application+ methods which are extremely
+useful in Rails 4 applications.
However, before all that takes place the +rails/ruby_version_check+ file is required first.
h4. +railties/lib/rails/ruby_version_check.rb+
-This file simply checks if the Ruby version is less than 1.8.7 or is 1.9.1 and raises an error if that is the case. Rails 3 simply will not run on earlier versions of Ruby than 1.8.7 or 1.9.1.
+This file simply checks if the Ruby version is less than 1.9.3 and
+raises an error if that is the case. Rails 4 simply will not run on
+earlier versions of Ruby.
NOTE: You should always endeavor to run the latest version of Ruby with your Rails applications. The benefits are many, including security fixes and the like, and very often there is a speed increase associated with it. The caveat is that you could have code that potentially breaks on the latest version, which should be fixed to work on the latest version rather than kept around as an excuse not to upgrade.
@@ -523,35 +573,28 @@ end
These methods can be used to silence STDERR responses and the +silence_stream+ allows you to also silence other streams. Additionally, this mixin allows you to suppress exceptions and capture streams. For more information see the "Silencing Warnings, Streams, and Exceptions":active_support_core_extensions.html#silencing-warnings-streams-and-exceptions section from the Active Support Core Extensions Guide.
-h4. +active_support/core_ext/logger.rb+
-
-The next file that is required is another Active Support core extension, this time to the +Logger+ class. This begins by defining the +around_[level]+ helpers for the +Logger+ class as well as other methods such as a +datetime_format+ getter and setter for the +formatter+ object tied to a +Logger+ object.
+h4. +active_support/core_ext/array/extract_options.rb+
-For more information see the "Extensions to Logger":active_support_core_extensions.html#extensions-to-logger section from the Active Support Core Extensions Guide.
+The next file that is required is another Active Support core extension,
+this time to the +Array+ and +Hash+ classes. This file defines an
++extract_options!+ method which Rails uses to extract options from
+parameters.
h4. +railties/lib/rails/application.rb+
-The next file required by +railties/lib/rails.rb+ is +application.rb+. This file defines the +Rails::Application+ constant which the application's class defined in +config/application.rb+ in a standard Rails application depends on. Before the +Rails::Application+ class is defined however, there's some other files that get required first.
-
-The first of these is +active_support/core_ext/hash/reverse_merge+ which can be "read about in the Active Support Core Extensions guide":active_support_core_extensions.html#merging under the "Merging" section.
-
-h4. +active_support/file_update_checker.rb+
-
-The +ActiveSupport::FileUpdateChecker+ class defined within this file is responsible for checking if a file has been updated since it was last checked. This is used for monitoring the routes file for changes during development environment runs.
+The next file required by +railties/lib/rails.rb+ is +application.rb+.
+This file defines the +Rails::Application+ constant which the
+application's class defined in +config/application.rb+ in a standard
+Rails application depends on.
-h4. +railties/lib/rails/plugin.rb+
+Before the +Rails::Application+ class is
+defined however, +rails/engine+ is also loaded, which is responsible for
+handling the behavior and definitions of Rails engines.
-This file defines +Rails::Plugin+ which inherits from +Rails::Engine+. Unlike +Rails::Engine+ and +Rails::Railtie+ however, this class is not designed to be inherited from. Instead, this is used simply for loading plugins from within an application and an engine.
+TIP: You can read more about engines in the "Getting Started with Engines":engines.html guide.
-This file begins by requiring +rails/engine.rb+
-
-h4. +railties/lib/rails/engine.rb+
-
-The +rails/engine.rb+ file defines the +Rails::Engine+ class which inherits from +Rails::Railtie+. The +Rails::Engine+ class defines much of the functionality found within a standard application class such as the +routes+ and +config+ methods.
-
-The "API documentation":http://api.rubyonrails.org/classes/Rails/Engine.html for +Rails::Engine+ explains the function of this class pretty well.
-
-This file's first line requires +rails/railtie.rb+.
+Among other things, Rails Engine is also responsible for loading the
+Railtie class.
h4. +railties/lib/rails/railtie.rb+
@@ -613,7 +656,7 @@ h4. +activesupport/lib/active_support/deprecation/proxy_wrappers.rb+
+proxy_wrappers.rb+ defines deprecation wrappers for methods, instance variables and constants. Previously, this was used for the +RAILS_ENV+ and +RAILS_ROOT+ constants for 3.0 but since then these constants have been removed. The deprecation message that would be raised from these would be something like:
<plain>
- BadConstant is deprecated! Use GoodConstant instead.
+BadConstant is deprecated! Use GoodConstant instead.
</plain>
h4. +active_support/ordered_options+
@@ -622,7 +665,30 @@ This file is the next file required from +rails/configuration.rb+ is the file th
The next file required is +active_support/core_ext/hash/deep_dup+ which is covered in "Active Support Core Extensions guide":active_support_core_extensions.html#deep_dup
-The file that is required next from is +rails/paths+
+h4. +active_support/core_ext/object+
+
+This file is responsible for requiring many more Active Support core extensions:
+
+<ruby>
+require 'active_support/core_ext/object/acts_like'
+require 'active_support/core_ext/object/blank'
+require 'active_support/core_ext/object/duplicable'
+require 'active_support/core_ext/object/deep_dup'
+require 'active_support/core_ext/object/try'
+require 'active_support/core_ext/object/inclusion'
+
+require 'active_support/core_ext/object/conversions'
+require 'active_support/core_ext/object/instance_variables'
+
+require 'active_support/core_ext/object/to_json'
+require 'active_support/core_ext/object/to_param'
+require 'active_support/core_ext/object/to_query'
+require 'active_support/core_ext/object/with_options'
+</ruby>
+
+The Rails API documentation covers them in great detail, so we're not going to explain each of them.
+
+The file that is required next from +rails/configuration+ is +rails/paths+.
h4. +railties/lib/rails/paths.rb+
@@ -638,7 +704,6 @@ module Rails
autoload :Debugger, "rails/rack/debugger"
autoload :Logger, "rails/rack/logger"
autoload :LogTailer, "rails/rack/log_tailer"
- autoload :Static, "rails/rack/static"
end
end
</ruby>
@@ -664,9 +729,23 @@ h4. +active_support/inflections+
This file references the +ActiveSupport::Inflector+ constant which isn't loaded by this point. But there were autoloads set up in +activesupport/lib/active_support.rb+ which will load the file which loads this constant and so then it will be defined. Then this file defines pluralization and singularization rules for words in Rails. This is how Rails knows how to pluralize "tomato" to "tomatoes".
+<ruby>
+inflect.irregular('zombie', 'zombies')
+</ruby>
+
h4. +activesupport/lib/active_support/inflector/transliterate.rb+
-In this file is where the "+transliterate+":http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-transliterate and +parameterize+:http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-parameterize methods are defined. The documentation for both of these methods is very much worth reading.
+This is the file that defines the "+transliterate+":http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-transliterate and "+parameterize+":http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-parameterize methods.
+
+h4. +active_support/core_ext/module/introspection+
+
+The next file loaded by +rails/railtie+ is the introspection core
+extension, which extends +Module+ with methods like +parent_name+, +parent+ and
++parents+.
+
+h4. +active_support/core_ext/module/delegation+
+
+The final file loaded by +rails/railtie+ is the delegation core extension, which defines the "+delegate+":http://api.rubyonrails.org/classes/Module.html#method-i-delegate method.
h4. Back to +railties/lib/rails/railtie.rb+
@@ -846,7 +925,7 @@ The +initializers_chain+ method referenced in the +initializers_for+ method is d
<ruby>
def initializers_chain
initializers = Collection.new
- ancestors.reverse_each do | klass |
+ ancestors.reverse_each do |klass|
next unless klass.respond_to?(:initializers)
initializers = initializers + klass.initializers
end
@@ -909,46 +988,35 @@ This file defines the +ActiveSupport::Railtie+ constant which like the +I18n::Ra
Then this Railtie sets up three more initializers:
-* +active_support.initialize_whiny_nils+
* +active_support.deprecation_behavior+
* +active_support.initialize_time_zone+
+* +active_support.set_configs+
We will cover what each of these initializers do when they run.
Once the +active_support/railtie+ file has finished loading the next file required from +railties/lib/rails.rb+ is the +action_dispatch/railtie+.
-h4. +activesupport/lib/action_dispatch/railtie.rb+
+h4. +actionpack/lib/action_dispatch/railtie.rb+
This file defines the +ActionDispatch::Railtie+ class, but not before requiring +action_dispatch+.
-h4. +activesupport/lib/action_dispatch.rb+
-
-This file attempts to locate the +active_support+ and +active_model+ libraries by looking a couple of directories back from the current file and then adds the +active_support+ and +active_model+ +lib+ directories to the load path, but only if they aren't already, which they are.
-
-<ruby>
-activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
-$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
-
-activemodel_path = File.expand_path('../../../activemodel/lib', __FILE__)
-$:.unshift(activemodel_path) if File.directory?(activemodel_path) && !$:.include?(activemodel_path)
-</ruby>
-
-In effect, these lines only define the +activesupport_path+ and +activemodel_path+ variables and nothing more.
+h4. +actionpack/lib/action_dispatch.rb+
-The next two requires in this file are already done, so they are not run:
+This file starts off with the following requires:
<ruby>
require 'active_support'
require 'active_support/dependencies/autoload'
+require 'active_support/core_ext/module/attribute_accessors'
</ruby>
-The following require is to +action_pack+ (+activesupport/lib/action_pack.rb+) which has a 22-line copyright notice at the top of it and ends in a simple require to +action_pack/version+. This file, like other +version.rb+ files before it, defines the +ActionPack::VERSION+ constant:
+The following require is to +action_pack+ (+actionpack/lib/action_pack.rb+) which contains a simple require to +action_pack/version+. This file, like other +version.rb+ files before it, defines the +ActionPack::VERSION+ constant:
<ruby>
module ActionPack
module VERSION #:nodoc:
- MAJOR = 3
- MINOR = 1
+ MAJOR = 4
+ MINOR = 0
TINY = 0
PRE = "beta"
@@ -966,8 +1034,8 @@ This file makes a require to +active_model/version+ which defines the version fo
<ruby>
module ActiveModel
module VERSION #:nodoc:
- MAJOR = 3
- MINOR = 1
+ MAJOR = 4
+ MINOR = 0
TINY = 0
PRE = "beta"
@@ -1004,7 +1072,7 @@ Once it has finished loading, the +I18n.load_path+ method is used to add the +ac
The loading of this file finishes the loading of +active_model+ and so we go back to +action_dispatch+.
-h4. Back to +activesupport/lib/action_dispatch.rb+
+h4. Back to +actionpack/lib/action_dispatch.rb+
The remainder of this file requires the +rack+ file from the Rack gem which defines the +Rack+ module. After +rack+, there's autoloads defined for the +Rack+, +ActionDispatch+, +ActionDispatch::Http+, +ActionDispatch::Session+. A new method called +autoload_under+ is used here, and this simply prefixes the files where the modules are autoloaded from with the path specified. For example here:
@@ -1018,7 +1086,7 @@ The +Assertions+ module is in the +action_dispatch/testing+ folder rather than s
Finally, this file defines a top-level autoload, the +Mime+ constant.
-h4. Back to +activesupport/lib/action_dispatch/railtie.rb+
+h4. Back to +actionpack/lib/action_dispatch/railtie.rb+
After +action_dispatch+ is required in this file, the +ActionDispatch::Railtie+ class is defined and is yet another class that inherits from +Rails::Railtie+. This class defines some initial configuration option defaults for +config.action_dispatch+ before setting up a single initializer called +action_dispatch.configure+.
@@ -1040,22 +1108,21 @@ h4. +activerecord/lib/active_record.rb+
This file begins by detecting if the +lib+ directories of +active_support+ and +active_model+ are not in the load path and if they aren't then adds them. As we saw back in +action_dispatch.rb+, these directories are already there.
-The first three requires have already been done by other files and so aren't loaded here, but the 4th require, the one to +arel+ will require the file provided by the Arel gem, which defines the +Arel+ module.
+The first couple of requires have already been done by other files and so aren't loaded here, but the next one to +arel+ will require the file provided by the Arel gem, which defines the +Arel+ module.
<ruby>
require 'active_support'
-require 'active_support/i18n'
require 'active_model'
require 'arel'
</ruby>
-The 5th require in this file is one to +active_record/version+ which defines the +ActiveRecord::VERSION+ constant:
+The file required next is +active_record/version+ which defines the +ActiveRecord::VERSION+ constant:
<ruby>
module ActiveRecord
module VERSION #:nodoc:
- MAJOR = 3
- MINOR = 1
+ MAJOR = 4
+ MINOR = 0
TINY = 0
PRE = "beta"
@@ -1079,7 +1146,9 @@ This will set the engine for +Arel::Table+ to be +ActiveRecord::Base+.
The file then finishes with this line:
<ruby>
-I18n.load_path << File.dirname(__FILE__) + '/active_record/locale/en.yml'
+ActiveSupport.on_load(:i18n) do
+ I18n.load_path << File.dirname(__FILE__) + '/active_record/locale/en.yml'
+end
</ruby>
This will add the translations from +activerecord/lib/active_record/locale/en.yml+ to the load path for +I18n+, with this file being parsed when all the translations are loaded.
diff --git a/guides/source/migrations.textile b/guides/source/migrations.textile
index 52dba76e68..342b5a4d57 100644
--- a/guides/source/migrations.textile
+++ b/guides/source/migrations.textile
@@ -8,8 +8,7 @@ production machines next time you deploy.
Active Record tracks which migrations have already been run so all you have to
do is update your source and run +rake db:migrate+. Active Record will work out
-which migrations should be run. It will also update your +db/schema.rb+ file to
-match the structure of your database.
+which migrations should be run. Active Record will also update your +db/schema.rb+ file to match the up-to-date structure of your database.
Migrations also allow you to describe these transformations using Ruby. The
great thing about this is that (like most of Active Record's functionality) it
diff --git a/guides/source/rails_on_rack.textile b/guides/source/rails_on_rack.textile
index ff862273fd..3a7c392508 100644
--- a/guides/source/rails_on_rack.textile
+++ b/guides/source/rails_on_rack.textile
@@ -23,29 +23,49 @@ h3. Rails on Rack
h4. Rails Application's Rack Object
-<tt>ActionController::Dispatcher.new</tt> is the primary Rack application object of a Rails application. Any Rack compliant web server should be using +ActionController::Dispatcher.new+ object to serve a Rails application.
+<tt>ApplicationName::Application</tt> is the primary Rack application object of a Rails application. Any Rack compliant web server should be using +ApplicationName::Application+ object to serve a Rails application.
h4. +rails server+
-<tt>rails server</tt> does the basic job of creating a +Rack::Builder+ object and starting the webserver. This is Rails' equivalent of Rack's +rackup+ script.
+<tt>rails server</tt> does the basic job of creating a +Rack::Server+ object and starting the webserver.
-Here's how +rails server+ creates an instance of +Rack::Builder+
+Here's how +rails server+ creates an instance of +Rack::Server+
<ruby>
-app = Rack::Builder.new {
- use Rails::Rack::LogTailer unless options[:detach]
- use Rails::Rack::Debugger if options[:debugger]
- use ActionDispatch::Static
- run ActionController::Dispatcher.new
-}.to_app
+Rails::Server.new.tap { |server|
+ require APP_PATH
+ Dir.chdir(Rails.application.root)
+ server.start
+}
</ruby>
-Middlewares used in the code above are primarily useful only in the development environment. The following table explains their usage:
+The +Rails::Server+ inherits from +Rack::Server+ and calls the +Rack::Server#start+ method this way:
+
+<ruby>
+class Server < ::Rack::Server
+ def start
+ ...
+ super
+ end
+end
+</ruby>
+
+Here's how it loads the middlewares:
+
+<ruby>
+def middleware
+ middlewares = []
+ middlewares << [Rails::Rack::Debugger] if options[:debugger]
+ middlewares << [::Rack::ContentLength]
+ Hash.new(middlewares)
+end
+</ruby>
+
++Rails::Rack::Debugger+ is primarily useful only in the development environment. The following table explains the usage of the loaded middlewares:
|_.Middleware|_.Purpose|
-|+Rails::Rack::LogTailer+|Appends log file output to console|
-|+ActionDispatch::Static+|Serves static files inside +Rails.root/public+ directory|
|+Rails::Rack::Debugger+|Starts Debugger|
+|+Rack::ContentLength+|Counts the number of bytes in the response and set the HTTP Content-Length header|
h4. +rackup+
@@ -55,9 +75,9 @@ To use +rackup+ instead of Rails' +rails server+, you can put the following insi
# Rails.root/config.ru
require "config/environment"
-use Rails::Rack::LogTailer
-use ActionDispatch::Static
-run ActionController::Dispatcher.new
+use Rack::Debugger
+use Rack::ContentLength
+run ApplicationName::Application
</ruby>
And start the server:
@@ -72,11 +92,11 @@ To find out more about different +rackup+ options:
$ rackup --help
</shell>
-h3. Action Controller Middleware Stack
+h3. Action Dispatcher Middleware Stack
-Many of Action Controller's internal components are implemented as Rack middlewares. +ActionController::Dispatcher+ uses +ActionController::MiddlewareStack+ to combine various internal and external middlewares to form a complete Rails Rack application.
+Many of Action Dispatchers's internal components are implemented as Rack middlewares. +Rails::Application+ uses +ActionDispatch::MiddlewareStack+ to combine various internal and external middlewares to form a complete Rails Rack application.
-NOTE: +ActionController::MiddlewareStack+ is Rails' equivalent of +Rack::Builder+, but built for better flexibility and more features to meet Rails' requirements.
+NOTE: +ActionDispatch::MiddlewareStack+ is Rails' equivalent of +Rack::Builder+, but built for better flexibility and more features to meet Rails' requirements.
h4. Inspecting Middleware Stack
@@ -111,7 +131,7 @@ use ActionDispatch::Head
use Rack::ConditionalGet
use Rack::ETag
use ActionDispatch::BestStandardsSupport
-run Blog::Application.routes
+run ApplicationName::Application.routes
</ruby>
Purpose of each of this middlewares is explained in the "Internal Middlewares":#internal-middleware-stack section.
@@ -152,9 +172,9 @@ You can swap an existing middleware in the middleware stack using +config.middle
config.middleware.swap ActionDispatch::ShowExceptions, Lifo::ShowExceptions
</ruby>
-h5. Middleware Stack is an Array
+h5. Middleware Stack is an Enumerable
-The middleware stack behaves just like a normal +Array+. You can use any +Array+ methods to insert, reorder, or remove items from the stack. Methods described in the section above are just convenience methods.
+The middleware stack behaves just like a normal +Enumerable+. You can use any +Enumerable+ methods to manipulate or interrogate the stack. The middleware stack also implements some +Array+ methods including <tt>[]</tt>, +unshift+ and +delete+. Methods described in the section above are just convenience methods.
Append following lines to your application configuration:
@@ -172,7 +192,7 @@ use ActionDispatch::Static
use #<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x00000001c304c8>
use Rack::Runtime
...
-run Myapp::Application.routes
+run Blog::Application.routes
</shell>
h4. Internal Middleware Stack
@@ -264,7 +284,7 @@ config.middleware.clear
<ruby>
# config.ru
use MyOwnStackFromScratch
-run ActionController::Dispatcher.new
+run ApplicationName::Application
</ruby>
h3. Resources
diff --git a/guides/source/routing.textile b/guides/source/routing.textile
index 4a50edbb15..0773a96c67 100644
--- a/guides/source/routing.textile
+++ b/guides/source/routing.textile
@@ -395,7 +395,7 @@ NOTE: You can't use +:namespace+ or +:module+ with a +:controller+ path segment.
get ':controller(/:action(/:id))', :controller => /admin\/[^\/]+/
</ruby>
-TIP: By default dynamic segments don't accept dots - this is because the dot is used as a separator for formatted routes. If you need to use a dot within a dynamic segment add a constraint which overrides this - for example +:id+ => /[^\/]+/ allows anything except a slash.
+TIP: By default dynamic segments don't accept dots - this is because the dot is used as a separator for formatted routes. If you need to use a dot within a dynamic segment, add a constraint that overrides this – for example, +:id+ => /[^\/]+/ allows anything except a slash.
h4. Static Segments
@@ -445,6 +445,14 @@ get 'exit' => 'sessions#destroy', :as => :logout
This will create +logout_path+ and +logout_url+ as named helpers in your application. Calling +logout_path+ will return +/exit+
+You can also use this to override routing methods defined by resources, like this:
+
+<ruby>
+get ':username', :to => "users#show", :as => :user
+</ruby>
+
+This will define a +user_path+ method that will be available in controllers, helpers and views that will go to a route such as +/bob+. Inside the +show+ action of +UsersController+, +params[:username]+ will contain the username for the user. Change +:username+ in the route definition if you do not want your parameter name to be +:username+.
+
h4. HTTP Verb Constraints
In general, you should use the +get+, +post+, +put+ and +delete+ methods to constrain a route to a particular verb. You can use the +match+ method with the +:via+ option to match multiple verbs at once:
diff --git a/guides/source/ruby_on_rails_guides_guidelines.textile b/guides/source/ruby_on_rails_guides_guidelines.textile
index f3e934d38c..dd209b61d6 100644
--- a/guides/source/ruby_on_rails_guides_guidelines.textile
+++ b/guides/source/ruby_on_rails_guides_guidelines.textile
@@ -47,7 +47,13 @@ h4. Generation
To generate all the guides, just +cd+ into the *+guides+* directory and execute:
<plain>
-bundle exec rake generate_guides
+bundle exec rake guides:generate
+</plain>
+
+or
+
+<plain>
+bundle exec rake guides:generate:html
</plain>
(You may need to run +bundle install+ first to install the required gems.)
@@ -56,7 +62,7 @@ To process +my_guide.textile+ and nothing else use the +ONLY+ environment variab
<plain>
touch my_guide.textile
-bundle exec rake generate_guides ONLY=my_guide
+bundle exec rake guides:generate ONLY=my_guide
</plain>
By default, guides that have not been modified are not processed, so +ONLY+ is rarely needed in practice.
@@ -68,7 +74,13 @@ It is also recommended that you work with +WARNINGS=1+. This detects duplicate I
If you want to generate guides in a language other than English, you can keep them in a separate directory under +source+ (eg. <tt>source/es</tt>) and use the +GUIDES_LANGUAGE+ environment variable:
<plain>
-bundle exec rake generate_guides GUIDES_LANGUAGE=es
+bundle exec rake guides:generate GUIDES_LANGUAGE=es
+</plain>
+
+If you want to see all the environment variables you can use to configure the generation script just run:
+
+<plain>
+rake
</plain>
h4. Validation
@@ -76,7 +88,7 @@ h4. Validation
Please validate the generated HTML with:
<plain>
-bundle exec rake validate_guides
+bundle exec rake guides:validate
</plain>
Particularly, titles get an ID generated from their content and this often leads to duplicates. Please set +WARNINGS=1+ when generating guides to detect them. The warning messages suggest a solution.
@@ -85,8 +97,8 @@ h3. Kindle Guides
h4(#generation-kindle). Generation
-To generate guides for the Kindle, you need to provide +KINDLE=1+ as an environment variable:
+To generate guides for the Kindle, use the following rake task:
<plain>
-KINDLE=1 bundle exec rake generate_guides
+bundle exec rake guides:generate:kindle
</plain>
diff --git a/guides/source/security.textile b/guides/source/security.textile
index ac55d60368..0931dd6393 100644
--- a/guides/source/security.textile
+++ b/guides/source/security.textile
@@ -30,7 +30,7 @@ A good place to start looking at security is with sessions, which can be vulnera
h4. What are Sessions?
--- _HTTP is a stateless protocol. Sessions make it stateful._
+NOTE: _HTTP is a stateless protocol. Sessions make it stateful._
Most applications need to keep track of certain state of a particular user. This could be the contents of a shopping basket or the user id of the currently logged in user. Without the idea of sessions, the user would have to identify, and probably authenticate, on every request.
Rails will create a new session automatically if a new user accesses the application. It will load an existing session if the user has already used the application.
@@ -44,13 +44,13 @@ User.find(session[:user_id])
h4. Session id
--- _The session id is a 32 byte long MD5 hash value._
+NOTE: _The session id is a 32 byte long MD5 hash value._
A session id consists of the hash value of a random string. The random string is the current time, a random number between 0 and 1, the process id number of the Ruby interpreter (also basically a random number) and a constant string. Currently it is not feasible to brute-force Rails' session ids. To date MD5 is uncompromised, but there have been collisions, so it is theoretically possible to create another input text with the same hash value. But this has had no security impact to date.
h4. Session Hijacking
--- _Stealing a user's session id lets an attacker use the web application in the victim's name._
+WARNING: _Stealing a user's session id lets an attacker use the web application in the victim's name._
Many web applications have an authentication system: a user provides a user name and password, the web application checks them and stores the corresponding user id in the session hash. From now on, the session is valid. On every request the application will load the user, identified by the user id in the session, without the need for new authentication. The session id in the cookie identifies the session.
@@ -72,7 +72,7 @@ The main objective of most attackers is to make money. The underground prices fo
h4. Session Guidelines
--- _Here are some general guidelines on sessions._
+Here are some general guidelines on sessions.
* _(highlight)Do not store large objects in a session_. Instead you should store them in the database and save their id in the session. This will eliminate synchronization headaches and it won't fill up your session storage space (depending on what session storage you chose, see below).
This will also be a good idea, if you modify the structure of an object and old versions of it are still in some user's cookies. With server-side session storages you can clear out the sessions, but with client-side storages, this is hard to mitigate.
@@ -81,7 +81,7 @@ This will also be a good idea, if you modify the structure of an object and old
h4. Session Storage
--- _Rails provides several storage mechanisms for the session hashes. The most important are ActiveRecord::SessionStore and ActionDispatch::Session::CookieStore._
+NOTE: _Rails provides several storage mechanisms for the session hashes. The most important are +ActiveRecord::SessionStore+ and +ActionDispatch::Session::CookieStore+._
There are a number of session storages, i.e. where Rails saves the session hash and session id. Most real-live applications choose ActiveRecord::SessionStore (or one of its derivatives) over file storage due to performance and maintenance reasons. ActiveRecord::SessionStore keeps the session id and hash in a database table and saves and retrieves the hash on every request.
@@ -104,7 +104,7 @@ There are, however, derivatives of CookieStore which encrypt the session hash, s
h4. Replay Attacks for CookieStore Sessions
--- _Another sort of attack you have to be aware of when using CookieStore is the replay attack._
+TIP: _Another sort of attack you have to be aware of when using +CookieStore+ is the replay attack._
It works like this:
@@ -120,7 +120,7 @@ The best _(highlight)solution against it is not to store this kind of data in a
h4. Session Fixation
--- _Apart from stealing a user's session id, the attacker may fix a session id known to him. This is called session fixation._
+NOTE: _Apart from stealing a user's session id, the attacker may fix a session id known to him. This is called session fixation._
!images/session_fixation.png(Session fixation)!
@@ -135,7 +135,7 @@ This attack focuses on fixing a user's session id known to the attacker, and for
h4. Session Fixation – Countermeasures
--- _One line of code will protect you from session fixation._
+TIP: _One line of code will protect you from session fixation._
The most effective countermeasure is to _(highlight)issue a new session identifier_ and declare the old one invalid after a successful login. That way, an attacker cannot use the fixed session identifier. This is a good countermeasure against session hijacking, as well. Here is how to create a new session in Rails:
@@ -149,7 +149,7 @@ Another countermeasure is to _(highlight)save user-specific properties in the se
h4. Session Expiry
--- _Sessions that never expire extend the time-frame for attacks such as cross-site reference forgery (CSRF), session hijacking and session fixation._
+NOTE: _Sessions that never expire extend the time-frame for attacks such as cross-site reference forgery (CSRF), session hijacking and session fixation._
One possibility is to set the expiry time-stamp of the cookie with the session id. However the client can edit cookies that are stored in the web browser so expiring sessions on the server is safer. Here is an example of how to _(highlight)expire sessions in a database table_. Call +Session.sweep("20 minutes")+ to expire sessions that were used longer than 20 minutes ago.
@@ -174,7 +174,7 @@ delete_all "updated_at < '#{time.ago.to_s(:db)}' OR
h3. Cross-Site Request Forgery (CSRF)
--- _This attack method works by including malicious code or a link in a page that accesses a web application that the user is believed to have authenticated. If the session for that web application has not timed out, an attacker may execute unauthorized commands._
+This attack method works by including malicious code or a link in a page that accesses a web application that the user is believed to have authenticated. If the session for that web application has not timed out, an attacker may execute unauthorized commands.
!images/csrf.png!
@@ -193,7 +193,7 @@ CSRF appears very rarely in CVE (Common Vulnerabilities and Exposures) -- less t
h4. CSRF Countermeasures
--- _First, as is required by the W3C, use GET and POST appropriately. Secondly, a security token in non-GET requests will protect your application from CSRF._
+NOTE: _First, as is required by the W3C, use GET and POST appropriately. Secondly, a security token in non-GET requests will protect your application from CSRF._
The HTTP protocol basically provides two main types of requests - GET and POST (and more, but they are not supported by most browsers). The World Wide Web Consortium (W3C) provides a checklist for choosing HTTP GET or POST:
@@ -236,6 +236,17 @@ protect_from_forgery :secret => "123456789012345678901234567890..."
This will automatically include a security token, calculated from the current session and the server-side secret, in all forms and Ajax requests generated by Rails. You won't need the secret, if you use CookieStorage as session storage. If the security token doesn't match what was expected, the session will be reset. *Note:* In Rails versions prior to 3.0.4, this raised an <tt>ActionController::InvalidAuthenticityToken</tt> error.
+It is common to use persistent cookies to store user information, with +cookies.permanent+ for example. In this case, the cookies will not be cleared and the out of the box CSRF protection will not be effective. If you are using a different cookie store than the session for this information, you must handle what to do with it yourself:
+
+<ruby>
+def handle_unverified_request
+ super
+ sign_out_user # Example method that will destroy the user cookies.
+end
+</ruby>
+
+The above method can be placed in the +ApplicationController+ and will be called when a CSRF token is not present on a non-GET request.
+
Note that _(highlight)cross-site scripting (XSS) vulnerabilities bypass all CSRF protections_. XSS gives the attacker access to all elements on a page, so he can read the CSRF security token from a form or directly submit the form. Read <a href="#cross-site-scripting-xss">more about XSS</a> later.
h3. Redirection and Files
@@ -244,7 +255,7 @@ Another class of security vulnerabilities surrounds the use of redirection and f
h4. Redirection
--- _Redirection in a web application is an underestimated cracker tool: Not only can the attacker forward the user to a trap web site, he may also create a self-contained attack._
+WARNING: _Redirection in a web application is an underestimated cracker tool: Not only can the attacker forward the user to a trap web site, he may also create a self-contained attack._
Whenever the user is allowed to pass (parts of) the URL for redirection, it is possibly vulnerable. The most obvious attack would be to redirect users to a fake web application which looks and feels exactly as the original one. This so-called phishing attack works by sending an unsuspicious link in an email to the users, injecting the link by XSS in the web application or putting the link into an external site. It is unsuspicious, because the link starts with the URL to the web application and the URL to the malicious site is hidden in the redirection parameter: http://www.example.com/site/redirect?to= www.attacker.com. Here is an example of a legacy action:
@@ -272,7 +283,7 @@ This example is a Base64 encoded JavaScript which displays a simple message box.
h4. File Uploads
--- _Make sure file uploads don't overwrite important files, and process media files asynchronously._
+NOTE: _Make sure file uploads don't overwrite important files, and process media files asynchronously._
Many web applications allow users to upload files. _(highlight)File names, which the user may choose (partly), should always be filtered_ as an attacker could use a malicious file name to overwrite any file on the server. If you store file uploads at /var/www/uploads, and the user enters a file name like “../../../etc/passwd”, it may overwrite an important file. Of course, the Ruby interpreter would need the appropriate permissions to do so – one more reason to run web servers, database servers and other programs as a less privileged Unix user.
@@ -297,7 +308,7 @@ The solution to this is best to _(highlight)process media files asynchronously_:
h4. Executable Code in File Uploads
--- _Source code in uploaded files may be executed when placed in specific directories. Do not place file uploads in Rails' /public directory if it is Apache's home directory._
+WARNING: _Source code in uploaded files may be executed when placed in specific directories. Do not place file uploads in Rails' /public directory if it is Apache's home directory._
The popular Apache web server has an option called DocumentRoot. This is the home directory of the web site, everything in this directory tree will be served by the web server. If there are files with a certain file name extension, the code in it will be executed when requested (might require some options to be set). Examples for this are PHP and CGI files. Now think of a situation where an attacker uploads a file “file.cgi” with code in it, which will be executed when someone downloads the file.
@@ -305,7 +316,7 @@ _(highlight)If your Apache DocumentRoot points to Rails' /public directory, do n
h4. File Downloads
--- _Make sure users cannot download arbitrary files._
+NOTE: _Make sure users cannot download arbitrary files._
Just as you have to filter file names for uploads, you have to do so for downloads. The send_file() method sends files from the server to the client. If you use a file name, that the user entered, without filtering, any file can be downloaded:
@@ -327,7 +338,7 @@ Another (additional) approach is to store the file names in the database and nam
h3. Intranet and Admin Security
--- _Intranet and administration interfaces are popular attack targets, because they allow privileged access. Although this would require several extra-security measures, the opposite is the case in the real world._
+Intranet and administration interfaces are popular attack targets, because they allow privileged access. Although this would require several extra-security measures, the opposite is the case in the real world.
In 2007 there was the first tailor-made trojan which stole information from an Intranet, namely the "Monster for employers" web site of Monster.com, an online recruitment web application. Tailor-made Trojans are very rare, so far, and the risk is quite low, but it is certainly a possibility and an example of how the security of the client host is important, too. However, the highest threat to Intranet and Admin applications are XSS and CSRF.

@@ -359,7 +370,7 @@ The common admin interface works like this: it's located at www.example.com/admi
h3. Mass Assignment
--- _Without any precautions Model.new(params[:model]) allows attackers to set any database column's value._
+WARNING: _Without any precautions +Model.new(params[:model]+) allows attackers to set any database column's value._
The mass-assignment feature may become a problem, as it allows an attacker to set any model's attributes by manipulating the hash passed to a model's +new()+ method:
@@ -471,7 +482,7 @@ This will create an empty whitelist of attributes available for mass-assignment
h3. User Management
--- _Almost every web application has to deal with authorization and authentication. Instead of rolling your own, it is advisable to use common plug-ins. But keep them up-to-date, too. A few additional precautions can make your application even more secure._
+NOTE: _Almost every web application has to deal with authorization and authentication. Instead of rolling your own, it is advisable to use common plug-ins. But keep them up-to-date, too. A few additional precautions can make your application even more secure._
There are a number of authentication plug-ins for Rails available. Good ones, such as the popular "devise":https://github.com/plataformatec/devise and "authlogic":https://github.com/binarylogic/authlogic, store only encrypted passwords, not plain-text passwords. In Rails 3.1 you can use the built-in +has_secure_password+ method which has similar features.
@@ -498,7 +509,7 @@ And thus it found the first user in the database, returned it and logged him in.
h4. Brute-Forcing Accounts
--- _Brute-force attacks on accounts are trial and error attacks on the login credentials. Fend them off with more generic error messages and possibly require to enter a CAPTCHA._
+NOTE: _Brute-force attacks on accounts are trial and error attacks on the login credentials. Fend them off with more generic error messages and possibly require to enter a CAPTCHA._
A list of user names for your web application may be misused to brute-force the corresponding passwords, because most people don't use sophisticated passwords. Most passwords are a combination of dictionary words and possibly numbers. So armed with a list of user names and a dictionary, an automatic program may find the correct password in a matter of minutes.
@@ -510,7 +521,7 @@ In order to mitigate such attacks, _(highlight)display a generic error message o
h4. Account Hijacking
--- _Many web applications make it easy to hijack user accounts. Why not be different and make it more difficult?_
+Many web applications make it easy to hijack user accounts. Why not be different and make it more difficult?.
h5. Passwords
@@ -526,7 +537,7 @@ Depending on your web application, there may be more ways to hijack the user's a
h4. CAPTCHAs
--- _A CAPTCHA is a challenge-response test to determine that the response is not generated by a computer. It is often used to protect comment forms from automatic spam bots by asking the user to type the letters of a distorted image. The idea of a negative CAPTCHA is not for a user to prove that he is human, but reveal that a robot is a robot._
+INFO: _A CAPTCHA is a challenge-response test to determine that the response is not generated by a computer. It is often used to protect comment forms from automatic spam bots by asking the user to type the letters of a distorted image. The idea of a negative CAPTCHA is not for a user to prove that he is human, but reveal that a robot is a robot._
But not only spam robots (bots) are a problem, but also automatic login bots. A popular CAPTCHA API is "reCAPTCHA":http://recaptcha.net/ which displays two distorted images of words from old books. It also adds an angled line, rather than a distorted background and high levels of warping on the text as earlier CAPTCHAs did, because the latter were broken. As a bonus, using reCAPTCHA helps to digitize old books. "ReCAPTCHA":http://ambethia.com/recaptcha/ is also a Rails plug-in with the same name as the API.
@@ -553,7 +564,7 @@ Note that this protects you only from automatic bots, targeted tailor-made bots
h4. Logging
--- _Tell Rails not to put passwords in the log files._
+WARNING: _Tell Rails not to put passwords in the log files._
By default, Rails logs all requests being made to the web application. But log files can be a huge security issue, as they may contain login credentials, credit card numbers et cetera. When designing a web application security concept, you should also think about what will happen if an attacker got (full) access to the web server. Encrypting secrets and passwords in the database will be quite useless, if the log files list them in clear text. You can _(highlight)filter certain request parameters from your log files_ by appending them to <tt>config.filter_parameters</tt> in the application configuration. These parameters will be marked [FILTERED] in the log.
@@ -563,7 +574,7 @@ config.filter_parameters << :password
h4. Good Passwords
--- _Do you find it hard to remember all your passwords? Don't write them down, but use the initial letters of each word in an easy to remember sentence._
+INFO: _Do you find it hard to remember all your passwords? Don't write them down, but use the initial letters of each word in an easy to remember sentence._
Bruce Schneier, a security technologist, "has analyzed":http://www.schneier.com/blog/archives/2006/12/realworld_passw.html 34,000 real-world user names and passwords from the MySpace phishing attack mentioned <a href="#examples-from-the-underground">below</a>. It turns out that most of the passwords are quite easy to crack. The 20 most common passwords are:
@@ -575,7 +586,7 @@ A good password is a long alphanumeric combination of mixed cases. As this is qu
h4. Regular Expressions
--- _A common pitfall in Ruby's regular expressions is to match the string's beginning and end by ^ and $, instead of \A and \z._
+INFO: _A common pitfall in Ruby's regular expressions is to match the string's beginning and end by ^ and $, instead of \A and \z._
Ruby uses a slightly different approach than many other languages to match the end and the beginning of a string. That is why even many Ruby and Rails books make this wrong. So how is this a security threat? Imagine you have a File model and you validate the file name by a regular expression like this:
@@ -599,7 +610,7 @@ Whereas %0A is a line feed in URL encoding, so Rails automatically converts it t
h4. Privilege Escalation
--- _Changing a single parameter may give the user unauthorized access. Remember that every parameter may be changed, no matter how much you hide or obfuscate it._
+WARNING: _Changing a single parameter may give the user unauthorized access. Remember that every parameter may be changed, no matter how much you hide or obfuscate it._
The most common parameter that a user might tamper with, is the id parameter, as in +http://www.domain.com/project/1+, whereas 1 is the id. It will be available in params in the controller. There, you will most likely do something like this:
@@ -619,13 +630,13 @@ Don't be fooled by security by obfuscation and JavaScript security. The Web Deve
h3. Injection
--- _Injection is a class of attacks that introduce malicious code or parameters into a web application in order to run it within its security context. Prominent examples of injection are cross-site scripting (XSS) and SQL injection._
+INFO: _Injection is a class of attacks that introduce malicious code or parameters into a web application in order to run it within its security context. Prominent examples of injection are cross-site scripting (XSS) and SQL injection._
Injection is very tricky, because the same code or parameter can be malicious in one context, but totally harmless in another. A context can be a scripting, query or programming language, the shell or a Ruby/Rails method. The following sections will cover all important contexts where injection attacks may happen. The first section, however, covers an architectural decision in connection with Injection.
h4. Whitelists versus Blacklists
--- _When sanitizing, protecting or verifying something, whitelists over blacklists._
+NOTE: _When sanitizing, protecting or verifying something, whitelists over blacklists._
A blacklist can be a list of bad e-mail addresses, non-public actions or bad HTML tags. This is opposed to a whitelist which lists the good e-mail addresses, public actions, good HTML tags and so on. Although sometimes it is not possible to create a whitelist (in a SPAM filter, for example), _(highlight)prefer to use whitelist approaches_:
@@ -640,7 +651,7 @@ Whitelists are also a good approach against the human factor of forgetting somet
h4. SQL Injection
--- _Thanks to clever methods, this is hardly a problem in most Rails applications. However, this is a very devastating and common attack in web applications, so it is important to understand the problem._
+INFO: _Thanks to clever methods, this is hardly a problem in most Rails applications. However, this is a very devastating and common attack in web applications, so it is important to understand the problem._
h5(#sql-injection-introduction). Introduction
@@ -719,7 +730,7 @@ The array or hash form is only available in model instances. You can try +saniti
h4. Cross-Site Scripting (XSS)
--- _The most widespread, and one of the most devastating security vulnerabilities in web applications is XSS. This malicious attack injects client-side executable code. Rails provides helper methods to fend these attacks off._
+INFO: _The most widespread, and one of the most devastating security vulnerabilities in web applications is XSS. This malicious attack injects client-side executable code. Rails provides helper methods to fend these attacks off._
h5. Entry Points
@@ -847,7 +858,7 @@ The MySpace Samy worm will be discussed in the CSS Injection section.
h4. CSS Injection
--- _CSS Injection is actually JavaScript injection, because some browsers (IE, some versions of Safari and others) allow JavaScript in CSS. Think twice about allowing custom CSS in your web application._
+INFO: _CSS Injection is actually JavaScript injection, because some browsers (IE, some versions of Safari and others) allow JavaScript in CSS. Think twice about allowing custom CSS in your web application._
CSS Injection is explained best by a well-known worm, the "MySpace Samy worm":http://namb.la/popular/tech.html. This worm automatically sent a friend request to Samy (the attacker) simply by visiting his profile. Within several hours he had over 1 million friend requests, but it creates too much traffic on MySpace, so that the site goes offline. The following is a technical explanation of the worm.
@@ -887,7 +898,7 @@ This example, again, showed that a blacklist filter is never complete. However,
h4. Textile Injection
--- _If you want to provide text formatting other than HTML (due to security), use a mark-up language which is converted to HTML on the server-side. "RedCloth":http://redcloth.org/ is such a language for Ruby, but without precautions, it is also vulnerable to XSS._
+If you want to provide text formatting other than HTML (due to security), use a mark-up language which is converted to HTML on the server-side. "RedCloth":http://redcloth.org/ is such a language for Ruby, but without precautions, it is also vulnerable to XSS.
For example, RedCloth translates +_test_+ to &lt;em&gt;test&lt;em&gt;, which makes the text italic. However, up to the current version 3.0.4, it is still vulnerable to XSS. Get the "all-new version 4":http://www.redcloth.org that removed serious bugs. However, even that version has "some security bugs":http://www.rorsecurity.info/journal/2008/10/13/new-redcloth-security.html, so the countermeasures still apply. Here is an example for version 3.0.4:
@@ -916,13 +927,13 @@ It is recommended to _(highlight)use RedCloth in combination with a whitelist in
h4. Ajax Injection
--- _The same security precautions have to be taken for Ajax actions as for “normal” ones. There is at least one exception, however: The output has to be escaped in the controller already, if the action doesn't render a view._
+NOTE: _The same security precautions have to be taken for Ajax actions as for “normal” ones. There is at least one exception, however: The output has to be escaped in the controller already, if the action doesn't render a view._
If you use the "in_place_editor plugin":http://dev.rubyonrails.org/browser/plugins/in_place_editing, or actions that return a string, rather than rendering a view, _(highlight)you have to escape the return value in the action_. Otherwise, if the return value contains a XSS string, the malicious code will be executed upon return to the browser. Escape any input value using the h() method.
h4. Command Line Injection
--- _Use user-supplied command line parameters with caution._
+NOTE: _Use user-supplied command line parameters with caution._
If your application has to execute commands in the underlying operating system, there are several methods in Ruby: exec(command), syscall(command), system(command) and `command`. You will have to be especially careful with these functions if the user may enter the whole command, or a part of it. This is because in most shells, you can execute another command at the end of the first one, concatenating them with a semicolon (;) or a vertical bar (|).
@@ -936,7 +947,7 @@ system("/bin/echo","hello; rm *")
h4. Header Injection
--- _HTTP headers are dynamically generated and under certain circumstances user input may be injected. This can lead to false redirection, XSS or HTTP response splitting._
+WARNING: _HTTP headers are dynamically generated and under certain circumstances user input may be injected. This can lead to false redirection, XSS or HTTP response splitting._
HTTP request headers have a Referer, User-Agent (client software), and Cookie field, among others. Response headers for example have a status code, Cookie and Location (redirection target URL) field. All of them are user-supplied and may be manipulated with more or less effort. _(highlight)Remember to escape these header fields, too._ For example when you display the user agent in an administration area.
diff --git a/guides/source/upgrading_ruby_on_rails.textile b/guides/source/upgrading_ruby_on_rails.textile
index 2b2e65c813..6cdc6ab289 100644
--- a/guides/source/upgrading_ruby_on_rails.textile
+++ b/guides/source/upgrading_ruby_on_rails.textile
@@ -34,13 +34,25 @@ h4(#plugins4_0). vendor/plugins
Rails 4.0 no longer supports loading plugins from <tt>vendor/plugins</tt>. You must replace any plugins by extracting them to gems and adding them to your Gemfile. If you choose not to make them gems, you can move them into, say, <tt>lib/my_plugin/*</tt> and add an appropriate initializer in <tt>config/initializers/my_plugin.rb</tt>.
-h4(#identity_map4_0). IdentityMap
+h4(#identity_map4_0). Identity Map
-Rails 4.0 has removed <tt>IdentityMap</tt> from <tt>ActiveRecord</tt>, due to "some inconsistencies with associations":https://github.com/rails/rails/commit/302c912bf6bcd0fa200d964ec2dc4a44abe328a6. If you have manually enabled it in your application, you will have to remove the following config that has no effect anymore: <tt>config.active_record.identity_map</tt>.
+Rails 4.0 has removed the identity map from Active Record, due to "some inconsistencies with associations":https://github.com/rails/rails/commit/302c912bf6bcd0fa200d964ec2dc4a44abe328a6. If you have manually enabled it in your application, you will have to remove the following config that has no effect anymore: <tt>config.active_record.identity_map</tt>.
-h4(#active_model4_0). ActiveModel
+h4(#active_record4_0). Active Record
-Rails 4.0 has changed how errors attach with the ConfirmationValidator. Now when confirmation validations fail the error will be attached to <tt>:#{attribute}_confirmation</tt> instead of <tt>attribute</tt>.
+The <tt>delete</tt> method in collection associations can now receive <tt>Fixnum</tt> or <tt>String</tt> arguments as record ids, besides records, pretty much like the <tt>destroy</tt> method does. Previously it raised <tt>ActiveRecord::AssociationTypeMismatch</tt> for such arguments. From Rails 4.0 on <tt>delete</tt> automatically tries to find the records matching the given ids before deleting them.
+
+h4(#active_model4_0). Active Model
+
+Rails 4.0 has changed how errors attach with the <tt>ActiveModel::Validations::ConfirmationValidator</tt>. Now when confirmation validations fail the error will be attached to <tt>:#{attribute}_confirmation</tt> instead of <tt>attribute</tt>.
+
+h4(#action_pack4_0). Action Pack
+
+Rails 4.0 changed how <tt>assert_generates</tt>, <tt>assert_recognizes</tt>, and <tt>assert_routing</tt> work. Now all these assertions raise <tt>Assertion</tt> instead of <tt>ActionController::RoutingError</tt>.
+
+h4(#helpers_order). Helpers Loading Order
+
+The loading order of helpers from more than one directory has changed in Rails 4.0. Previously, helpers from all directories were gathered and then sorted alphabetically. After upgrade to Rails 4.0 helpers will preserve the order of loaded directories and will be sorted alphabetically only within each directory. Unless you explicitly use <tt>helpers_path</tt> parameter, this change will only impact the way of loading helpers from engines. If you rely on the fact that particular helper from engine loads before or after another helper from application or another engine, you should check if correct methods are available after upgrade. If you would like to change order in which engines are loaded, you can use <tt>config.railties_order=</tt> method.
h3. Upgrading from Rails 3.1 to Rails 3.2