From dde5b8737bf7ec666f96ae04479074dfae7a63d9 Mon Sep 17 00:00:00 2001 From: Trek Glowacki Date: Tue, 16 Aug 2011 16:27:07 -0400 Subject: When a route references a missing controller, raise ActionController::RoutingError with a clearer message --- actionpack/lib/action_dispatch/routing/route_set.rb | 10 +++++++--- actionpack/test/controller/routing_test.rb | 10 ++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 11228c597d..15a6415342 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -556,9 +556,13 @@ module ActionDispatch dispatcher = dispatcher.app end - if dispatcher.is_a?(Dispatcher) && dispatcher.controller(params, false) - dispatcher.prepare_params!(params) - return params + if dispatcher.is_a?(Dispatcher) + if dispatcher.controller(params, false) + dispatcher.prepare_params!(params) + return params + else + raise ActionController::RoutingError, "A route matches #{path.inspect}, but references missing controller: #{params[:controller].camelize}Controller" + end end end diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb index 5bf68decca..3602c8a9e3 100644 --- a/actionpack/test/controller/routing_test.rb +++ b/actionpack/test/controller/routing_test.rb @@ -902,6 +902,16 @@ class RouteSetTest < ActiveSupport::TestCase end end + def test_route_error_with_missing_controller + set.draw do + get "/people" => "missing#index" + end + + assert_raise(ActionController::RoutingError) { + set.recognize_path("/people", :method => :get) + } + end + def test_recognize_with_encoded_id_and_regex set.draw do match 'page/:id' => 'pages#show', :id => /[a-zA-Z0-9\+]+/ -- cgit v1.2.3 From 8d3cd530c4d165b1bbd2e551d491dd81e2c3bff0 Mon Sep 17 00:00:00 2001 From: Robert Glaser Date: Tue, 18 Oct 2011 15:29:16 +0200 Subject: Fixed DataMapper namings in symbols and constants. --- railties/lib/rails/engine/configuration.rb | 2 +- railties/lib/rails/generators/active_model.rb | 2 +- railties/test/application/generators_test.rb | 18 +++++++++--------- railties/test/railties/engine_test.rb | 4 ++-- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/railties/lib/rails/engine/configuration.rb b/railties/lib/rails/engine/configuration.rb index f424492bb4..99e0201e31 100644 --- a/railties/lib/rails/engine/configuration.rb +++ b/railties/lib/rails/engine/configuration.rb @@ -21,7 +21,7 @@ module Rails # Holds generators configuration: # # config.generators do |g| - # g.orm :datamapper, :migration => true + # g.orm :data_mapper, :migration => true # g.template_engine :haml # g.test_framework :rspec # end diff --git a/railties/lib/rails/generators/active_model.rb b/railties/lib/rails/generators/active_model.rb index 4b828340d2..7af893e1fd 100644 --- a/railties/lib/rails/generators/active_model.rb +++ b/railties/lib/rails/generators/active_model.rb @@ -11,7 +11,7 @@ module Rails # ActiveRecord::Generators::ActiveModel.find(Foo, "params[:id]") # # => "Foo.find(params[:id])" # - # Datamapper::Generators::ActiveModel.find(Foo, "params[:id]") + # DataMapper::Generators::ActiveModel.find(Foo, "params[:id]") # # => "Foo.get(params[:id])" # # On initialization, the ActiveModel accepts the instance name that will diff --git a/railties/test/application/generators_test.rb b/railties/test/application/generators_test.rb index 4365d00b1f..8718f27de1 100644 --- a/railties/test/application/generators_test.rb +++ b/railties/test/application/generators_test.rb @@ -45,10 +45,10 @@ module ApplicationTests test "generators set rails options" do with_bare_config do |c| - c.generators.orm = :datamapper + c.generators.orm = :data_mapper c.generators.test_framework = :rspec c.generators.helper = false - expected = { :rails => { :orm => :datamapper, :test_framework => :rspec, :helper => false } } + expected = { :rails => { :orm => :data_mapper, :test_framework => :rspec, :helper => false } } assert_equal(expected, c.generators.options) end end @@ -64,7 +64,7 @@ module ApplicationTests test "generators aliases, options, templates and fallbacks on initialization" do add_to_config <<-RUBY config.generators.rails :aliases => { :test_framework => "-w" } - config.generators.orm :datamapper + config.generators.orm :data_mapper config.generators.test_framework :rspec config.generators.fallbacks[:shoulda] = :test_unit config.generators.templates << "some/where" @@ -95,15 +95,15 @@ module ApplicationTests test "generators with hashes for options and aliases" do with_bare_config do |c| c.generators do |g| - g.orm :datamapper, :migration => false + g.orm :data_mapper, :migration => false g.plugin :aliases => { :generator => "-g" }, :generator => true end expected = { - :rails => { :orm => :datamapper }, + :rails => { :orm => :data_mapper }, :plugin => { :generator => true }, - :datamapper => { :migration => false } + :data_mapper => { :migration => false } } assert_equal expected, c.generators.options @@ -114,12 +114,12 @@ module ApplicationTests test "generators with string and hash for options should generate symbol keys" do with_bare_config do |c| c.generators do |g| - g.orm 'datamapper', :migration => false + g.orm 'data_mapper', :migration => false end expected = { - :rails => { :orm => :datamapper }, - :datamapper => { :migration => false } + :rails => { :orm => :data_mapper }, + :data_mapper => { :migration => false } } assert_equal expected, c.generators.options diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb index 06a60cd858..f8b84e49c9 100644 --- a/railties/test/railties/engine_test.rb +++ b/railties/test/railties/engine_test.rb @@ -524,7 +524,7 @@ module RailtiesTest module Bukkits class Engine < ::Rails::Engine config.generators do |g| - g.orm :datamapper + g.orm :data_mapper g.template_engine :haml g.test_framework :rspec end @@ -553,7 +553,7 @@ module RailtiesTest assert_equal :test_unit, app_generators[:test_framework] generators = Bukkits::Engine.config.generators.options[:rails] - assert_equal :datamapper, generators[:orm] + assert_equal :data_mapper, generators[:orm] assert_equal :haml , generators[:template_engine] assert_equal :rspec , generators[:test_framework] end -- cgit v1.2.3 From 5662ea511225b34d3b533d03614c496c007215b0 Mon Sep 17 00:00:00 2001 From: "Juan M. Cuello" Date: Wed, 21 Dec 2011 17:00:25 -0300 Subject: Reset postgreSQL search path in db:test:clone_structure. This patch resets the postgres search path in the structure.sql after the structure is dumped in order to find schema_migrations table when multiples schemas are used. Fixes #945 --- activerecord/lib/active_record/railties/databases.rake | 1 + 1 file changed, 1 insertion(+) diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index 199eee4359..482901f23f 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -387,6 +387,7 @@ db_namespace = namespace :db do end `pg_dump -i -s -x -O -f #{filename} #{search_path} #{abcs[Rails.env]['database']}` raise 'Error dumping database' if $?.exitstatus == 1 + File.open(filename, "a") { |f| f << "SET search_path TO #{ActiveRecord::Base.connection.schema_search_path};\n\n" } when /sqlite/ dbfile = abcs[Rails.env]['database'] `sqlite3 #{dbfile} .schema > #{filename}` -- cgit v1.2.3 From b52c66f1bedb6ed5a08c106a199a53f67c9f6ec2 Mon Sep 17 00:00:00 2001 From: Winston Date: Wed, 22 Feb 2012 19:19:05 +0800 Subject: #read_entry in ActiveSupport::Cache::FileStore should log details of the exception when an exception is thrown. --- activesupport/lib/active_support/cache/file_store.rb | 3 ++- activesupport/test/caching_test.rb | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/activesupport/lib/active_support/cache/file_store.rb b/activesupport/lib/active_support/cache/file_store.rb index b7712a4a15..70116c0b36 100644 --- a/activesupport/lib/active_support/cache/file_store.rb +++ b/activesupport/lib/active_support/cache/file_store.rb @@ -81,7 +81,8 @@ module ActiveSupport if File.exist?(file_name) File.open(file_name) { |f| Marshal.load(f) } end - rescue + rescue => e + logger.error("FileStoreError (#{e}): #{e.message}") if logger nil end diff --git a/activesupport/test/caching_test.rb b/activesupport/test/caching_test.rb index b03865da93..d6aefa6629 100644 --- a/activesupport/test/caching_test.rb +++ b/activesupport/test/caching_test.rb @@ -549,6 +549,9 @@ class FileStoreTest < ActiveSupport::TestCase @cache = ActiveSupport::Cache.lookup_store(:file_store, cache_dir, :expires_in => 60) @peek = ActiveSupport::Cache.lookup_store(:file_store, cache_dir, :expires_in => 60) @cache_with_pathname = ActiveSupport::Cache.lookup_store(:file_store, Pathname.new(cache_dir), :expires_in => 60) + + @buffer = StringIO.new + @cache.logger = ActiveSupport::Logger.new(@buffer) end def teardown @@ -591,6 +594,12 @@ class FileStoreTest < ActiveSupport::TestCase ActiveSupport::Cache::FileStore.new('/test/cache/directory').delete_matched(/does_not_exist/) end end + + def test_log_exception_when_cache_read_fails + File.expects(:exist?).raises(StandardError, "failed") + @cache.send(:read_entry, "winston", {}) + assert_present @buffer.string + end end class MemoryStoreTest < ActiveSupport::TestCase -- cgit v1.2.3 From a2bf014330310da718dd92ffdfd0435463ed3a4f Mon Sep 17 00:00:00 2001 From: Fotos Georgiadis Date: Fri, 2 Mar 2012 19:12:11 +0200 Subject: Maximum wait_timeout on Windows is 2147483 --- activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb index 3f45f23de8..b343898854 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -260,7 +260,7 @@ module ActiveRecord # increase timeout so mysql server doesn't disconnect us wait_timeout = @config[:wait_timeout] - wait_timeout = 2592000 unless wait_timeout.is_a?(Fixnum) + wait_timeout = 2147483 unless wait_timeout.is_a?(Fixnum) variable_assignments << "@@wait_timeout = #{wait_timeout}" execute("SET #{variable_assignments.join(', ')}", :skip_logging) -- cgit v1.2.3 From fa5f037551dfb860bf6359acf901915856646fea Mon Sep 17 00:00:00 2001 From: Yves Senn Date: Mon, 24 Oct 2011 14:47:01 +0200 Subject: allow the :converter Proc form composed_of to return nil This makes it possible to filter invalid input values before they are passed into the value-object (like empty strings). This behaviour is only relevant if the :allow_nil options is set to true. Otherwise you will get the resulting NoMethodError. --- activerecord/lib/active_record/aggregations.rb | 15 ++++++++------- activerecord/test/cases/aggregations_test.rb | 18 ++++++++++++++++++ activerecord/test/models/customer.rb | 5 +++++ 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/activerecord/lib/active_record/aggregations.rb b/activerecord/lib/active_record/aggregations.rb index 90d3b58c78..f7dcc019c8 100644 --- a/activerecord/lib/active_record/aggregations.rb +++ b/activerecord/lib/active_record/aggregations.rb @@ -187,7 +187,8 @@ module ActiveRecord # * :converter - A symbol specifying the name of a class method of :class_name # or a Proc that is called when a new value is assigned to the value object. The converter is # passed the single value that is used in the assignment and is only called if the new value is - # not an instance of :class_name. + # not an instance of :class_name. If :allow_nil is set to true, the converter + # can return nil to skip the assignment. # # Option examples: # composed_of :temperature, :mapping => %w(reading celsius) @@ -234,16 +235,16 @@ module ActiveRecord def writer_method(name, class_name, mapping, allow_nil, converter) define_method("#{name}=") do |part| + unless part.is_a?(class_name.constantize) || converter.nil? || part.nil? + part = converter.respond_to?(:call) ? + converter.call(part) : + class_name.constantize.send(converter, part) + end + if part.nil? && allow_nil mapping.each { |pair| self[pair.first] = nil } @aggregation_cache[name] = nil else - unless part.is_a?(class_name.constantize) || converter.nil? - part = converter.respond_to?(:call) ? - converter.call(part) : - class_name.constantize.send(converter, part) - end - mapping.each { |pair| self[pair.first] = part.send(pair.last) } @aggregation_cache[name] = part.freeze end diff --git a/activerecord/test/cases/aggregations_test.rb b/activerecord/test/cases/aggregations_test.rb index 3e0e6dce2c..5bd8f76ba2 100644 --- a/activerecord/test/cases/aggregations_test.rb +++ b/activerecord/test/cases/aggregations_test.rb @@ -109,6 +109,24 @@ class AggregationsTest < ActiveRecord::TestCase assert_nil customers(:david).gps_location end + def test_nil_return_from_converter_is_respected_when_allow_nil_is_true + customers(:david).non_blank_gps_location = "" + customers(:david).save + customers(:david).reload + assert_nil customers(:david).non_blank_gps_location + end + + def test_nil_return_from_converter_results_in_failure_when_allow_nil_is_false + assert_raises(NoMethodError) do + customers(:barney).gps_location = "" + end + end + + def test_do_not_run_the_converter_when_nil_was_set + customers(:david).non_blank_gps_location = nil + assert_nil Customer.gps_conversion_was_run + end + def test_custom_constructor assert_equal 'Barney GUMBLE', customers(:barney).fullname.to_s assert_kind_of Fullname, customers(:barney).fullname diff --git a/activerecord/test/models/customer.rb b/activerecord/test/models/customer.rb index 777f6b5ba0..807f25b687 100644 --- a/activerecord/test/models/customer.rb +++ b/activerecord/test/models/customer.rb @@ -1,7 +1,12 @@ class Customer < ActiveRecord::Base + + cattr_accessor :gps_conversion_was_run + composed_of :address, :mapping => [ %w(address_street street), %w(address_city city), %w(address_country country) ], :allow_nil => true composed_of :balance, :class_name => "Money", :mapping => %w(balance amount), :converter => Proc.new { |balance| balance.to_money } composed_of :gps_location, :allow_nil => true + composed_of :non_blank_gps_location, :class_name => "GpsLocation", :allow_nil => true, :mapping => %w(gps_location gps_location), + :converter => lambda { |gps| self.gps_conversion_was_run = true; gps.blank? ? nil : GpsLocation.new(gps)} composed_of :fullname, :mapping => %w(name to_s), :constructor => Proc.new { |name| Fullname.parse(name) }, :converter => :parse end -- cgit v1.2.3 From 60da3bdc779f6b81a44f8c3b8b90aff66dddf3ea Mon Sep 17 00:00:00 2001 From: Ayrton De Craene Date: Mon, 7 May 2012 19:12:41 +0200 Subject: Compressed all images from the guide through ImageOptim which saves sometimes up to 74.6% in size [ci skip] --- guides/assets/images/belongs_to.png | Bin 34017 -> 26076 bytes guides/assets/images/book_icon.gif | Bin 337 -> 329 bytes guides/assets/images/challenge.png | Bin 54134 -> 33373 bytes guides/assets/images/chapters_icon.gif | Bin 628 -> 620 bytes guides/assets/images/check_bullet.gif | Bin 384 -> 376 bytes guides/assets/images/credits_pic_blank.gif | Bin 613 -> 597 bytes guides/assets/images/csrf.png | Bin 41996 -> 32179 bytes guides/assets/images/customized_error_messages.png | Bin 5055 -> 2561 bytes guides/assets/images/edge_badge.png | Bin 7945 -> 5964 bytes guides/assets/images/error_messages.png | Bin 14645 -> 10964 bytes .../images/getting_started/confirm_dialog.png | Bin 36070 -> 29542 bytes .../images/getting_started/form_with_errors.png | Bin 20820 -> 14031 bytes .../index_action_with_edit_link.png | Bin 15547 -> 9772 bytes guides/assets/images/getting_started/new_post.png | Bin 14334 -> 5888 bytes .../images/getting_started/post_with_comments.png | Bin 31630 -> 18496 bytes .../routing_error_no_controller.png | Bin 15744 -> 6268 bytes .../routing_error_no_route_matches.png | Bin 16065 -> 6508 bytes .../getting_started/show_action_for_posts.png | Bin 6885 -> 2991 bytes .../template_is_missing_posts_new.png | Bin 15168 -> 5851 bytes .../getting_started/undefined_method_post_path.png | Bin 15254 -> 9217 bytes .../unknown_action_create_for_posts.png | Bin 12652 -> 4146 bytes .../unknown_action_new_for_posts.png | Bin 12756 -> 4208 bytes guides/assets/images/grey_bullet.gif | Bin 45 -> 37 bytes guides/assets/images/habtm.png | Bin 63801 -> 49332 bytes guides/assets/images/has_many.png | Bin 38582 -> 28988 bytes guides/assets/images/has_many_through.png | Bin 100220 -> 79428 bytes guides/assets/images/has_one.png | Bin 39022 -> 29072 bytes guides/assets/images/has_one_through.png | Bin 92594 -> 72434 bytes guides/assets/images/header_backdrop.png | Bin 882 -> 224 bytes guides/assets/images/i18n/demo_html_safe.png | Bin 11946 -> 10073 bytes .../assets/images/i18n/demo_localized_pirate.png | Bin 15027 -> 11485 bytes guides/assets/images/i18n/demo_translated_en.png | Bin 12057 -> 9325 bytes .../assets/images/i18n/demo_translated_pirate.png | Bin 13392 -> 10202 bytes .../images/i18n/demo_translation_missing.png | Bin 13143 -> 10260 bytes guides/assets/images/i18n/demo_untranslated.png | Bin 11925 -> 9224 bytes guides/assets/images/icons/callouts/1.png | Bin 329 -> 147 bytes guides/assets/images/icons/callouts/10.png | Bin 361 -> 183 bytes guides/assets/images/icons/callouts/11.png | Bin 565 -> 290 bytes guides/assets/images/icons/callouts/12.png | Bin 617 -> 322 bytes guides/assets/images/icons/callouts/13.png | Bin 623 -> 328 bytes guides/assets/images/icons/callouts/14.png | Bin 411 -> 246 bytes guides/assets/images/icons/callouts/15.png | Bin 640 -> 340 bytes guides/assets/images/icons/callouts/2.png | Bin 353 -> 168 bytes guides/assets/images/icons/callouts/3.png | Bin 350 -> 170 bytes guides/assets/images/icons/callouts/4.png | Bin 345 -> 165 bytes guides/assets/images/icons/callouts/5.png | Bin 348 -> 169 bytes guides/assets/images/icons/callouts/6.png | Bin 355 -> 176 bytes guides/assets/images/icons/callouts/7.png | Bin 344 -> 160 bytes guides/assets/images/icons/callouts/8.png | Bin 357 -> 176 bytes guides/assets/images/icons/callouts/9.png | Bin 357 -> 177 bytes guides/assets/images/icons/caution.png | Bin 2554 -> 2300 bytes guides/assets/images/icons/example.png | Bin 2354 -> 2079 bytes guides/assets/images/icons/home.png | Bin 1340 -> 1163 bytes guides/assets/images/icons/important.png | Bin 2657 -> 2451 bytes guides/assets/images/icons/next.png | Bin 1302 -> 1146 bytes guides/assets/images/icons/note.png | Bin 2730 -> 2155 bytes guides/assets/images/icons/prev.png | Bin 1348 -> 1126 bytes guides/assets/images/icons/tip.png | Bin 2602 -> 2248 bytes guides/assets/images/icons/up.png | Bin 1320 -> 1133 bytes guides/assets/images/icons/warning.png | Bin 2828 -> 2616 bytes guides/assets/images/nav_arrow.gif | Bin 427 -> 419 bytes guides/assets/images/polymorphic.png | Bin 85248 -> 66415 bytes guides/assets/images/rails_guides_logo.gif | Bin 5114 -> 5106 bytes guides/assets/images/rails_welcome.png | Bin 121314 -> 71979 bytes guides/assets/images/session_fixation.png | Bin 47860 -> 38451 bytes guides/assets/images/tab_grey.gif | Bin 4924 -> 4684 bytes guides/assets/images/tab_info.gif | Bin 4762 -> 4522 bytes guides/assets/images/tab_note.gif | Bin 4807 -> 4566 bytes guides/assets/images/tab_red.gif | Bin 4753 -> 4507 bytes guides/assets/images/tab_yellow.gif | Bin 4759 -> 4519 bytes guides/assets/images/tab_yellow.png | Bin 1611 -> 1441 bytes guides/assets/images/validation_error_messages.png | Bin 1107 -> 583 bytes 72 files changed, 0 insertions(+), 0 deletions(-) diff --git a/guides/assets/images/belongs_to.png b/guides/assets/images/belongs_to.png index 44243edbca..43c963ffa8 100644 Binary files a/guides/assets/images/belongs_to.png and b/guides/assets/images/belongs_to.png differ diff --git a/guides/assets/images/book_icon.gif b/guides/assets/images/book_icon.gif index c81d5db520..efc5e06880 100644 Binary files a/guides/assets/images/book_icon.gif and b/guides/assets/images/book_icon.gif differ diff --git a/guides/assets/images/challenge.png b/guides/assets/images/challenge.png index d163748640..30be3d7028 100644 Binary files a/guides/assets/images/challenge.png and b/guides/assets/images/challenge.png differ diff --git a/guides/assets/images/chapters_icon.gif b/guides/assets/images/chapters_icon.gif index 06fb415f4a..a61c28c02d 100644 Binary files a/guides/assets/images/chapters_icon.gif and b/guides/assets/images/chapters_icon.gif differ diff --git a/guides/assets/images/check_bullet.gif b/guides/assets/images/check_bullet.gif index 1fcfeba250..bd54ef64c9 100644 Binary files a/guides/assets/images/check_bullet.gif and b/guides/assets/images/check_bullet.gif differ diff --git a/guides/assets/images/credits_pic_blank.gif b/guides/assets/images/credits_pic_blank.gif index f6f654fc65..a6b335d0c9 100644 Binary files a/guides/assets/images/credits_pic_blank.gif and b/guides/assets/images/credits_pic_blank.gif differ diff --git a/guides/assets/images/csrf.png b/guides/assets/images/csrf.png index ab73baafe8..a8123d47c3 100644 Binary files a/guides/assets/images/csrf.png and b/guides/assets/images/csrf.png differ diff --git a/guides/assets/images/customized_error_messages.png b/guides/assets/images/customized_error_messages.png index fa676991e3..fcf47b4be0 100644 Binary files a/guides/assets/images/customized_error_messages.png and b/guides/assets/images/customized_error_messages.png differ diff --git a/guides/assets/images/edge_badge.png b/guides/assets/images/edge_badge.png index cddd46c4b8..a35dc9f8ee 100644 Binary files a/guides/assets/images/edge_badge.png and b/guides/assets/images/edge_badge.png differ diff --git a/guides/assets/images/error_messages.png b/guides/assets/images/error_messages.png index 428892194a..1189e486d4 100644 Binary files a/guides/assets/images/error_messages.png and b/guides/assets/images/error_messages.png 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 Binary files a/guides/assets/images/getting_started/confirm_dialog.png and b/guides/assets/images/getting_started/confirm_dialog.png 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 Binary files a/guides/assets/images/getting_started/form_with_errors.png and b/guides/assets/images/getting_started/form_with_errors.png 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 Binary files a/guides/assets/images/getting_started/index_action_with_edit_link.png and b/guides/assets/images/getting_started/index_action_with_edit_link.png 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 Binary files a/guides/assets/images/getting_started/new_post.png and b/guides/assets/images/getting_started/new_post.png 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 Binary files a/guides/assets/images/getting_started/post_with_comments.png and b/guides/assets/images/getting_started/post_with_comments.png 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 Binary files a/guides/assets/images/getting_started/routing_error_no_controller.png and b/guides/assets/images/getting_started/routing_error_no_controller.png 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 Binary files a/guides/assets/images/getting_started/routing_error_no_route_matches.png and b/guides/assets/images/getting_started/routing_error_no_route_matches.png 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 Binary files a/guides/assets/images/getting_started/show_action_for_posts.png and b/guides/assets/images/getting_started/show_action_for_posts.png 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 Binary files a/guides/assets/images/getting_started/template_is_missing_posts_new.png and b/guides/assets/images/getting_started/template_is_missing_posts_new.png 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 Binary files a/guides/assets/images/getting_started/undefined_method_post_path.png and b/guides/assets/images/getting_started/undefined_method_post_path.png 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 Binary files a/guides/assets/images/getting_started/unknown_action_create_for_posts.png and b/guides/assets/images/getting_started/unknown_action_create_for_posts.png 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 Binary files a/guides/assets/images/getting_started/unknown_action_new_for_posts.png and b/guides/assets/images/getting_started/unknown_action_new_for_posts.png differ diff --git a/guides/assets/images/grey_bullet.gif b/guides/assets/images/grey_bullet.gif index e75e8e93a1..3c08b1571c 100644 Binary files a/guides/assets/images/grey_bullet.gif and b/guides/assets/images/grey_bullet.gif differ diff --git a/guides/assets/images/habtm.png b/guides/assets/images/habtm.png index fea78b0b5c..b062bc73fe 100644 Binary files a/guides/assets/images/habtm.png and b/guides/assets/images/habtm.png differ diff --git a/guides/assets/images/has_many.png b/guides/assets/images/has_many.png index 6cff58460d..e7589e3b75 100644 Binary files a/guides/assets/images/has_many.png and b/guides/assets/images/has_many.png differ diff --git a/guides/assets/images/has_many_through.png b/guides/assets/images/has_many_through.png index 85d7599925..858c898dc1 100644 Binary files a/guides/assets/images/has_many_through.png and b/guides/assets/images/has_many_through.png differ diff --git a/guides/assets/images/has_one.png b/guides/assets/images/has_one.png index a70ddaaa86..93faa05b07 100644 Binary files a/guides/assets/images/has_one.png and b/guides/assets/images/has_one.png differ diff --git a/guides/assets/images/has_one_through.png b/guides/assets/images/has_one_through.png index 89a7617a30..07dac1a27d 100644 Binary files a/guides/assets/images/has_one_through.png and b/guides/assets/images/has_one_through.png differ diff --git a/guides/assets/images/header_backdrop.png b/guides/assets/images/header_backdrop.png index ff2982175e..72b030478f 100644 Binary files a/guides/assets/images/header_backdrop.png and b/guides/assets/images/header_backdrop.png 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 Binary files a/guides/assets/images/i18n/demo_html_safe.png and b/guides/assets/images/i18n/demo_html_safe.png 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 Binary files a/guides/assets/images/i18n/demo_localized_pirate.png and b/guides/assets/images/i18n/demo_localized_pirate.png 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 Binary files a/guides/assets/images/i18n/demo_translated_en.png and b/guides/assets/images/i18n/demo_translated_en.png 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 Binary files a/guides/assets/images/i18n/demo_translated_pirate.png and b/guides/assets/images/i18n/demo_translated_pirate.png 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 Binary files a/guides/assets/images/i18n/demo_translation_missing.png and b/guides/assets/images/i18n/demo_translation_missing.png differ diff --git a/guides/assets/images/i18n/demo_untranslated.png b/guides/assets/images/i18n/demo_untranslated.png index 3603f43463..2ea6404822 100644 Binary files a/guides/assets/images/i18n/demo_untranslated.png and b/guides/assets/images/i18n/demo_untranslated.png differ diff --git a/guides/assets/images/icons/callouts/1.png b/guides/assets/images/icons/callouts/1.png index 7d473430b7..c5d02adcf4 100644 Binary files a/guides/assets/images/icons/callouts/1.png and b/guides/assets/images/icons/callouts/1.png differ diff --git a/guides/assets/images/icons/callouts/10.png b/guides/assets/images/icons/callouts/10.png index 997bbc8246..fe89f9ef83 100644 Binary files a/guides/assets/images/icons/callouts/10.png and b/guides/assets/images/icons/callouts/10.png differ diff --git a/guides/assets/images/icons/callouts/11.png b/guides/assets/images/icons/callouts/11.png index ce47dac3f5..9244a1ac4b 100644 Binary files a/guides/assets/images/icons/callouts/11.png and b/guides/assets/images/icons/callouts/11.png differ diff --git a/guides/assets/images/icons/callouts/12.png b/guides/assets/images/icons/callouts/12.png index 31daf4e2f2..ae56459f4c 100644 Binary files a/guides/assets/images/icons/callouts/12.png and b/guides/assets/images/icons/callouts/12.png differ diff --git a/guides/assets/images/icons/callouts/13.png b/guides/assets/images/icons/callouts/13.png index 14021a89c2..1181f9f892 100644 Binary files a/guides/assets/images/icons/callouts/13.png and b/guides/assets/images/icons/callouts/13.png differ diff --git a/guides/assets/images/icons/callouts/14.png b/guides/assets/images/icons/callouts/14.png index 64014b75fe..4274e6580a 100644 Binary files a/guides/assets/images/icons/callouts/14.png and b/guides/assets/images/icons/callouts/14.png differ diff --git a/guides/assets/images/icons/callouts/15.png b/guides/assets/images/icons/callouts/15.png index 0d65765fcf..39304de94f 100644 Binary files a/guides/assets/images/icons/callouts/15.png and b/guides/assets/images/icons/callouts/15.png differ diff --git a/guides/assets/images/icons/callouts/2.png b/guides/assets/images/icons/callouts/2.png index 5d09341b2f..8c57970ba9 100644 Binary files a/guides/assets/images/icons/callouts/2.png and b/guides/assets/images/icons/callouts/2.png differ diff --git a/guides/assets/images/icons/callouts/3.png b/guides/assets/images/icons/callouts/3.png index ef7b700471..57a33d15b4 100644 Binary files a/guides/assets/images/icons/callouts/3.png and b/guides/assets/images/icons/callouts/3.png differ diff --git a/guides/assets/images/icons/callouts/4.png b/guides/assets/images/icons/callouts/4.png index adb8364eb5..f061ab02b8 100644 Binary files a/guides/assets/images/icons/callouts/4.png and b/guides/assets/images/icons/callouts/4.png differ diff --git a/guides/assets/images/icons/callouts/5.png b/guides/assets/images/icons/callouts/5.png index 4d7eb46002..b4de02da11 100644 Binary files a/guides/assets/images/icons/callouts/5.png and b/guides/assets/images/icons/callouts/5.png differ diff --git a/guides/assets/images/icons/callouts/6.png b/guides/assets/images/icons/callouts/6.png index 0ba694af6c..0e055eec1e 100644 Binary files a/guides/assets/images/icons/callouts/6.png and b/guides/assets/images/icons/callouts/6.png differ diff --git a/guides/assets/images/icons/callouts/7.png b/guides/assets/images/icons/callouts/7.png index 472e96f8ac..5ead87d040 100644 Binary files a/guides/assets/images/icons/callouts/7.png and b/guides/assets/images/icons/callouts/7.png differ diff --git a/guides/assets/images/icons/callouts/8.png b/guides/assets/images/icons/callouts/8.png index 5e60973c21..cb99545eb6 100644 Binary files a/guides/assets/images/icons/callouts/8.png and b/guides/assets/images/icons/callouts/8.png differ diff --git a/guides/assets/images/icons/callouts/9.png b/guides/assets/images/icons/callouts/9.png index a0676d26cc..0ac03602f6 100644 Binary files a/guides/assets/images/icons/callouts/9.png and b/guides/assets/images/icons/callouts/9.png differ diff --git a/guides/assets/images/icons/caution.png b/guides/assets/images/icons/caution.png index cb9d5ea0df..031e19c776 100644 Binary files a/guides/assets/images/icons/caution.png and b/guides/assets/images/icons/caution.png differ diff --git a/guides/assets/images/icons/example.png b/guides/assets/images/icons/example.png index bba1c0010d..1b0e482059 100644 Binary files a/guides/assets/images/icons/example.png and b/guides/assets/images/icons/example.png differ diff --git a/guides/assets/images/icons/home.png b/guides/assets/images/icons/home.png index 37a5231bac..24149d6e78 100644 Binary files a/guides/assets/images/icons/home.png and b/guides/assets/images/icons/home.png differ diff --git a/guides/assets/images/icons/important.png b/guides/assets/images/icons/important.png index 1096c23295..dafcf0f59e 100644 Binary files a/guides/assets/images/icons/important.png and b/guides/assets/images/icons/important.png differ diff --git a/guides/assets/images/icons/next.png b/guides/assets/images/icons/next.png index 64e126bdda..355b329f5a 100644 Binary files a/guides/assets/images/icons/next.png and b/guides/assets/images/icons/next.png differ diff --git a/guides/assets/images/icons/note.png b/guides/assets/images/icons/note.png index 841820f7c4..08d35a6f5c 100644 Binary files a/guides/assets/images/icons/note.png and b/guides/assets/images/icons/note.png differ diff --git a/guides/assets/images/icons/prev.png b/guides/assets/images/icons/prev.png index 3e8f12fe24..ea564c865e 100644 Binary files a/guides/assets/images/icons/prev.png and b/guides/assets/images/icons/prev.png differ diff --git a/guides/assets/images/icons/tip.png b/guides/assets/images/icons/tip.png index a3a029d898..d834e6d1bb 100644 Binary files a/guides/assets/images/icons/tip.png and b/guides/assets/images/icons/tip.png differ diff --git a/guides/assets/images/icons/up.png b/guides/assets/images/icons/up.png index 2db1ce62fa..379f0045af 100644 Binary files a/guides/assets/images/icons/up.png and b/guides/assets/images/icons/up.png differ diff --git a/guides/assets/images/icons/warning.png b/guides/assets/images/icons/warning.png index 0b0c419df2..72a8a5d873 100644 Binary files a/guides/assets/images/icons/warning.png and b/guides/assets/images/icons/warning.png differ diff --git a/guides/assets/images/nav_arrow.gif b/guides/assets/images/nav_arrow.gif index c4f57658d7..ff081819ad 100644 Binary files a/guides/assets/images/nav_arrow.gif and b/guides/assets/images/nav_arrow.gif differ diff --git a/guides/assets/images/polymorphic.png b/guides/assets/images/polymorphic.png index ff2fd9f76d..a3cbc4502a 100644 Binary files a/guides/assets/images/polymorphic.png and b/guides/assets/images/polymorphic.png differ diff --git a/guides/assets/images/rails_guides_logo.gif b/guides/assets/images/rails_guides_logo.gif index a24683a34e..9b0ad5af28 100644 Binary files a/guides/assets/images/rails_guides_logo.gif and b/guides/assets/images/rails_guides_logo.gif differ diff --git a/guides/assets/images/rails_welcome.png b/guides/assets/images/rails_welcome.png index f2aa210d19..8ad2d351de 100644 Binary files a/guides/assets/images/rails_welcome.png and b/guides/assets/images/rails_welcome.png differ diff --git a/guides/assets/images/session_fixation.png b/guides/assets/images/session_fixation.png index 6b084508db..ac3ab01614 100644 Binary files a/guides/assets/images/session_fixation.png and b/guides/assets/images/session_fixation.png differ diff --git a/guides/assets/images/tab_grey.gif b/guides/assets/images/tab_grey.gif index e9680b7136..995adb76cf 100644 Binary files a/guides/assets/images/tab_grey.gif and b/guides/assets/images/tab_grey.gif differ diff --git a/guides/assets/images/tab_info.gif b/guides/assets/images/tab_info.gif index 458fea9a61..e9dd164f18 100644 Binary files a/guides/assets/images/tab_info.gif and b/guides/assets/images/tab_info.gif differ diff --git a/guides/assets/images/tab_note.gif b/guides/assets/images/tab_note.gif index 1d5c171ed6..f9b546c6f8 100644 Binary files a/guides/assets/images/tab_note.gif and b/guides/assets/images/tab_note.gif differ diff --git a/guides/assets/images/tab_red.gif b/guides/assets/images/tab_red.gif index daf140b5a8..0613093ddc 100644 Binary files a/guides/assets/images/tab_red.gif and b/guides/assets/images/tab_red.gif differ diff --git a/guides/assets/images/tab_yellow.gif b/guides/assets/images/tab_yellow.gif index dc961c99dd..39a3c2dc6a 100644 Binary files a/guides/assets/images/tab_yellow.gif and b/guides/assets/images/tab_yellow.gif differ diff --git a/guides/assets/images/tab_yellow.png b/guides/assets/images/tab_yellow.png index cceea6581f..3ab1c56c4d 100644 Binary files a/guides/assets/images/tab_yellow.png and b/guides/assets/images/tab_yellow.png differ diff --git a/guides/assets/images/validation_error_messages.png b/guides/assets/images/validation_error_messages.png index 622d35da5d..30e4ca4a3d 100644 Binary files a/guides/assets/images/validation_error_messages.png and b/guides/assets/images/validation_error_messages.png differ -- cgit v1.2.3 From 6f3489c52a407040888605b5a984e010236aec01 Mon Sep 17 00:00:00 2001 From: Ivan Evtukhovich Date: Tue, 17 Apr 2012 12:26:23 +0400 Subject: Remove prepared statement from system query in postgresql adapter --- .../connection_adapters/postgresql_adapter.rb | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 4d5459939b..871393b37b 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -916,22 +916,22 @@ module ActiveRecord binds = [[nil, table]] binds << [nil, schema] if schema - exec_query(<<-SQL, 'SCHEMA', binds).rows.first[0].to_i > 0 + exec_query(<<-SQL, 'SCHEMA').rows.first[0].to_i > 0 SELECT COUNT(*) FROM pg_class c LEFT JOIN pg_namespace n ON n.oid = c.relnamespace WHERE c.relkind in ('v','r') - AND c.relname = $1 - AND n.nspname = #{schema ? '$2' : 'ANY (current_schemas(false))'} + AND c.relname = '#{table.gsub(/(^"|"$)/,'')}' + AND n.nspname = #{schema ? "'#{schema}'" : 'ANY (current_schemas(false))'} SQL end # Returns true if schema exists. def schema_exists?(name) - exec_query(<<-SQL, 'SCHEMA', [[nil, name]]).rows.first[0].to_i > 0 + exec_query(<<-SQL, 'SCHEMA').rows.first[0].to_i > 0 SELECT COUNT(*) FROM pg_namespace - WHERE nspname = $1 + WHERE nspname = '#{name}' SQL end @@ -1062,8 +1062,8 @@ module ActiveRecord end def serial_sequence(table, column) - result = exec_query(<<-eosql, 'SCHEMA', [[nil, table], [nil, column]]) - SELECT pg_get_serial_sequence($1, $2) + result = exec_query(<<-eosql, 'SCHEMA') + SELECT pg_get_serial_sequence('#{table}', '#{column}') eosql result.rows.first.first end @@ -1140,13 +1140,13 @@ module ActiveRecord # Returns just a table's primary key def primary_key(table) - row = exec_query(<<-end_sql, 'SCHEMA', [[nil, table]]).rows.first + row = exec_query(<<-end_sql, 'SCHEMA').rows.first SELECT DISTINCT(attr.attname) FROM pg_attribute attr INNER JOIN pg_depend dep ON attr.attrelid = dep.refobjid AND attr.attnum = dep.refobjsubid INNER JOIN pg_constraint cons ON attr.attrelid = cons.conrelid AND attr.attnum = cons.conkey[1] WHERE cons.contype = 'p' - AND dep.refobjid = $1::regclass + AND dep.refobjid = '#{table}'::regclass end_sql row && row.first @@ -1408,7 +1408,7 @@ module ActiveRecord end def last_insert_id_result(sequence_name) #:nodoc: - exec_query("SELECT currval($1)", 'SQL', [[nil, sequence_name]]) + exec_query("SELECT currval('#{sequence_name}')", 'SQL') end # Executes a SELECT query and returns the results, performing any data type -- cgit v1.2.3 From c140a27fc55e294a130b874f075748c5cd03de1e Mon Sep 17 00:00:00 2001 From: ayaya Date: Tue, 31 Jan 2012 18:43:54 +0800 Subject: fix `alias_attribute` will raise a syntax error if make an alias on a column that named as a ruby keyword --- activemodel/lib/active_model/attribute_methods.rb | 8 ++++---- activemodel/test/cases/attribute_methods_test.rb | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/activemodel/lib/active_model/attribute_methods.rb b/activemodel/lib/active_model/attribute_methods.rb index 97a83e58af..dc4423d488 100644 --- a/activemodel/lib/active_model/attribute_methods.rb +++ b/activemodel/lib/active_model/attribute_methods.rb @@ -184,7 +184,7 @@ module ActiveModel attribute_method_matchers.each do |matcher| matcher_new = matcher.method_name(new_name).to_s matcher_old = matcher.method_name(old_name).to_s - define_optimized_call self, matcher_new, matcher_old + define_proxy_call false, self, matcher_new, matcher_old end end @@ -226,7 +226,7 @@ module ActiveModel if respond_to?(generate_method, true) send(generate_method, attr_name) else - define_optimized_call generated_attribute_methods, method_name, matcher.method_missing_target, attr_name.to_s + define_proxy_call true, generated_attribute_methods, method_name, matcher.method_missing_target, attr_name.to_s end end end @@ -285,7 +285,7 @@ module ActiveModel # Define a method `name` in `mod` that dispatches to `send` # using the given `extra` args. This fallbacks `define_method` # and `send` if the given names cannot be compiled. - def define_optimized_call(mod, name, send, *extra) #:nodoc: + def define_proxy_call(include_private, mod, name, send, *extra) #:nodoc: if name =~ NAME_COMPILABLE_REGEXP defn = "def #{name}(*args)" else @@ -295,7 +295,7 @@ module ActiveModel extra = (extra.map(&:inspect) << "*args").join(", ") if send =~ CALL_COMPILABLE_REGEXP - target = "#{send}(#{extra})" + target = "#{"self." unless include_private}#{send}(#{extra})" else target = "send(:'#{send}', #{extra})" end diff --git a/activemodel/test/cases/attribute_methods_test.rb b/activemodel/test/cases/attribute_methods_test.rb index 34298d31c2..efbf2db1eb 100644 --- a/activemodel/test/cases/attribute_methods_test.rb +++ b/activemodel/test/cases/attribute_methods_test.rb @@ -76,6 +76,19 @@ private end end +class ModelWithRubyKeywordNamedAttributes + include ActiveModel::AttributeMethods + + def attributes + { :begin => 'value of begin', :end => 'value of end' } + end + +private + def attribute(name) + attributes[name.to_sym] + end +end + class ModelWithoutAttributesMethod include ActiveModel::AttributeMethods end @@ -148,6 +161,15 @@ class AttributeMethodsTest < ActiveModel::TestCase assert_equal "value of foo bar", ModelWithAttributesWithSpaces.new.foo_bar end + test '#alias_attribute works with attributes named as a ruby keyword' do + ModelWithRubyKeywordNamedAttributes.define_attribute_methods([:begin, :end]) + ModelWithRubyKeywordNamedAttributes.alias_attribute(:from, :begin) + ModelWithRubyKeywordNamedAttributes.alias_attribute(:to, :end) + + assert_equal "value of begin", ModelWithRubyKeywordNamedAttributes.new.from + assert_equal "value of end", ModelWithRubyKeywordNamedAttributes.new.to + end + test '#undefine_attribute_methods removes attribute methods' do ModelWithAttributes.define_attribute_methods([:foo]) ModelWithAttributes.undefine_attribute_methods -- cgit v1.2.3 From d3f57fbf6e751aedb90691a7315158a3be62c61f Mon Sep 17 00:00:00 2001 From: Oscar Del Ben Date: Fri, 18 May 2012 08:45:03 -0700 Subject: Add oscardelben to authors --- guides/assets/images/oscardelben.jpg | Bin 0 -> 6299 bytes guides/source/credits.html.erb | 4 ++++ 2 files changed, 4 insertions(+) create mode 100644 guides/assets/images/oscardelben.jpg diff --git a/guides/assets/images/oscardelben.jpg b/guides/assets/images/oscardelben.jpg new file mode 100644 index 0000000000..9f3f67c2c7 Binary files /dev/null and b/guides/assets/images/oscardelben.jpg differ 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 RubyX and has been working with Rails since 2006. He's co-authoring a book called Rails 3 in Action and he's written many gems which can be seen on his GitHub page and he also tweets prolifically as @ryanbigg. <% end %> +<%= author('Oscar Del Ben', 'oscardelben', 'oscardelben.jpg') do %> +Oscar Del Ben is a software engineer at Wildfire. He's a regular open source contributor (Github account) and tweets regularly at @oscardelben. + <% 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 spacevatican.org. <% end %> -- cgit v1.2.3 From 42d0b1c8ddab9c3ffa8951bf085f5c758673e94b Mon Sep 17 00:00:00 2001 From: Oscar Del Ben Date: Mon, 2 Apr 2012 16:41:43 +0300 Subject: Call undefine_attribute_methods only when defining new attributes --- activemodel/lib/active_model/attribute_methods.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/activemodel/lib/active_model/attribute_methods.rb b/activemodel/lib/active_model/attribute_methods.rb index 99918fdb96..039cd8bdf3 100644 --- a/activemodel/lib/active_model/attribute_methods.rb +++ b/activemodel/lib/active_model/attribute_methods.rb @@ -102,7 +102,6 @@ module ActiveModel # person.name # => nil def attribute_method_prefix(*prefixes) self.attribute_method_matchers += prefixes.map { |prefix| AttributeMethodMatcher.new :prefix => prefix } - undefine_attribute_methods end # Declares a method available for all attributes with the given suffix. @@ -139,7 +138,6 @@ module ActiveModel # person.name_short? # => true def attribute_method_suffix(*suffixes) self.attribute_method_matchers += suffixes.map { |suffix| AttributeMethodMatcher.new :suffix => suffix } - undefine_attribute_methods end # Declares a method available for all attributes with the given prefix @@ -177,7 +175,6 @@ module ActiveModel # person.name # => 'Gemma' def attribute_method_affix(*affixes) self.attribute_method_matchers += affixes.map { |affix| AttributeMethodMatcher.new :prefix => affix[:prefix], :suffix => affix[:suffix] } - undefine_attribute_methods end @@ -225,6 +222,7 @@ module ActiveModel # end # end def define_attribute_methods(*attr_names) + undefine_attribute_methods attr_names.flatten.each { |attr_name| define_attribute_method(attr_name) } end -- cgit v1.2.3 From 117382f914e0911de0de3420ed14f71c083acabf Mon Sep 17 00:00:00 2001 From: Alexey Vakhov Date: Wed, 28 Mar 2012 12:23:21 +0400 Subject: Make AC::LogSubscriber#send_file like #send_data --- actionpack/lib/action_controller/log_subscriber.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/actionpack/lib/action_controller/log_subscriber.rb b/actionpack/lib/action_controller/log_subscriber.rb index 11aa393bf9..0fb419f941 100644 --- a/actionpack/lib/action_controller/log_subscriber.rb +++ b/actionpack/lib/action_controller/log_subscriber.rb @@ -33,9 +33,7 @@ module ActionController end def send_file(event) - message = "Sent file %s" - message << " (%.1fms)" - info(message % [event.payload[:path], event.duration]) + info("Sent file %s (%.1fms)" % [event.payload[:path], event.duration]) end def redirect_to(event) -- cgit v1.2.3 From 99e9a733c8852f4ff065f2ede9c9cd03475411a2 Mon Sep 17 00:00:00 2001 From: Marc-Andre Lafortune Date: Fri, 4 May 2012 23:57:11 -0400 Subject: Make constantize look down the ancestor chain (excluding Object) --- activesupport/lib/active_support/inflector/methods.rb | 14 +++++++++++++- activesupport/test/constantize_test_cases.rb | 17 +++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/activesupport/lib/active_support/inflector/methods.rb b/activesupport/lib/active_support/inflector/methods.rb index 48296841aa..274dc90eff 100644 --- a/activesupport/lib/active_support/inflector/methods.rb +++ b/activesupport/lib/active_support/inflector/methods.rb @@ -203,7 +203,19 @@ module ActiveSupport names.shift if names.empty? || names.first.empty? names.inject(Object) do |constant, name| - constant.const_get(name, false) + candidate = constant.const_get(name) + if constant.const_defined?(name, false) || !Object.const_defined?(name) + candidate + else + # Go down the ancestors to check it it's owned + # directly before we reach Object or the end of ancestors. + constant.ancestors.each do |ancestor| + break if ancestor == Object + return candidate if ancestor.const_defined?(name, false) + end + # owner is in Object, so raise + constant.const_get(name, false) + end end end diff --git a/activesupport/test/constantize_test_cases.rb b/activesupport/test/constantize_test_cases.rb index 135f894056..908f9e9a37 100644 --- a/activesupport/test/constantize_test_cases.rb +++ b/activesupport/test/constantize_test_cases.rb @@ -1,7 +1,14 @@ module Ace module Base class Case + class Dice + end end + class Fase < Case + end + end + class Gas + include Base end end @@ -9,6 +16,9 @@ module ConstantizeTestCases def run_constantize_tests_on assert_nothing_raised { assert_equal Ace::Base::Case, yield("Ace::Base::Case") } assert_nothing_raised { assert_equal Ace::Base::Case, yield("::Ace::Base::Case") } + assert_nothing_raised { assert_equal Ace::Base::Case::Dice, yield("Ace::Base::Case::Dice") } + assert_nothing_raised { assert_equal Ace::Base::Fase::Dice, yield("Ace::Base::Fase::Dice") } + assert_nothing_raised { assert_equal Ace::Gas::Case, yield("Ace::Gas::Case") } assert_nothing_raised { assert_equal ConstantizeTestCases, yield("ConstantizeTestCases") } assert_nothing_raised { assert_equal ConstantizeTestCases, yield("::ConstantizeTestCases") } assert_raise(NameError) { yield("UnknownClass") } @@ -18,11 +28,16 @@ module ConstantizeTestCases assert_raise(NameError) { yield("InvalidClass\n") } assert_raise(NameError) { yield("Ace::ConstantizeTestCases") } assert_raise(NameError) { yield("Ace::Base::ConstantizeTestCases") } + assert_raise(NameError) { yield("Ace::Gas::Base") } + assert_raise(NameError) { yield("Ace::Gas::ConstantizeTestCases") } end def run_safe_constantize_tests_on assert_nothing_raised { assert_equal Ace::Base::Case, yield("Ace::Base::Case") } assert_nothing_raised { assert_equal Ace::Base::Case, yield("::Ace::Base::Case") } + assert_nothing_raised { assert_equal Ace::Base::Case::Dice, yield("Ace::Base::Case::Dice") } + assert_nothing_raised { assert_equal Ace::Base::Fase::Dice, yield("Ace::Base::Fase::Dice") } + assert_nothing_raised { assert_equal Ace::Gas::Case, yield("Ace::Gas::Case") } assert_nothing_raised { assert_equal ConstantizeTestCases, yield("ConstantizeTestCases") } assert_nothing_raised { assert_equal ConstantizeTestCases, yield("::ConstantizeTestCases") } assert_nothing_raised { assert_equal nil, yield("UnknownClass") } @@ -33,6 +48,8 @@ module ConstantizeTestCases assert_nothing_raised { assert_equal nil, yield("blargle") } assert_nothing_raised { assert_equal nil, yield("Ace::ConstantizeTestCases") } assert_nothing_raised { assert_equal nil, yield("Ace::Base::ConstantizeTestCases") } + assert_nothing_raised { assert_equal nil, yield("Ace::Gas::Base") } + assert_nothing_raised { assert_equal nil, yield("Ace::Gas::ConstantizeTestCases") } assert_nothing_raised { assert_equal nil, yield("#::Nested_1") } end end -- cgit v1.2.3 From eb09411460d11c7b1b1b54272ba345a1e1cf472d Mon Sep 17 00:00:00 2001 From: Marc-Andre Lafortune Date: Sat, 5 May 2012 10:13:33 -0400 Subject: Fix constantize so top level constants are looked up properly. --- activesupport/lib/active_support/inflector/methods.rb | 2 +- activesupport/test/constantize_test_cases.rb | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/activesupport/lib/active_support/inflector/methods.rb b/activesupport/lib/active_support/inflector/methods.rb index 274dc90eff..11f3c4c46f 100644 --- a/activesupport/lib/active_support/inflector/methods.rb +++ b/activesupport/lib/active_support/inflector/methods.rb @@ -204,7 +204,7 @@ module ActiveSupport names.inject(Object) do |constant, name| candidate = constant.const_get(name) - if constant.const_defined?(name, false) || !Object.const_defined?(name) + if constant.const_defined?(name, false) || constant == Object || !Object.const_defined?(name) candidate else # Go down the ancestors to check it it's owned diff --git a/activesupport/test/constantize_test_cases.rb b/activesupport/test/constantize_test_cases.rb index 908f9e9a37..470213e9bd 100644 --- a/activesupport/test/constantize_test_cases.rb +++ b/activesupport/test/constantize_test_cases.rb @@ -12,6 +12,16 @@ module Ace end end +class Object + module AddtlGlobalConstants + class Case + class Dice + end + end + end + include AddtlGlobalConstants +end + module ConstantizeTestCases def run_constantize_tests_on assert_nothing_raised { assert_equal Ace::Base::Case, yield("Ace::Base::Case") } @@ -19,8 +29,12 @@ module ConstantizeTestCases assert_nothing_raised { assert_equal Ace::Base::Case::Dice, yield("Ace::Base::Case::Dice") } assert_nothing_raised { assert_equal Ace::Base::Fase::Dice, yield("Ace::Base::Fase::Dice") } assert_nothing_raised { assert_equal Ace::Gas::Case, yield("Ace::Gas::Case") } + assert_nothing_raised { assert_equal Case::Dice, yield("Case::Dice") } + assert_nothing_raised { assert_equal Case::Dice, yield("Object::Case::Dice") } assert_nothing_raised { assert_equal ConstantizeTestCases, yield("ConstantizeTestCases") } assert_nothing_raised { assert_equal ConstantizeTestCases, yield("::ConstantizeTestCases") } + assert_nothing_raised { assert_equal Object, yield("") } + assert_nothing_raised { assert_equal Object, yield("::") } assert_raise(NameError) { yield("UnknownClass") } assert_raise(NameError) { yield("UnknownClass::Ace") } assert_raise(NameError) { yield("UnknownClass::Ace::Base") } @@ -38,8 +52,12 @@ module ConstantizeTestCases assert_nothing_raised { assert_equal Ace::Base::Case::Dice, yield("Ace::Base::Case::Dice") } assert_nothing_raised { assert_equal Ace::Base::Fase::Dice, yield("Ace::Base::Fase::Dice") } assert_nothing_raised { assert_equal Ace::Gas::Case, yield("Ace::Gas::Case") } + assert_nothing_raised { assert_equal Case::Dice, yield("Case::Dice") } + assert_nothing_raised { assert_equal Case::Dice, yield("Object::Case::Dice") } assert_nothing_raised { assert_equal ConstantizeTestCases, yield("ConstantizeTestCases") } assert_nothing_raised { assert_equal ConstantizeTestCases, yield("::ConstantizeTestCases") } + assert_nothing_raised { assert_equal Object, yield("") } + assert_nothing_raised { assert_equal Object, yield("::") } assert_nothing_raised { assert_equal nil, yield("UnknownClass") } assert_nothing_raised { assert_equal nil, yield("UnknownClass::Ace") } assert_nothing_raised { assert_equal nil, yield("UnknownClass::Ace::Base") } -- cgit v1.2.3 From 3d0e4895cdc82bee9fb6ccc1208baa93fc5101ef Mon Sep 17 00:00:00 2001 From: Andrew White Date: Sat, 19 May 2012 15:44:19 +0100 Subject: Handle case where ancestor is not the end of the chain --- activesupport/lib/active_support/inflector/methods.rb | 19 ++++++++++++------- activesupport/test/constantize_test_cases.rb | 2 ++ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/activesupport/lib/active_support/inflector/methods.rb b/activesupport/lib/active_support/inflector/methods.rb index 11f3c4c46f..e5b0cf4f9e 100644 --- a/activesupport/lib/active_support/inflector/methods.rb +++ b/activesupport/lib/active_support/inflector/methods.rb @@ -198,21 +198,26 @@ module ActiveSupport # # NameError is raised when the name is not in CamelCase or the constant is # unknown. - def constantize(camel_cased_word) #:nodoc: + def constantize(camel_cased_word) names = camel_cased_word.split('::') names.shift if names.empty? || names.first.empty? names.inject(Object) do |constant, name| - candidate = constant.const_get(name) - if constant.const_defined?(name, false) || constant == Object || !Object.const_defined?(name) - candidate + if constant == Object + constant.const_get(name) else + candidate = constant.const_get(name) + next candidate if constant.const_defined?(name, false) + next candidate unless Object.const_defined?(name) + # Go down the ancestors to check it it's owned # directly before we reach Object or the end of ancestors. - constant.ancestors.each do |ancestor| - break if ancestor == Object - return candidate if ancestor.const_defined?(name, false) + constant = constant.ancestors.inject do |constant, ancestor| + break constant if ancestor == Object + break ancestor if ancestor.const_defined?(name, false) + constant end + # owner is in Object, so raise constant.const_get(name, false) end diff --git a/activesupport/test/constantize_test_cases.rb b/activesupport/test/constantize_test_cases.rb index 470213e9bd..ec05213409 100644 --- a/activesupport/test/constantize_test_cases.rb +++ b/activesupport/test/constantize_test_cases.rb @@ -29,6 +29,7 @@ module ConstantizeTestCases assert_nothing_raised { assert_equal Ace::Base::Case::Dice, yield("Ace::Base::Case::Dice") } assert_nothing_raised { assert_equal Ace::Base::Fase::Dice, yield("Ace::Base::Fase::Dice") } assert_nothing_raised { assert_equal Ace::Gas::Case, yield("Ace::Gas::Case") } + assert_nothing_raised { assert_equal Ace::Gas::Case::Dice, yield("Ace::Gas::Case::Dice") } assert_nothing_raised { assert_equal Case::Dice, yield("Case::Dice") } assert_nothing_raised { assert_equal Case::Dice, yield("Object::Case::Dice") } assert_nothing_raised { assert_equal ConstantizeTestCases, yield("ConstantizeTestCases") } @@ -52,6 +53,7 @@ module ConstantizeTestCases assert_nothing_raised { assert_equal Ace::Base::Case::Dice, yield("Ace::Base::Case::Dice") } assert_nothing_raised { assert_equal Ace::Base::Fase::Dice, yield("Ace::Base::Fase::Dice") } assert_nothing_raised { assert_equal Ace::Gas::Case, yield("Ace::Gas::Case") } + assert_nothing_raised { assert_equal Ace::Gas::Case::Dice, yield("Ace::Gas::Case::Dice") } assert_nothing_raised { assert_equal Case::Dice, yield("Case::Dice") } assert_nothing_raised { assert_equal Case::Dice, yield("Object::Case::Dice") } assert_nothing_raised { assert_equal ConstantizeTestCases, yield("ConstantizeTestCases") } -- cgit v1.2.3 From 329a5a43227be48b408b702438b355c087fd2866 Mon Sep 17 00:00:00 2001 From: Andrew White Date: Sat, 19 May 2012 15:46:12 +0100 Subject: Add CHANGELOG entry for constantize - closes #6165. --- activesupport/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index 636aca2b8f..79ea9c70ea 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,5 +1,7 @@ ## Rails 4.0.0 (unreleased) ## +* `constantize` now looks in the ancestor chain. *Marc-Andre Lafortune & Andrew White* + * `Object#try` can't call private methods. *Vasiliy Ermolovich* * `AS::Callbacks#run_callbacks` remove `key` argument. *Francesco Rodriguez* -- cgit v1.2.3 From 3f1caaf23a60df82a72873b4bfce4dc47aa51029 Mon Sep 17 00:00:00 2001 From: kennyj Date: Sat, 19 May 2012 23:54:52 +0900 Subject: Fix warning: shadowing outer local variable - constant. --- activesupport/lib/active_support/inflector/methods.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/activesupport/lib/active_support/inflector/methods.rb b/activesupport/lib/active_support/inflector/methods.rb index e5b0cf4f9e..2acc6ddee5 100644 --- a/activesupport/lib/active_support/inflector/methods.rb +++ b/activesupport/lib/active_support/inflector/methods.rb @@ -212,10 +212,10 @@ module ActiveSupport # Go down the ancestors to check it it's owned # directly before we reach Object or the end of ancestors. - constant = constant.ancestors.inject do |constant, ancestor| - break constant if ancestor == Object + constant = constant.ancestors.inject do |const, ancestor| + break const if ancestor == Object break ancestor if ancestor.const_defined?(name, false) - constant + const end # owner is in Object, so raise -- cgit v1.2.3 From e5e2ba14c31f3eb97e5fba31a50da8d26ea3a77e Mon Sep 17 00:00:00 2001 From: kennyj Date: Sun, 20 May 2012 00:14:40 +0900 Subject: Don't use assert_block method. It will be deprecated. --- actionpack/test/ts_isolated.rb | 2 +- activesupport/test/ts_isolated.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/actionpack/test/ts_isolated.rb b/actionpack/test/ts_isolated.rb index 595b4018e9..c44c5d8968 100644 --- a/actionpack/test/ts_isolated.rb +++ b/actionpack/test/ts_isolated.rb @@ -9,7 +9,7 @@ class TestIsolated < ActiveSupport::TestCase define_method("test #{file}") do command = "#{ruby} -Ilib:test #{file}" result = silence_stderr { `#{command}` } - assert_block("#{command}\n#{result}") { $?.to_i.zero? } + assert $?.to_i.zero?, "#{command}\n#{result}" end end end diff --git a/activesupport/test/ts_isolated.rb b/activesupport/test/ts_isolated.rb index 938bb4ee99..2c217157d3 100644 --- a/activesupport/test/ts_isolated.rb +++ b/activesupport/test/ts_isolated.rb @@ -10,7 +10,7 @@ class TestIsolated < ActiveSupport::TestCase define_method("test #{file}") do command = "#{ruby} -Ilib:test #{file}" result = silence_stderr { `#{command}` } - assert_block("#{command}\n#{result}") { $?.to_i.zero? } + assert $?.to_i.zero?, "#{command}\n#{result}" end end end -- cgit v1.2.3 From 2fe281323c8ccebc592d423b69b5b03ac9254b29 Mon Sep 17 00:00:00 2001 From: kennyj Date: Sun, 20 May 2012 01:38:14 +0900 Subject: Fix a problem of translate_exception method in Japanese. --- .../active_record/connection_adapters/postgresql_adapter.rb | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 14bc95abfe..15c3d7be36 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -1336,11 +1336,15 @@ module ActiveRecord @connection.server_version end + # See http://www.postgresql.org/docs/9.1/static/errcodes-appendix.html + FOREIGN_KEY_VIOLATION = "23503" + UNIQUE_VIOLATION = "23505" + def translate_exception(exception, message) - case exception.message - when /duplicate key value violates unique constraint/ + case exception.result.error_field(PGresult::PG_DIAG_SQLSTATE) + when UNIQUE_VIOLATION RecordNotUnique.new(message, exception) - when /violates foreign key constraint/ + when FOREIGN_KEY_VIOLATION InvalidForeignKey.new(message, exception) else super -- cgit v1.2.3 From c2d416fe7712cbaf69036f9e638c825e08415e34 Mon Sep 17 00:00:00 2001 From: Patrick Mahoney Date: Sat, 19 May 2012 11:45:55 -0500 Subject: Synchronize read and modification of @reserved_connections hash to avoid concurrency error. --- .../connection_adapters/abstract/connection_pool.rb | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb index 46c7fc71ac..c6699737b4 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -139,14 +139,18 @@ module ActiveRecord # #connection can be called any number of times; the connection is # held in a hash keyed by the thread id. def connection - @reserved_connections[current_connection_id] ||= checkout + synchronize do + @reserved_connections[current_connection_id] ||= checkout + end end # Is there an open connection that is being used for the current thread? def active_connection? - @reserved_connections.fetch(current_connection_id) { - return false - }.in_use? + synchronize do + @reserved_connections.fetch(current_connection_id) { + return false + }.in_use? + end end # Signal that the thread is finished with the current connection. -- cgit v1.2.3 From 32a433e1c04264b891a4b4793ac0c75f0acaf9df Mon Sep 17 00:00:00 2001 From: Dmitry Vorotilin Date: Sun, 29 Apr 2012 19:16:32 +0400 Subject: Show in log correct wrapped keys --- actionpack/lib/action_controller/metal/params_wrapper.rb | 3 ++- actionpack/test/controller/params_wrapper_test.rb | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_controller/metal/params_wrapper.rb b/actionpack/lib/action_controller/metal/params_wrapper.rb index 1f52c164de..aa67fa7f23 100644 --- a/actionpack/lib/action_controller/metal/params_wrapper.rb +++ b/actionpack/lib/action_controller/metal/params_wrapper.rb @@ -193,7 +193,8 @@ module ActionController def process_action(*args) if _wrapper_enabled? wrapped_hash = _wrap_parameters request.request_parameters - wrapped_filtered_hash = _wrap_parameters request.filtered_parameters + wrapped_keys = request.request_parameters.keys + wrapped_filtered_hash = _wrap_parameters request.filtered_parameters.slice(*wrapped_keys) # This will make the wrapped hash accessible from controller and view request.parameters.merge! wrapped_hash diff --git a/actionpack/test/controller/params_wrapper_test.rb b/actionpack/test/controller/params_wrapper_test.rb index fa1608b9df..5b05f77045 100644 --- a/actionpack/test/controller/params_wrapper_test.rb +++ b/actionpack/test/controller/params_wrapper_test.rb @@ -37,6 +37,14 @@ class ParamsWrapperTest < ActionController::TestCase UsersController.last_parameters = nil end + def test_filtered_parameters + with_default_wrapper_options do + @request.env['CONTENT_TYPE'] = 'application/json' + post :parse, { 'username' => 'sikachu' } + assert_equal @request.filtered_parameters, { 'controller' => 'params_wrapper_test/users', 'action' => 'parse', 'username' => 'sikachu', 'user' => { 'username' => 'sikachu' } } + end + end + def test_derived_name_from_controller with_default_wrapper_options do @request.env['CONTENT_TYPE'] = 'application/json' -- cgit v1.2.3 From 2575508a385f4a8003ea1277025c018583971e1d Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Sun, 20 May 2012 00:24:35 -0700 Subject: Improve docs for `try` by adding note on `BasicObject` [ci skip] closes #5790 --- activesupport/lib/active_support/core_ext/object/try.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/activesupport/lib/active_support/core_ext/object/try.rb b/activesupport/lib/active_support/core_ext/object/try.rb index 48eb546a7d..30c835f5cd 100644 --- a/activesupport/lib/active_support/core_ext/object/try.rb +++ b/activesupport/lib/active_support/core_ext/object/try.rb @@ -7,6 +7,10 @@ class Object # # If try is called without a method to call, it will yield any given block with the object. # + # Please also note that +try+ is defined on +Object+, therefore it won't work with + # subclasses of +BasicObject+. For example, using try with +SimpleDelegator+ will + # delegate +try+ to target instead of calling it on delegator itself. + # # ==== Examples # # Without +try+ -- cgit v1.2.3 From dcce01132de9734c9f7a6973bfff1b16b07ef84a Mon Sep 17 00:00:00 2001 From: David Chelimsky Date: Sat, 19 May 2012 16:28:14 -0500 Subject: Raise Assertion instead of RoutingError for routing assertion failures. Before this change, assert_recognizes, assert_generates, and assert_routing raised ActionController::RoutingError when they failed to recognize the route. This commit changes them to raise Assertion instead. This aligns with convention for logical failures, and supports reporting tools that care about the difference between logical failures and errors e.g. the summary at the end of a test run. - Fixes #5899 --- actionpack/CHANGELOG.md | 3 +++ .../action_dispatch/testing/assertions/routing.rb | 20 +++++++++++++------- actionpack/test/controller/resources_test.rb | 10 +++++----- actionpack/test/dispatch/routing_assertions_test.rb | 12 ++++++------ 4 files changed, 27 insertions(+), 18 deletions(-) diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index e625bbe7af..0f0e7b0975 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -186,6 +186,9 @@ * `ActionView::Helpers::TextHelper#highlight` now defaults to the HTML5 `mark` element. *Brian Cardarella* +* `assert_generates`, `assert_recognizes`, and `assert_routing` all raise + `Assertion` instead of `RoutingError` *David Chelimsky* + ## Rails 3.2.3 (March 30, 2012) ## diff --git a/actionpack/lib/action_dispatch/testing/assertions/routing.rb b/actionpack/lib/action_dispatch/testing/assertions/routing.rb index 567ca0c392..41fa3a4b95 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/routing.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/routing.rb @@ -69,11 +69,9 @@ module ActionDispatch # assert_generates "changesets/12", { :controller => 'scm', :action => 'show_diff', :revision => "12" } def assert_generates(expected_path, options, defaults={}, extras = {}, message=nil) if expected_path =~ %r{://} - begin + fail_on(URI::InvalidURIError) do uri = URI.parse(expected_path) expected_path = uri.path.to_s.empty? ? "/" : uri.path - rescue URI::InvalidURIError => e - raise ActionController::RoutingError, e.message end else expected_path = "/#{expected_path}" unless expected_path.first == '/' @@ -189,14 +187,12 @@ module ActionDispatch request = ActionController::TestRequest.new if path =~ %r{://} - begin + fail_on(URI::InvalidURIError) do uri = URI.parse(path) request.env["rack.url_scheme"] = uri.scheme || "http" request.host = uri.host if uri.host request.port = uri.port if uri.port request.path = uri.path.to_s.empty? ? "/" : uri.path - rescue URI::InvalidURIError => e - raise ActionController::RoutingError, e.message end else path = "/#{path}" unless path.first == "/" @@ -205,11 +201,21 @@ module ActionDispatch request.request_method = method if method - params = @routes.recognize_path(path, { :method => method, :extras => extras }) + params = fail_on(ActionController::RoutingError) do + @routes.recognize_path(path, { :method => method, :extras => extras }) + end request.path_parameters = params.with_indifferent_access request end + + def fail_on(exception_class) + begin + yield + rescue exception_class => e + raise MiniTest::Assertion, e.message + end + end end end end diff --git a/actionpack/test/controller/resources_test.rb b/actionpack/test/controller/resources_test.rb index 9fc875014c..de1bff17eb 100644 --- a/actionpack/test/controller/resources_test.rb +++ b/actionpack/test/controller/resources_test.rb @@ -109,7 +109,7 @@ class ResourcesTest < ActionController::TestCase expected_options = {:controller => 'messages', :action => 'show', :id => '1.1.1'} with_restful_routing :messages do - assert_raise(ActionController::RoutingError) do + assert_raise(Assertion) do assert_recognizes(expected_options, :path => 'messages/1.1.1', :method => :get) end end @@ -660,15 +660,15 @@ class ResourcesTest < ActionController::TestCase options = { :controller => controller_name.to_s } collection_path = "/#{controller_name}" - assert_raise(ActionController::RoutingError) do + assert_raise(Assertion) do assert_recognizes(options.merge(:action => 'update'), :path => collection_path, :method => :patch) end - assert_raise(ActionController::RoutingError) do + assert_raise(Assertion) do assert_recognizes(options.merge(:action => 'update'), :path => collection_path, :method => :put) end - assert_raise(ActionController::RoutingError) do + assert_raise(Assertion) do assert_recognizes(options.merge(:action => 'destroy'), :path => collection_path, :method => :delete) end end @@ -1353,7 +1353,7 @@ class ResourcesTest < ActionController::TestCase end def assert_not_recognizes(expected_options, path) - assert_raise ActionController::RoutingError, Assertion do + assert_raise Assertion do assert_recognizes(expected_options, path) end end diff --git a/actionpack/test/dispatch/routing_assertions_test.rb b/actionpack/test/dispatch/routing_assertions_test.rb index 517354ae58..aea4489852 100644 --- a/actionpack/test/dispatch/routing_assertions_test.rb +++ b/actionpack/test/dispatch/routing_assertions_test.rb @@ -54,21 +54,21 @@ class RoutingAssertionsTest < ActionController::TestCase end def test_assert_recognizes_with_hash_constraint - assert_raise(ActionController::RoutingError) do + assert_raise(Assertion) do assert_recognizes({ :controller => 'secure_articles', :action => 'index' }, 'http://test.host/secure/articles') end assert_recognizes({ :controller => 'secure_articles', :action => 'index', :protocol => 'https://' }, 'https://test.host/secure/articles') end def test_assert_recognizes_with_block_constraint - assert_raise(ActionController::RoutingError) do + assert_raise(Assertion) do assert_recognizes({ :controller => 'block_articles', :action => 'index' }, 'http://test.host/block/articles') end assert_recognizes({ :controller => 'block_articles', :action => 'index' }, 'https://test.host/block/articles') end def test_assert_recognizes_with_query_constraint - assert_raise(ActionController::RoutingError) do + assert_raise(Assertion) do assert_recognizes({ :controller => 'query_articles', :action => 'index', :use_query => 'false' }, '/query/articles', { :use_query => 'false' }) end assert_recognizes({ :controller => 'query_articles', :action => 'index', :use_query => 'true' }, '/query/articles', { :use_query => 'true' }) @@ -87,14 +87,14 @@ class RoutingAssertionsTest < ActionController::TestCase end def test_assert_routing_with_hash_constraint - assert_raise(ActionController::RoutingError) do + assert_raise(Assertion) do assert_routing('http://test.host/secure/articles', { :controller => 'secure_articles', :action => 'index' }) end assert_routing('https://test.host/secure/articles', { :controller => 'secure_articles', :action => 'index', :protocol => 'https://' }) end def test_assert_routing_with_block_constraint - assert_raise(ActionController::RoutingError) do + assert_raise(Assertion) do assert_routing('http://test.host/block/articles', { :controller => 'block_articles', :action => 'index' }) end assert_routing('https://test.host/block/articles', { :controller => 'block_articles', :action => 'index' }) @@ -107,7 +107,7 @@ class RoutingAssertionsTest < ActionController::TestCase end assert_routing('/artikel', :controller => 'articles', :action => 'index') - assert_raise(ActionController::RoutingError) do + assert_raise(Assertion) do assert_routing('/articles', { :controller => 'articles', :action => 'index' }) end end -- cgit v1.2.3 From ad3f47dc2f27a74b43c29ae66820f15239c81f21 Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Sun, 20 May 2012 21:12:25 +0530 Subject: fix closing tag [ci skip] --- actionpack/lib/action_view/helpers/tag_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/action_view/helpers/tag_helper.rb b/actionpack/lib/action_view/helpers/tag_helper.rb index 498be596ad..9572f1c192 100644 --- a/actionpack/lib/action_view/helpers/tag_helper.rb +++ b/actionpack/lib/action_view/helpers/tag_helper.rb @@ -41,7 +41,7 @@ module ActionView # thus accessed as dataset.userId. # # Values are encoded to JSON, with the exception of strings and symbols. - # This may come in handy when using jQuery's HTML5-aware .data() + # This may come in handy when using jQuery's HTML5-aware .data() # from 1.4.3. # # ==== Examples -- cgit v1.2.3 From 972376a9952ce3a1cb1babb9e408900d314ac577 Mon Sep 17 00:00:00 2001 From: Andrew White Date: Sun, 20 May 2012 09:58:15 +0100 Subject: Correct order of expected and actual arguments --- actionpack/lib/action_dispatch/testing/assertions/response.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/action_dispatch/testing/assertions/response.rb b/actionpack/lib/action_dispatch/testing/assertions/response.rb index 3d121b6b9c..b4c8f839ac 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/response.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/response.rb @@ -28,7 +28,7 @@ module ActionDispatch assert @response.send("#{type}?"), message else code = Rack::Utils::SYMBOL_TO_STATUS_CODE[type] - assert_equal @response.response_code, code, message + assert_equal code, @response.response_code, message end else assert_equal type, @response.response_code, message -- cgit v1.2.3 From 66eb3f02cc0894f08c4f912ba8bf6fb1f87e9a4a Mon Sep 17 00:00:00 2001 From: Andrew White Date: Sun, 20 May 2012 10:04:12 +0100 Subject: Raise ActionController::BadRequest for malformed parameter hashes. Currently Rack raises a TypeError when it encounters a malformed or ambiguous hash like `foo[]=bar&foo[4]=bar`. Rather than pass this through to the application this commit captures the exception and re-raises it using a new ActionController::BadRequest exception. The new ActionController::BadRequest exception returns a 400 error instead of the 500 error that would've been returned by the original TypeError. This allows exception notification libraries to ignore these errors if so desired. Closes #3051 --- actionpack/CHANGELOG.md | 2 ++ actionpack/lib/action_controller/metal/exceptions.rb | 5 ++++- actionpack/lib/action_dispatch/http/request.rb | 13 ++++++++++--- .../lib/action_dispatch/middleware/exception_wrapper.rb | 3 ++- actionpack/test/dispatch/debug_exceptions_test.rb | 6 ++++++ .../test/dispatch/request/query_string_parsing_test.rb | 11 +++++++++++ .../dispatch/request/url_encoded_params_parsing_test.rb | 11 +++++++++++ actionpack/test/dispatch/request_test.rb | 2 +- 8 files changed, 47 insertions(+), 6 deletions(-) diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index 0f0e7b0975..5d4ae16c09 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,5 +1,7 @@ ## Rails 4.0.0 (unreleased) ## +* Malformed query and request parameter hashes now raise ActionController::BadRequest. *Andrew White* + * Add `divider` option to `grouped_options_for_select` to generate a separator `optgroup` automatically, and deprecate `prompt` as third argument, in favor of using an options hash. *Nicholas Greenfield* diff --git a/actionpack/lib/action_controller/metal/exceptions.rb b/actionpack/lib/action_controller/metal/exceptions.rb index 90648c37ad..8fd8f4797c 100644 --- a/actionpack/lib/action_controller/metal/exceptions.rb +++ b/actionpack/lib/action_controller/metal/exceptions.rb @@ -2,6 +2,9 @@ module ActionController class ActionControllerError < StandardError #:nodoc: end + class BadRequest < ActionControllerError #:nodoc: + end + class RenderError < ActionControllerError #:nodoc: end @@ -38,7 +41,7 @@ module ActionController class UnknownHttpMethod < ActionControllerError #:nodoc: end - + class UnknownFormat < ActionControllerError #:nodoc: end end diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index 56908b5794..aa5ba3e8a5 100644 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -231,17 +231,24 @@ module ActionDispatch # Override Rack's GET method to support indifferent access def GET - @env["action_dispatch.request.query_parameters"] ||= (normalize_parameters(super) || {}) + begin + @env["action_dispatch.request.query_parameters"] ||= (normalize_parameters(super) || {}) + rescue TypeError => e + raise ActionController::BadRequest, "Invalid query parameters: #{e.message}" + end end alias :query_parameters :GET # Override Rack's POST method to support indifferent access def POST - @env["action_dispatch.request.request_parameters"] ||= (normalize_parameters(super) || {}) + begin + @env["action_dispatch.request.request_parameters"] ||= (normalize_parameters(super) || {}) + rescue TypeError => e + raise ActionController::BadRequest, "Invalid request parameters: #{e.message}" + end end alias :request_parameters :POST - # Returns the authorization header regardless of whether it was specified directly or through one of the # proxy alternatives. def authorization diff --git a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb index a8f49bd3bd..7349b578d2 100644 --- a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb +++ b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb @@ -12,7 +12,8 @@ module ActionDispatch 'ActionController::MethodNotAllowed' => :method_not_allowed, 'ActionController::NotImplemented' => :not_implemented, 'ActionController::UnknownFormat' => :not_acceptable, - 'ActionController::InvalidAuthenticityToken' => :unprocessable_entity + 'ActionController::InvalidAuthenticityToken' => :unprocessable_entity, + 'ActionController::BadRequest' => :bad_request ) cattr_accessor :rescue_templates diff --git a/actionpack/test/dispatch/debug_exceptions_test.rb b/actionpack/test/dispatch/debug_exceptions_test.rb index 11c292d61a..6ff651ad52 100644 --- a/actionpack/test/dispatch/debug_exceptions_test.rb +++ b/actionpack/test/dispatch/debug_exceptions_test.rb @@ -35,6 +35,8 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest raise ActionController::InvalidAuthenticityToken when "/not_found_original_exception" raise ActionView::Template::Error.new('template', AbstractController::ActionNotFound.new) + when "/bad_request" + raise ActionController::BadRequest else raise "puke!" end @@ -88,6 +90,10 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest get "/method_not_allowed", {}, {'action_dispatch.show_exceptions' => true} assert_response 405 assert_match(/ActionController::MethodNotAllowed/, body) + + get "/bad_request", {}, {'action_dispatch.show_exceptions' => true} + assert_response 400 + assert_match(/ActionController::BadRequest/, body) end test "does not show filtered parameters" do diff --git a/actionpack/test/dispatch/request/query_string_parsing_test.rb b/actionpack/test/dispatch/request/query_string_parsing_test.rb index d14f188e30..c3f009ab15 100644 --- a/actionpack/test/dispatch/request/query_string_parsing_test.rb +++ b/actionpack/test/dispatch/request/query_string_parsing_test.rb @@ -105,6 +105,17 @@ class QueryStringParsingTest < ActionDispatch::IntegrationTest ) end + test "ambiguous query string returns a bad request" do + with_routing do |set| + set.draw do + get ':action', :to => ::QueryStringParsingTest::TestController + end + + get "/parse", nil, "QUERY_STRING" => "foo[]=bar&foo[4]=bar" + assert_response :bad_request + end + end + private def assert_parses(expected, actual) with_routing do |set| diff --git a/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb b/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb index 568e220b15..e9b59f55a7 100644 --- a/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb +++ b/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb @@ -126,6 +126,17 @@ class UrlEncodedParamsParsingTest < ActionDispatch::IntegrationTest assert_parses expected, query end + test "ambiguous params returns a bad request" do + with_routing do |set| + set.draw do + post ':action', :to => ::UrlEncodedParamsParsingTest::TestController + end + + post "/parse", "foo[]=bar&foo[4]=bar" + assert_response :bad_request + end + end + private def with_test_routing with_routing do |set| diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb index 94d0e09842..54fc1b208d 100644 --- a/actionpack/test/dispatch/request_test.rb +++ b/actionpack/test/dispatch/request_test.rb @@ -561,7 +561,7 @@ class RequestTest < ActiveSupport::TestCase begin request = stub_request(mock_rack_env) request.parameters - rescue TypeError + rescue ActionController::BadRequest # rack will raise a TypeError when parsing this query string end assert_equal({}, request.parameters) -- cgit v1.2.3 From 3fc561a1f71edf1c2bae695cafa03909d24a5ca3 Mon Sep 17 00:00:00 2001 From: Andrew White Date: Sun, 20 May 2012 16:44:42 +0100 Subject: Return 400 Bad Request for URL paths with invalid encoding. Passing path parameters with invalid encoding is likely to trigger errors further on like `ArgumentError (invalid byte sequence in UTF-8)`. This will result in a 500 error whereas the better error to return is a 400 error which allows exception notification libraries to filter it out if they wish. Closes #4450 --- actionpack/CHANGELOG.md | 2 ++ .../lib/action_dispatch/routing/redirection.rb | 9 +++++++ .../lib/action_dispatch/routing/route_set.rb | 9 +++++++ actionpack/test/dispatch/routing_test.rb | 31 ++++++++++++++++++++++ 4 files changed, 51 insertions(+) diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index 5d4ae16c09..94b3490b80 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,5 +1,7 @@ ## Rails 4.0.0 (unreleased) ## +* URL path parameters with invalid encoding now raise ActionController::BadRequest. *Andrew White* + * Malformed query and request parameter hashes now raise ActionController::BadRequest. *Andrew White* * Add `divider` option to `grouped_options_for_select` to generate a separator diff --git a/actionpack/lib/action_dispatch/routing/redirection.rb b/actionpack/lib/action_dispatch/routing/redirection.rb index b3823bb496..205ff44b1c 100644 --- a/actionpack/lib/action_dispatch/routing/redirection.rb +++ b/actionpack/lib/action_dispatch/routing/redirection.rb @@ -2,6 +2,7 @@ require 'action_dispatch/http/request' require 'active_support/core_ext/uri' require 'active_support/core_ext/array/extract_options' require 'rack/utils' +require 'action_controller/metal/exceptions' module ActionDispatch module Routing @@ -16,6 +17,14 @@ module ActionDispatch def call(env) req = Request.new(env) + # If any of the path parameters has a invalid encoding then + # raise since it's likely to trigger errors further on. + req.symbolized_path_parameters.each do |key, value| + unless value.valid_encoding? + raise ActionController::BadRequest, "Invalid parameter: #{key} => #{value}" + end + end + uri = URI.parse(path(req.symbolized_path_parameters, req)) uri.scheme ||= req.scheme uri.host ||= req.host diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 0ae668d42a..1d0a67d0d2 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -26,6 +26,15 @@ module ActionDispatch def call(env) params = env[PARAMETERS_KEY] + + # If any of the path parameters has a invalid encoding then + # raise since it's likely to trigger errors further on. + params.each do |key, value| + unless value.valid_encoding? + raise ActionController::BadRequest, "Invalid parameter: #{key} => #{value}" + end + end + prepare_params!(params) # Just raise undefined constant errors if a controller was specified as default. diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index 1a8f40037f..00d09282ca 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -2697,3 +2697,34 @@ class TestUrlConstraints < ActionDispatch::IntegrationTest assert_response :success end end + +class TestInvalidUrls < ActionDispatch::IntegrationTest + class FooController < ActionController::Base + def show + render :text => "foo#show" + end + end + + test "invalid UTF-8 encoding returns a 400 Bad Request" do + with_routing do |set| + set.draw do + get "/bar/:id", :to => redirect("/foo/show/%{id}") + get "/foo/show(/:id)", :to => "test_invalid_urls/foo#show" + get "/foo(/:action(/:id))", :to => "test_invalid_urls/foo" + get "/:controller(/:action(/:id))" + end + + get "/%E2%EF%BF%BD%A6" + assert_response :bad_request + + get "/foo/%E2%EF%BF%BD%A6" + assert_response :bad_request + + get "/foo/show/%E2%EF%BF%BD%A6" + assert_response :bad_request + + get "/bar/%E2%EF%BF%BD%A6" + assert_response :bad_request + end + end +end \ No newline at end of file -- cgit v1.2.3 From 79b38c386ae3817df5321522ab9ea169c028de96 Mon Sep 17 00:00:00 2001 From: Andrew White Date: Sun, 20 May 2012 19:02:58 +0100 Subject: Escape the extension when normalizing the action cache path. Although no recognized formats use non-ASCII characters, sometimes they can be included in the :format parameter because of invalid URLS. To prevent encoding incompatibility errors we need to escape them before passing the path to URI.unescape. Closes #4379 --- .../lib/action_controller/caching/actions.rb | 5 ++-- actionpack/test/controller/caching_test.rb | 31 +++++++++++++++++++++- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/actionpack/lib/action_controller/caching/actions.rb b/actionpack/lib/action_controller/caching/actions.rb index 80901b8bf3..0238135bc1 100644 --- a/actionpack/lib/action_controller/caching/actions.rb +++ b/actionpack/lib/action_controller/caching/actions.rb @@ -47,7 +47,7 @@ module ActionController #:nodoc: # And you can also use :if (or :unless) to pass a # proc that specifies when the action should be cached. # - # As of Rails 3.0, you can also pass :expires_in with a time + # As of Rails 3.0, you can also pass :expires_in with a time # interval (in seconds) to schedule expiration of the cached item. # # The following example depicts some of the points made above: @@ -178,8 +178,9 @@ module ActionController #:nodoc: private def normalize!(path) + ext = URI.parser.escape(extension) if extension path << 'index' if path[-1] == ?/ - path << ".#{extension}" if extension and !path.split('?', 2).first.ends_with?(".#{extension}") + path << ".#{ext}" if extension and !path.split('?', 2).first.ends_with?(".#{ext}") URI.parser.unescape(path) end end diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index 9efe328d62..d5afef9086 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -223,6 +223,7 @@ end class ActionCachingTestController < CachingController rescue_from(Exception) { head 500 } + rescue_from(ActionController::UnknownFormat) { head :not_acceptable } if defined? ActiveRecord rescue_from(ActiveRecord::RecordNotFound) { head :not_found } end @@ -230,7 +231,7 @@ class ActionCachingTestController < CachingController # Eliminate uninitialized ivar warning before_filter { @title = nil } - caches_action :index, :redirected, :forbidden, :if => Proc.new { |c| !c.request.format.json? }, :expires_in => 1.hour + caches_action :index, :redirected, :forbidden, :if => Proc.new { |c| c.request.format && !c.request.format.json? }, :expires_in => 1.hour caches_action :show, :cache_path => 'http://test.host/custom/show' caches_action :edit, :cache_path => Proc.new { |c| c.params[:id] ? "http://test.host/#{c.params[:id]};edit" : "http://test.host/edit" } caches_action :with_layout @@ -239,6 +240,7 @@ class ActionCachingTestController < CachingController caches_action :with_layout_proc_param, :layout => Proc.new { |c| c.params[:layout] } caches_action :record_not_found, :four_oh_four, :simple_runtime_error caches_action :streaming + caches_action :invalid layout 'talk_from_action' @@ -303,6 +305,14 @@ class ActionCachingTestController < CachingController def streaming render :text => "streaming", :stream => true end + + def invalid + @cache_this = MockTime.now.to_f.to_s + + respond_to do |format| + format.json{ render :json => @cache_this } + end + end end class MockTime < Time @@ -690,6 +700,25 @@ class ActionCacheTest < ActionController::TestCase assert fragment_exist?('hostname.com/action_caching_test/streaming') end + def test_invalid_format_returns_not_acceptable + get :invalid, :format => "json" + assert_response :success + cached_time = content_to_cache + assert_equal cached_time, @response.body + + assert fragment_exist?("hostname.com/action_caching_test/invalid.json") + + get :invalid, :format => "json" + assert_response :success + assert_equal cached_time, @response.body + + get :invalid, :format => "xml" + assert_response :not_acceptable + + get :invalid, :format => "\xC3\x83" + assert_response :not_acceptable + end + private def content_to_cache assigns(:cache_this) -- cgit v1.2.3 From 08a5b10eb1c750927c05e50f182e070c1321fb81 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Sun, 20 May 2012 11:11:20 -0700 Subject: Revert "Merge pull request #5702 from oscardelben/patch-4" This reverts commit cae1ca7d1be9c79c7ef012a1f62aef9d3bb815f8, reversing changes made to da97cf016a8ffd1f54f804cd881f393e5d6efc18. These changes break the build, it needs more investigation. --- activemodel/lib/active_model/attribute_methods.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/activemodel/lib/active_model/attribute_methods.rb b/activemodel/lib/active_model/attribute_methods.rb index 039cd8bdf3..99918fdb96 100644 --- a/activemodel/lib/active_model/attribute_methods.rb +++ b/activemodel/lib/active_model/attribute_methods.rb @@ -102,6 +102,7 @@ module ActiveModel # person.name # => nil def attribute_method_prefix(*prefixes) self.attribute_method_matchers += prefixes.map { |prefix| AttributeMethodMatcher.new :prefix => prefix } + undefine_attribute_methods end # Declares a method available for all attributes with the given suffix. @@ -138,6 +139,7 @@ module ActiveModel # person.name_short? # => true def attribute_method_suffix(*suffixes) self.attribute_method_matchers += suffixes.map { |suffix| AttributeMethodMatcher.new :suffix => suffix } + undefine_attribute_methods end # Declares a method available for all attributes with the given prefix @@ -175,6 +177,7 @@ module ActiveModel # person.name # => 'Gemma' def attribute_method_affix(*affixes) self.attribute_method_matchers += affixes.map { |affix| AttributeMethodMatcher.new :prefix => affix[:prefix], :suffix => affix[:suffix] } + undefine_attribute_methods end @@ -222,7 +225,6 @@ module ActiveModel # end # end def define_attribute_methods(*attr_names) - undefine_attribute_methods attr_names.flatten.each { |attr_name| define_attribute_method(attr_name) } end -- cgit v1.2.3 From 45d059b401f4fdd926d263ad8a3195b5b2223a1c Mon Sep 17 00:00:00 2001 From: Ivan Kukobko Date: Sun, 20 May 2012 22:11:32 +0300 Subject: fixed typo in word finiding --- activerecord/test/cases/relations_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 4a56ae0d23..2dc8f0053b 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -133,7 +133,7 @@ class RelationTest < ActiveRecord::TestCase assert topics.loaded? end - def test_finiding_with_subquery + def test_finding_with_subquery relation = Topic.where(:approved => true) assert_equal relation.to_a, Topic.select('*').from(relation).to_a assert_equal relation.to_a, Topic.select('subquery.*').from(relation).to_a -- cgit v1.2.3 From 03402d206ae1d1977e5283173ecb43a88aacead0 Mon Sep 17 00:00:00 2001 From: Francesco Rodriguez Date: Sun, 20 May 2012 16:11:52 -0500 Subject: update CollectionProxy#destroy_all documentation --- .../lib/active_record/associations/collection_proxy.rb | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index 647d495d56..21c5e3fc5a 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -221,18 +221,26 @@ module ActiveRecord ## # :method: destroy_all - # Destroy all the records from this association. + # Deletes the records of the collection directly from the database. # # class Person < ActiveRecord::Base # has_many :pets # end # # person.pets.size # => 3 + # person.pets + # # => [ + # # #, + # # #, + # # # + # # ] # # person.pets.destroy_all # # person.pets.size # => 0 # person.pets # => [] + # + # Pet.find(1) # => Couldn't find Pet with id=1 ## # :method: empty? -- cgit v1.2.3 From a78ee05da102b85f45ecc1a6f230817430fe2aea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Sun, 20 May 2012 18:16:03 -0300 Subject: Fix CHANGELOG order and add a brief description of the changes in the Action Pack in the upgrading guide. [ci skip] --- actionpack/CHANGELOG.md | 6 +++--- guides/source/upgrading_ruby_on_rails.textile | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index 94b3490b80..1e6e84ea4a 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,5 +1,8 @@ ## Rails 4.0.0 (unreleased) ## +* `assert_generates`, `assert_recognizes`, and `assert_routing` all raise + `Assertion` instead of `RoutingError` *David Chelimsky* + * URL path parameters with invalid encoding now raise ActionController::BadRequest. *Andrew White* * Malformed query and request parameter hashes now raise ActionController::BadRequest. *Andrew White* @@ -190,9 +193,6 @@ * `ActionView::Helpers::TextHelper#highlight` now defaults to the HTML5 `mark` element. *Brian Cardarella* -* `assert_generates`, `assert_recognizes`, and `assert_routing` all raise - `Assertion` instead of `RoutingError` *David Chelimsky* - ## Rails 3.2.3 (March 30, 2012) ## diff --git a/guides/source/upgrading_ruby_on_rails.textile b/guides/source/upgrading_ruby_on_rails.textile index 2b2e65c813..02407a5fe8 100644 --- a/guides/source/upgrading_ruby_on_rails.textile +++ b/guides/source/upgrading_ruby_on_rails.textile @@ -42,6 +42,10 @@ h4(#active_model4_0). ActiveModel Rails 4.0 has changed how errors attach with the ConfirmationValidator. Now when confirmation validations fail the error will be attached to :#{attribute}_confirmation instead of attribute. +h4(#action_pack4_0). ActionPack + +Rails 4.0 changed how assert_generates, assert_recognizes, and assert_routing work. Now all these assertions raise Assertion instead of RoutingError. + h3. Upgrading from Rails 3.1 to Rails 3.2 If your application is currently on any version of Rails older than 3.1.x, you should upgrade to Rails 3.1 before attempting an update to Rails 3.2. -- cgit v1.2.3 From 74c4e7ba342d6450b25763652ec0266494a56458 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sun, 20 May 2012 14:01:52 -0700 Subject: Merge pull request #6407 from pinetops/565c1b0a0772ac6cf91c77e9285806f7b028614c Template concurrency fixes Conflicts: actionpack/lib/action_view/template.rb --- actionpack/lib/action_view/template.rb | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb index edb3d427d5..cd79468502 100644 --- a/actionpack/lib/action_view/template.rb +++ b/actionpack/lib/action_view/template.rb @@ -1,6 +1,7 @@ require 'active_support/core_ext/object/blank' require 'active_support/core_ext/object/try' require 'active_support/core_ext/kernel/singleton_class' +require 'thread' module ActionView # = Action View Template @@ -122,6 +123,7 @@ module ActionView @virtual_path = details[:virtual_path] @updated_at = details[:updated_at] || Time.now @formats = Array(format).map { |f| f.is_a?(Mime::Type) ? f.ref : f } + @compile_mutex = Mutex.new end # Returns if the underlying handler supports streaming. If so, @@ -223,18 +225,28 @@ module ActionView def compile!(view) #:nodoc: return if @compiled - if view.is_a?(ActionView::CompiledTemplates) - mod = ActionView::CompiledTemplates - else - mod = view.singleton_class - end + # Templates can be used concurrently in threaded environments + # so compilation and any instance variable modification must + # be synchronized + @compile_mutex.synchronize do + # Any thread holding this lock will be compiling the template needed + # by the threads waiting. So re-check the @compiled flag to avoid + # re-compilation + return if @compiled + + if view.is_a?(ActionView::CompiledTemplates) + mod = ActionView::CompiledTemplates + else + mod = view.singleton_class + end - compile(view, mod) + compile(view, mod) - # Just discard the source if we have a virtual path. This - # means we can get the template back. - @source = nil if @virtual_path - @compiled = true + # Just discard the source if we have a virtual path. This + # means we can get the template back. + @source = nil if @virtual_path + @compiled = true + end end # Among other things, this method is responsible for properly setting -- cgit v1.2.3 From 7c95be54b4c3f8ad2273eea39afa233f8f8b31c1 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Sun, 20 May 2012 16:19:11 -0700 Subject: Fix generators to help with ambiguous `ApplicationController` issue In development mode, dependencies are loaded dynamically at runtime, using `const_missing`. Because of that, when one of the constants is already loaded and `const_missing` is not triggered, user can end up with unexpected results. Given such file in an Engine: ```ruby module Blog class PostsController < ApplicationController end end ``` If you load it first, before loading any application files, it will correctly load `Blog::ApplicationController`, because second line will hit `const_missing`. However if you load `ApplicationController` first, the constant will be loaded already, `const_missing` hook will not be fired and in result `PostsController` will inherit from `ApplicationController` instead of `Blog::ApplicationController`. Since it can't be fixed in `AS::Dependencies`, the easiest fix is to just explicitly load application controller. closes #6413 --- railties/lib/rails/generators/named_base.rb | 4 ++++ .../generators/rails/controller/templates/controller.rb | 4 ++++ .../rails/scaffold_controller/templates/controller.rb | 4 ++++ railties/test/generators/namespaced_generators_test.rb | 17 ++++++++++++----- 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/railties/lib/rails/generators/named_base.rb b/railties/lib/rails/generators/named_base.rb index e85d1b8fa2..63703176de 100644 --- a/railties/lib/rails/generators/named_base.rb +++ b/railties/lib/rails/generators/named_base.rb @@ -79,6 +79,10 @@ module Rails @class_path end + def namespaced_file_path + @namespaced_file_path ||= namespaced_class_path.join("/") + end + def namespaced_class_path @namespaced_class_path ||= begin namespace_path = namespace.name.split("::").map {|m| m.underscore } diff --git a/railties/lib/rails/generators/rails/controller/templates/controller.rb b/railties/lib/rails/generators/rails/controller/templates/controller.rb index 52243f4a2f..9b04192126 100644 --- a/railties/lib/rails/generators/rails/controller/templates/controller.rb +++ b/railties/lib/rails/generators/rails/controller/templates/controller.rb @@ -1,3 +1,7 @@ +<% if namespaced? -%> +require "<%= namespaced_file_path %>/application_controller" +<% end -%> + <% module_namespacing do -%> class <%= class_name %>Controller < ApplicationController <% actions.each do |action| -%> diff --git a/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb index b95aea5f19..5cd31bf2ee 100644 --- a/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb +++ b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb @@ -1,3 +1,7 @@ +<% if namespaced? -%> +require "<%= namespaced_file_path %>/application_controller" +<% end -%> + <% module_namespacing do -%> class <%= controller_class_name %>Controller < ApplicationController # GET <%= route_url %> diff --git a/railties/test/generators/namespaced_generators_test.rb b/railties/test/generators/namespaced_generators_test.rb index c495258343..903465392d 100644 --- a/railties/test/generators/namespaced_generators_test.rb +++ b/railties/test/generators/namespaced_generators_test.rb @@ -20,8 +20,14 @@ class NamespacedControllerGeneratorTest < NamespacedGeneratorTestCase def test_namespaced_controller_skeleton_is_created run_generator - assert_file "app/controllers/test_app/account_controller.rb", /module TestApp/, / class AccountController < ApplicationController/ - assert_file "test/functional/test_app/account_controller_test.rb", /module TestApp/, / class AccountControllerTest/ + assert_file "app/controllers/test_app/account_controller.rb", + /require "test_app\/application_controller"/, + /module TestApp/, + / class AccountController < ApplicationController/ + + assert_file "test/functional/test_app/account_controller_test.rb", + /module TestApp/, + / class AccountControllerTest/ end def test_skipping_namespace @@ -227,9 +233,10 @@ class NamespacedScaffoldGeneratorTest < NamespacedGeneratorTestCase end # Controller - assert_file "app/controllers/test_app/product_lines_controller.rb" do |content| - assert_match(/module TestApp\n class ProductLinesController < ApplicationController/, content) - end + assert_file "app/controllers/test_app/product_lines_controller.rb", + /require "test_app\/application_controller"/, + /module TestApp/, + /class ProductLinesController < ApplicationController/ assert_file "test/functional/test_app/product_lines_controller_test.rb", /module TestApp\n class ProductLinesControllerTest < ActionController::TestCase/ -- cgit v1.2.3 From d06674d5dfcecb6355890020ee2245b6e87b07e4 Mon Sep 17 00:00:00 2001 From: Patrick Mahoney Date: Sun, 20 May 2012 21:46:08 -0500 Subject: Make connection pool fair with respect to waiting threads. --- .../abstract/connection_pool.rb | 120 +++++++++++++++------ .../connection_adapters/abstract_adapter_test.rb | 2 +- activerecord/test/cases/connection_pool_test.rb | 115 ++++++++++++++++++++ 3 files changed, 202 insertions(+), 35 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb index c6699737b4..450ef69744 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -2,7 +2,6 @@ require 'thread' require 'monitor' require 'set' require 'active_support/core_ext/module/deprecation' -require 'timeout' module ActiveRecord # Raised when a connection could not be obtained within the connection @@ -92,21 +91,6 @@ module ActiveRecord attr_accessor :automatic_reconnect, :timeout attr_reader :spec, :connections, :size, :reaper - class Latch # :nodoc: - def initialize - @mutex = Mutex.new - @cond = ConditionVariable.new - end - - def release - @mutex.synchronize { @cond.broadcast } - end - - def await - @mutex.synchronize { @cond.wait @mutex } - end - end - # Creates a new ConnectionPool object. +spec+ is a ConnectionSpecification # object which describes database connection information (e.g. adapter, # host name, username, password, etc), as well as the maximum size for @@ -128,9 +112,25 @@ module ActiveRecord # default max pool size to 5 @size = (spec.config[:pool] && spec.config[:pool].to_i) || 5 - @latch = Latch.new @connections = [] @automatic_reconnect = true + + # connections available to be checked out + @available = [] + + # number of threads waiting to check out a connection + @num_waiting = 0 + + # signal threads waiting + @cond = new_cond + end + + # Hack for tests to be able to add connections. Do not call outside of tests + def insert_connection_for_test!(c) + synchronize do + @connections << c + @available << c + end end # Retrieve the connection associated with the current thread, or call @@ -188,6 +188,7 @@ module ActiveRecord conn.disconnect! end @connections = [] + @available = [] end end @@ -202,6 +203,9 @@ module ActiveRecord @connections.delete_if do |conn| conn.requires_reloading? end + @available.delete_if do |conn| + conn.requires_reloading? + end end end @@ -225,23 +229,19 @@ module ActiveRecord # Raises: # - PoolFullError: no connection can be obtained from the pool. def checkout - loop do - # Checkout an available connection - synchronize do - # Try to find a connection that hasn't been leased, and lease it - conn = connections.find { |c| c.lease } - - # If all connections were leased, and we have room to expand, - # create a new connection and lease it. - if !conn && connections.size < size - conn = checkout_new_connection - conn.lease - end + synchronize do + conn = nil + + if @num_waiting == 0 + conn = acquire_connection + end - return checkout_and_verify(conn) if conn + unless conn + conn = wait_until(@timeout) { acquire_connection } end - Timeout.timeout(@timeout, PoolFullError) { @latch.await } + conn.lease + checkout_and_verify(conn) end end @@ -257,8 +257,10 @@ module ActiveRecord end release conn + + @available.unshift conn + @cond.signal end - @latch.release end # Remove a connection from the connection pool. The connection will @@ -266,12 +268,14 @@ module ActiveRecord def remove(conn) synchronize do @connections.delete conn + @available.delete conn # FIXME: we might want to store the key on the connection so that removing # from the reserved hash will be a little easier. release conn + + @cond.signal # can make a new connection now end - @latch.release end # Removes dead connections from the pool. A dead connection can occur @@ -283,12 +287,60 @@ module ActiveRecord connections.dup.each do |conn| remove conn if conn.in_use? && stale > conn.last_use && !conn.active? end + @cond.broadcast # may violate fairness end - @latch.release end private + # Take an available connection or, if possible, create a new + # one, or nil. + # + # Monitor must be held while calling this method. + # + # Returns: a newly acquired connection. + def acquire_connection + if @available.any? + @available.pop + elsif connections.size < size + checkout_new_connection + end + end + + # Wait on +@cond+ until the block returns non-nil. Note that + # unlike MonitorMixin::ConditionVariable#wait_until, this method + # does not test the block before the first wait period. + # + # Monitor must be held when calling this method. + # + # +timeout+: Integer timeout in seconds + # + # Returns: the result of the block + # + # Raises: + # - PoolFullError: timeout elapsed before +&block+ returned a connection + def wait_until(timeout, &block) + @num_waiting += 1 + begin + t0 = Time.now + loop do + elapsed = Time.now - t0 + if elapsed >= timeout + msg = 'could not obtain a database connection within %0.3f seconds (waited %0.3f seconds)' % + [timeout, elapsed] + raise PoolFullError, msg + end + + @cond.wait(timeout - elapsed) + + conn = yield + return conn if conn + end + ensure + @num_waiting -= 1 + end + end + def release(conn) thread_id = if @reserved_connections[current_connection_id] == conn current_connection_id diff --git a/activerecord/test/cases/connection_adapters/abstract_adapter_test.rb b/activerecord/test/cases/connection_adapters/abstract_adapter_test.rb index 7dc6e8afcb..3e3d6e2769 100644 --- a/activerecord/test/cases/connection_adapters/abstract_adapter_test.rb +++ b/activerecord/test/cases/connection_adapters/abstract_adapter_test.rb @@ -36,7 +36,7 @@ module ActiveRecord def test_close pool = ConnectionPool.new(ConnectionSpecification.new({}, nil)) - pool.connections << adapter + pool.insert_connection_for_test! adapter adapter.pool = pool # Make sure the pool marks the connection in use diff --git a/activerecord/test/cases/connection_pool_test.rb b/activerecord/test/cases/connection_pool_test.rb index 8dc9f761c2..6871e628aa 100644 --- a/activerecord/test/cases/connection_pool_test.rb +++ b/activerecord/test/cases/connection_pool_test.rb @@ -200,6 +200,121 @@ module ActiveRecord end.join end + # The connection pool is "fair" if threads waiting for + # connections receive them the order in which they began + # waiting. This ensures that we don't timeout one HTTP request + # even while well under capacity in a multi-threaded environment + # such as a Java servlet container. + # + # We don't need strict fairness: if two connections become + # available at the same time, it's fine of two threads that were + # waiting acquire the connections out of order. + # + # Thus this test prepares waiting threads and then trickles in + # available connections slowly, ensuring the wakeup order is + # correct in this case. + # + # Try a few times since it might work out just by chance. + def test_checkout_fairness + 4.times { setup; do_checkout_fairness } + end + + def do_checkout_fairness + expected = (1..@pool.size).to_a.freeze + # check out all connections so our threads start out waiting + conns = expected.map { @pool.checkout } + mutex = Mutex.new + order = [] + errors = [] + + threads = expected.map do |i| + t = Thread.new { + begin + conn = @pool.checkout # never checked back in + mutex.synchronize { order << i } + rescue => e + mutex.synchronize { errors << e } + end + } + Thread.pass until t.status == "sleep" + t + end + + # this should wake up the waiting threads one by one in order + conns.each { |conn| @pool.checkin(conn); sleep 0.1 } + + threads.each(&:join) + + raise errors.first if errors.any? + + assert_equal(expected, order) + end + + # As mentioned in #test_checkout_fairness, we don't care about + # strict fairness. This test creates two groups of threads: + # group1 whose members all start waiting before any thread in + # group2. Enough connections are checked in to wakeup all + # group1 threads, and the fact that only group1 and no group2 + # threads acquired a connection is enforced. + # + # Try a few times since it might work out just by chance. + def test_checkout_fairness_by_group + 4.times { setup; do_checkout_fairness_by_group } + end + + def do_checkout_fairness_by_group + @pool.instance_variable_set(:@size, 10) + # take all the connections + conns = (1..10).map { @pool.checkout } + mutex = Mutex.new + successes = [] # threads that successfully got a connection + errors = [] + + make_thread = proc do |i| + t = Thread.new { + begin + conn = @pool.checkout # never checked back in + mutex.synchronize { successes << i } + rescue => e + mutex.synchronize { errors << e } + end + } + Thread.pass until t.status == "sleep" + t + end + + # all group1 threads start waiting before any in group2 + group1 = (1..5).map(&make_thread) + group2 = (6..10).map(&make_thread) + + # checkin n connections back to the pool + checkin = proc do |n| + n.times do + c = conns.pop + @pool.checkin(c) + end + end + + checkin.call(group1.size) # should wake up all group1 + + loop do + sleep 0.1 + break if mutex.synchronize { (successes.size + errors.size) == group1.size } + end + + winners = mutex.synchronize { successes.dup } + checkin.call(group2.size) # should wake up everyone remaining + + group1.each(&:join) + group2.each(&:join) + + assert_equal((1..group1.size).to_a, winners.sort) + + if errors.any? + raise errors.first + end + end + def test_automatic_reconnect= pool = ConnectionPool.new ActiveRecord::Base.connection_pool.spec assert pool.automatic_reconnect -- cgit v1.2.3 From ae8b09c310989860ed37df072ffa7c6a533bf5ba Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Sun, 20 May 2012 23:30:37 -0700 Subject: More info on commit messages in contributing guide Add more info on how to write a good commit messages along with example showing nicely formatted commit message. Rails git history does not look too well when you try to figure out why particular changes were introduced. We can do much better than that and it's never too late to start. --- .../source/contributing_to_ruby_on_rails.textile | 32 +++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/guides/source/contributing_to_ruby_on_rails.textile b/guides/source/contributing_to_ruby_on_rails.textile index df475a2359..a2254a550c 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: -$ git commit -a -m "Here is a commit message on what I changed in this commit" +$ git commit -a +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: + + +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 + + 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 -- cgit v1.2.3 From d83173483d397df8cdff913d9a4929684c7bd4ce Mon Sep 17 00:00:00 2001 From: Francesco Rodriguez Date: Mon, 21 May 2012 10:16:43 -0500 Subject: add CollectionProxy#destroy documentation --- .../active_record/associations/collection_proxy.rb | 43 +++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index 21c5e3fc5a..a3797e9d59 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -222,6 +222,8 @@ module ActiveRecord ## # :method: destroy_all # Deletes the records of the collection directly from the database. + # This will _always_ remove the records ignoring the +:dependent+ + # option. # # class Person < ActiveRecord::Base # has_many :pets @@ -242,6 +244,45 @@ module ActiveRecord # # Pet.find(1) # => Couldn't find Pet with id=1 + ## + # :method: destroy + # Destroy the +records+ supplied and remove them from the collection. + # This method will _always_ remove record from the database ignoring + # the +:dependent+ option. Returns an array with the deleted records. + # + # class Person < ActiveRecord::Base + # has_many :pets + # end + # + # person.pets.size # => 3 + # person.pets + # # => [ + # # #, + # # #, + # # # + # # ] + # + # person.pets.destroy(Pet.find(1)) + # # => [#] + # + # person.pets.size # => 2 + # person.pets + # # => [ + # # #, + # # # + # # ] + # + # person.pets.destroy(Pet.find(2), Pet.find(3)) + # # => [ + # # #, + # # # + # # ] + # + # person.pets.size # => 0 + # person.pets # => [] + # + # Pet.find([1, 2, 3]) # => ActiveRecord::RecordNotFound: Couldn't find all Pets with IDs (1, 2, 3) + ## # :method: empty? # Returns true if the collection is empty. @@ -257,7 +298,7 @@ module ActiveRecord # # person.pets.count # => 0 # person.pets.empty? # => true - + ## # :method: any? # Returns true if the collection is not empty. -- cgit v1.2.3 From ff83df36a48103675f16152f9d6bf67e11ea9f1a Mon Sep 17 00:00:00 2001 From: Andrey Vakarev Date: Mon, 21 May 2012 19:13:24 +0300 Subject: Refactoring: turn unless/else into if/else --- actionpack/examples/performance.rb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/actionpack/examples/performance.rb b/actionpack/examples/performance.rb index 994e745bb0..8ea4758961 100644 --- a/actionpack/examples/performance.rb +++ b/actionpack/examples/performance.rb @@ -166,15 +166,7 @@ def run_all!(times, verbose) Runner.run(:diff_100, times, verbose) end -unless ENV["PROFILE"] - run_all!(1, false) - - (ENV["M"] || 1).to_i.times do - $ran = [] - run_all!(N, true) - Runner.done - end -else +if ENV["PROFILE"] Runner.run(ENV["PROFILE"].to_sym, 1, false) require "ruby-prof" RubyProf.start @@ -182,4 +174,12 @@ else result = RubyProf.stop printer = RubyProf::CallStackPrinter.new(result) printer.print(File.open("output.html", "w")) +else + run_all!(1, false) + + (ENV["M"] || 1).to_i.times do + $ran = [] + run_all!(N, true) + Runner.done + end end \ No newline at end of file -- cgit v1.2.3 From 1f5c1a14236b2df638d20bcf1617110c47a4bfe8 Mon Sep 17 00:00:00 2001 From: Francesco Rodriguez Date: Mon, 21 May 2012 11:56:00 -0500 Subject: improve CollectionProxy#destroy documentation --- .../active_record/associations/collection_proxy.rb | 42 +++++++++++++++++++--- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index a3797e9d59..e3ebe03121 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -248,7 +248,7 @@ module ActiveRecord # :method: destroy # Destroy the +records+ supplied and remove them from the collection. # This method will _always_ remove record from the database ignoring - # the +:dependent+ option. Returns an array with the deleted records. + # the +:dependent+ option. Returns an array with the removed records. # # class Person < ActiveRecord::Base # has_many :pets @@ -278,10 +278,42 @@ module ActiveRecord # # # # # ] # - # person.pets.size # => 0 - # person.pets # => [] + # person.pets.size # => 0 + # person.pets # => [] # - # Pet.find([1, 2, 3]) # => ActiveRecord::RecordNotFound: Couldn't find all Pets with IDs (1, 2, 3) + # Pet.find(1, 2, 3) # => ActiveRecord::RecordNotFound: Couldn't find all Pets with IDs (1, 2, 3) + # + # You can pass +Fixnum+ or +String+ values, it finds the records + # responding to the +id+ and then deletes them from the database. + # + # person.pets.size # => 3 + # person.pets + # # => [ + # # #, + # # #, + # # # + # # ] + # + # person.pets.destroy("4") + # # => # + # + # person.pets.size # => 2 + # person.pets + # # => [ + # # #, + # # # + # # ] + # + # person.pets.destroy(5, 6) + # # => [ + # # #, + # # # + # # ] + # + # person.pets.size # => 0 + # person.pets # => [] + # + # Pet.find(4, 5, 6) # => ActiveRecord::RecordNotFound: Couldn't find all Pets with IDs (4, 5, 6) ## # :method: empty? @@ -298,7 +330,7 @@ module ActiveRecord # # person.pets.count # => 0 # person.pets.empty? # => true - + ## # :method: any? # Returns true if the collection is not empty. -- cgit v1.2.3 From 158a71b2cbd6be9ef9c88282b48a3e39e47908ed Mon Sep 17 00:00:00 2001 From: Francesco Rodriguez Date: Mon, 21 May 2012 12:19:34 -0500 Subject: add CollectionProxy#reload documentation --- .../lib/active_record/associations/collection_proxy.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index e3ebe03121..80a1715ee2 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -516,6 +516,24 @@ module ActiveRecord self end + # Reloads the collection from the database. Returns +self+. + # Equivalent to +collection(true)+. + # + # class Person < ActiveRecord::Base + # has_many :pets + # end + # + # person.pets # fetches pets from the database + # # => [#] + # + # person.pets # uses the pets cache + # # => [#] + # + # person.pets.reload # fetches pets from the database + # # => [#] + # + # person.pets(true)  # fetches pets from the database + # # => [#] def reload proxy_association.reload self -- cgit v1.2.3 From ab2e2a9d2b772cf4aef4d9f4f2d506a03c205035 Mon Sep 17 00:00:00 2001 From: Francesco Rodriguez Date: Mon, 21 May 2012 12:26:04 -0500 Subject: fix CollectionProxy documentation markup --- .../lib/active_record/associations/collection_proxy.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index 80a1715ee2..b419b9a749 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -112,7 +112,7 @@ module ActiveRecord ## # :method: first # Returns the first record, or the first +n+ records, from the collection. - # If the collection is empty, the first form returns nil, and the second + # If the collection is empty, the first form returns +nil+, and the second # form returns an empty array. # # class Person < ActiveRecord::Base @@ -141,7 +141,7 @@ module ActiveRecord ## # :method: last # Returns the last record, or the last +n+ records, from the collection. - # If the collection is empty, the first form returns nil, and the second + # If the collection is empty, the first form returns +nil+, and the second # form returns an empty array. # # class Person < ActiveRecord::Base @@ -317,7 +317,7 @@ module ActiveRecord ## # :method: empty? - # Returns true if the collection is empty. + # Returns +true+ if the collection is empty. # # class Person < ActiveRecord::Base # has_many :pets @@ -333,7 +333,7 @@ module ActiveRecord ## # :method: any? - # Returns true if the collection is not empty. + # Returns +true+ if the collection is not empty. # # class Person < ActiveRecord::Base # has_many :pets @@ -366,7 +366,7 @@ module ActiveRecord ## # :method: many? # Returns true if the collection has more than one record. - # Equivalent to +collection.size > 1+. + # Equivalent to collection.size > 1. # # class Person < ActiveRecord::Base # has_many :pets @@ -402,7 +402,7 @@ module ActiveRecord ## # :method: include? - # Returns true if the given object is present in the collection. + # Returns +true+ if the given object is present in the collection. # # class Person < ActiveRecord::Base # has_many :pets @@ -499,7 +499,7 @@ module ActiveRecord # # Pet.find(1) # => # # - # If they are associated with +dependent: :destroy+ option, it deletes + # If they are associated with dependent: :destroy option, it deletes # them directly from the database. # # class Person < ActiveRecord::Base @@ -517,7 +517,7 @@ module ActiveRecord end # Reloads the collection from the database. Returns +self+. - # Equivalent to +collection(true)+. + # Equivalent to collection(true). # # class Person < ActiveRecord::Base # has_many :pets -- cgit v1.2.3 From 685192bbcba7f887236ddf43ebb7d7dcf7409bd9 Mon Sep 17 00:00:00 2001 From: Tom Clarke Date: Sun, 20 May 2012 01:03:34 -0400 Subject: Make the Resolver template cache threadsafe - closes #6404 The Template cache in the Resolver can be accessed by multiple threads similtaneously in multi-threaded environments. The cache is implemented using a Hash, which isn't threadsafe in all VMs (notably JRuby). This commit extracts the cache to a new Cache class and adds mutexes to prevent concurrent access. --- actionpack/lib/action_view/template/resolver.rb | 69 ++++++++++++++++++------- actionpack/test/template/lookup_context_test.rb | 8 +-- 2 files changed, 54 insertions(+), 23 deletions(-) diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb index fa2038f78d..b33aebd3bc 100644 --- a/actionpack/lib/action_view/template/resolver.rb +++ b/actionpack/lib/action_view/template/resolver.rb @@ -2,6 +2,7 @@ require "pathname" require "active_support/core_ext/class" require "active_support/core_ext/class/attribute_accessors" require "action_view/template" +require "thread" module ActionView # = Action View Resolver @@ -24,6 +25,46 @@ module ActionView end end + # Threadsafe template cache + class Cache #:nodoc: + def initialize + @data = Hash.new { |h1,k1| h1[k1] = Hash.new { |h2,k2| + h2[k2] = Hash.new { |h3,k3| h3[k3] = Hash.new { |h4,k4| h4[k4] = {} } } } } + @mutex = Mutex.new + end + + # Cache the templates returned by the block + def cache(key, name, prefix, partial, locals) + @mutex.synchronize do + if Resolver.caching? + # all templates are cached forever the first time they are accessed + @data[key][name][prefix][partial][locals] ||= yield + else + # templates are still cached, but are only returned if they are + # all still current + fresh = yield + + cache = @data[key][name][prefix][partial][locals] + mtime = cache && cache.map(&:updated_at).max + + newer = !mtime || fresh.empty? || fresh.any? { |t| t.updated_at > mtime } + + if newer + @data[key][name][prefix][partial][locals] = fresh + else + @data[key][name][prefix][partial][locals] + end + end + end + end + + def clear + @mutex.synchronize do + @data.clear + end + end + end + cattr_accessor :caching self.caching = true @@ -32,12 +73,11 @@ module ActionView end def initialize - @cached = Hash.new { |h1,k1| h1[k1] = Hash.new { |h2,k2| - h2[k2] = Hash.new { |h3,k3| h3[k3] = Hash.new { |h4,k4| h4[k4] = {} } } } } + @cache = Cache.new end def clear_cache - @cached.clear + @cache.clear end # Normalizes the arguments and passes it on to find_template. @@ -65,27 +105,18 @@ module ActionView # Handles templates caching. If a key is given and caching is on # always check the cache before hitting the resolver. Otherwise, - # it always hits the resolver but check if the resolver is fresher - # before returning it. + # it always hits the resolver but if the key is present, check if the + # resolver is fresher before returning it. def cached(key, path_info, details, locals) #:nodoc: name, prefix, partial = path_info locals = locals.map { |x| x.to_s }.sort! - if key && caching? - @cached[key][name][prefix][partial][locals] ||= decorate(yield, path_info, details, locals) - else - fresh = decorate(yield, path_info, details, locals) - return fresh unless key - - scope = @cached[key][name][prefix][partial] - cache = scope[locals] - mtime = cache && cache.map(&:updated_at).max - - if !mtime || fresh.empty? || fresh.any? { |t| t.updated_at > mtime } - scope[locals] = fresh - else - cache + if key + @cache.cache(key, name, prefix, partial, locals) do + decorate(yield, path_info, details, locals) end + else + decorate(yield, path_info, details, locals) end end diff --git a/actionpack/test/template/lookup_context_test.rb b/actionpack/test/template/lookup_context_test.rb index 96b14a0acd..ef9c5ce10c 100644 --- a/actionpack/test/template/lookup_context_test.rb +++ b/actionpack/test/template/lookup_context_test.rb @@ -169,7 +169,7 @@ class LookupContextTest < ActiveSupport::TestCase assert_not_equal template, old_template end - + test "responds to #prefixes" do assert_equal [], @lookup_context.prefixes @lookup_context.prefixes = ["foo"] @@ -180,7 +180,7 @@ end class LookupContextWithFalseCaching < ActiveSupport::TestCase def setup @resolver = ActionView::FixtureResolver.new("test/_foo.erb" => ["Foo", Time.utc(2000)]) - @resolver.stubs(:caching?).returns(false) + ActionView::Resolver.stubs(:caching?).returns(false) @lookup_context = ActionView::LookupContext.new(@resolver, {}) end @@ -247,6 +247,6 @@ class TestMissingTemplate < ActiveSupport::TestCase @lookup_context.view_paths.find("foo", "parent", true, details) end assert_match %r{Missing partial parent/foo with .* Searched in:\n \* "/Path/to/views"\n}, e.message - end - + end + end -- cgit v1.2.3 From 719b008f1dae30c5fb6d09a371ae8d949c867a0c Mon Sep 17 00:00:00 2001 From: Tom Clarke Date: Mon, 21 May 2012 09:41:04 -0400 Subject: More granular locking of the Resolver template cache In order to avoid holding a global lock when doing template resolution, instead add individual locks on a per cache entry basis. The global lock is now only used for manipulation of the main cache data structure. --- actionpack/lib/action_view/template/resolver.rb | 28 ++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb index b33aebd3bc..8f87d6da8b 100644 --- a/actionpack/lib/action_view/template/resolver.rb +++ b/actionpack/lib/action_view/template/resolver.rb @@ -27,6 +27,16 @@ module ActionView # Threadsafe template cache class Cache #:nodoc: + class CacheEntry + attr_accessor :templates + + delegate :synchronize, :to => "@mutex" + + def initialize + @mutex = Mutex.new + end + end + def initialize @data = Hash.new { |h1,k1| h1[k1] = Hash.new { |h2,k2| h2[k2] = Hash.new { |h3,k3| h3[k3] = Hash.new { |h4,k4| h4[k4] = {} } } } } @@ -35,24 +45,32 @@ module ActionView # Cache the templates returned by the block def cache(key, name, prefix, partial, locals) + cache_entry = nil + + # first obtain a lock on the main data structure to create the cache entry @mutex.synchronize do + cache_entry = @data[key][name][prefix][partial][locals] ||= CacheEntry.new + end + + # then to avoid a long lasting global lock, obtain a more granular lock + # on the CacheEntry itself + cache_entry.synchronize do if Resolver.caching? # all templates are cached forever the first time they are accessed - @data[key][name][prefix][partial][locals] ||= yield + cache_entry.templates ||= yield else # templates are still cached, but are only returned if they are # all still current fresh = yield - cache = @data[key][name][prefix][partial][locals] - mtime = cache && cache.map(&:updated_at).max + mtime = cache_entry.templates && cache_entry.templates.map(&:updated_at).max newer = !mtime || fresh.empty? || fresh.any? { |t| t.updated_at > mtime } if newer - @data[key][name][prefix][partial][locals] = fresh + cache_entry.templates = fresh else - @data[key][name][prefix][partial][locals] + cache_entry.templates end end end -- cgit v1.2.3 From 776ea1090fb9ba4353035d4983cf1926a67b3294 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 21 May 2012 21:01:02 +0200 Subject: Revert "Merge pull request #6425 from pinetops/resolver_concurrency_fix" This reverts commit 254c04286c5916ae7f91eb6e173b312e7a74e364, reversing changes made to 513a0525c24c2944630acfa465b22cd2f4601adf. --- actionpack/lib/action_view/template/resolver.rb | 87 ++++++------------------- actionpack/test/template/lookup_context_test.rb | 8 +-- 2 files changed, 23 insertions(+), 72 deletions(-) diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb index 8f87d6da8b..fa2038f78d 100644 --- a/actionpack/lib/action_view/template/resolver.rb +++ b/actionpack/lib/action_view/template/resolver.rb @@ -2,7 +2,6 @@ require "pathname" require "active_support/core_ext/class" require "active_support/core_ext/class/attribute_accessors" require "action_view/template" -require "thread" module ActionView # = Action View Resolver @@ -25,64 +24,6 @@ module ActionView end end - # Threadsafe template cache - class Cache #:nodoc: - class CacheEntry - attr_accessor :templates - - delegate :synchronize, :to => "@mutex" - - def initialize - @mutex = Mutex.new - end - end - - def initialize - @data = Hash.new { |h1,k1| h1[k1] = Hash.new { |h2,k2| - h2[k2] = Hash.new { |h3,k3| h3[k3] = Hash.new { |h4,k4| h4[k4] = {} } } } } - @mutex = Mutex.new - end - - # Cache the templates returned by the block - def cache(key, name, prefix, partial, locals) - cache_entry = nil - - # first obtain a lock on the main data structure to create the cache entry - @mutex.synchronize do - cache_entry = @data[key][name][prefix][partial][locals] ||= CacheEntry.new - end - - # then to avoid a long lasting global lock, obtain a more granular lock - # on the CacheEntry itself - cache_entry.synchronize do - if Resolver.caching? - # all templates are cached forever the first time they are accessed - cache_entry.templates ||= yield - else - # templates are still cached, but are only returned if they are - # all still current - fresh = yield - - mtime = cache_entry.templates && cache_entry.templates.map(&:updated_at).max - - newer = !mtime || fresh.empty? || fresh.any? { |t| t.updated_at > mtime } - - if newer - cache_entry.templates = fresh - else - cache_entry.templates - end - end - end - end - - def clear - @mutex.synchronize do - @data.clear - end - end - end - cattr_accessor :caching self.caching = true @@ -91,11 +32,12 @@ module ActionView end def initialize - @cache = Cache.new + @cached = Hash.new { |h1,k1| h1[k1] = Hash.new { |h2,k2| + h2[k2] = Hash.new { |h3,k3| h3[k3] = Hash.new { |h4,k4| h4[k4] = {} } } } } end def clear_cache - @cache.clear + @cached.clear end # Normalizes the arguments and passes it on to find_template. @@ -123,18 +65,27 @@ module ActionView # Handles templates caching. If a key is given and caching is on # always check the cache before hitting the resolver. Otherwise, - # it always hits the resolver but if the key is present, check if the - # resolver is fresher before returning it. + # it always hits the resolver but check if the resolver is fresher + # before returning it. def cached(key, path_info, details, locals) #:nodoc: name, prefix, partial = path_info locals = locals.map { |x| x.to_s }.sort! - if key - @cache.cache(key, name, prefix, partial, locals) do - decorate(yield, path_info, details, locals) - end + if key && caching? + @cached[key][name][prefix][partial][locals] ||= decorate(yield, path_info, details, locals) else - decorate(yield, path_info, details, locals) + fresh = decorate(yield, path_info, details, locals) + return fresh unless key + + scope = @cached[key][name][prefix][partial] + cache = scope[locals] + mtime = cache && cache.map(&:updated_at).max + + if !mtime || fresh.empty? || fresh.any? { |t| t.updated_at > mtime } + scope[locals] = fresh + else + cache + end end end diff --git a/actionpack/test/template/lookup_context_test.rb b/actionpack/test/template/lookup_context_test.rb index ef9c5ce10c..96b14a0acd 100644 --- a/actionpack/test/template/lookup_context_test.rb +++ b/actionpack/test/template/lookup_context_test.rb @@ -169,7 +169,7 @@ class LookupContextTest < ActiveSupport::TestCase assert_not_equal template, old_template end - + test "responds to #prefixes" do assert_equal [], @lookup_context.prefixes @lookup_context.prefixes = ["foo"] @@ -180,7 +180,7 @@ end class LookupContextWithFalseCaching < ActiveSupport::TestCase def setup @resolver = ActionView::FixtureResolver.new("test/_foo.erb" => ["Foo", Time.utc(2000)]) - ActionView::Resolver.stubs(:caching?).returns(false) + @resolver.stubs(:caching?).returns(false) @lookup_context = ActionView::LookupContext.new(@resolver, {}) end @@ -247,6 +247,6 @@ class TestMissingTemplate < ActiveSupport::TestCase @lookup_context.view_paths.find("foo", "parent", true, details) end assert_match %r{Missing partial parent/foo with .* Searched in:\n \* "/Path/to/views"\n}, e.message - end - + end + end -- cgit v1.2.3 From 89ebd28d4ec899d840bddbef7711983a1ae2a162 Mon Sep 17 00:00:00 2001 From: Marc-Andre Lafortune Date: Mon, 21 May 2012 15:24:18 -0400 Subject: Fix bug when Rails.application is defined but is nil. See #881 --- actionpack/lib/action_dispatch/testing/test_request.rb | 2 +- actionpack/test/dispatch/test_request_test.rb | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_dispatch/testing/test_request.rb b/actionpack/lib/action_dispatch/testing/test_request.rb index d04be2099c..a86b510719 100644 --- a/actionpack/lib/action_dispatch/testing/test_request.rb +++ b/actionpack/lib/action_dispatch/testing/test_request.rb @@ -11,7 +11,7 @@ module ActionDispatch end def initialize(env = {}) - env = Rails.application.env_config.merge(env) if defined?(Rails.application) + env = Rails.application.env_config.merge(env) if defined?(Rails.application) && Rails.application super(DEFAULT_ENV.merge(env)) self.host = 'test.host' diff --git a/actionpack/test/dispatch/test_request_test.rb b/actionpack/test/dispatch/test_request_test.rb index 4ee1d61146..6047631ba3 100644 --- a/actionpack/test/dispatch/test_request_test.rb +++ b/actionpack/test/dispatch/test_request_test.rb @@ -55,6 +55,13 @@ class TestRequestTest < ActiveSupport::TestCase assert_cookies({"user_name" => "david"}, req.cookie_jar) end + test "does not complain when Rails.application is nil" do + Rails.stubs(:application).returns(nil) + req = ActionDispatch::TestRequest.new + + assert_equal false, req.env.empty? + end + private def assert_cookies(expected, cookie_jar) assert_equal(expected, cookie_jar.instance_variable_get("@cookies")) -- cgit v1.2.3 From 1ce4b5b33d694eeebdb0495aef70d8d1b50cd02d Mon Sep 17 00:00:00 2001 From: Carlos Galdino Date: Wed, 16 May 2012 19:20:32 -0300 Subject: Add HTML5 input[type="color"] helper --- actionpack/CHANGELOG.md | 2 ++ actionpack/lib/action_view/helpers/form_helper.rb | 9 ++++++++ .../lib/action_view/helpers/form_tag_helper.rb | 8 +++++++ actionpack/lib/action_view/helpers/tags.rb | 1 + .../lib/action_view/helpers/tags/color_field.rb | 25 ++++++++++++++++++++++ actionpack/test/lib/controller/fake_models.rb | 3 +++ actionpack/test/template/form_helper_test.rb | 13 +++++++++++ actionpack/test/template/form_tag_helper_test.rb | 5 +++++ guides/source/form_helpers.textile | 6 ++++-- 9 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 actionpack/lib/action_view/helpers/tags/color_field.rb diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index 1e6e84ea4a..d6fcae4571 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,5 +1,7 @@ ## Rails 4.0.0 (unreleased) ## +* Add `color_field` and `color_field_tag` helpers. *Carlos Galdino* + * `assert_generates`, `assert_recognizes`, and `assert_routing` all raise `Assertion` instead of `RoutingError` *David Chelimsky* diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index 6510610034..c5a9057698 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -939,6 +939,15 @@ module ActionView Tags::RadioButton.new(object_name, method, self, tag_value, options).render end + # Returns a text_field of type "color". + # + # color_field("car", "color") + # # => + # + def color_field(object_name, method, options = {}) + Tags::ColorField.new(object_name, method, self, options).render + end + # Returns an input of type "search" for accessing a specified attribute (identified by +method+) on an object # assigned to the template (identified by +object_name+). Inputs of type "search" may be styled differently by # some browsers. diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index e65b4e3e95..7da67cd2f9 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -524,6 +524,14 @@ module ActionView output.safe_concat("") end + # Creates a text field of type "color". + # + # ==== Options + # * Accepts the same options as text_field_tag. + def color_field_tag(name, value = nil, options = {}) + text_field_tag(name, value, options.stringify_keys.update("type" => "color")) + end + # Creates a text field of type "search". # # ==== Options diff --git a/actionpack/lib/action_view/helpers/tags.rb b/actionpack/lib/action_view/helpers/tags.rb index 5cd77c8ec3..c56165c769 100644 --- a/actionpack/lib/action_view/helpers/tags.rb +++ b/actionpack/lib/action_view/helpers/tags.rb @@ -8,6 +8,7 @@ module ActionView autoload :CollectionCheckBoxes autoload :CollectionRadioButtons autoload :CollectionSelect + autoload :ColorField autoload :DateField autoload :DateSelect autoload :DatetimeSelect diff --git a/actionpack/lib/action_view/helpers/tags/color_field.rb b/actionpack/lib/action_view/helpers/tags/color_field.rb new file mode 100644 index 0000000000..6f08f8483a --- /dev/null +++ b/actionpack/lib/action_view/helpers/tags/color_field.rb @@ -0,0 +1,25 @@ +module ActionView + module Helpers + module Tags + class ColorField < TextField #:nodoc: + def render + options = @options.stringify_keys + options["value"] = @options.fetch("value") { validate_color_string(value(object)) } + @options = options + super + end + + private + + def validate_color_string(string) + regex = /#[0-9a-fA-F]{6}/ + if regex.match(string) + string.downcase + else + "#000000" + end + end + end + end + end +end diff --git a/actionpack/test/lib/controller/fake_models.rb b/actionpack/test/lib/controller/fake_models.rb index bbb4cc5ef3..82f38b5309 100644 --- a/actionpack/test/lib/controller/fake_models.rb +++ b/actionpack/test/lib/controller/fake_models.rb @@ -214,3 +214,6 @@ class RenderJsonTestException < Exception return { :error => self.class.name, :message => self.to_s }.to_json end end + +class Car < Struct.new(:color) +end diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index 27cc3ad48a..76a18fa76a 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -83,6 +83,8 @@ class FormHelperTest < ActionView::TestCase @post.tags << Tag.new @blog_post = Blog::Post.new("And his name will be forty and four.", 44) + + @car = Car.new("#000FFF") end Routes = ActionDispatch::Routing::RouteSet.new @@ -610,6 +612,17 @@ class FormHelperTest < ActionView::TestCase ) end + def test_color_field_with_valid_hex_color_string + expected = %{} + assert_dom_equal(expected, color_field("car", "color")) + end + + def test_color_field_with_invalid_hex_color_string + expected = %{} + @car.color = "#1234TR" + assert_dom_equal(expected, color_field("car", "color")) + end + def test_search_field expected = %{} assert_dom_equal(expected, search_field("contact", "notes_query")) diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb index 6574e13558..195adce180 100644 --- a/actionpack/test/template/form_tag_helper_test.rb +++ b/actionpack/test/template/form_tag_helper_test.rb @@ -444,6 +444,11 @@ class FormTagHelperTest < ActionView::TestCase ) end + def test_color_field_tag + expected = %{} + assert_dom_equal(expected, color_field_tag("car")) + end + def test_search_field_tag expected = %{} assert_dom_equal(expected, search_field_tag("query")) diff --git a/guides/source/form_helpers.textile b/guides/source/form_helpers.textile index 033b33ec3b..11d48551c4 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, URL fields and email fields: <%= text_area_tag(:message, "Hi, nice site", :size => "24x6") %> @@ -161,6 +161,7 @@ Other form controls worth mentioning are textareas, password fields, hidden fiel <%= date_field(:user, :born_on) %> <%= url_field(:user, :homepage) %> <%= email_field(:user, :address) %> +<%= color_field(:user, :favorite_color) %> <%= time_field(:task, :started_at) %> @@ -175,12 +176,13 @@ Output: + 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, 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. -- cgit v1.2.3 From b02d14aad515a039c284c93a68845503dc1658e2 Mon Sep 17 00:00:00 2001 From: Carlos Galdino Date: Wed, 16 May 2012 18:24:16 -0300 Subject: Add several HTML5 input helpers The input types added are: - input[type="month"] - input[type="week"] - input[type="datetime"] - input[type="datetime-local"] --- actionpack/CHANGELOG.md | 3 + actionpack/lib/action_view/helpers/form_helper.rb | 68 ++++++++++ .../lib/action_view/helpers/form_tag_helper.rb | 44 +++++++ actionpack/lib/action_view/helpers/tags.rb | 4 + .../lib/action_view/helpers/tags/datetime_field.rb | 22 ++++ .../helpers/tags/datetime_local_field.rb | 23 ++++ .../lib/action_view/helpers/tags/month_field.rb | 22 ++++ .../lib/action_view/helpers/tags/week_field.rb | 22 ++++ actionpack/test/template/form_helper_test.rb | 140 +++++++++++++++++++++ actionpack/test/template/form_tag_helper_test.rb | 20 +++ guides/source/form_helpers.textile | 12 +- 11 files changed, 378 insertions(+), 2 deletions(-) create mode 100644 actionpack/lib/action_view/helpers/tags/datetime_field.rb create mode 100644 actionpack/lib/action_view/helpers/tags/datetime_local_field.rb create mode 100644 actionpack/lib/action_view/helpers/tags/month_field.rb create mode 100644 actionpack/lib/action_view/helpers/tags/week_field.rb diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index d6fcae4571..920858d8c0 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,5 +1,8 @@ ## Rails 4.0.0 (unreleased) ## +* Add `week_field`, `week_field_tag`, `month_field`, `month_field_tag`, `datetime_local_field`, + `datetime_local_field_tag`, `datetime_field` and `datetime_field_tag` helpers. *Carlos Galdino* + * Add `color_field` and `color_field_tag` helpers. *Carlos Galdino* * `assert_generates`, `assert_recognizes`, and `assert_routing` all raise diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index c5a9057698..ad8885b708 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -1016,6 +1016,74 @@ module ActionView Tags::TimeField.new(object_name, method, self, options).render end + # Returns a text_field of type "datetime". + # + # datetime_field("user", "born_on") + # # => + # + # The default value is generated by trying to call +strftime+ with "%Y-%m-%dT%T.%L%z" + # on the object's value, which makes it behave as expected for instances + # of DateTime and ActiveSupport::TimeWithZone. + # + # @user.born_on = Date.new(1984, 1, 12) + # datetime_field("user", "born_on") + # # => + # + def datetime_field(object_name, method, options = {}) + Tags::DatetimeField.new(object_name, method, self, options).render + end + + # Returns a text_field of type "datetime-local". + # + # datetime_local_field("user", "born_on") + # # => + # + # The default value is generated by trying to call +strftime+ with "%Y-%m-%dT%T" + # on the object's value, which makes it behave as expected for instances + # of DateTime and ActiveSupport::TimeWithZone. + # + # @user.born_on = Date.new(1984, 1, 12) + # datetime_local_field("user", "born_on") + # # => + # + def datetime_local_field(object_name, method, options = {}) + Tags::DatetimeLocalField.new(object_name, method, self, options).render + end + + # Returns a text_field of type "month". + # + # month_field("user", "born_on") + # # => + # + # The default value is generated by trying to call +strftime+ with "%Y-%m" + # on the object's value, which makes it behave as expected for instances + # of DateTime and ActiveSupport::TimeWithZone. + # + # @user.born_on = Date.new(1984, 1, 27) + # month_field("user", "born_on") + # # => + # + def month_field(object_name, method, options = {}) + Tags::MonthField.new(object_name, method, self, options).render + end + + # Returns a text_field of type "week". + # + # week_field("user", "born_on") + # # => + # + # The default value is generated by trying to call +strftime+ with "%Y-W%W" + # on the object's value, which makes it behave as expected for instances + # of DateTime and ActiveSupport::TimeWithZone. + # + # @user.born_on = Date.new(1984, 5, 12) + # week_field("user", "born_on") + # # => + # + def week_field(object_name, method, options = {}) + Tags::WeekField.new(object_name, method, self, options).render + end + # Returns a text_field of type "url". # # url_field("user", "homepage") diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index 7da67cd2f9..1a0019a48c 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -568,6 +568,50 @@ module ActionView text_field_tag(name, value, options.stringify_keys.update("type" => "time")) end + # Creates a text field of type "datetime". + # + # === Options + # * :min - The minimum acceptable value. + # * :max - The maximum acceptable value. + # * :step - The acceptable value granularity. + # * Otherwise accepts the same options as text_field_tag. + def datetime_field_tag(name, value = nil, options = {}) + text_field_tag(name, value, options.stringify_keys.update("type" => "datetime")) + end + + # Creates a text field of type "datetime-local". + # + # === Options + # * :min - The minimum acceptable value. + # * :max - The maximum acceptable value. + # * :step - The acceptable value granularity. + # * Otherwise accepts the same options as text_field_tag. + def datetime_local_field_tag(name, value = nil, options = {}) + text_field_tag(name, value, options.stringify_keys.update("type" => "datetime-local")) + end + + # Creates a text field of type "month". + # + # === Options + # * :min - The minimum acceptable value. + # * :max - The maximum acceptable value. + # * :step - The acceptable value granularity. + # * Otherwise accepts the same options as text_field_tag. + def month_field_tag(name, value = nil, options = {}) + text_field_tag(name, value, options.stringify_keys.update("type" => "month")) + end + + # Creates a text field of type "week". + # + # === Options + # * :min - The minimum acceptable value. + # * :max - The maximum acceptable value. + # * :step - The acceptable value granularity. + # * Otherwise accepts the same options as text_field_tag. + def week_field_tag(name, value = nil, options = {}) + text_field_tag(name, value, options.stringify_keys.update("type" => "week")) + end + # Creates a text field of type "url". # # ==== Options diff --git a/actionpack/lib/action_view/helpers/tags.rb b/actionpack/lib/action_view/helpers/tags.rb index c56165c769..a05e16979a 100644 --- a/actionpack/lib/action_view/helpers/tags.rb +++ b/actionpack/lib/action_view/helpers/tags.rb @@ -11,12 +11,15 @@ module ActionView autoload :ColorField autoload :DateField autoload :DateSelect + autoload :DatetimeField + autoload :DatetimeLocalField autoload :DatetimeSelect autoload :EmailField autoload :FileField autoload :GroupedCollectionSelect autoload :HiddenField autoload :Label + autoload :MonthField autoload :NumberField autoload :PasswordField autoload :RadioButton @@ -30,6 +33,7 @@ module ActionView autoload :TimeSelect autoload :TimeZoneSelect autoload :UrlField + autoload :WeekField end end end diff --git a/actionpack/lib/action_view/helpers/tags/datetime_field.rb b/actionpack/lib/action_view/helpers/tags/datetime_field.rb new file mode 100644 index 0000000000..11d58744fd --- /dev/null +++ b/actionpack/lib/action_view/helpers/tags/datetime_field.rb @@ -0,0 +1,22 @@ +module ActionView + module Helpers + module Tags + class DatetimeField < TextField #:nodoc: + def render + options = @options.stringify_keys + options["value"] = @options.fetch("value") { format_global_date_time_string(value(object)) } + options["min"] = format_global_date_time_string(options["min"]) + options["max"] = format_global_date_time_string(options["max"]) + @options = options + super + end + + private + + def format_global_date_time_string(value) + value.try(:strftime, "%Y-%m-%dT%T.%L%z") + end + end + end + end +end diff --git a/actionpack/lib/action_view/helpers/tags/datetime_local_field.rb b/actionpack/lib/action_view/helpers/tags/datetime_local_field.rb new file mode 100644 index 0000000000..7593a3c733 --- /dev/null +++ b/actionpack/lib/action_view/helpers/tags/datetime_local_field.rb @@ -0,0 +1,23 @@ +module ActionView + module Helpers + module Tags + class DatetimeLocalField < TextField #:nodoc: + def render + options = @options.stringify_keys + options["type"] = "datetime-local" + options["value"] = @options.fetch("value") { format_local_date_time_string(value(object)) } + options["min"] = format_local_date_time_string(options["min"]) + options["max"] = format_local_date_time_string(options["max"]) + @options = options + super + end + + private + + def format_local_date_time_string(value) + value.try(:strftime, "%Y-%m-%dT%T") + end + end + end + end +end diff --git a/actionpack/lib/action_view/helpers/tags/month_field.rb b/actionpack/lib/action_view/helpers/tags/month_field.rb new file mode 100644 index 0000000000..56bd85a90b --- /dev/null +++ b/actionpack/lib/action_view/helpers/tags/month_field.rb @@ -0,0 +1,22 @@ +module ActionView + module Helpers + module Tags + class MonthField < TextField #:nodoc: + def render + options = @options.stringify_keys + options["value"] = @options.fetch("value") { format_month_string(value(object)) } + options["min"] = format_month_string(options["min"]) + options["max"] = format_month_string(options["max"]) + @options = options + super + end + + private + + def format_month_string(value) + value.try(:strftime, "%Y-%m") + end + end + end + end +end diff --git a/actionpack/lib/action_view/helpers/tags/week_field.rb b/actionpack/lib/action_view/helpers/tags/week_field.rb new file mode 100644 index 0000000000..a1265d9928 --- /dev/null +++ b/actionpack/lib/action_view/helpers/tags/week_field.rb @@ -0,0 +1,22 @@ +module ActionView + module Helpers + module Tags + class WeekField < TextField #:nodoc: + def render + options = @options.stringify_keys + options["value"] = @options.fetch("value") { format_week_string(value(object)) } + options["min"] = format_week_string(options["min"]) + options["max"] = format_week_string(options["max"]) + @options = options + super + end + + private + + def format_week_string(value) + value.try(:strftime, "%Y-W%W") + end + end + end + end +end diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index 76a18fa76a..97c8025db3 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -685,6 +685,146 @@ class FormHelperTest < ActionView::TestCase assert_dom_equal(expected, time_field("post", "written_on")) end + def test_datetime_field + expected = %{} + assert_dom_equal(expected, datetime_field("post", "written_on")) + end + + def test_datetime_field_with_datetime_value + expected = %{} + @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3) + assert_dom_equal(expected, datetime_field("post", "written_on")) + end + + def test_datetime_field_with_extra_attrs + expected = %{} + @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3) + min_value = DateTime.new(2000, 6, 15, 20, 45, 30) + max_value = DateTime.new(2010, 8, 15, 10, 25, 00) + step = 60 + assert_dom_equal(expected, datetime_field("post", "written_on", :min => min_value, :max => max_value, :step => step)) + end + + def test_datetime_field_with_timewithzone_value + previous_time_zone, Time.zone = Time.zone, 'UTC' + expected = %{} + @post.written_on = Time.zone.parse('2004-06-15 15:30:45') + assert_dom_equal(expected, datetime_field("post", "written_on")) + ensure + Time.zone = previous_time_zone + end + + def test_datetime_field_with_nil_value + expected = %{} + @post.written_on = nil + assert_dom_equal(expected, datetime_field("post", "written_on")) + end + + def test_datetime_local_field + expected = %{} + assert_dom_equal(expected, datetime_local_field("post", "written_on")) + end + + def test_datetime_local_field_with_datetime_value + expected = %{} + @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3) + assert_dom_equal(expected, datetime_local_field("post", "written_on")) + end + + def test_datetime_local_field_with_extra_attrs + expected = %{} + @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3) + min_value = DateTime.new(2000, 6, 15, 20, 45, 30) + max_value = DateTime.new(2010, 8, 15, 10, 25, 00) + step = 60 + assert_dom_equal(expected, datetime_local_field("post", "written_on", :min => min_value, :max => max_value, :step => step)) + end + + def test_datetime_local_field_with_timewithzone_value + previous_time_zone, Time.zone = Time.zone, 'UTC' + expected = %{} + @post.written_on = Time.zone.parse('2004-06-15 15:30:45') + assert_dom_equal(expected, datetime_local_field("post", "written_on")) + ensure + Time.zone = previous_time_zone + end + + def test_datetime_local_field_with_nil_value + expected = %{} + @post.written_on = nil + assert_dom_equal(expected, datetime_local_field("post", "written_on")) + end + + def test_month_field + expected = %{} + assert_dom_equal(expected, month_field("post", "written_on")) + end + + def test_month_field_with_nil_value + expected = %{} + @post.written_on = nil + assert_dom_equal(expected, month_field("post", "written_on")) + end + + def test_month_field_with_datetime_value + expected = %{} + @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3) + assert_dom_equal(expected, month_field("post", "written_on")) + end + + def test_month_field_with_extra_attrs + expected = %{} + @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3) + min_value = DateTime.new(2000, 2, 13) + max_value = DateTime.new(2010, 12, 23) + step = 2 + assert_dom_equal(expected, month_field("post", "written_on", :min => min_value, :max => max_value, :step => step)) + end + + def test_month_field_with_timewithzone_value + previous_time_zone, Time.zone = Time.zone, 'UTC' + expected = %{} + @post.written_on = Time.zone.parse('2004-06-15 15:30:45') + assert_dom_equal(expected, month_field("post", "written_on")) + ensure + Time.zone = previous_time_zone + end + + def test_week_field + expected = %{} + assert_dom_equal(expected, week_field("post", "written_on")) + end + + def test_week_field_with_nil_value + expected = %{} + @post.written_on = nil + assert_dom_equal(expected, week_field("post", "written_on")) + end + + def test_week_field_with_datetime_value + expected = %{} + @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3) + assert_dom_equal(expected, week_field("post", "written_on")) + end + + def test_week_field_with_extra_attrs + expected = %{} + @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3) + min_value = DateTime.new(2000, 2, 13) + max_value = DateTime.new(2010, 12, 23) + step = 2 + assert_dom_equal(expected, week_field("post", "written_on", :min => min_value, :max => max_value, :step => step)) + end + + def test_week_field_with_timewithzone_value + previous_time_zone, Time.zone = Time.zone, 'UTC' + expected = %{} + @post.written_on = Time.zone.parse('2004-06-15 15:30:45') + assert_dom_equal(expected, week_field("post", "written_on")) + ensure + Time.zone = previous_time_zone + end + def test_url_field expected = %{} assert_dom_equal(expected, url_field("user", "homepage")) diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb index 195adce180..5d19e3274d 100644 --- a/actionpack/test/template/form_tag_helper_test.rb +++ b/actionpack/test/template/form_tag_helper_test.rb @@ -469,6 +469,26 @@ class FormTagHelperTest < ActionView::TestCase assert_dom_equal(expected, time_field_tag("cell")) end + def test_datetime_field_tag + expected = %{} + assert_dom_equal(expected, datetime_field_tag("appointment")) + end + + def test_datetime_local_field_tag + expected = %{} + assert_dom_equal(expected, datetime_local_field_tag("appointment")) + end + + def test_month_field_tag + expected = %{} + assert_dom_equal(expected, month_field_tag("birthday")) + end + + def test_week_field_tag + expected = %{} + assert_dom_equal(expected, week_field_tag("birthday")) + end + def test_url_field_tag expected = %{} assert_dom_equal(expected, url_field_tag("homepage")) diff --git a/guides/source/form_helpers.textile b/guides/source/form_helpers.textile index 11d48551c4..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, color 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: <%= text_area_tag(:message, "Hi, nice site", :size => "24x6") %> @@ -159,6 +159,10 @@ 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) %> @@ -174,6 +178,10 @@ Output: + + + + @@ -182,7 +190,7 @@ Output: 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, color, 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. -- cgit v1.2.3 From e4569b50d1d20f52633a3fe036014acd5117fa73 Mon Sep 17 00:00:00 2001 From: Alexey Vakhov Date: Sat, 25 Feb 2012 01:29:00 +0400 Subject: Add instance_accessor option to class_attribute --- actionpack/lib/abstract_controller/layouts.rb | 3 +-- activesupport/CHANGELOG.md | 2 ++ activesupport/lib/active_support/core_ext/class/attribute.rb | 6 ++++-- activesupport/test/core_ext/class/attribute_test.rb | 7 +++++++ 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb index bc9f6fc3e8..c1b3994035 100644 --- a/actionpack/lib/abstract_controller/layouts.rb +++ b/actionpack/lib/abstract_controller/layouts.rb @@ -203,8 +203,7 @@ module AbstractController include Rendering included do - class_attribute :_layout, :_layout_conditions, - :instance_reader => false, :instance_writer => false + class_attribute :_layout, :_layout_conditions, :instance_accessor => false self._layout = nil self._layout_conditions = {} _write_layout_method diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index 79ea9c70ea..c1fef1b9d9 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,5 +1,7 @@ ## Rails 4.0.0 (unreleased) ## +* Add `:instance_accessor` option for `class_attribute`. *Alexey Vakhov* + * `constantize` now looks in the ancestor chain. *Marc-Andre Lafortune & Andrew White* * `Object#try` can't call private methods. *Vasiliy Ermolovich* diff --git a/activesupport/lib/active_support/core_ext/class/attribute.rb b/activesupport/lib/active_support/core_ext/class/attribute.rb index c64685a694..7b6f8ab0a1 100644 --- a/activesupport/lib/active_support/core_ext/class/attribute.rb +++ b/activesupport/lib/active_support/core_ext/class/attribute.rb @@ -65,10 +65,12 @@ class Class # To opt out of the instance writer method, pass :instance_writer => false. # # object.setting = false # => NoMethodError + # + # To opt out of both instance methods, pass :instance_accessor => false. def class_attribute(*attrs) options = attrs.extract_options! - instance_reader = options.fetch(:instance_reader, true) - instance_writer = options.fetch(:instance_writer, true) + instance_reader = options.fetch(:instance_accessor, true) && options.fetch(:instance_reader, true) + instance_writer = options.fetch(:instance_accessor, true) && options.fetch(:instance_writer, true) attrs.each do |name| class_eval <<-RUBY, __FILE__, __LINE__ + 1 diff --git a/activesupport/test/core_ext/class/attribute_test.rb b/activesupport/test/core_ext/class/attribute_test.rb index e290a6e012..1c3ba8a7a0 100644 --- a/activesupport/test/core_ext/class/attribute_test.rb +++ b/activesupport/test/core_ext/class/attribute_test.rb @@ -66,6 +66,13 @@ class ClassAttributeTest < ActiveSupport::TestCase assert_raise(NoMethodError) { object.setting? } end + test 'disabling both instance writer and reader' do + object = Class.new { class_attribute :setting, :instance_accessor => false }.new + assert_raise(NoMethodError) { object.setting } + assert_raise(NoMethodError) { object.setting? } + assert_raise(NoMethodError) { object.setting = 'boom' } + end + test 'works well with singleton classes' do object = @klass.new object.singleton_class.setting = 'foo' -- cgit v1.2.3 From d5d9a281aaf9bc0fd7f5e92e1609a7677f25887c Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Mon, 21 May 2012 18:34:31 -0300 Subject: Refactor aggregation writer method Only constantize class_name once. --- activerecord/lib/active_record/aggregations.rb | 7 +++---- activerecord/test/models/customer.rb | 1 - 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/activerecord/lib/active_record/aggregations.rb b/activerecord/lib/active_record/aggregations.rb index 5de10a8dd6..f0b549e5ad 100644 --- a/activerecord/lib/active_record/aggregations.rb +++ b/activerecord/lib/active_record/aggregations.rb @@ -242,10 +242,9 @@ module ActiveRecord def writer_method(name, class_name, mapping, allow_nil, converter) define_method("#{name}=") do |part| - unless part.is_a?(class_name.constantize) || converter.nil? || part.nil? - part = converter.respond_to?(:call) ? - converter.call(part) : - class_name.constantize.send(converter, part) + klass = class_name.constantize + unless part.is_a?(klass) || converter.nil? || part.nil? + part = converter.respond_to?(:call) ? converter.call(part) : klass.send(converter, part) end if part.nil? && allow_nil diff --git a/activerecord/test/models/customer.rb b/activerecord/test/models/customer.rb index 807f25b687..7e8e82542f 100644 --- a/activerecord/test/models/customer.rb +++ b/activerecord/test/models/customer.rb @@ -1,5 +1,4 @@ class Customer < ActiveRecord::Base - cattr_accessor :gps_conversion_was_run composed_of :address, :mapping => [ %w(address_street street), %w(address_city city), %w(address_country country) ], :allow_nil => true -- cgit v1.2.3 From 03886d817307e091024ff3bd26844447abd8c408 Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Mon, 21 May 2012 18:35:44 -0300 Subject: Remove not used variables from connection poll test These variables were issuing some "not used" warnings. --- activerecord/test/cases/connection_pool_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/activerecord/test/cases/connection_pool_test.rb b/activerecord/test/cases/connection_pool_test.rb index 6871e628aa..b1905515d3 100644 --- a/activerecord/test/cases/connection_pool_test.rb +++ b/activerecord/test/cases/connection_pool_test.rb @@ -230,7 +230,7 @@ module ActiveRecord threads = expected.map do |i| t = Thread.new { begin - conn = @pool.checkout # never checked back in + @pool.checkout # never checked back in mutex.synchronize { order << i } rescue => e mutex.synchronize { errors << e } @@ -273,7 +273,7 @@ module ActiveRecord make_thread = proc do |i| t = Thread.new { begin - conn = @pool.checkout # never checked back in + @pool.checkout # never checked back in mutex.synchronize { successes << i } rescue => e mutex.synchronize { errors << e } -- cgit v1.2.3 From 5b7b705d36c58508e7da0a87dd6232f699653969 Mon Sep 17 00:00:00 2001 From: Alexey Vakhov Date: Tue, 22 May 2012 01:37:03 +0400 Subject: Fix AR preloader example --- activerecord/lib/active_record/associations/preloader.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/associations/preloader.rb b/activerecord/lib/active_record/associations/preloader.rb index fafed94ff2..54705e4950 100644 --- a/activerecord/lib/active_record/associations/preloader.rb +++ b/activerecord/lib/active_record/associations/preloader.rb @@ -12,7 +12,7 @@ module ActiveRecord # and all of its books via a single query: # # SELECT * FROM authors - # LEFT OUTER JOIN books ON authors.id = books.id + # LEFT OUTER JOIN books ON authors.id = books.author_id # WHERE authors.name = 'Ken Akamatsu' # # However, this could result in many rows that contain redundant data. After -- cgit v1.2.3 From cb847b9f2e56eeff737323d9a42a2a0a6c23804d Mon Sep 17 00:00:00 2001 From: Godfrey Chan Date: Mon, 21 May 2012 14:57:04 -0700 Subject: Restore the frozen state on rollback. Fixes #6417. Currently, when saving a frozen record, an exception would be thrown which causes a rollback. However, there is a bug in active record that "defrost" the record as a side effect: >> t = Topic.new => # >> t.freeze => # >> t.save RuntimeError: can't modify a frozen Hash >> t.frozen? => false >> t.save => true This patch fixes the bug by explictly restoring the frozen state on the attributes Hash after every rollback. --- activerecord/lib/active_record/transactions.rb | 4 +++- activerecord/test/cases/transactions_test.rb | 10 ++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb index 30e1035300..9cb9b4627b 100644 --- a/activerecord/lib/active_record/transactions.rb +++ b/activerecord/lib/active_record/transactions.rb @@ -329,7 +329,8 @@ module ActiveRecord @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1 if @_start_transaction_state[:level] < 1 restore_state = remove_instance_variable(:@_start_transaction_state) - @attributes = @attributes.dup if @attributes.frozen? + was_frozen = @attributes.frozen? + @attributes = @attributes.dup if was_frozen @new_record = restore_state[:new_record] @destroyed = restore_state[:destroyed] if restore_state.has_key?(:id) @@ -338,6 +339,7 @@ module ActiveRecord @attributes.delete(self.class.primary_key) @attributes_cache.delete(self.class.primary_key) end + @attributes.freeze if was_frozen end end end diff --git a/activerecord/test/cases/transactions_test.rb b/activerecord/test/cases/transactions_test.rb index 203dd054f1..a9ccd00fac 100644 --- a/activerecord/test/cases/transactions_test.rb +++ b/activerecord/test/cases/transactions_test.rb @@ -362,6 +362,16 @@ class TransactionTest < ActiveRecord::TestCase end end + def test_rollback_when_saving_a_frozen_record + topic = Topic.new(:title => 'test') + topic.freeze + e = assert_raise(RuntimeError) { topic.save } + assert_equal "can't modify frozen Hash", e.message + assert !topic.persisted?, 'not persisted' + assert_nil topic.id + assert topic.frozen?, 'not frozen' + end + def test_restore_active_record_state_for_all_records_in_a_transaction topic_1 = Topic.new(:title => 'test_1') topic_2 = Topic.new(:title => 'test_2') -- cgit v1.2.3 From edb87b19d42b2a47708a78e0762a9e761aaf1277 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 21 May 2012 16:20:18 -0700 Subject: using __method__ for the command method calls --- railties/lib/rails/configuration.rb | 10 ++-- .../configuration/middleware_stack_proxy_test.rb | 59 ++++++++++++++++++++++ 2 files changed, 64 insertions(+), 5 deletions(-) create mode 100644 railties/test/configuration/middleware_stack_proxy_test.rb diff --git a/railties/lib/rails/configuration.rb b/railties/lib/rails/configuration.rb index 3d66019e5e..5fa7f043c6 100644 --- a/railties/lib/rails/configuration.rb +++ b/railties/lib/rails/configuration.rb @@ -39,25 +39,25 @@ module Rails end def insert_before(*args, &block) - @operations << [:insert_before, args, block] + @operations << [__method__, args, block] end alias :insert :insert_before def insert_after(*args, &block) - @operations << [:insert_after, args, block] + @operations << [__method__, args, block] end def swap(*args, &block) - @operations << [:swap, args, block] + @operations << [__method__, args, block] end def use(*args, &block) - @operations << [:use, args, block] + @operations << [__method__, args, block] end def delete(*args, &block) - @operations << [:delete, args, block] + @operations << [__method__, args, block] end def merge_into(other) #:nodoc: diff --git a/railties/test/configuration/middleware_stack_proxy_test.rb b/railties/test/configuration/middleware_stack_proxy_test.rb new file mode 100644 index 0000000000..5984c0b425 --- /dev/null +++ b/railties/test/configuration/middleware_stack_proxy_test.rb @@ -0,0 +1,59 @@ +require 'minitest/autorun' +require 'rails/configuration' +require 'active_support/test_case' + +module Rails + module Configuration + class MiddlewareStackProxyTest < ActiveSupport::TestCase + def setup + @stack = MiddlewareStackProxy.new + end + + def test_playback_insert_before + @stack.insert_before :foo + assert_playback :insert_before, :foo + end + + def test_playback_insert_after + @stack.insert_after :foo + assert_playback :insert_after, :foo + end + + def test_playback_swap + @stack.swap :foo + assert_playback :swap, :foo + end + + def test_playback_use + @stack.use :foo + assert_playback :use, :foo + end + + def test_playback_delete + @stack.delete :foo + assert_playback :delete, :foo + end + + def test_order + @stack.swap :foo + @stack.delete :foo + + mock = MiniTest::Mock.new + mock.expect :send, nil, [:swap, :foo] + mock.expect :send, nil, [:delete, :foo] + + @stack.merge_into mock + mock.verify + end + + private + + def assert_playback(msg_name, args) + mock = MiniTest::Mock.new + mock.expect :send, nil, [msg_name, args] + @stack.merge_into(mock) + mock.verify + end + end + end +end -- cgit v1.2.3 From f9a718eb5e3fe969c3a01cf084c6686cc2ce7aff Mon Sep 17 00:00:00 2001 From: Francesco Rodriguez Date: Mon, 21 May 2012 23:30:13 -0500 Subject: add CollectionProxy#delete_all documentation --- .../active_record/associations/collection_proxy.rb | 65 ++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index b419b9a749..650d68a64a 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -218,6 +218,71 @@ module ActiveRecord # # person.pets.replace(["doo", "ggie", "gaga"]) # # => ActiveRecord::AssociationTypeMismatch: Pet expected, got String + + + ## + # :method: delete_all + # Deletes all the records from the collection. For +has_many+ it will do the + # deletion according to the strategy specified by the :dependent + # option. Returns an array with the deleted records. + # + # If no :dependent option is given, then it will follow the + # default strategy. The default strategy is :nullify. This + # sets the foreign keys to NULL. + # + # class Person < ActiveRecord::Base + # has_many :pets # dependent: :nullify option by default + # end + # + # person.pets.size # => 3 + # person.pets + # # => [ + # # #, + # # #, + # # # + # # ] + # + # person.pets.delete_all + # # => [ + # # #, + # # #, + # # # + # # ] + # + # person.pets.size # => 0 + # person.pets # => [] + # + # Pet.find(1, 2, 3) + # # => [ + # # #, + # # #, + # # # + # # ] + # + # If it is set to :destroy all the objects from the collection + # are destroyed by calling their +destroy+ method. + # + # class Person < ActiveRecord::Base + # has_many :pets, dependent: :destroy + # end + # + # person.pets.size # => 3 + # person.pets + # # => [ + # # #, + # # #, + # # # + # # ] + # + # person.pets.delete_all + # # => [ + # # #, + # # #, + # # # + # # ] + # + # Pet.find(1, 2, 3) + # # => ActiveRecord::RecordNotFound ## # :method: destroy_all -- cgit v1.2.3 From 1bcd5e42ed6c2efed4d1a53e74b4f8d6631b119d Mon Sep 17 00:00:00 2001 From: Francesco Rodriguez Date: Mon, 21 May 2012 23:49:41 -0500 Subject: update CollectionProxy#delete_all documentation --- .../active_record/associations/collection_proxy.rb | 31 ++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index 650d68a64a..f0c4688ee3 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -228,7 +228,8 @@ module ActiveRecord # # If no :dependent option is given, then it will follow the # default strategy. The default strategy is :nullify. This - # sets the foreign keys to NULL. + # sets the foreign keys to NULL. For, +has_many+ :through, + # the default strategy is +delete_all+. # # class Person < ActiveRecord::Base # has_many :pets # dependent: :nullify option by default @@ -260,7 +261,8 @@ module ActiveRecord # # ] # # If it is set to :destroy all the objects from the collection - # are destroyed by calling their +destroy+ method. + # are removed by calling their +destroy+ method. See +destroy+ for more + # information. # # class Person < ActiveRecord::Base # has_many :pets, dependent: :destroy @@ -283,6 +285,31 @@ module ActiveRecord # # Pet.find(1, 2, 3) # # => ActiveRecord::RecordNotFound + # + # If it is set to :delete_all, all the objects are deleted + # *without* calling their +destroy+ method. + # + # class Person < ActiveRecord::Base + # has_many :pets, dependent: :delete_all + # end + # + # person.pets.size # => 3 + # person.pets + # # => [ + # # #, + # # #, + # # # + # # ] + # + # person.pets.delete_all + # # => [ + # # #, + # # #, + # # # + # # ] + # + # Pet.find(1, 2, 3) + # # => ActiveRecord::RecordNotFound ## # :method: destroy_all -- cgit v1.2.3 From 8281194fee1a049826c50f9e0a095ea1abb91277 Mon Sep 17 00:00:00 2001 From: Francesco Rodriguez Date: Mon, 21 May 2012 23:51:31 -0500 Subject: update CollectionProxy#clear documentation --- activerecord/lib/active_record/associations/collection_proxy.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index f0c4688ee3..468bf5c2f8 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -577,9 +577,8 @@ module ActiveRecord end alias_method :push, :<< - # Removes every object from the collection. This does not destroy - # the objects, it sets their foreign keys to +NULL+. Returns +self+ - # so methods can be chained. + # Equivalent to +delete_all+. The difference is that returns +self+, instead + # of an array with the deleted objects, so methods can be chained. # # class Person < ActiveRecord::Base # has_many :pets -- cgit v1.2.3 From a060c41ef77cf3a0e4d236a70f3fef260ff9a261 Mon Sep 17 00:00:00 2001 From: Alexey Vakhov Date: Fri, 4 May 2012 12:54:20 +0400 Subject: Use relative path to sqlite3 db in `rails db` command Rails uses sqlit3 db file with a path relative to the rails root. It allows to execute server not from rails root only. For example you can fire `./spec/dummy/script/rails s` to start dummy application server if you develop some engine gem. Now the `rails db` command uses relative paths also and you can explore your dummy db via `./spec/dummy/script/rails db` command. --- railties/lib/rails/commands/dbconsole.rb | 2 +- railties/test/commands/dbconsole_test.rb | 17 +++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/railties/lib/rails/commands/dbconsole.rb b/railties/lib/rails/commands/dbconsole.rb index aaba47117f..cdff9c6f86 100644 --- a/railties/lib/rails/commands/dbconsole.rb +++ b/railties/lib/rails/commands/dbconsole.rb @@ -96,7 +96,7 @@ module Rails args << "-#{options['mode']}" if options['mode'] args << "-header" if options['header'] - args << config['database'] + args << File.expand_path(config['database'], Rails.root) find_cmd_and_exec('sqlite3', *args) diff --git a/railties/test/commands/dbconsole_test.rb b/railties/test/commands/dbconsole_test.rb index 85a7edfacd..57074cd0ad 100644 --- a/railties/test/commands/dbconsole_test.rb +++ b/railties/test/commands/dbconsole_test.rb @@ -92,20 +92,25 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase end def test_sqlite3 - dbconsole.expects(:find_cmd_and_exec).with('sqlite3', 'db') - start(adapter: 'sqlite3', database: 'db') + dbconsole.expects(:find_cmd_and_exec).with('sqlite3', Rails.root.join('db.sqlite3').to_s) + start(adapter: 'sqlite3', database: 'db.sqlite3') assert !aborted end def test_sqlite3_mode - dbconsole.expects(:find_cmd_and_exec).with('sqlite3', '-html', 'db') - start({adapter: 'sqlite3', database: 'db'}, ['--mode', 'html']) + dbconsole.expects(:find_cmd_and_exec).with('sqlite3', '-html', Rails.root.join('db.sqlite3').to_s) + start({adapter: 'sqlite3', database: 'db.sqlite3'}, ['--mode', 'html']) assert !aborted end def test_sqlite3_header - dbconsole.expects(:find_cmd_and_exec).with('sqlite3', '-header', 'db') - start({adapter: 'sqlite3', database: 'db'}, ['--header']) + dbconsole.expects(:find_cmd_and_exec).with('sqlite3', '-header', Rails.root.join('db.sqlite3').to_s) + start({adapter: 'sqlite3', database: 'db.sqlite3'}, ['--header']) + end + + def test_sqlite3_db_absolute_path + dbconsole.expects(:find_cmd_and_exec).with('sqlite3', '/tmp/db.sqlite3') + start(adapter: 'sqlite3', database: '/tmp/db.sqlite3') assert !aborted end -- cgit v1.2.3 From 1fed1f14fc0ecb375d8a7c542669dad96541582d Mon Sep 17 00:00:00 2001 From: Alexey Vakhov Date: Fri, 4 May 2012 22:04:53 +0400 Subject: Fix `rails db -h` and cosmetic fixes in usage banners Ruby tries to use '-h' as short version of '--header' by default https://github.com/ruby/ruby/blob/trunk/lib/optparse.rb#L1372-1381. To force `rails db -h` prints an usage message we should add the `-h` options explicitly. --- railties/lib/rails/commands/console.rb | 2 +- railties/lib/rails/commands/dbconsole.rb | 7 ++++++- railties/lib/rails/commands/runner.rb | 2 +- railties/test/commands/dbconsole_test.rb | 18 ++++++++++++++++++ 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/railties/lib/rails/commands/console.rb b/railties/lib/rails/commands/console.rb index cd6a03fe51..b95df3e545 100644 --- a/railties/lib/rails/commands/console.rb +++ b/railties/lib/rails/commands/console.rb @@ -22,7 +22,7 @@ module Rails options = {} OptionParser.new do |opt| - opt.banner = "Usage: console [environment] [options]" + opt.banner = "Usage: rails console [environment] [options]" opt.on('-s', '--sandbox', 'Rollback database modifications on exit.') { |v| options[:sandbox] = v } opt.on("-e", "--environment=name", String, "Specifies the environment to run this console under (test/development/production).", diff --git a/railties/lib/rails/commands/dbconsole.rb b/railties/lib/rails/commands/dbconsole.rb index cdff9c6f86..cc7caffc3d 100644 --- a/railties/lib/rails/commands/dbconsole.rb +++ b/railties/lib/rails/commands/dbconsole.rb @@ -42,7 +42,7 @@ module Rails include_password = false options = {} OptionParser.new do |opt| - opt.banner = "Usage: dbconsole [environment] [options]" + opt.banner = "Usage: rails dbconsole [environment] [options]" opt.on("-p", "--include-password", "Automatically provide the password from database.yml") do |v| include_password = true end @@ -56,6 +56,11 @@ module Rails options['header'] = h end + opt.on("-h", "--help", "Show this help message.") do + puts opt + exit + end + opt.parse!(arguments) abort opt.to_s unless (0..1).include?(arguments.size) end diff --git a/railties/lib/rails/commands/runner.rb b/railties/lib/rails/commands/runner.rb index 2802981e7a..77f1b15fb4 100644 --- a/railties/lib/rails/commands/runner.rb +++ b/railties/lib/rails/commands/runner.rb @@ -9,7 +9,7 @@ if ARGV.first.nil? end ARGV.clone.options do |opts| - opts.banner = "Usage: runner [options] ('Some.ruby(code)' or a filename)" + opts.banner = "Usage: rails runner [options] ('Some.ruby(code)' or a filename)" opts.separator "" diff --git a/railties/test/commands/dbconsole_test.rb b/railties/test/commands/dbconsole_test.rb index 57074cd0ad..6d0f5ca073 100644 --- a/railties/test/commands/dbconsole_test.rb +++ b/railties/test/commands/dbconsole_test.rb @@ -132,6 +132,24 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase assert_match /Unknown command-line client for db/, output end + def test_print_help_short + stdout = capture(:stdout) do + start({}, ['-h']) + end + assert aborted + assert_equal '', output + assert_match /Usage:.*dbconsole/, stdout + end + + def test_print_help_long + stdout = capture(:stdout) do + start({}, ['--help']) + end + assert aborted + assert_equal '', output + assert_match /Usage:.*dbconsole/, stdout + end + private attr_reader :aborted, :output -- cgit v1.2.3 From 4220290d09e682d8454048312b89efaf84f028be Mon Sep 17 00:00:00 2001 From: Gaurish Sharma Date: Tue, 22 May 2012 11:19:32 +0530 Subject: Fix broken link --- guides/source/debugging_rails_applications.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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/ -- cgit v1.2.3 From 09be6921590a7e4ded515deb8ce77566fa41fed5 Mon Sep 17 00:00:00 2001 From: Alexey Vakhov Date: Tue, 22 May 2012 11:45:59 +0400 Subject: Remove obsolete comment from generator gem method This comment about :env option for gem method was actual for rails 2.3 without bundler. Now bundler uses grups for this goal. --- railties/lib/rails/generators/actions.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb index 6cd2ea2bbd..703501e6f0 100644 --- a/railties/lib/rails/generators/actions.rb +++ b/railties/lib/rails/generators/actions.rb @@ -5,8 +5,7 @@ module Rails module Generators module Actions - # Adds an entry into Gemfile for the supplied gem. If env - # is specified, add the gem to the given environment. + # Adds an entry into Gemfile for the supplied gem. # # gem "rspec", :group => :test # gem "technoweenie-restful-authentication", :lib => "restful-authentication", :source => "http://gems.github.com/" -- cgit v1.2.3 From 3ed92c876c5cebea908f23020457bd494755f54b Mon Sep 17 00:00:00 2001 From: Jan Xie Date: Tue, 22 May 2012 16:18:42 +0800 Subject: remove useless require --- activesupport/lib/active_support/dependencies/autoload.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/activesupport/lib/active_support/dependencies/autoload.rb b/activesupport/lib/active_support/dependencies/autoload.rb index a1626ebeba..4045db3232 100644 --- a/activesupport/lib/active_support/dependencies/autoload.rb +++ b/activesupport/lib/active_support/dependencies/autoload.rb @@ -1,5 +1,4 @@ require "active_support/inflector/methods" -require "active_support/lazy_load_hooks" module ActiveSupport module Autoload -- cgit v1.2.3 From 29d17d3ab65633695babc9123463c78248e41a67 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Tue, 22 May 2012 01:40:51 -0700 Subject: Use require_dependency in generated controllers Using require in development mode will prevent required files from reloading, even if they're changed. In order to keep namespaced application_controller reloadable, we need to use require_dependency instead of require. --- .../lib/rails/generators/rails/controller/templates/controller.rb | 2 +- .../generators/rails/scaffold_controller/templates/controller.rb | 2 +- railties/test/generators/namespaced_generators_test.rb | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/railties/lib/rails/generators/rails/controller/templates/controller.rb b/railties/lib/rails/generators/rails/controller/templates/controller.rb index 9b04192126..ece6bbba3b 100644 --- a/railties/lib/rails/generators/rails/controller/templates/controller.rb +++ b/railties/lib/rails/generators/rails/controller/templates/controller.rb @@ -1,5 +1,5 @@ <% if namespaced? -%> -require "<%= namespaced_file_path %>/application_controller" +require_dependency "<%= namespaced_file_path %>/application_controller" <% end -%> <% module_namespacing do -%> diff --git a/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb index 5cd31bf2ee..0294bde582 100644 --- a/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb +++ b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb @@ -1,5 +1,5 @@ <% if namespaced? -%> -require "<%= namespaced_file_path %>/application_controller" +require_dependency "<%= namespaced_file_path %>/application_controller" <% end -%> <% module_namespacing do -%> diff --git a/railties/test/generators/namespaced_generators_test.rb b/railties/test/generators/namespaced_generators_test.rb index 903465392d..09169ef2d2 100644 --- a/railties/test/generators/namespaced_generators_test.rb +++ b/railties/test/generators/namespaced_generators_test.rb @@ -21,7 +21,7 @@ class NamespacedControllerGeneratorTest < NamespacedGeneratorTestCase def test_namespaced_controller_skeleton_is_created run_generator assert_file "app/controllers/test_app/account_controller.rb", - /require "test_app\/application_controller"/, + /require_dependency "test_app\/application_controller"/, /module TestApp/, / class AccountController < ApplicationController/ @@ -234,7 +234,7 @@ class NamespacedScaffoldGeneratorTest < NamespacedGeneratorTestCase # Controller assert_file "app/controllers/test_app/product_lines_controller.rb", - /require "test_app\/application_controller"/, + /require_dependency "test_app\/application_controller"/, /module TestApp/, /class ProductLinesController < ApplicationController/ -- cgit v1.2.3 From fe7038eac8c1a4df57a0aacf4dd77da5ef87f6df Mon Sep 17 00:00:00 2001 From: Alexey Vakhov Date: Tue, 22 May 2012 13:26:06 +0400 Subject: Use new hash syntax for generators gem method The Gemfile of new application uses ruby 1.9 hashes. Gem method of generators should use them too. It prevents from mixing two kinds of syntax in one file. --- railties/lib/rails/generators/actions.rb | 2 +- .../lib/rails/generators/rails/plugin_new/plugin_new_generator.rb | 2 +- railties/test/generators/actions_test.rb | 8 ++++++++ railties/test/generators/plugin_new_generator_test.rb | 4 ++-- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb index 6cd2ea2bbd..92f40b9e31 100644 --- a/railties/lib/rails/generators/actions.rb +++ b/railties/lib/rails/generators/actions.rb @@ -27,7 +27,7 @@ module Rails log :gemfile, message options.each do |option, value| - parts << ":#{option} => #{value.inspect}" + parts << "#{option}: #{value.inspect}" end in_root do diff --git a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb index 722e37e20b..7088367462 100644 --- a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +++ b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb @@ -139,7 +139,7 @@ task :default => :test gemfile_in_app_path = File.join(rails_app_path, "Gemfile") if File.exist? gemfile_in_app_path - entry = "gem '#{name}', :path => '#{relative_path}'" + entry = "gem '#{name}', path: '#{relative_path}'" append_file gemfile_in_app_path, entry end end diff --git a/railties/test/generators/actions_test.rb b/railties/test/generators/actions_test.rb index a8c8fcd5b7..bc086c5986 100644 --- a/railties/test/generators/actions_test.rb +++ b/railties/test/generators/actions_test.rb @@ -67,6 +67,14 @@ class ActionsTest < Rails::Generators::TestCase assert_file 'Gemfile', /^gem "rspec-rails"$/ end + def test_gem_should_include_options + run_generator + + action :gem, 'rspec', github: 'dchelimsky/rspec', tag: '1.2.9.rc1' + + assert_file 'Gemfile', /gem "rspec", github: "dchelimsky\/rspec", tag: "1\.2\.9\.rc1"/ + end + def test_gem_group_should_wrap_gems_in_a_group run_generator diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb index 51374e5f3f..58740978aa 100644 --- a/railties/test/generators/plugin_new_generator_test.rb +++ b/railties/test/generators/plugin_new_generator_test.rb @@ -279,7 +279,7 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase run_generator [destination_root] - assert_file gemfile_path, /gem 'bukkits', :path => 'tmp\/bukkits'/ + assert_file gemfile_path, /gem 'bukkits', path: 'tmp\/bukkits'/ ensure Object.send(:remove_const, 'APP_PATH') FileUtils.rm gemfile_path @@ -294,7 +294,7 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase run_generator [destination_root, "--skip-gemfile-entry"] assert_file gemfile_path do |contents| - assert_no_match(/gem 'bukkits', :path => 'tmp\/bukkits'/, contents) + assert_no_match(/gem 'bukkits', path: 'tmp\/bukkits'/, contents) end ensure Object.send(:remove_const, 'APP_PATH') -- cgit v1.2.3 From a807db9d198f533cbb1a6bac27c3c211f4729cd8 Mon Sep 17 00:00:00 2001 From: Jan Xie Date: Tue, 22 May 2012 21:50:16 +0800 Subject: refactor lazy_load_hooks load position --- activesupport/lib/active_support.rb | 1 + activesupport/lib/active_support/i18n.rb | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb index 8f018dcbc6..56d6676961 100644 --- a/activesupport/lib/active_support.rb +++ b/activesupport/lib/active_support.rb @@ -25,6 +25,7 @@ require 'securerandom' require "active_support/dependencies/autoload" require "active_support/version" require "active_support/logger" +require "active_support/lazy_load_hooks" module ActiveSupport extend ActiveSupport::Autoload diff --git a/activesupport/lib/active_support/i18n.rb b/activesupport/lib/active_support/i18n.rb index 188653bd9b..27234d89e1 100644 --- a/activesupport/lib/active_support/i18n.rb +++ b/activesupport/lib/active_support/i18n.rb @@ -1,6 +1,5 @@ begin require 'i18n' - require 'active_support/lazy_load_hooks' rescue LoadError => e $stderr.puts "The i18n gem is not available. Please add it to your Gemfile and run bundle install" raise e -- cgit v1.2.3 From feaa7b35a0214240eb34780ab51b843571e74904 Mon Sep 17 00:00:00 2001 From: Gaurish Sharma Date: Tue, 22 May 2012 19:29:25 +0530 Subject: Remove Obsolute root specifiying short syntax This syntax does not seem to work. Throws the error "can't convert String into Hash (TypeError)" Tested on: * Ruby 1.9.3 * Rails 3.2.3 --- guides/source/routing.textile | 1 - 1 file changed, 1 deletion(-) diff --git a/guides/source/routing.textile b/guides/source/routing.textile index 4a50edbb15..6081651364 100644 --- a/guides/source/routing.textile +++ b/guides/source/routing.textile @@ -629,7 +629,6 @@ You can specify what Rails should route +"/"+ to with the +root+ method: root :to => 'pages#main' -root 'pages#main' # shortcut for the above You should put the +root+ route at the top of the file, because it is the most popular route and should be matched first. You also need to delete the +public/index.html+ file for the root route to take effect. -- cgit v1.2.3 From 940c135175cba6e6611cb67a93b9370da4e81fd9 Mon Sep 17 00:00:00 2001 From: Andrey Voronkov Date: Tue, 22 May 2012 18:08:36 +0400 Subject: Convert Hash to HashWithIndifferentAccess in ActiveRecord::Store. In order to make migration from 3.x apps easier, we should try to convert Hash instances to HashWithIndifferentAccess, to allow accessing values with both symbol and a string. This is follow up to changes in 3c0bf043. --- activerecord/lib/active_record/store.rb | 37 ++++++++++++++++++++++++--------- activerecord/test/cases/store_test.rb | 34 ++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 10 deletions(-) diff --git a/activerecord/lib/active_record/store.rb b/activerecord/lib/active_record/store.rb index ce2ea85ef9..fdd82b489a 100644 --- a/activerecord/lib/active_record/store.rb +++ b/activerecord/lib/active_record/store.rb @@ -1,3 +1,5 @@ +require 'active_support/core_ext/hash/indifferent_access' + module ActiveRecord # Store gives you a thin wrapper around serialize for the purpose of storing hashes in a single column. # It's like a simple key/value store backed into your record when you don't care about being able to @@ -13,9 +15,6 @@ module ActiveRecord # You can set custom coder to encode/decode your serialized attributes to/from different formats. # JSON, YAML, Marshal are supported out of the box. Generally it can be any wrapper that provides +load+ and +dump+. # - # String keys should be used for direct access to virtual attributes because of most of the coders do not - # distinguish symbols and strings as keys. - # # Examples: # # class User < ActiveRecord::Base @@ -23,8 +22,12 @@ module ActiveRecord # end # # u = User.new(color: 'black', homepage: '37signals.com') - # u.color # Accessor stored attribute - # u.settings['country'] = 'Denmark' # Any attribute, even if not specified with an accessor + # u.color # Accessor stored attribute + # u.settings[:country] = 'Denmark' # Any attribute, even if not specified with an accessor + # + # # There is no difference between strings and symbols for accessing custom attributes + # u.settings[:country] # => 'Denmark' + # u.settings['country'] # => 'Denmark' # # # Add additional accessors to an existing store through store_accessor # class SuperUser < User @@ -35,24 +38,38 @@ module ActiveRecord module ClassMethods def store(store_attribute, options = {}) - serialize store_attribute, options.fetch(:coder, Hash) + serialize store_attribute, options.fetch(:coder, ActiveSupport::HashWithIndifferentAccess) store_accessor(store_attribute, options[:accessors]) if options.has_key? :accessors end def store_accessor(store_attribute, *keys) keys.flatten.each do |key| define_method("#{key}=") do |value| - send("#{store_attribute}=", {}) unless send(store_attribute).is_a?(Hash) - send(store_attribute)[key.to_s] = value + initialize_store_attribute(store_attribute) + send(store_attribute)[key] = value send("#{store_attribute}_will_change!") end define_method(key) do - send("#{store_attribute}=", {}) unless send(store_attribute).is_a?(Hash) - send(store_attribute)[key.to_s] + initialize_store_attribute(store_attribute) + send(store_attribute)[key] end end end end + + private + def initialize_store_attribute(store_attribute) + case attribute = send(store_attribute) + when ActiveSupport::HashWithIndifferentAccess + # Already initialized. Do nothing. + when Hash + # Initialized as a Hash. Convert to indifferent access. + send :"#{store_attribute}=", attribute.with_indifferent_access + else + # Uninitialized. Set to an indifferent hash. + send :"#{store_attribute}=", ActiveSupport::HashWithIndifferentAccess.new + end + end end end diff --git a/activerecord/test/cases/store_test.rb b/activerecord/test/cases/store_test.rb index e1d0f1f799..3a5d84df9f 100644 --- a/activerecord/test/cases/store_test.rb +++ b/activerecord/test/cases/store_test.rb @@ -41,6 +41,40 @@ class StoreTest < ActiveRecord::TestCase assert_equal false, @john.remember_login end + test "preserve store attributes data in HashWithIndifferentAccess format without any conversion" do + @john.json_data = HashWithIndifferentAccess.new(:height => 'tall', 'weight' => 'heavy') + @john.height = 'low' + assert_equal true, @john.json_data.instance_of?(HashWithIndifferentAccess) + assert_equal 'low', @john.json_data[:height] + assert_equal 'low', @john.json_data['height'] + assert_equal 'heavy', @john.json_data[:weight] + assert_equal 'heavy', @john.json_data['weight'] + end + + test "convert store attributes from Hash to HashWithIndifferentAccess saving the data and access attributes indifferently" do + @john.json_data = { :height => 'tall', 'weight' => 'heavy' } + assert_equal true, @john.json_data.instance_of?(Hash) + assert_equal 'tall', @john.json_data[:height] + assert_equal nil, @john.json_data['height'] + assert_equal nil, @john.json_data[:weight] + assert_equal 'heavy', @john.json_data['weight'] + @john.height = 'low' + assert_equal true, @john.json_data.instance_of?(HashWithIndifferentAccess) + assert_equal 'low', @john.json_data[:height] + assert_equal 'low', @john.json_data['height'] + assert_equal 'heavy', @john.json_data[:weight] + assert_equal 'heavy', @john.json_data['weight'] + end + + test "convert store attributes from any format other than Hash or HashWithIndifferent access losing the data" do + @john.json_data = "somedata" + @john.height = 'low' + assert_equal true, @john.json_data.instance_of?(HashWithIndifferentAccess) + assert_equal 'low', @john.json_data[:height] + assert_equal 'low', @john.json_data['height'] + assert_equal false, @john.json_data.delete_if { |k, v| k == 'height' }.any? + end + test "reading store attributes through accessors encoded with JSON" do assert_equal 'tall', @john.height assert_nil @john.weight -- cgit v1.2.3 From 43fa48e5aa981bf86635fa31ace9eede24e93826 Mon Sep 17 00:00:00 2001 From: Gaurish Sharma Date: Tue, 22 May 2012 19:51:02 +0530 Subject: Move root method at TOP of routes file Made the change as per the following text in routing guide:- "You should put the root route at the top of the file, because it is the most popular route and should be matched first." However, if root is best left at bottom. We will change to fix that text --- railties/lib/rails/generators/rails/app/templates/config/routes.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/railties/lib/rails/generators/rails/app/templates/config/routes.rb b/railties/lib/rails/generators/rails/app/templates/config/routes.rb index 286e93c3cf..303e47877f 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/routes.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/routes.rb @@ -1,6 +1,10 @@ <%= app_const %>.routes.draw do # 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' # Sample of regular route: # get 'products/:id' => 'catalog#view' @@ -46,9 +50,6 @@ # resources :products # end - # You can have the root of your site routed with "root" - # just remember to delete public/index.html. - # root :to => 'welcome#index' # See how all your routes lay out with "rake routes" end \ No newline at end of file -- cgit v1.2.3 From 38293ea828ab52043fceecbdc96946b5bc9bb0e5 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 22 May 2012 11:01:16 -0300 Subject: require active_support/lazy_load_hooks where is needed --- actionpack/lib/action_view.rb | 1 + activemodel/lib/active_model.rb | 1 + activerecord/lib/active_record.rb | 1 + activesupport/lib/active_support.rb | 1 - activesupport/lib/active_support/i18n.rb | 1 + 5 files changed, 4 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb index 3823f87027..2408207865 100644 --- a/actionpack/lib/action_view.rb +++ b/actionpack/lib/action_view.rb @@ -22,6 +22,7 @@ #++ require 'active_support' +require 'active_support/lazy_load_hooks' require 'action_pack' module ActionView diff --git a/activemodel/lib/active_model.rb b/activemodel/lib/active_model.rb index ded1b752df..451f3e4742 100644 --- a/activemodel/lib/active_model.rb +++ b/activemodel/lib/active_model.rb @@ -22,6 +22,7 @@ #++ require 'active_support' +require 'active_support/lazy_load_hooks' require 'active_model/version' module ActiveModel diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb index 210820062b..2cbe04ee44 100644 --- a/activerecord/lib/active_record.rb +++ b/activerecord/lib/active_record.rb @@ -22,6 +22,7 @@ #++ require 'active_support' +require 'active_support/lazy_load_hooks' require 'active_model' require 'arel' require 'active_record_deprecated_finders' diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb index 56d6676961..8f018dcbc6 100644 --- a/activesupport/lib/active_support.rb +++ b/activesupport/lib/active_support.rb @@ -25,7 +25,6 @@ require 'securerandom' require "active_support/dependencies/autoload" require "active_support/version" require "active_support/logger" -require "active_support/lazy_load_hooks" module ActiveSupport extend ActiveSupport::Autoload diff --git a/activesupport/lib/active_support/i18n.rb b/activesupport/lib/active_support/i18n.rb index 27234d89e1..188653bd9b 100644 --- a/activesupport/lib/active_support/i18n.rb +++ b/activesupport/lib/active_support/i18n.rb @@ -1,5 +1,6 @@ begin require 'i18n' + require 'active_support/lazy_load_hooks' rescue LoadError => e $stderr.puts "The i18n gem is not available. Please add it to your Gemfile and run bundle install" raise e -- cgit v1.2.3 From d1cab8e5e0aba87e307a387f1b8267e5c41419c6 Mon Sep 17 00:00:00 2001 From: Francesco Rodriguez Date: Tue, 22 May 2012 09:55:13 -0500 Subject: remove repeated documentation in CollectionProxy#clear --- .../active_record/associations/collection_proxy.rb | 26 ++-------------------- 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index 468bf5c2f8..9ee69157b3 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -578,30 +578,8 @@ module ActiveRecord alias_method :push, :<< # Equivalent to +delete_all+. The difference is that returns +self+, instead - # of an array with the deleted objects, so methods can be chained. - # - # class Person < ActiveRecord::Base - # has_many :pets - # end - # - # person.pets # => [#] - # person.pets.clear # => [] - # person.pets.size # => 0 - # - # Pet.find(1) # => # - # - # If they are associated with dependent: :destroy option, it deletes - # them directly from the database. - # - # class Person < ActiveRecord::Base - # has_many :pets, dependent: :destroy - # end - # - # person.pets # => [#] - # person.pets.clear # => [] - # person.pets.size # => 0 - # - # Pet.find(2) # => ActiveRecord::RecordNotFound: Couldn't find Pet with id=2 + # of an array with the deleted objects, so methods can be chained. See + # +delete_all+ for more information. def clear delete_all self -- cgit v1.2.3 From 344ea048659f2ba47012f0330183ea4a96752732 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 22 May 2012 12:10:35 -0300 Subject: Fix the build --- actionpack/lib/action_view.rb | 1 - activemodel/lib/active_model.rb | 1 - activerecord/lib/active_record.rb | 1 - activesupport/lib/active_support.rb | 1 + 4 files changed, 1 insertion(+), 3 deletions(-) diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb index 2408207865..3823f87027 100644 --- a/actionpack/lib/action_view.rb +++ b/actionpack/lib/action_view.rb @@ -22,7 +22,6 @@ #++ require 'active_support' -require 'active_support/lazy_load_hooks' require 'action_pack' module ActionView diff --git a/activemodel/lib/active_model.rb b/activemodel/lib/active_model.rb index 451f3e4742..ded1b752df 100644 --- a/activemodel/lib/active_model.rb +++ b/activemodel/lib/active_model.rb @@ -22,7 +22,6 @@ #++ require 'active_support' -require 'active_support/lazy_load_hooks' require 'active_model/version' module ActiveModel diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb index 2cbe04ee44..210820062b 100644 --- a/activerecord/lib/active_record.rb +++ b/activerecord/lib/active_record.rb @@ -22,7 +22,6 @@ #++ require 'active_support' -require 'active_support/lazy_load_hooks' require 'active_model' require 'arel' require 'active_record_deprecated_finders' diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb index 8f018dcbc6..56d6676961 100644 --- a/activesupport/lib/active_support.rb +++ b/activesupport/lib/active_support.rb @@ -25,6 +25,7 @@ require 'securerandom' require "active_support/dependencies/autoload" require "active_support/version" require "active_support/logger" +require "active_support/lazy_load_hooks" module ActiveSupport extend ActiveSupport::Autoload -- cgit v1.2.3 From acdf8ac58dbf71ac274dc93fd9b4c6da539a36b3 Mon Sep 17 00:00:00 2001 From: Oscar Del Ben Date: Tue, 22 May 2012 08:32:12 -0700 Subject: The initialization guide will cover Rails 4 --- guides/source/initialization.textile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/guides/source/initialization.textile b/guides/source/initialization.textile index 155a439e64..361045282a 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. -- cgit v1.2.3 From d4d87941cbf4d8204c8d3ac6f4a87c29e42445b0 Mon Sep 17 00:00:00 2001 From: Oscar Del Ben Date: Tue, 22 May 2012 08:35:49 -0700 Subject: [Guides] change rails bin section --- guides/source/initialization.textile | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/guides/source/initialization.textile b/guides/source/initialization.textile index 361045282a..5ffa62fd67 100644 --- a/guides/source/initialization.textile +++ b/guides/source/initialization.textile @@ -24,16 +24,15 @@ The actual +rails+ command is kept in _bin/rails_: #!/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" -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+ -- cgit v1.2.3 From 987a74da23b7ef28a9564f20a3bf87b26530fa2f Mon Sep 17 00:00:00 2001 From: Oscar Del Ben Date: Tue, 22 May 2012 08:43:14 -0700 Subject: [Guides] Review bin/rails section --- guides/source/initialization.textile | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/guides/source/initialization.textile b/guides/source/initialization.textile index 5ffa62fd67..a1420d3b6a 100644 --- a/guides/source/initialization.textile +++ b/guides/source/initialization.textile @@ -47,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 @@ -57,7 +57,7 @@ else end -The +rbconfig+ file from the Ruby standard library provides us with the +RbConfig+ class which contains detailed information about the Ruby environment, including how Ruby was compiled. We can see this in use in +railties/lib/rails/script_rails_loader+. +The +rbconfig+ file from the Ruby standard library provides us with the +RbConfig+ class which contains detailed information about the Ruby environment, including how Ruby was compiled. We can see thisin use in +railties/lib/rails/script_rails_loader+. require 'pathname' @@ -121,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: -- cgit v1.2.3 From ba55dd59ece04aa11bdb305dddfe4e975de9177a Mon Sep 17 00:00:00 2001 From: Oscar Del Ben Date: Tue, 22 May 2012 08:48:46 -0700 Subject: [Guides] Change bundler section --- guides/source/initialization.textile | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/guides/source/initialization.textile b/guides/source/initialization.textile index a1420d3b6a..fdbee7b332 100644 --- a/guides/source/initialization.textile +++ b/guides/source/initialization.textile @@ -138,23 +138,23 @@ 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: # 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']) -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) -- cgit v1.2.3 From 63f094bf2984127132589f5c93e6dabcad898b12 Mon Sep 17 00:00:00 2001 From: Oscar Del Ben Date: Tue, 22 May 2012 08:55:59 -0700 Subject: [Guides] Update rails commands section --- guides/source/initialization.textile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/guides/source/initialization.textile b/guides/source/initialization.textile index fdbee7b332..dc089bfb90 100644 --- a/guides/source/initialization.textile +++ b/guides/source/initialization.textile @@ -187,6 +187,8 @@ 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: +ARGV << '--help' if ARGV.empty? + aliases = { "g" => "generate", "c" => "console", @@ -199,6 +201,9 @@ command = ARGV.shift command = aliases[command] || command +TIP: As you can see, an empty ARGV list will make Rails show the help +snippet. + If we used s rather than +server+, Rails will use the +aliases+ defined in the file and match them to their respective commands. With the +server+ command, Rails will run this code: -- cgit v1.2.3 From 2c62dd64dbaf1b3c758e7259fa8fefbafbbdcf81 Mon Sep 17 00:00:00 2001 From: Francesco Rodriguez Date: Tue, 22 May 2012 11:02:43 -0500 Subject: add CollectionProxy#build documentation --- .../active_record/associations/collection_proxy.rb | 31 ++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index 9ee69157b3..6c8fcec0c4 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -167,6 +167,37 @@ module ActiveRecord # another_person_without.pets.last # => nil # another_person_without.pets.last(3) # => [] + ## + # :method: build + # + # :call-seq: + # build(attributes = {}, options = {}, &block) + # + # Returns a new object of the collection type that has been instantiated + # with +attributes+ and linked to this object, but have not yet been saved. + # You can pass an array of attributes hashes, this will return an array + # with the new objects. + # + # class Person + # has_many :pets + # end + # + # person.pets.build + # # => # + # + # person.pets.build(name: 'Fancy-Fancy') + # # => # + # + # person.pets.build([{name: 'Spook'}, {name: 'Choo-Choo'}, {name: 'Brain'}]) + # # => [ + # # #, + # # #, + # # # + # # ] + # + # person.pets.size # => 5 # size of the collection + # person.pets.count # => 0 # count from database + ## # :method: concat # Add one or more records to the collection by setting their foreign keys -- cgit v1.2.3 From 21f4c2eb593f62658bbf5691c60ec3da3b0ab76d Mon Sep 17 00:00:00 2001 From: Francesco Rodriguez Date: Tue, 22 May 2012 11:13:31 -0500 Subject: adding :call-seq: to CollectionProxy methods --- .../active_record/associations/collection_proxy.rb | 39 ++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index 6c8fcec0c4..6d1ba188c3 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -39,6 +39,10 @@ module ActiveRecord ## # :method: select # + # :call-seq: + # select(select = nil) + # select(&block) + # # Works in two ways. # # *First:* Specify a subset of fields to be selected from the result set. @@ -91,6 +95,10 @@ module ActiveRecord ## # :method: find + # + # :call-seq: + # find(*args, &block) + # # Finds an object in the collection responding to the +id+. Uses the same # rules as +ActiveRecord::Base.find+. Returns +ActiveRecord::RecordNotFound++ # error if the object can not be found. @@ -111,6 +119,7 @@ module ActiveRecord ## # :method: first + # # Returns the first record, or the first +n+ records, from the collection. # If the collection is empty, the first form returns +nil+, and the second # form returns an empty array. @@ -140,6 +149,7 @@ module ActiveRecord ## # :method: last + # # Returns the last record, or the last +n+ records, from the collection. # If the collection is empty, the first form returns +nil+, and the second # form returns an empty array. @@ -200,6 +210,10 @@ module ActiveRecord ## # :method: concat + # + # :call-seq: + # concat(*records) + # # Add one or more records to the collection by setting their foreign keys # to the association's primary key. Since << flattens its argument list and # inserts each record, +push+ and +concat+ behave identically. Returns +self+ @@ -227,6 +241,10 @@ module ActiveRecord ## # :method: replace + # + # :call-seq: + # replace(other_array) + # # Replace this collection with +other_array+. This will perform a diff # and delete/add only records that have changed. # @@ -253,6 +271,7 @@ module ActiveRecord ## # :method: delete_all + # # Deletes all the records from the collection. For +has_many+ it will do the # deletion according to the strategy specified by the :dependent # option. Returns an array with the deleted records. @@ -344,6 +363,7 @@ module ActiveRecord ## # :method: destroy_all + # # Deletes the records of the collection directly from the database. # This will _always_ remove the records ignoring the +:dependent+ # option. @@ -369,6 +389,10 @@ module ActiveRecord ## # :method: destroy + # + # :call-seq: + # destroy(*records) + # # Destroy the +records+ supplied and remove them from the collection. # This method will _always_ remove record from the database ignoring # the +:dependent+ option. Returns an array with the removed records. @@ -440,6 +464,7 @@ module ActiveRecord ## # :method: empty? + # # Returns +true+ if the collection is empty. # # class Person < ActiveRecord::Base @@ -456,6 +481,11 @@ module ActiveRecord ## # :method: any? + # + # :call-seq: + # any? + # any?{|item| block} + # # Returns +true+ if the collection is not empty. # # class Person < ActiveRecord::Base @@ -488,6 +518,11 @@ module ActiveRecord ## # :method: many? + # + # :call-seq: + # many? + # many?{|item| block} + # # Returns true if the collection has more than one record. # Equivalent to collection.size > 1. # @@ -525,6 +560,10 @@ module ActiveRecord ## # :method: include? + # + # :call-seq: + # include?(record) + # # Returns +true+ if the given object is present in the collection. # # class Person < ActiveRecord::Base -- cgit v1.2.3 From e0859e569c007cd108797883eec402c876b9e8a0 Mon Sep 17 00:00:00 2001 From: Francesco Rodriguez Date: Tue, 22 May 2012 11:27:04 -0500 Subject: add more examples to CollectionProxy#find --- activerecord/lib/active_record/associations/collection_proxy.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index 6d1ba188c3..33779a9ad7 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -116,6 +116,15 @@ module ActiveRecord # # person.pets.find(1) # => # # person.pets.find(4) # => ActiveRecord::RecordNotFound: Couldn't find Pet with id=4 + # + # person.pets.find(2) { |pet| pet.name.downcase! } + # # => # + # + # person.pets.find(2, 3) + # # => [ + # # #, + # # # + # # ] ## # :method: first -- cgit v1.2.3 From 9c38cfc44afc2c8a9ab79801ff23c53f833d1085 Mon Sep 17 00:00:00 2001 From: Francesco Rodriguez Date: Tue, 22 May 2012 11:39:13 -0500 Subject: add CollectionProxy#create documentation --- .../active_record/associations/collection_proxy.rb | 33 ++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index 33779a9ad7..6e73ac79e2 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -217,6 +217,39 @@ module ActiveRecord # person.pets.size # => 5 # size of the collection # person.pets.count # => 0 # count from database + ## + # :method: create + # + # :call-seq: + # create(attributes = {}, options = {}, &block) + # + # Returns a new object of the collection type that has been instantiated with + # attributes, linked to this object and that has already been saved (if it + # passed the validations). + # + # class Person + # has_many :pets + # end + # + # person.pets.create(name: 'Fancy-Fancy') + # # => # + # + # person.pets.create([{name: 'Spook'}, {name: 'Choo-Choo'}]) + # # => [ + # # #, + # # # + # # ] + # + # person.pets.size # => 3 + # person.pets.count # => 3 + # + # person.pets.find(1, 2, 3) + # # => [ + # # #, + # # #, + # # # + # # ] + ## # :method: concat # -- cgit v1.2.3 From 7e5beca38fe64344eb8b97c9fba93096ff533543 Mon Sep 17 00:00:00 2001 From: Francesco Rodriguez Date: Tue, 22 May 2012 11:52:14 -0500 Subject: add CollectionProxy#create! documentation --- .../active_record/associations/collection_proxy.rb | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index 6e73ac79e2..6d001e8d10 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -249,6 +249,28 @@ module ActiveRecord # # #, # # # # # ] + + ## + # :method: create! + # + # :call-seq: + # create!(attributes = {}, options = {}, &block) + # + # Like +create+, except that if the record is invalid will + # raise an exception. + # + # class Person + # has_many :pets + # end + # + # class Pet + # attr_accessible :name + # validates :name, presence: true + # end + # + # person.pets.create!(name: nil) + # # => ActiveRecord::RecordInvalid: Validation failed: Name can't be blank + ## # :method: concat -- cgit v1.2.3 From 3e847afbdd88d53bbf85eb2436ead2dab88f6e5b Mon Sep 17 00:00:00 2001 From: Francesco Rodriguez Date: Tue, 22 May 2012 11:55:30 -0500 Subject: add :call-seq: to +first+ and +last+ CollectionProxy methods --- activerecord/lib/active_record/associations/collection_proxy.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index 6d001e8d10..776d65294e 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -129,6 +129,9 @@ module ActiveRecord ## # :method: first # + # :call-seq: + # first(limit = nil) + # # Returns the first record, or the first +n+ records, from the collection. # If the collection is empty, the first form returns +nil+, and the second # form returns an empty array. @@ -159,6 +162,9 @@ module ActiveRecord ## # :method: last # + # :call-seq: + # last(limit = nil) + # # Returns the last record, or the last +n+ records, from the collection. # If the collection is empty, the first form returns +nil+, and the second # form returns an empty array. -- cgit v1.2.3 From f539d98cc8838b0f7c3c31465cdc070ab9c1e9f3 Mon Sep 17 00:00:00 2001 From: Francesco Rodriguez Date: Tue, 22 May 2012 12:17:00 -0500 Subject: add CollectionProxy#size documentation --- .../active_record/associations/collection_proxy.rb | 27 ++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index 776d65294e..bc310cd13e 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -277,7 +277,6 @@ module ActiveRecord # person.pets.create!(name: nil) # # => ActiveRecord::RecordInvalid: Validation failed: Name can't be blank - ## # :method: concat # @@ -337,7 +336,6 @@ module ActiveRecord # # person.pets.replace(["doo", "ggie", "gaga"]) # # => ActiveRecord::AssociationTypeMismatch: Pet expected, got String - ## # :method: delete_all @@ -531,6 +529,31 @@ module ActiveRecord # person.pets # => [] # # Pet.find(4, 5, 6) # => ActiveRecord::RecordNotFound: Couldn't find all Pets with IDs (4, 5, 6) + + ## + # :method: size + # + # Returns the size of the collection. If the collection hasn't been loaded, + # it executes a SELECT COUNT(*) query. + # + # class Person < ActiveRecord::Base + # has_many :pets + # end + # + # # This will execute: + # # SELECT COUNT(*) FROM "pets" WHERE "pets"."person_id" = ? [["person_id", 1]] + # person.pets.size # => 3 + # + # person.pets + # # => [ + # # #, + # # #, + # # # + # # ] + # + # # Because the collection is already loaded, this will behave like + # collection.size and no SQL count query is executed. + # person.pets.size # => 3 ## # :method: empty? -- cgit v1.2.3 From eb2c0a4f712b015bf6886286efd6e5b2eeaf54aa Mon Sep 17 00:00:00 2001 From: Francesco Rodriguez Date: Tue, 22 May 2012 12:34:12 -0500 Subject: add CollectionProxy#length documentation --- .../active_record/associations/collection_proxy.rb | 42 +++++++++++++++++++--- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index bc310cd13e..6fd5c466f6 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -540,20 +540,52 @@ module ActiveRecord # has_many :pets # end # - # # This will execute: - # # SELECT COUNT(*) FROM "pets" WHERE "pets"."person_id" = ? [["person_id", 1]] # person.pets.size # => 3 + # # Executes: + # # + # # SELECT COUNT(*) + # # FROM "pets" + # # WHERE "pets"."person_id" = 1 # - # person.pets + # person.pets # This will execute a SELECT * FROM query # # => [ # # #, # # #, # # # # # ] # - # # Because the collection is already loaded, this will behave like - # collection.size and no SQL count query is executed. # person.pets.size # => 3 + # # Because the collection is already loaded, this will behave like + # # collection.size and no SQL count query is executed. + + ## + # :method: length + # + # Returns the size of the collection calling +size+ on the target. + # If the collection has been already loaded +length+ and +size+ are + # equivalent. If not and you are going to need the records anyway this + # method will take one less query because loads the collection. Otherwise + # +size+ is more efficient. + # + # class Person < ActiveRecord::Base + # has_many :pets + # end + # + # person.pets.length # => 3 + # # Executes: + # # + # # SELECT "pets".* + # #  FROM "pets" + # # WHERE "pets"."person_id" = 1 + # + # # Because the collection is loaded, you can + # # call the collection without execute a query: + # person.pets + # # => [ + # # #, + # # #, + # # # + # # ] ## # :method: empty? -- cgit v1.2.3 From 7c69e2db36d3892b050ddc248d3ea4d0f4f4f8db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Tue, 22 May 2012 15:01:36 -0300 Subject: Revert "Merge pull request #6416 from pmahoney/threadsafe-connection-pool" This reverts commit d2901f0fc4270a765717ad572d559dc49a56b3a8, reversing changes made to 525839fdd8cc34d6d524f204528d5b6f36fe410c. Conflicts: activerecord/test/cases/connection_pool_test.rb Reason: This change broke the build (http://travis-ci.org/#!/rails/rails/builds/1391490) and we don't have any solution until now. I asked the author to try to fix it and open a new pull request. --- .../abstract/connection_pool.rb | 120 ++++++--------------- .../connection_adapters/abstract_adapter_test.rb | 2 +- activerecord/test/cases/connection_pool_test.rb | 115 -------------------- 3 files changed, 35 insertions(+), 202 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb index 450ef69744..c6699737b4 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -2,6 +2,7 @@ require 'thread' require 'monitor' require 'set' require 'active_support/core_ext/module/deprecation' +require 'timeout' module ActiveRecord # Raised when a connection could not be obtained within the connection @@ -91,6 +92,21 @@ module ActiveRecord attr_accessor :automatic_reconnect, :timeout attr_reader :spec, :connections, :size, :reaper + class Latch # :nodoc: + def initialize + @mutex = Mutex.new + @cond = ConditionVariable.new + end + + def release + @mutex.synchronize { @cond.broadcast } + end + + def await + @mutex.synchronize { @cond.wait @mutex } + end + end + # Creates a new ConnectionPool object. +spec+ is a ConnectionSpecification # object which describes database connection information (e.g. adapter, # host name, username, password, etc), as well as the maximum size for @@ -112,25 +128,9 @@ module ActiveRecord # default max pool size to 5 @size = (spec.config[:pool] && spec.config[:pool].to_i) || 5 + @latch = Latch.new @connections = [] @automatic_reconnect = true - - # connections available to be checked out - @available = [] - - # number of threads waiting to check out a connection - @num_waiting = 0 - - # signal threads waiting - @cond = new_cond - end - - # Hack for tests to be able to add connections. Do not call outside of tests - def insert_connection_for_test!(c) - synchronize do - @connections << c - @available << c - end end # Retrieve the connection associated with the current thread, or call @@ -188,7 +188,6 @@ module ActiveRecord conn.disconnect! end @connections = [] - @available = [] end end @@ -203,9 +202,6 @@ module ActiveRecord @connections.delete_if do |conn| conn.requires_reloading? end - @available.delete_if do |conn| - conn.requires_reloading? - end end end @@ -229,19 +225,23 @@ module ActiveRecord # Raises: # - PoolFullError: no connection can be obtained from the pool. def checkout - synchronize do - conn = nil - - if @num_waiting == 0 - conn = acquire_connection - end + loop do + # Checkout an available connection + synchronize do + # Try to find a connection that hasn't been leased, and lease it + conn = connections.find { |c| c.lease } + + # If all connections were leased, and we have room to expand, + # create a new connection and lease it. + if !conn && connections.size < size + conn = checkout_new_connection + conn.lease + end - unless conn - conn = wait_until(@timeout) { acquire_connection } + return checkout_and_verify(conn) if conn end - conn.lease - checkout_and_verify(conn) + Timeout.timeout(@timeout, PoolFullError) { @latch.await } end end @@ -257,10 +257,8 @@ module ActiveRecord end release conn - - @available.unshift conn - @cond.signal end + @latch.release end # Remove a connection from the connection pool. The connection will @@ -268,14 +266,12 @@ module ActiveRecord def remove(conn) synchronize do @connections.delete conn - @available.delete conn # FIXME: we might want to store the key on the connection so that removing # from the reserved hash will be a little easier. release conn - - @cond.signal # can make a new connection now end + @latch.release end # Removes dead connections from the pool. A dead connection can occur @@ -287,60 +283,12 @@ module ActiveRecord connections.dup.each do |conn| remove conn if conn.in_use? && stale > conn.last_use && !conn.active? end - @cond.broadcast # may violate fairness end + @latch.release end private - # Take an available connection or, if possible, create a new - # one, or nil. - # - # Monitor must be held while calling this method. - # - # Returns: a newly acquired connection. - def acquire_connection - if @available.any? - @available.pop - elsif connections.size < size - checkout_new_connection - end - end - - # Wait on +@cond+ until the block returns non-nil. Note that - # unlike MonitorMixin::ConditionVariable#wait_until, this method - # does not test the block before the first wait period. - # - # Monitor must be held when calling this method. - # - # +timeout+: Integer timeout in seconds - # - # Returns: the result of the block - # - # Raises: - # - PoolFullError: timeout elapsed before +&block+ returned a connection - def wait_until(timeout, &block) - @num_waiting += 1 - begin - t0 = Time.now - loop do - elapsed = Time.now - t0 - if elapsed >= timeout - msg = 'could not obtain a database connection within %0.3f seconds (waited %0.3f seconds)' % - [timeout, elapsed] - raise PoolFullError, msg - end - - @cond.wait(timeout - elapsed) - - conn = yield - return conn if conn - end - ensure - @num_waiting -= 1 - end - end - def release(conn) thread_id = if @reserved_connections[current_connection_id] == conn current_connection_id diff --git a/activerecord/test/cases/connection_adapters/abstract_adapter_test.rb b/activerecord/test/cases/connection_adapters/abstract_adapter_test.rb index 3e3d6e2769..7dc6e8afcb 100644 --- a/activerecord/test/cases/connection_adapters/abstract_adapter_test.rb +++ b/activerecord/test/cases/connection_adapters/abstract_adapter_test.rb @@ -36,7 +36,7 @@ module ActiveRecord def test_close pool = ConnectionPool.new(ConnectionSpecification.new({}, nil)) - pool.insert_connection_for_test! adapter + pool.connections << adapter adapter.pool = pool # Make sure the pool marks the connection in use diff --git a/activerecord/test/cases/connection_pool_test.rb b/activerecord/test/cases/connection_pool_test.rb index b1905515d3..8dc9f761c2 100644 --- a/activerecord/test/cases/connection_pool_test.rb +++ b/activerecord/test/cases/connection_pool_test.rb @@ -200,121 +200,6 @@ module ActiveRecord end.join end - # The connection pool is "fair" if threads waiting for - # connections receive them the order in which they began - # waiting. This ensures that we don't timeout one HTTP request - # even while well under capacity in a multi-threaded environment - # such as a Java servlet container. - # - # We don't need strict fairness: if two connections become - # available at the same time, it's fine of two threads that were - # waiting acquire the connections out of order. - # - # Thus this test prepares waiting threads and then trickles in - # available connections slowly, ensuring the wakeup order is - # correct in this case. - # - # Try a few times since it might work out just by chance. - def test_checkout_fairness - 4.times { setup; do_checkout_fairness } - end - - def do_checkout_fairness - expected = (1..@pool.size).to_a.freeze - # check out all connections so our threads start out waiting - conns = expected.map { @pool.checkout } - mutex = Mutex.new - order = [] - errors = [] - - threads = expected.map do |i| - t = Thread.new { - begin - @pool.checkout # never checked back in - mutex.synchronize { order << i } - rescue => e - mutex.synchronize { errors << e } - end - } - Thread.pass until t.status == "sleep" - t - end - - # this should wake up the waiting threads one by one in order - conns.each { |conn| @pool.checkin(conn); sleep 0.1 } - - threads.each(&:join) - - raise errors.first if errors.any? - - assert_equal(expected, order) - end - - # As mentioned in #test_checkout_fairness, we don't care about - # strict fairness. This test creates two groups of threads: - # group1 whose members all start waiting before any thread in - # group2. Enough connections are checked in to wakeup all - # group1 threads, and the fact that only group1 and no group2 - # threads acquired a connection is enforced. - # - # Try a few times since it might work out just by chance. - def test_checkout_fairness_by_group - 4.times { setup; do_checkout_fairness_by_group } - end - - def do_checkout_fairness_by_group - @pool.instance_variable_set(:@size, 10) - # take all the connections - conns = (1..10).map { @pool.checkout } - mutex = Mutex.new - successes = [] # threads that successfully got a connection - errors = [] - - make_thread = proc do |i| - t = Thread.new { - begin - @pool.checkout # never checked back in - mutex.synchronize { successes << i } - rescue => e - mutex.synchronize { errors << e } - end - } - Thread.pass until t.status == "sleep" - t - end - - # all group1 threads start waiting before any in group2 - group1 = (1..5).map(&make_thread) - group2 = (6..10).map(&make_thread) - - # checkin n connections back to the pool - checkin = proc do |n| - n.times do - c = conns.pop - @pool.checkin(c) - end - end - - checkin.call(group1.size) # should wake up all group1 - - loop do - sleep 0.1 - break if mutex.synchronize { (successes.size + errors.size) == group1.size } - end - - winners = mutex.synchronize { successes.dup } - checkin.call(group2.size) # should wake up everyone remaining - - group1.each(&:join) - group2.each(&:join) - - assert_equal((1..group1.size).to_a, winners.sort) - - if errors.any? - raise errors.first - end - end - def test_automatic_reconnect= pool = ConnectionPool.new ActiveRecord::Base.connection_pool.spec assert pool.automatic_reconnect -- cgit v1.2.3 From f09c84ca26a73304943421d473faa3ea808d18ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rory=20O=E2=80=99Kane?= Date: Tue, 22 May 2012 15:50:19 -0300 Subject: clarified how file naming affects load order of initializers --- guides/source/configuring.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 -- cgit v1.2.3 From 40c0b3a25d901247c51f92c5f295b229b4c61965 Mon Sep 17 00:00:00 2001 From: Philip Arndt Date: Tue, 22 May 2012 18:56:23 +1200 Subject: Fixed typo new_defautls -> new_defaults. * Added tests for 'else' case in ActionView::Helpers::TranslationHelper#wrap_translate_defaults * Also updated the testing syntax of translation.html_safe? asserts to provide better output upon failure. --- actionpack/lib/action_view/helpers/translation_helper.rb | 4 ++-- actionpack/test/template/translation_helper_test.rb | 16 +++++++++++++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/actionpack/lib/action_view/helpers/translation_helper.rb b/actionpack/lib/action_view/helpers/translation_helper.rb index 8171bea8ed..552c9ba660 100644 --- a/actionpack/lib/action_view/helpers/translation_helper.rb +++ b/actionpack/lib/action_view/helpers/translation_helper.rb @@ -64,7 +64,7 @@ module ActionView # Delegates to I18n.localize with no additional functionality. # - # See http://rubydoc.info/github/svenfuchs/i18n/master/I18n/Backend/Base:localize + # See http://rubydoc.info/github/svenfuchs/i18n/master/I18n/Backend/Base:localize # for more information. def localize(*args) I18n.localize(*args) @@ -96,7 +96,7 @@ module ActionView new_defaults << lambda { |_, options| translate key, options.merge(:default => defaults) } break else - new_defautls << key + new_defaults << key end end diff --git a/actionpack/test/template/translation_helper_test.rb b/actionpack/test/template/translation_helper_test.rb index 97777ccff0..d496dbb35e 100644 --- a/actionpack/test/template/translation_helper_test.rb +++ b/actionpack/test/template/translation_helper_test.rb @@ -111,18 +111,28 @@ class TranslationHelperTest < ActiveSupport::TestCase def test_translate_with_default_named_html translation = translate(:'translations.missing', :default => :'translations.hello_html') assert_equal 'Hello World', translation - assert translation.html_safe? + assert_equal true, translation.html_safe? end def test_translate_with_two_defaults_named_html translation = translate(:'translations.missing', :default => [:'translations.missing_html', :'translations.hello_html']) assert_equal 'Hello World', translation - assert translation.html_safe? + assert_equal true, translation.html_safe? end def test_translate_with_last_default_named_html translation = translate(:'translations.missing', :default => [:'translations.missing', :'translations.hello_html']) assert_equal 'Hello World', translation - assert translation.html_safe? + assert_equal true, translation.html_safe? + end + + def test_translate_with_string_default + translation = translate(:'translations.missing', default: 'A Generic String') + assert_equal 'A Generic String', translation + end + + def test_translate_with_array_of_string_defaults + translation = translate(:'translations.missing', default: ['A Generic String', 'Second generic string']) + assert_equal 'A Generic String', translation end end -- cgit v1.2.3 From 8662722f4fea34259da4d37abd6c55ec717f9d2a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 22 May 2012 16:33:08 -0700 Subject: initialize our instance variables --- railties/lib/rails/engine.rb | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index 47856c87c6..33bd339b46 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -340,6 +340,18 @@ module Rails autoload :Configuration, "rails/engine/configuration" autoload :Railties, "rails/engine/railties" + def initialize + @_all_autoload_paths = nil + @_all_load_paths = nil + @app = nil + @config = nil + @env_config = nil + @helpers = nil + @railties = nil + @routes = nil + super + end + def load_generators(app=self) initialize_generators railties.all { |r| r.load_generators(app) } @@ -615,14 +627,14 @@ module Rails end end - protected + protected def initialize_generators require "rails/generators" end def routes? - defined?(@routes) && @routes + @routes end def has_migrations? -- cgit v1.2.3 From 580333fdc200eb7d2422f087e28d912bc324c42c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 22 May 2012 16:36:08 -0700 Subject: initialize instance variables --- railties/lib/rails/application.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index c4edbae55b..5c52235318 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -75,8 +75,12 @@ module Rails def initialize super - @initialized = false - @reloaders = [] + @initialized = false + @reloaders = [] + @routes_reloader = nil + @env_config = nil + @ordered_railties = nil + @queue = nil end # This method is called just after an application inherits from Rails::Application, -- cgit v1.2.3 From 1ca1b1ab9176c780989be7e5a11d27fb97fe663a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 22 May 2012 16:43:12 -0700 Subject: use RUBY_PLATFORM in case of cross compiled ruby --- railties/lib/rails/engine.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index 33bd339b46..3dc5a29d4a 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -652,7 +652,7 @@ module Rails root = File.exist?("#{root_path}/#{flag}") ? root_path : default raise "Could not find root path for #{self}" unless root - RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ ? + RUBY_PLATFORM =~ /mswin|mingw/ ? Pathname.new(root).expand_path : Pathname.new(root).realpath end -- cgit v1.2.3 From 3f870f607d2c1f422d0699e85017e5289aebef97 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 22 May 2012 17:22:06 -0700 Subject: use File.realpath and avoid making Pathname objects --- railties/lib/rails/engine.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index 3dc5a29d4a..b327dd1e4a 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -652,8 +652,7 @@ module Rails root = File.exist?("#{root_path}/#{flag}") ? root_path : default raise "Could not find root path for #{self}" unless root - RUBY_PLATFORM =~ /mswin|mingw/ ? - Pathname.new(root).expand_path : Pathname.new(root).realpath + File.realpath root end def default_middleware_stack -- cgit v1.2.3 From d7de7a79c5a0c24373f90dcc569816c80501d456 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 22 May 2012 19:21:56 -0700 Subject: I guess we have to return a pathname object. o_O --- railties/lib/rails/engine.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index b327dd1e4a..e0950c6929 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -652,7 +652,7 @@ module Rails root = File.exist?("#{root_path}/#{flag}") ? root_path : default raise "Could not find root path for #{self}" unless root - File.realpath root + Pathname.new File.realpath root end def default_middleware_stack -- cgit v1.2.3 From a9a9e8a3cb64faddc347271c00f975e04a92e394 Mon Sep 17 00:00:00 2001 From: Carlos Galdino Date: Mon, 21 May 2012 18:52:56 -0300 Subject: Refactor date related helpers --- actionpack/lib/action_view/helpers/tags/date_field.rb | 13 ++++++------- .../lib/action_view/helpers/tags/datetime_field.rb | 8 ++++---- .../lib/action_view/helpers/tags/datetime_local_field.rb | 16 ++++++---------- actionpack/lib/action_view/helpers/tags/month_field.rb | 13 ++----------- actionpack/lib/action_view/helpers/tags/time_field.rb | 13 ++++++------- actionpack/lib/action_view/helpers/tags/week_field.rb | 13 ++----------- 6 files changed, 26 insertions(+), 50 deletions(-) diff --git a/actionpack/lib/action_view/helpers/tags/date_field.rb b/actionpack/lib/action_view/helpers/tags/date_field.rb index 0e79609d52..64c29dea3d 100644 --- a/actionpack/lib/action_view/helpers/tags/date_field.rb +++ b/actionpack/lib/action_view/helpers/tags/date_field.rb @@ -1,13 +1,12 @@ module ActionView module Helpers module Tags - class DateField < TextField #:nodoc: - def render - options = @options.stringify_keys - options["value"] = @options.fetch("value") { value(object).try(:to_date) } - @options = options - super - end + class DateField < DatetimeField #:nodoc: + private + + def format_date(value) + value.try(:strftime, "%Y-%m-%d") + end end end end diff --git a/actionpack/lib/action_view/helpers/tags/datetime_field.rb b/actionpack/lib/action_view/helpers/tags/datetime_field.rb index 11d58744fd..e407146e96 100644 --- a/actionpack/lib/action_view/helpers/tags/datetime_field.rb +++ b/actionpack/lib/action_view/helpers/tags/datetime_field.rb @@ -4,16 +4,16 @@ module ActionView class DatetimeField < TextField #:nodoc: def render options = @options.stringify_keys - options["value"] = @options.fetch("value") { format_global_date_time_string(value(object)) } - options["min"] = format_global_date_time_string(options["min"]) - options["max"] = format_global_date_time_string(options["max"]) + options["value"] = @options.fetch("value") { format_date(value(object)) } + options["min"] = format_date(options["min"]) + options["max"] = format_date(options["max"]) @options = options super end private - def format_global_date_time_string(value) + def format_date(value) value.try(:strftime, "%Y-%m-%dT%T.%L%z") end end diff --git a/actionpack/lib/action_view/helpers/tags/datetime_local_field.rb b/actionpack/lib/action_view/helpers/tags/datetime_local_field.rb index 7593a3c733..6668d6d718 100644 --- a/actionpack/lib/action_view/helpers/tags/datetime_local_field.rb +++ b/actionpack/lib/action_view/helpers/tags/datetime_local_field.rb @@ -1,20 +1,16 @@ module ActionView module Helpers module Tags - class DatetimeLocalField < TextField #:nodoc: - def render - options = @options.stringify_keys - options["type"] = "datetime-local" - options["value"] = @options.fetch("value") { format_local_date_time_string(value(object)) } - options["min"] = format_local_date_time_string(options["min"]) - options["max"] = format_local_date_time_string(options["max"]) - @options = options - super + class DatetimeLocalField < DatetimeField #:nodoc: + class << self + def field_type + @field_type ||= "datetime-local" + end end private - def format_local_date_time_string(value) + def format_date(value) value.try(:strftime, "%Y-%m-%dT%T") end end diff --git a/actionpack/lib/action_view/helpers/tags/month_field.rb b/actionpack/lib/action_view/helpers/tags/month_field.rb index 56bd85a90b..3d3c32d847 100644 --- a/actionpack/lib/action_view/helpers/tags/month_field.rb +++ b/actionpack/lib/action_view/helpers/tags/month_field.rb @@ -1,19 +1,10 @@ module ActionView module Helpers module Tags - class MonthField < TextField #:nodoc: - def render - options = @options.stringify_keys - options["value"] = @options.fetch("value") { format_month_string(value(object)) } - options["min"] = format_month_string(options["min"]) - options["max"] = format_month_string(options["max"]) - @options = options - super - end - + class MonthField < DatetimeField #:nodoc: private - def format_month_string(value) + def format_date(value) value.try(:strftime, "%Y-%m") end end diff --git a/actionpack/lib/action_view/helpers/tags/time_field.rb b/actionpack/lib/action_view/helpers/tags/time_field.rb index 271dc00c54..a3941860c9 100644 --- a/actionpack/lib/action_view/helpers/tags/time_field.rb +++ b/actionpack/lib/action_view/helpers/tags/time_field.rb @@ -1,13 +1,12 @@ module ActionView module Helpers module Tags - class TimeField < TextField #:nodoc: - def render - options = @options.stringify_keys - options["value"] = @options.fetch("value") { value(object).try(:strftime, "%T.%L") } - @options = options - super - end + class TimeField < DatetimeField #:nodoc: + private + + def format_date(value) + value.try(:strftime, "%T.%L") + end end end end diff --git a/actionpack/lib/action_view/helpers/tags/week_field.rb b/actionpack/lib/action_view/helpers/tags/week_field.rb index a1265d9928..1e13939a0a 100644 --- a/actionpack/lib/action_view/helpers/tags/week_field.rb +++ b/actionpack/lib/action_view/helpers/tags/week_field.rb @@ -1,19 +1,10 @@ module ActionView module Helpers module Tags - class WeekField < TextField #:nodoc: - def render - options = @options.stringify_keys - options["value"] = @options.fetch("value") { format_week_string(value(object)) } - options["min"] = format_week_string(options["min"]) - options["max"] = format_week_string(options["max"]) - @options = options - super - end - + class WeekField < DatetimeField #:nodoc: private - def format_week_string(value) + def format_date(value) value.try(:strftime, "%Y-W%W") end end -- cgit v1.2.3 From 30847b499b3c824864c9652f6d12ceb8219b363d Mon Sep 17 00:00:00 2001 From: Carlos Galdino Date: Tue, 22 May 2012 21:04:12 -0300 Subject: Add tests for time_field and date_field helpers These tests check the values of 'min' and 'max' input attrs --- actionpack/test/template/form_helper_test.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index 97c8025db3..c9b39ed18f 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -644,6 +644,15 @@ class FormHelperTest < ActionView::TestCase assert_dom_equal(expected, date_field("post", "written_on")) end + def test_date_field_with_extra_attrs + expected = %{} + @post.written_on = DateTime.new(2004, 6, 15) + min_value = DateTime.new(2000, 6, 15) + max_value = DateTime.new(2010, 8, 15) + step = 2 + assert_dom_equal(expected, date_field("post", "written_on", :min => min_value, :max => max_value, :step => step)) + end + def test_date_field_with_timewithzone_value previous_time_zone, Time.zone = Time.zone, 'UTC' expected = %{} @@ -670,6 +679,15 @@ class FormHelperTest < ActionView::TestCase assert_dom_equal(expected, time_field("post", "written_on")) end + def test_time_field_with_extra_attrs + expected = %{} + @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3) + min_value = DateTime.new(2000, 6, 15, 20, 45, 30) + max_value = DateTime.new(2010, 8, 15, 10, 25, 00) + step = 60 + assert_dom_equal(expected, time_field("post", "written_on", :min => min_value, :max => max_value, :step => step)) + end + def test_time_field_with_timewithzone_value previous_time_zone, Time.zone = Time.zone, 'UTC' expected = %{} -- cgit v1.2.3 From 83f62a069e6723c994365855bd9509d5b1a218bc Mon Sep 17 00:00:00 2001 From: Rafael Magana Date: Tue, 22 May 2012 21:33:49 -0500 Subject: use ApplicationName::Application instead of ActionController::Dispatcher.new since Dispatcher class no longer exists --- guides/source/rails_on_rack.textile | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/guides/source/rails_on_rack.textile b/guides/source/rails_on_rack.textile index d8910cf1d0..0080982b67 100644 --- a/guides/source/rails_on_rack.textile +++ b/guides/source/rails_on_rack.textile @@ -23,7 +23,7 @@ h3. Rails on Rack h4. Rails Application's Rack Object -ActionController::Dispatcher.new 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. +ApplicationName::Application 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+ @@ -36,7 +36,7 @@ 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 + run ApplicationName::Application }.to_app @@ -57,7 +57,7 @@ require "config/environment" use Rails::Rack::LogTailer use ActionDispatch::Static -run ActionController::Dispatcher.new +run ApplicationName::Application And start the server: @@ -111,7 +111,7 @@ use ActionDispatch::Head use Rack::ConditionalGet use Rack::ETag use ActionDispatch::BestStandardsSupport -run Blog::Application.routes +run ApplicationName::Application.routes Purpose of each of this middlewares is explained in the "Internal Middlewares":#internal-middleware-stack section. @@ -172,7 +172,7 @@ use ActionDispatch::Static use # use Rack::Runtime ... -run Myapp::Application.routes +run Blog::Application.routes h4. Internal Middleware Stack @@ -264,7 +264,7 @@ config.middleware.clear # config.ru use MyOwnStackFromScratch -run ActionController::Dispatcher.new +run ApplicationName::Application h3. Resources -- cgit v1.2.3 From 6ac458d3417cc3dff064ddf0167d3afff6043cf9 Mon Sep 17 00:00:00 2001 From: Philip Arndt Date: Wed, 23 May 2012 14:24:08 +1200 Subject: Added ActionDispatch::Request::Session#keys and ActionDispatch::Request::Session#values --- actionpack/lib/action_dispatch/request/session.rb | 8 ++++++++ actionpack/test/dispatch/request/session_test.rb | 16 ++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/actionpack/lib/action_dispatch/request/session.rb b/actionpack/lib/action_dispatch/request/session.rb index 4ad7071820..d8bcc28613 100644 --- a/actionpack/lib/action_dispatch/request/session.rb +++ b/actionpack/lib/action_dispatch/request/session.rb @@ -87,6 +87,14 @@ module ActionDispatch alias :key? :has_key? alias :include? :has_key? + def keys + @delegate.keys + end + + def values + @delegate.values + end + def []=(key, value) load_for_write! @delegate[key.to_s] = value diff --git a/actionpack/test/dispatch/request/session_test.rb b/actionpack/test/dispatch/request/session_test.rb index 4d24456ba6..80d5a13171 100644 --- a/actionpack/test/dispatch/request/session_test.rb +++ b/actionpack/test/dispatch/request/session_test.rb @@ -36,6 +36,22 @@ module ActionDispatch assert_equal s, Session.find(env) end + def test_keys + env = {} + s = Session.create(store, env, {}) + s['rails'] = 'ftw' + s['adequate'] = 'awesome' + assert_equal %w[rails adequate], s.keys + end + + def test_values + env = {} + s = Session.create(store, env, {}) + s['rails'] = 'ftw' + s['adequate'] = 'awesome' + assert_equal %w[ftw awesome], s.values + end + private def store Class.new { -- cgit v1.2.3 From 2227064b2a26914f662878482fb00dc25546ecd8 Mon Sep 17 00:00:00 2001 From: David Morton Date: Tue, 22 May 2012 22:00:31 -0500 Subject: Fix incorrect example for fields_for - without the '=' it will not output anything. --- actionpack/lib/action_view/helpers/form_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index 61e7a89585..12576ecd01 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -342,7 +342,7 @@ module ActionView # Example: # # <%= form_for(@post) do |f| %> - # <% f.fields_for(:comments, :include_id => false) do |cf| %> + # <%= f.fields_for(:comments, :include_id => false) do |cf| %> # ... # <% end %> # <% end %> -- cgit v1.2.3 From 56ad6ca3ffe739e9ef445f39bf7c6ff3111ca42b Mon Sep 17 00:00:00 2001 From: Rafael Magana Date: Tue, 22 May 2012 22:02:20 -0500 Subject: update loaded middlewares and use of Rack::Server instead of Rack::Builder --- guides/source/rails_on_rack.textile | 46 ++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/guides/source/rails_on_rack.textile b/guides/source/rails_on_rack.textile index 0080982b67..b85b09241e 100644 --- a/guides/source/rails_on_rack.textile +++ b/guides/source/rails_on_rack.textile @@ -27,25 +27,45 @@ h4. Rails Application's Rack Object h4. +rails server+ -rails server does the basic job of creating a +Rack::Builder+ object and starting the webserver. This is Rails' equivalent of Rack's +rackup+ script. +rails server 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+ -app = Rack::Builder.new { - use Rails::Rack::LogTailer unless options[:detach] - use Rails::Rack::Debugger if options[:debugger] - use ActionDispatch::Static - run ApplicationName::Application -}.to_app +Rails::Server.new.tap { |server| + require APP_PATH + Dir.chdir(Rails.application.root) + server.start +} -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: + + +class Server < ::Rack::Server + def start + ... + super + end +end + + +Here's how it loads the middlewares: + + +def middleware + middlewares = [] + middlewares << [Rails::Rack::Debugger] if options[:debugger] + middlewares << [::Rack::ContentLength] + Hash.new(middlewares) +end + + ++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,8 +75,8 @@ 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 +use Rack::Debugger +use Rack::ContentLength run ApplicationName::Application -- cgit v1.2.3 From 7cabb57f6b9ceaef48a7500e2333cddb69c90de0 Mon Sep 17 00:00:00 2001 From: Rafael Magana Date: Tue, 22 May 2012 22:09:43 -0500 Subject: use ActionDispatch::MiddlewareStack instead of ActionController::MiddlewareStack --- guides/source/rails_on_rack.textile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/guides/source/rails_on_rack.textile b/guides/source/rails_on_rack.textile index b85b09241e..3a7c392508 100644 --- a/guides/source/rails_on_rack.textile +++ b/guides/source/rails_on_rack.textile @@ -92,11 +92,11 @@ To find out more about different +rackup+ options: $ rackup --help -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 -- cgit v1.2.3 From bd9953f11e8e72f8a8a507182d7328f3c8802e27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?U=C4=A3is=20Ozols?= Date: Wed, 23 May 2012 11:45:08 +0300 Subject: Remove unnecessary comment. --- railties/test/generators/assets_generator_test.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/railties/test/generators/assets_generator_test.rb b/railties/test/generators/assets_generator_test.rb index d6338bd3da..a2b94f2e50 100644 --- a/railties/test/generators/assets_generator_test.rb +++ b/railties/test/generators/assets_generator_test.rb @@ -1,7 +1,6 @@ require 'generators/generators_test_helper' require 'rails/generators/rails/assets/assets_generator' -# FIXME: Silence the 'Could not find task "using_coffee?"' message in tests due to the public stub class AssetsGeneratorTest < Rails::Generators::TestCase include GeneratorsTestHelper arguments %w(posts) -- cgit v1.2.3 From 5646d65d01845adf669b9e6c4899b6ac15849bb9 Mon Sep 17 00:00:00 2001 From: Angelo capilleri Date: Wed, 23 May 2012 09:59:13 +0200 Subject: changed xml type datetime to dateTime, fixes #6328 XmlMini define the xml 'datatime', but according to http://www.w3.org/TR/xmlschema-2/#dateTime could be better change this to 'dateTime' with upper case letter 'T. So 'DateTime' and 'Time' are redefined from 'datetime' to 'dateTime' add the changing to the changelog --- activemodel/lib/active_model/serializers/xml.rb | 2 +- .../test/cases/serializers/xml_serialization_test.rb | 2 +- .../lib/active_record/serializers/xml_serializer.rb | 4 ++-- activerecord/test/cases/xml_serialization_test.rb | 14 +++++++------- activesupport/CHANGELOG.md | 2 ++ .../lib/active_support/core_ext/hash/conversions.rb | 4 ++-- activesupport/lib/active_support/xml_mini.rb | 9 +++++---- activesupport/test/core_ext/hash_ext_test.rb | 4 ++-- 8 files changed, 22 insertions(+), 19 deletions(-) diff --git a/activemodel/lib/active_model/serializers/xml.rb b/activemodel/lib/active_model/serializers/xml.rb index b78f1ff3f3..2b3e9ce134 100644 --- a/activemodel/lib/active_model/serializers/xml.rb +++ b/activemodel/lib/active_model/serializers/xml.rb @@ -172,7 +172,7 @@ module ActiveModel # 1 # David # 16 - # 2011-01-30T22:29:23Z + # 2011-01-30T22:29:23Z # # # The :only and :except options can be used to limit the attributes diff --git a/activemodel/test/cases/serializers/xml_serialization_test.rb b/activemodel/test/cases/serializers/xml_serialization_test.rb index 5fa227e0e0..7eb48abc3c 100644 --- a/activemodel/test/cases/serializers/xml_serialization_test.rb +++ b/activemodel/test/cases/serializers/xml_serialization_test.rb @@ -140,7 +140,7 @@ class XmlSerializationTest < ActiveModel::TestCase end test "should serialize datetime" do - assert_match %r{2006-08-01T00:00:00Z}, @contact.to_xml + assert_match %r{2006-08-01T00:00:00Z}, @contact.to_xml end test "should serialize boolean" do diff --git a/activerecord/lib/active_record/serializers/xml_serializer.rb b/activerecord/lib/active_record/serializers/xml_serializer.rb index 2e60521638..b833af64fe 100644 --- a/activerecord/lib/active_record/serializers/xml_serializer.rb +++ b/activerecord/lib/active_record/serializers/xml_serializer.rb @@ -18,8 +18,8 @@ module ActiveRecord #:nodoc: # 1 # false # 0 - # 2000-01-01T08:28:00+12:00 - # 2003-07-16T09:28:00+1200 + # 2000-01-01T08:28:00+12:00 + # 2003-07-16T09:28:00+1200 # Have a nice day # david@loudthinking.com # diff --git a/activerecord/test/cases/xml_serialization_test.rb b/activerecord/test/cases/xml_serialization_test.rb index 88751a72f9..12373333b0 100644 --- a/activerecord/test/cases/xml_serialization_test.rb +++ b/activerecord/test/cases/xml_serialization_test.rb @@ -92,7 +92,7 @@ class DefaultXmlSerializationTest < ActiveRecord::TestCase end def test_should_serialize_datetime - assert_match %r{2006-08-01T00:00:00Z}, @xml + assert_match %r{2006-08-01T00:00:00Z}, @xml end def test_should_serialize_boolean @@ -109,7 +109,7 @@ class DefaultXmlSerializationTimezoneTest < ActiveRecord::TestCase timezone, Time.zone = Time.zone, "Pacific Time (US & Canada)" toy = Toy.create(:name => 'Mickey', :updated_at => Time.utc(2006, 8, 1)) - assert_match %r{2006-07-31T17:00:00-07:00}, toy.to_xml + assert_match %r{2006-07-31T17:00:00-07:00}, toy.to_xml ensure Time.zone = timezone end @@ -118,7 +118,7 @@ class DefaultXmlSerializationTimezoneTest < ActiveRecord::TestCase timezone, Time.zone = Time.zone, "Pacific Time (US & Canada)" toy = Toy.create(:name => 'Minnie', :updated_at => Time.utc(2006, 8, 1)).reload - assert_match %r{2006-07-31T17:00:00-07:00}, toy.to_xml + assert_match %r{2006-07-31T17:00:00-07:00}, toy.to_xml ensure Time.zone = timezone end @@ -152,7 +152,7 @@ class NilXmlSerializationTest < ActiveRecord::TestCase assert %r{}.match(@xml) attributes = $1 assert_match %r{nil="true"}, attributes - assert_match %r{type="datetime"}, attributes + assert_match %r{type="dateTime"}, attributes end def test_should_serialize_boolean @@ -188,7 +188,7 @@ class DatabaseConnectedXmlSerializationTest < ActiveRecord::TestCase assert_equal "integer" , xml.elements["//replies-count"].attributes['type'] assert_equal written_on_in_current_timezone, xml.elements["//written-on"].text - assert_equal "datetime" , xml.elements["//written-on"].attributes['type'] + assert_equal "dateTime" , xml.elements["//written-on"].attributes['type'] assert_equal "david@loudthinking.com", xml.elements["//author-email-address"].text @@ -198,7 +198,7 @@ class DatabaseConnectedXmlSerializationTest < ActiveRecord::TestCase if current_adapter?(:SybaseAdapter) assert_equal last_read_in_current_timezone, xml.elements["//last-read"].text - assert_equal "datetime" , xml.elements["//last-read"].attributes['type'] + assert_equal "dateTime" , xml.elements["//last-read"].attributes['type'] else # Oracle enhanced adapter allows to define Date attributes in model class (see topic.rb) assert_equal "2004-04-15", xml.elements["//last-read"].text @@ -211,7 +211,7 @@ class DatabaseConnectedXmlSerializationTest < ActiveRecord::TestCase assert_equal "boolean" , xml.elements["//approved"].attributes['type'] assert_equal bonus_time_in_current_timezone, xml.elements["//bonus-time"].text - assert_equal "datetime" , xml.elements["//bonus-time"].attributes['type'] + assert_equal "dateTime" , xml.elements["//bonus-time"].attributes['type'] end end diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index c1fef1b9d9..dace2f81f5 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,5 +1,7 @@ ## Rails 4.0.0 (unreleased) ## +* Changed xml type `datetime` to `dateTime` (with upper case letter `T`). *Angelo Capilleri* + * Add `:instance_accessor` option for `class_attribute`. *Alexey Vakhov* * `constantize` now looks in the ancestor chain. *Marc-Andre Lafortune & Andrew White* diff --git a/activesupport/lib/active_support/core_ext/hash/conversions.rb b/activesupport/lib/active_support/core_ext/hash/conversions.rb index 469dc41f2d..43ba05a256 100644 --- a/activesupport/lib/active_support/core_ext/hash/conversions.rb +++ b/activesupport/lib/active_support/core_ext/hash/conversions.rb @@ -57,8 +57,8 @@ class Hash # "TrueClass" => "boolean", # "FalseClass" => "boolean", # "Date" => "date", - # "DateTime" => "datetime", - # "Time" => "datetime" + # "DateTime" => "dateTime", + # "Time" => "dateTime" # } # # By default the root node is "hash", but that's configurable via the :root option. diff --git a/activesupport/lib/active_support/xml_mini.rb b/activesupport/lib/active_support/xml_mini.rb index 677e9910bb..88e18f6fff 100644 --- a/activesupport/lib/active_support/xml_mini.rb +++ b/activesupport/lib/active_support/xml_mini.rb @@ -39,8 +39,8 @@ module ActiveSupport "TrueClass" => "boolean", "FalseClass" => "boolean", "Date" => "date", - "DateTime" => "datetime", - "Time" => "datetime", + "DateTime" => "dateTime", + "Time" => "dateTime", "Array" => "array", "Hash" => "hash" } unless defined?(TYPE_NAMES) @@ -48,7 +48,7 @@ module ActiveSupport FORMATTING = { "symbol" => Proc.new { |symbol| symbol.to_s }, "date" => Proc.new { |date| date.to_s(:db) }, - "datetime" => Proc.new { |time| time.xmlschema }, + "dateTime" => Proc.new { |time| time.xmlschema }, "binary" => Proc.new { |binary| ::Base64.encode64(binary) }, "yaml" => Proc.new { |yaml| yaml.to_yaml } } unless defined?(FORMATTING) @@ -111,6 +111,7 @@ module ActiveSupport type_name ||= TYPE_NAMES[value.class.name] type_name ||= value.class.name if value && !value.respond_to?(:to_str) type_name = type_name.to_s if type_name + type_name = "dateTime" if type_name == "datetime" key = rename_key(key.to_s, options) @@ -145,7 +146,7 @@ module ActiveSupport "#{left}#{middle.tr('_ ', '--')}#{right}" end - # TODO: Add support for other encodings + # TODO: Add support for other encodings def _parse_binary(bin, entity) #:nodoc: case entity['encoding'] when 'base64' diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb index 8239054117..0b0e7da4a5 100644 --- a/activesupport/test/core_ext/hash_ext_test.rb +++ b/activesupport/test/core_ext/hash_ext_test.rb @@ -672,8 +672,8 @@ class HashToXmlTest < ActiveSupport::TestCase :created_at => Time.utc(1999,2,2), :local_created_at => Time.utc(1999,2,2).in_time_zone('Eastern Time (US & Canada)') }.to_xml(@xml_options) - assert_match %r{1999-02-02T00:00:00Z}, xml - assert_match %r{1999-02-01T19:00:00-05:00}, xml + assert_match %r{1999-02-02T00:00:00Z}, xml + assert_match %r{1999-02-01T19:00:00-05:00}, xml end def test_multiple_records_from_xml_with_attributes_other_than_type_ignores_them_without_exploding -- cgit v1.2.3 From 6ff887321b930197a8d62ddd0fc1dcb965ccda29 Mon Sep 17 00:00:00 2001 From: Mark McSpadden Date: Thu, 10 May 2012 16:05:19 -0500 Subject: Add Hash#transform_keys and Hash#transform_keys! and refactor *_keys methods to use them. --- activesupport/CHANGELOG.md | 2 + .../lib/active_support/core_ext/hash/keys.rb | 43 +++++++++++++--------- activesupport/test/core_ext/hash_ext_test.rb | 15 ++++++++ .../source/active_support_core_extensions.textile | 32 ++++++++++++++++ 4 files changed, 74 insertions(+), 18 deletions(-) diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index dace2f81f5..b2bacde799 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,5 +1,7 @@ ## Rails 4.0.0 (unreleased) ## +* Add `Hash#transform_keys` and `Hash#transform_keys!`. *Mark McSpadden* + * Changed xml type `datetime` to `dateTime` (with upper case letter `T`). *Angelo Capilleri* * Add `:instance_accessor` option for `class_attribute`. *Alexey Vakhov* diff --git a/activesupport/lib/active_support/core_ext/hash/keys.rb b/activesupport/lib/active_support/core_ext/hash/keys.rb index be4d611ce7..8b24ef3350 100644 --- a/activesupport/lib/active_support/core_ext/hash/keys.rb +++ b/activesupport/lib/active_support/core_ext/hash/keys.rb @@ -1,46 +1,53 @@ class Hash - # Return a new hash with all keys converted to strings. + # Return a new hash with all keys converted using the block operation. # - # { :name => 'Rob', :years => '28' }.stringify_keys - # #=> { "name" => "Rob", "years" => "28" } - def stringify_keys + # { :name => 'Rob', :years => '28' }.transform_keys{ |key| key.to_s.upcase } + # # => { "NAME" => "Rob", "YEARS" => "28" } + def transform_keys result = {} keys.each do |key| - result[key.to_s] = self[key] + result[yield(key)] = self[key] end result end - # Destructively convert all keys to strings. Same as - # +stringify_keys+, but modifies +self+. - def stringify_keys! + # Destructively convert all keys using the block operations. + # Same as transform_keys but modifies +self+ + def transform_keys! keys.each do |key| - self[key.to_s] = delete(key) + self[yield(key)] = delete(key) end self end + # Return a new hash with all keys converted to strings. + # + # { :name => 'Rob', :years => '28' }.stringify_keys + # #=> { "name" => "Rob", "years" => "28" } + def stringify_keys + transform_keys{ |key| key.to_s } + end + + # Destructively convert all keys to strings. Same as + # +stringify_keys+, but modifies +self+. + def stringify_keys! + transform_keys!{ |key| key.to_s } + end + # Return a new hash with all keys converted to symbols, as long as # they respond to +to_sym+. # # { 'name' => 'Rob', 'years' => '28' }.symbolize_keys # #=> { :name => "Rob", :years => "28" } def symbolize_keys - result = {} - keys.each do |key| - result[(key.to_sym rescue key)] = self[key] - end - result + transform_keys{ |key| key.to_sym rescue key } end alias_method :to_options, :symbolize_keys # Destructively convert all keys to symbols, as long as they respond # to +to_sym+. Same as +symbolize_keys+, but modifies +self+. def symbolize_keys! - keys.each do |key| - self[(key.to_sym rescue key)] = delete(key) - end - self + transform_keys!{ |key| key.to_sym rescue key } end alias_method :to_options!, :symbolize_keys! diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb index 0b0e7da4a5..b13ee4c9ff 100644 --- a/activesupport/test/core_ext/hash_ext_test.rb +++ b/activesupport/test/core_ext/hash_ext_test.rb @@ -28,10 +28,13 @@ class HashExtTest < ActiveSupport::TestCase @mixed = { :a => 1, 'b' => 2 } @fixnums = { 0 => 1, 1 => 2 } @illegal_symbols = { [] => 3 } + @upcase_strings = { 'A' => 1, 'B' => 2 } end def test_methods h = {} + assert_respond_to h, :transform_keys + assert_respond_to h, :transform_keys! assert_respond_to h, :symbolize_keys assert_respond_to h, :symbolize_keys! assert_respond_to h, :stringify_keys @@ -40,6 +43,18 @@ class HashExtTest < ActiveSupport::TestCase assert_respond_to h, :to_options! end + def test_transform_keys + assert_equal @upcase_strings, @strings.transform_keys{ |key| key.to_s.upcase } + assert_equal @upcase_strings, @symbols.transform_keys{ |key| key.to_s.upcase } + assert_equal @upcase_strings, @mixed.transform_keys{ |key| key.to_s.upcase } + end + + def test_transform_keys! + assert_equal @upcase_strings, @symbols.dup.transform_keys!{ |key| key.to_s.upcase } + assert_equal @upcase_strings, @strings.dup.transform_keys!{ |key| key.to_s.upcase } + assert_equal @upcase_strings, @mixed.dup.transform_keys!{ |key| key.to_s.upcase } + end + def test_symbolize_keys assert_equal @symbols, @symbols.symbolize_keys assert_equal @symbols, @strings.symbolize_keys diff --git a/guides/source/active_support_core_extensions.textile b/guides/source/active_support_core_extensions.textile index 80faffa49c..1f92d9d5f5 100644 --- a/guides/source/active_support_core_extensions.textile +++ b/guides/source/active_support_core_extensions.textile @@ -2549,6 +2549,38 @@ 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: + + +{nil => nil, 1 => 1, :a => :a}.transform_keys{ |key| key.to_s.upcase } +# => {"" => nil, "A" => :a, "1" => 1} + + +The result in case of collision is undefined: + + +{"a" => 1, :a => 2}.transform_keys{ |key| key.to_s.upcase } +# => {"A" => 2}, in my test, can't rely on this result though + + +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: + + +def stringify_keys + transform_keys{ |key| key.to_s } +end +... +def symbolize_keys + transform_keys{ |key| key.to_sym rescue key } +end + + +There's also the bang variant +transform_keys!+ that applies the block operations to keys in the very receiver. + +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: -- cgit v1.2.3 From a4bb195c91fa9bb25e136aa8850f3acafea0a597 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20H=C3=BAngaro?= Date: Sun, 29 Apr 2012 15:43:06 -0300 Subject: Adding deep versions of stringify_keys and symbolize_keys (plain and bang) for nested hashes --- activesupport/CHANGELOG.md | 6 +- .../lib/active_support/core_ext/hash/keys.rb | 44 +++++++++++ .../active_support/hash_with_indifferent_access.rb | 4 + activesupport/test/core_ext/hash_ext_test.rb | 92 ++++++++++++++++++++++ .../source/active_support_core_extensions.textile | 14 ++++ 5 files changed, 159 insertions(+), 1 deletion(-) diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index b2bacde799..0171742347 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -2,12 +2,16 @@ * Add `Hash#transform_keys` and `Hash#transform_keys!`. *Mark McSpadden* -* Changed xml type `datetime` to `dateTime` (with upper case letter `T`). *Angelo Capilleri* +* Changed xml type `datetime` to `dateTime` (with upper case letter `T`). *Angelo Capilleri* * Add `:instance_accessor` option for `class_attribute`. *Alexey Vakhov* * `constantize` now looks in the ancestor chain. *Marc-Andre Lafortune & Andrew White* +* Adds `Hash#deep_stringify_keys` and `Hash#deep_stringify_keys!` to convert all keys from a +Hash+ instance into strings *Lucas Húngaro* + +* Adds `Hash#deep_symbolize_keys` and `Hash#deep_symbolize_keys!` to convert all keys from a +Hash+ instance into symbols *Lucas Húngaro* + * `Object#try` can't call private methods. *Vasiliy Ermolovich* * `AS::Callbacks#run_callbacks` remove `key` argument. *Francesco Rodriguez* diff --git a/activesupport/lib/active_support/core_ext/hash/keys.rb b/activesupport/lib/active_support/core_ext/hash/keys.rb index 8b24ef3350..5eb861934d 100644 --- a/activesupport/lib/active_support/core_ext/hash/keys.rb +++ b/activesupport/lib/active_support/core_ext/hash/keys.rb @@ -64,4 +64,48 @@ class Hash raise ArgumentError.new("Unknown key: #{k}") unless valid_keys.include?(k) end end + + # Return a new hash with all keys converted to strings. + # This includes the keys from the root hash and from all + # nested hashes. + def deep_stringify_keys + result = {} + each do |key, value| + result[key.to_s] = value.is_a?(Hash) ? value.deep_stringify_keys : value + end + result + end + + # Destructively convert all keys to strings. + # This includes the keys from the root hash and from all + # nested hashes. + def deep_stringify_keys! + keys.each do |key| + val = delete(key) + self[key.to_s] = val.is_a?(Hash) ? val.deep_stringify_keys! : val + end + self + end + + # Destructively convert all keys to symbols, as long as they respond + # to +to_sym+. This includes the keys from the root hash and from all + # nested hashes. + def deep_symbolize_keys! + keys.each do |key| + val = delete(key) + self[(key.to_sym rescue key)] = val.is_a?(Hash) ? val.deep_stringify_keys! : val + end + self + end + + # Return a new hash with all keys converted to symbols, as long as + # they respond to +to_sym+. This includes the keys from the root hash + # and from all nested hashes. + def deep_symbolize_keys + result = {} + each do |key, value| + result[(key.to_sym rescue key)] = value.is_a?(Hash) ? value.deep_symbolize_keys : value + end + result + end end diff --git a/activesupport/lib/active_support/hash_with_indifferent_access.rb b/activesupport/lib/active_support/hash_with_indifferent_access.rb index 91459f3e5b..6e1c0da991 100644 --- a/activesupport/lib/active_support/hash_with_indifferent_access.rb +++ b/activesupport/lib/active_support/hash_with_indifferent_access.rb @@ -141,9 +141,13 @@ module ActiveSupport end def stringify_keys!; self end + def deep_stringify_keys!; self end def stringify_keys; dup end + def deep_stringify_keys; dup end undef :symbolize_keys! + undef :deep_symbolize_keys! def symbolize_keys; to_hash.symbolize_keys end + def deep_symbolize_keys; to_hash.deep_symbolize_keys end def to_options!; self end # Convert to a Hash with String keys. diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb index b13ee4c9ff..e68733db8b 100644 --- a/activesupport/test/core_ext/hash_ext_test.rb +++ b/activesupport/test/core_ext/hash_ext_test.rb @@ -24,11 +24,16 @@ class HashExtTest < ActiveSupport::TestCase def setup @strings = { 'a' => 1, 'b' => 2 } + @nested_strings = { 'a' => { 'b' => { 'c' => 3 } } } @symbols = { :a => 1, :b => 2 } + @nested_symbols = { :a => { :b => { :c => 3 } } } @mixed = { :a => 1, 'b' => 2 } + @nested_mixed = { 'a' => { :b => { 'c' => 3 } } } @fixnums = { 0 => 1, 1 => 2 } + @nested_fixnums = { 0 => { 1 => { 2 => 3} } } @illegal_symbols = { [] => 3 } @upcase_strings = { 'A' => 1, 'B' => 2 } + @nested_illegal_symbols = { [] => { [] => 3} } end def test_methods @@ -37,8 +42,12 @@ class HashExtTest < ActiveSupport::TestCase assert_respond_to h, :transform_keys! assert_respond_to h, :symbolize_keys assert_respond_to h, :symbolize_keys! + assert_respond_to h, :deep_symbolize_keys + assert_respond_to h, :deep_symbolize_keys! assert_respond_to h, :stringify_keys assert_respond_to h, :stringify_keys! + assert_respond_to h, :deep_stringify_keys + assert_respond_to h, :deep_stringify_keys! assert_respond_to h, :to_options assert_respond_to h, :to_options! end @@ -61,34 +70,68 @@ class HashExtTest < ActiveSupport::TestCase assert_equal @symbols, @mixed.symbolize_keys end + def test_deep_symbolize_keys + assert_equal @nested_symbols, @nested_symbols.deep_symbolize_keys + assert_equal @nested_symbols, @nested_strings.deep_symbolize_keys + assert_equal @nested_symbols, @nested_mixed.deep_symbolize_keys + end + def test_symbolize_keys! assert_equal @symbols, @symbols.dup.symbolize_keys! assert_equal @symbols, @strings.dup.symbolize_keys! assert_equal @symbols, @mixed.dup.symbolize_keys! end + def test_deep_symbolize_keys! + assert_equal @nested_symbols, @nested_symbols.dup.deep_symbolize_keys! + assert_equal @nested_symbols, @nested_strings.dup.deep_symbolize_keys! + assert_equal @nested_symbols, @nested_mixed.dup.deep_symbolize_keys! + end + def test_symbolize_keys_preserves_keys_that_cant_be_symbolized assert_equal @illegal_symbols, @illegal_symbols.symbolize_keys assert_equal @illegal_symbols, @illegal_symbols.dup.symbolize_keys! end + def test_deep_symbolize_keys_preserves_keys_that_cant_be_symbolized + assert_equal @nested_illegal_symbols, @nested_illegal_symbols.deep_symbolize_keys + assert_equal @nested_illegal_symbols, @nested_illegal_symbols.dup.deep_symbolize_keys! + end + def test_symbolize_keys_preserves_fixnum_keys assert_equal @fixnums, @fixnums.symbolize_keys assert_equal @fixnums, @fixnums.dup.symbolize_keys! end + def test_deep_symbolize_keys_preserves_fixnum_keys + assert_equal @nested_fixnums, @nested_fixnums.deep_symbolize_keys + assert_equal @nested_fixnums, @nested_fixnums.dup.deep_symbolize_keys! + end + def test_stringify_keys assert_equal @strings, @symbols.stringify_keys assert_equal @strings, @strings.stringify_keys assert_equal @strings, @mixed.stringify_keys end + def test_deep_stringify_keys + assert_equal @nested_strings, @nested_symbols.deep_stringify_keys + assert_equal @nested_strings, @nested_strings.deep_stringify_keys + assert_equal @nested_strings, @nested_mixed.deep_stringify_keys + end + def test_stringify_keys! assert_equal @strings, @symbols.dup.stringify_keys! assert_equal @strings, @strings.dup.stringify_keys! assert_equal @strings, @mixed.dup.stringify_keys! end + def test_deep_stringify_keys! + assert_equal @nested_strings, @nested_symbols.dup.deep_stringify_keys! + assert_equal @nested_strings, @nested_strings.dup.deep_stringify_keys! + assert_equal @nested_strings, @nested_mixed.dup.deep_stringify_keys! + end + def test_symbolize_keys_for_hash_with_indifferent_access assert_instance_of Hash, @symbols.with_indifferent_access.symbolize_keys assert_equal @symbols, @symbols.with_indifferent_access.symbolize_keys @@ -96,22 +139,46 @@ class HashExtTest < ActiveSupport::TestCase assert_equal @symbols, @mixed.with_indifferent_access.symbolize_keys end + def test_deep_symbolize_keys_for_hash_with_indifferent_access + assert_instance_of Hash, @nested_symbols.with_indifferent_access.deep_symbolize_keys + assert_equal @nested_symbols, @nested_symbols.with_indifferent_access.deep_symbolize_keys + assert_equal @nested_symbols, @nested_strings.with_indifferent_access.deep_symbolize_keys + assert_equal @nested_symbols, @nested_mixed.with_indifferent_access.deep_symbolize_keys + end + + def test_symbolize_keys_bang_for_hash_with_indifferent_access assert_raise(NoMethodError) { @symbols.with_indifferent_access.dup.symbolize_keys! } assert_raise(NoMethodError) { @strings.with_indifferent_access.dup.symbolize_keys! } assert_raise(NoMethodError) { @mixed.with_indifferent_access.dup.symbolize_keys! } end + def test_deep_symbolize_keys_bang_for_hash_with_indifferent_access + assert_raise(NoMethodError) { @nested_symbols.with_indifferent_access.dup.deep_symbolize_keys! } + assert_raise(NoMethodError) { @nested_strings.with_indifferent_access.dup.deep_symbolize_keys! } + assert_raise(NoMethodError) { @nested_mixed.with_indifferent_access.dup.deep_symbolize_keys! } + end + def test_symbolize_keys_preserves_keys_that_cant_be_symbolized_for_hash_with_indifferent_access assert_equal @illegal_symbols, @illegal_symbols.with_indifferent_access.symbolize_keys assert_raise(NoMethodError) { @illegal_symbols.with_indifferent_access.dup.symbolize_keys! } end + def test_deep_symbolize_keys_preserves_keys_that_cant_be_symbolized_for_hash_with_indifferent_access + assert_equal @nested_illegal_symbols, @nested_illegal_symbols.with_indifferent_access.deep_symbolize_keys + assert_raise(NoMethodError) { @nested_illegal_symbols.with_indifferent_access.dup.deep_symbolize_keys! } + end + def test_symbolize_keys_preserves_fixnum_keys_for_hash_with_indifferent_access assert_equal @fixnums, @fixnums.with_indifferent_access.symbolize_keys assert_raise(NoMethodError) { @fixnums.with_indifferent_access.dup.symbolize_keys! } end + def test_deep_symbolize_keys_preserves_fixnum_keys_for_hash_with_indifferent_access + assert_equal @nested_fixnums, @nested_fixnums.with_indifferent_access.deep_symbolize_keys + assert_raise(NoMethodError) { @nested_fixnums.with_indifferent_access.dup.deep_symbolize_keys! } + end + def test_stringify_keys_for_hash_with_indifferent_access assert_instance_of ActiveSupport::HashWithIndifferentAccess, @symbols.with_indifferent_access.stringify_keys assert_equal @strings, @symbols.with_indifferent_access.stringify_keys @@ -119,6 +186,13 @@ class HashExtTest < ActiveSupport::TestCase assert_equal @strings, @mixed.with_indifferent_access.stringify_keys end + def test_deep_stringify_keys_for_hash_with_indifferent_access + assert_instance_of ActiveSupport::HashWithIndifferentAccess, @nested_symbols.with_indifferent_access.deep_stringify_keys + assert_equal @nested_strings, @nested_symbols.with_indifferent_access.deep_stringify_keys + assert_equal @nested_strings, @nested_strings.with_indifferent_access.deep_stringify_keys + assert_equal @nested_strings, @nested_mixed.with_indifferent_access.deep_stringify_keys + end + def test_stringify_keys_bang_for_hash_with_indifferent_access assert_instance_of ActiveSupport::HashWithIndifferentAccess, @symbols.with_indifferent_access.dup.stringify_keys! assert_equal @strings, @symbols.with_indifferent_access.dup.stringify_keys! @@ -126,6 +200,13 @@ class HashExtTest < ActiveSupport::TestCase assert_equal @strings, @mixed.with_indifferent_access.dup.stringify_keys! end + def test_deep_stringify_keys_bang_for_hash_with_indifferent_access + assert_instance_of ActiveSupport::HashWithIndifferentAccess, @nested_symbols.with_indifferent_access.dup.deep_stringify_keys! + assert_equal @nested_strings, @nested_symbols.with_indifferent_access.dup.deep_stringify_keys! + assert_equal @nested_strings, @nested_strings.with_indifferent_access.dup.deep_stringify_keys! + assert_equal @nested_strings, @nested_mixed.with_indifferent_access.dup.deep_stringify_keys! + end + def test_nested_under_indifferent_access foo = { "foo" => SubclassingHash.new.tap { |h| h["bar"] = "baz" } }.with_indifferent_access assert_kind_of ActiveSupport::HashWithIndifferentAccess, foo["foo"] @@ -312,6 +393,17 @@ class HashExtTest < ActiveSupport::TestCase assert_equal 1, h[:first] end + def test_deep_stringify_and_deep_symbolize_keys_on_indifferent_preserves_hash + h = HashWithIndifferentAccess.new + h[:first] = 1 + h = h.deep_stringify_keys + assert_equal 1, h['first'] + h = HashWithIndifferentAccess.new + h['first'] = 1 + h = h.deep_symbolize_keys + assert_equal 1, h[:first] + end + def test_to_options_on_indifferent_preserves_hash h = HashWithIndifferentAccess.new h['first'] = 1 diff --git a/guides/source/active_support_core_extensions.textile b/guides/source/active_support_core_extensions.textile index 1f92d9d5f5..e2118e8f61 100644 --- a/guides/source/active_support_core_extensions.textile +++ b/guides/source/active_support_core_extensions.textile @@ -2611,6 +2611,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: + + +{nil => nil, 1 => 1, :nested => {:a => 3, 5 => 5}}.deep_stringify_keys +# => {""=>nil, "1"=>1, "nested"=>{"a"=>3, "5"=>5}} + + NOTE: Defined in +active_support/core_ext/hash/keys.rb+. h5. +symbolize_keys+ and +symbolize_keys!+ @@ -2645,6 +2652,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: + + +{nil => nil, 1 => 1, "nested" => {"a" => 3, 5 => 5}}.deep_symbolize_keys +# => {nil=>nil, 1=>1, :nested=>{:a=>3, 5=>5}} + + NOTE: Defined in +active_support/core_ext/hash/keys.rb+. h5. +to_options+ and +to_options!+ -- cgit v1.2.3 From 05a4d8b8597b7cc70ea79b087ee491ffaaf8f504 Mon Sep 17 00:00:00 2001 From: Oscar Del Ben Date: Wed, 23 May 2012 08:45:48 -0700 Subject: [Guides] Rewrite server start section --- guides/source/initialization.textile | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/guides/source/initialization.textile b/guides/source/initialization.textile index dc089bfb90..78790a5e3c 100644 --- a/guides/source/initialization.textile +++ b/guides/source/initialization.textile @@ -370,8 +370,9 @@ This method is defined like this: 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] @@ -381,6 +382,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. @@ -389,7 +399,15 @@ ensure end -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: def start -- cgit v1.2.3 From 13612ae5014a98cdbb86d703b50cbdf66adbcb57 Mon Sep 17 00:00:00 2001 From: Oscar Del Ben Date: Wed, 23 May 2012 08:53:08 -0700 Subject: [Guides] Rewrite server start section --- guides/source/initialization.textile | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/guides/source/initialization.textile b/guides/source/initialization.textile index 78790a5e3c..5ce8173e85 100644 --- a/guides/source/initialization.textile +++ b/guides/source/initialization.textile @@ -410,7 +410,7 @@ instance of +ActiveSupport::Logger+. The +super+ method will call +Rack::Server.start+ which begins its definition like this: -def start +def start &blk if options[:warn] $-w = true end @@ -430,22 +430,37 @@ def start pp wrapped_app pp app end -end - -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] - -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 -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. @wrapped_app ||= build_app app -Then the +app+ method here is defined like so: +The +app+ method here is defined like so: def app -- cgit v1.2.3 From 07f73219c0aed3d633d9d9f809f45a1758a718ef Mon Sep 17 00:00:00 2001 From: Oscar Del Ben Date: Wed, 23 May 2012 09:01:21 -0700 Subject: [Guides] Fix sample code --- guides/source/initialization.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/source/initialization.textile b/guides/source/initialization.textile index 5ce8173e85..12b2eb7458 100644 --- a/guides/source/initialization.textile +++ b/guides/source/initialization.textile @@ -482,7 +482,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 %> -- cgit v1.2.3 From cb6f839359bd894feb0a1105b79af72b336aa41e Mon Sep 17 00:00:00 2001 From: Jonathan Rochkind Date: Wed, 23 May 2012 12:08:11 -0400 Subject: ConnectionPool wait_timeout no longer used for different types of timeouts. #6441 An AR ConnectionSpec `wait_timeout` is pre-patch used for three different things: * mysql2 uses it for MySQL's own wait_timeout (how long MySQL should allow an idle connection before closing it), and defaults to 2592000 seconds. * ConnectionPool uses it for "number of seconds to block and wait for a connection before giving up and raising a timeout error", default 5 seconds. * ConnectionPool uses it for the Reaper, for deciding if a 'dead' connection can be reaped. Default 5 seconds. Previously, if you want to change these from defaults, you need to change them all together. This is problematic _especially_ for the mysql2/ConnectionPool conflict, you will generally _not_ want them to be the same, as evidenced by their wildly different defaults. This has caused real problems for people #6441 #2894 But as long as we're changing this, forcing renaming the ConnectionPool key to be more specific, it made sense to seperate the two ConnectionPool uses too -- these two types of ConnectionPool timeouts ought to be able to be changed independently, you won't neccesarily want them to be the same, even though the defaults are (currently) the same. --- .../abstract/connection_pool.rb | 23 +++++++++++++++------- activerecord/test/cases/connection_pool_test.rb | 4 ++-- activerecord/test/cases/pooled_connections_test.rb | 4 ++-- activerecord/test/cases/reaper_test.rb | 2 +- 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb index c6699737b4..be36c9695f 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -55,19 +55,27 @@ module ActiveRecord # # == Options # - # There are two connection-pooling-related options that you can add to + # There are several connection-pooling-related options that you can add to # your database connection configuration: # # * +pool+: number indicating size of connection pool (default 5) - # * +wait_timeout+: number of seconds to block and wait for a connection + # * +checkout_timeout+: number of seconds to block and wait for a connection # before giving up and raising a timeout error (default 5 seconds). + # * +reaping_frequency+: frequency in seconds to periodically run the + # Reaper, which attempts to find and close dead connections, which can + # occur if a programmer forgets to close a connection at the end of a + # thread or a thread dies unexpectedly. (Default nil, which means don't + # run the Reaper). + # * +dead_connection_timeout+: number of seconds from last checkout + # after which the Reaper will consider a connection reapable. (default + # 5 seconds). class ConnectionPool # Every +frequency+ seconds, the reaper will call +reap+ on +pool+. # A reaper instantiated with a nil frequency will never reap the # connection pool. # # Configure the frequency by setting "reaping_frequency" in your - # database yaml file. + # database yaml file. class Reaper attr_reader :pool, :frequency @@ -89,7 +97,7 @@ module ActiveRecord include MonitorMixin - attr_accessor :automatic_reconnect, :timeout + attr_accessor :automatic_reconnect, :checkout_timeout, :dead_connection_timeout attr_reader :spec, :connections, :size, :reaper class Latch # :nodoc: @@ -121,7 +129,8 @@ module ActiveRecord # The cache of reserved connections mapped to threads @reserved_connections = {} - @timeout = spec.config[:wait_timeout] || 5 + @checkout_timeout = spec.config[:checkout_timeout] || 5 + @dead_connection_timeout = spec.config[:dead_connection_timeout] @reaper = Reaper.new self, spec.config[:reaping_frequency] @reaper.run @@ -241,7 +250,7 @@ module ActiveRecord return checkout_and_verify(conn) if conn end - Timeout.timeout(@timeout, PoolFullError) { @latch.await } + Timeout.timeout(@checkout_timeout, PoolFullError) { @latch.await } end end @@ -279,7 +288,7 @@ module ActiveRecord # or a thread dies unexpectedly. def reap synchronize do - stale = Time.now - @timeout + stale = Time.now - @dead_connection_timeout connections.dup.each do |conn| remove conn if conn.in_use? && stale > conn.last_use && !conn.active? end diff --git a/activerecord/test/cases/connection_pool_test.rb b/activerecord/test/cases/connection_pool_test.rb index 8dc9f761c2..bba7815d73 100644 --- a/activerecord/test/cases/connection_pool_test.rb +++ b/activerecord/test/cases/connection_pool_test.rb @@ -124,7 +124,7 @@ module ActiveRecord @pool.checkout @pool.checkout @pool.checkout - @pool.timeout = 0 + @pool.dead_connection_timeout = 0 connections = @pool.connections.dup @@ -137,7 +137,7 @@ module ActiveRecord @pool.checkout @pool.checkout @pool.checkout - @pool.timeout = 0 + @pool.dead_connection_timeout = 0 connections = @pool.connections.dup connections.each do |conn| diff --git a/activerecord/test/cases/pooled_connections_test.rb b/activerecord/test/cases/pooled_connections_test.rb index fba3006ebe..0a6354f5cc 100644 --- a/activerecord/test/cases/pooled_connections_test.rb +++ b/activerecord/test/cases/pooled_connections_test.rb @@ -17,7 +17,7 @@ class PooledConnectionsTest < ActiveRecord::TestCase end def checkout_connections - ActiveRecord::Model.establish_connection(@connection.merge({:pool => 2, :wait_timeout => 0.3})) + ActiveRecord::Model.establish_connection(@connection.merge({:pool => 2, :checkout_timeout => 0.3})) @connections = [] @timed_out = 0 @@ -34,7 +34,7 @@ class PooledConnectionsTest < ActiveRecord::TestCase # Will deadlock due to lack of Monitor timeouts in 1.9 def checkout_checkin_connections(pool_size, threads) - ActiveRecord::Model.establish_connection(@connection.merge({:pool => pool_size, :wait_timeout => 0.5})) + ActiveRecord::Model.establish_connection(@connection.merge({:pool => pool_size, :checkout_timeout => 0.5})) @connection_count = 0 @timed_out = 0 threads.times do diff --git a/activerecord/test/cases/reaper_test.rb b/activerecord/test/cases/reaper_test.rb index 576ab60090..e53a27d5dd 100644 --- a/activerecord/test/cases/reaper_test.rb +++ b/activerecord/test/cases/reaper_test.rb @@ -64,7 +64,7 @@ module ActiveRecord spec.config[:reaping_frequency] = 0.0001 pool = ConnectionPool.new spec - pool.timeout = 0 + pool.dead_connection_timeout = 0 conn = pool.checkout count = pool.connections.length -- cgit v1.2.3 From 6c7b250ac0292001e293ee19157f3d58b7553f41 Mon Sep 17 00:00:00 2001 From: Matt Griffin Date: Fri, 21 Oct 2011 14:24:33 -0400 Subject: Add license field to gemspecs, by Matt Griffin --- actionmailer/actionmailer.gemspec | 1 + actionpack/actionpack.gemspec | 1 + activemodel/activemodel.gemspec | 1 + activerecord/activerecord.gemspec | 1 + activesupport/activesupport.gemspec | 1 + rails.gemspec | 1 + railties/railties.gemspec | 1 + 7 files changed, 7 insertions(+) diff --git a/actionmailer/actionmailer.gemspec b/actionmailer/actionmailer.gemspec index 90503edc20..0c669e2e91 100644 --- a/actionmailer/actionmailer.gemspec +++ b/actionmailer/actionmailer.gemspec @@ -7,6 +7,7 @@ Gem::Specification.new do |s| s.summary = 'Email composition, delivery, and receiving framework (part of Rails).' s.description = 'Email on Rails. Compose, deliver, receive, and test emails using the familiar controller/view pattern. First-class support for multipart email and attachments.' s.required_ruby_version = '>= 1.9.3' + s.license = 'MIT' s.author = 'David Heinemeier Hansson' s.email = 'david@loudthinking.com' diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec index 589a67dc02..ae26d6f9e5 100644 --- a/actionpack/actionpack.gemspec +++ b/actionpack/actionpack.gemspec @@ -7,6 +7,7 @@ Gem::Specification.new do |s| s.summary = 'Web-flow and rendering framework putting the VC in MVC (part of Rails).' s.description = 'Web apps on Rails. Simple, battle-tested conventions for building and testing MVC web applications. Works with any Rack-compatible server.' s.required_ruby_version = '>= 1.9.3' + s.license = 'MIT' s.author = 'David Heinemeier Hansson' s.email = 'david@loudthinking.com' diff --git a/activemodel/activemodel.gemspec b/activemodel/activemodel.gemspec index f2d004fb0a..66f324a1a1 100644 --- a/activemodel/activemodel.gemspec +++ b/activemodel/activemodel.gemspec @@ -8,6 +8,7 @@ Gem::Specification.new do |s| s.description = 'A toolkit for building modeling frameworks like Active Record. Rich support for attributes, callbacks, validations, observers, serialization, internationalization, and testing.' s.required_ruby_version = '>= 1.9.3' + s.license = 'MIT' s.author = 'David Heinemeier Hansson' s.email = 'david@loudthinking.com' diff --git a/activerecord/activerecord.gemspec b/activerecord/activerecord.gemspec index e8e5f4adfe..dca7f13fd2 100644 --- a/activerecord/activerecord.gemspec +++ b/activerecord/activerecord.gemspec @@ -8,6 +8,7 @@ Gem::Specification.new do |s| s.description = 'Databases on Rails. Build a persistent domain model by mapping database tables to Ruby classes. Strong conventions for associations, validations, aggregations, migrations, and testing come baked-in.' s.required_ruby_version = '>= 1.9.3' + s.license = 'MIT' s.author = 'David Heinemeier Hansson' s.email = 'david@loudthinking.com' diff --git a/activesupport/activesupport.gemspec b/activesupport/activesupport.gemspec index 2c874e932e..30221f2401 100644 --- a/activesupport/activesupport.gemspec +++ b/activesupport/activesupport.gemspec @@ -8,6 +8,7 @@ Gem::Specification.new do |s| s.description = 'A toolkit of support libraries and Ruby core extensions extracted from the Rails framework. Rich support for multibyte strings, internationalization, time zones, and testing.' s.required_ruby_version = '>= 1.9.3' + s.license = 'MIT' s.author = 'David Heinemeier Hansson' s.email = 'david@loudthinking.com' diff --git a/rails.gemspec b/rails.gemspec index 8314036ad1..52f92f46c6 100644 --- a/rails.gemspec +++ b/rails.gemspec @@ -9,6 +9,7 @@ Gem::Specification.new do |s| s.required_ruby_version = '>= 1.9.3' s.required_rubygems_version = ">= 1.8.11" + s.license = 'MIT' s.author = 'David Heinemeier Hansson' s.email = 'david@loudthinking.com' diff --git a/railties/railties.gemspec b/railties/railties.gemspec index 7067253279..2a39826c8d 100644 --- a/railties/railties.gemspec +++ b/railties/railties.gemspec @@ -7,6 +7,7 @@ Gem::Specification.new do |s| s.summary = 'Tools for creating, working with, and running Rails applications.' s.description = 'Rails internals: application bootup, plugins, generators, and rake tasks.' s.required_ruby_version = '>= 1.9.3' + s.license = 'MIT' s.author = 'David Heinemeier Hansson' s.email = 'david@loudthinking.com' -- cgit v1.2.3 From 2642c2961cda2074cc1495a4635898ca8ab33adf Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Wed, 23 May 2012 22:42:49 +0530 Subject: copy edit[ci skip] --- actionpack/lib/abstract_controller/base.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actionpack/lib/abstract_controller/base.rb b/actionpack/lib/abstract_controller/base.rb index 32ec7ced0f..9c3960961b 100644 --- a/actionpack/lib/abstract_controller/base.rb +++ b/actionpack/lib/abstract_controller/base.rb @@ -141,7 +141,7 @@ module AbstractController # # Notice that action_methods.include?("foo") may return # false and available_action?("foo") returns true because - # available action consider actions that are also available + # this method considers actions that are also available # through other means, for example, implicit render ones. # # ==== Parameters -- cgit v1.2.3 From 1ad0b378cc081937c117577ab628f2160fcc448d Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Wed, 23 May 2012 22:43:08 +0530 Subject: Revert "Remove blank trailing comments" This reverts commit fa6d921e11363e9b8c4bc10f7aed0b9faffdc33a. Reason: Not a fan of such massive changes. We usually close such changes if made to Rails master as a pull request. Following the same principle here and reverting. [ci skip] --- Rakefile | 1 + actionmailer/lib/action_mailer/delivery_methods.rb | 1 + .../lib/rails/generators/mailer/templates/mailer.rb | 1 + actionpack/lib/abstract_controller/helpers.rb | 1 + actionpack/lib/action_controller/base.rb | 1 + actionpack/lib/action_controller/metal.rb | 2 ++ actionpack/lib/action_controller/metal/helpers.rb | 1 + actionpack/lib/action_controller/metal/mime_responds.rb | 1 + actionpack/lib/action_controller/metal/responder.rb | 10 ++++++++++ actionpack/lib/action_controller/metal/streaming.rb | 1 + actionpack/lib/action_dispatch/http/mime_negotiation.rb | 2 ++ actionpack/lib/action_dispatch/middleware/reloader.rb | 1 + actionpack/lib/action_dispatch/routing.rb | 1 + actionpack/lib/action_dispatch/routing/mapper.rb | 1 + .../lib/action_dispatch/routing/polymorphic_routes.rb | 2 ++ actionpack/lib/action_dispatch/routing/redirection.rb | 1 + actionpack/lib/action_dispatch/routing/route_set.rb | 1 + actionpack/lib/action_dispatch/routing/url_for.rb | 1 + .../lib/action_dispatch/testing/assertions/routing.rb | 1 + .../helpers/asset_tag_helpers/stylesheet_tag_helpers.rb | 1 + actionpack/lib/action_view/helpers/capture_helper.rb | 1 + actionpack/lib/action_view/helpers/form_helper.rb | 11 +++++++++++ actionpack/lib/action_view/helpers/form_options_helper.rb | 3 +++ actionpack/lib/action_view/helpers/form_tag_helper.rb | 3 +++ actionpack/lib/action_view/helpers/number_helper.rb | 1 + actionpack/lib/action_view/helpers/output_safety_helper.rb | 1 + actionpack/lib/action_view/helpers/record_tag_helper.rb | 2 ++ actionpack/lib/action_view/helpers/rendering_helper.rb | 1 + actionpack/lib/action_view/helpers/sanitize_helper.rb | 12 ++++++++++++ actionpack/lib/action_view/helpers/tags/select.rb | 1 + actionpack/lib/action_view/helpers/url_helper.rb | 1 + actionpack/lib/action_view/template/resolver.rb | 1 + activemodel/lib/active_model/attribute_methods.rb | 1 + activemodel/lib/active_model/callbacks.rb | 1 + activemodel/lib/active_model/conversion.rb | 1 + activemodel/lib/active_model/errors.rb | 1 + activemodel/lib/active_model/lint.rb | 2 ++ activemodel/lib/active_model/mass_assignment_security.rb | 2 ++ activemodel/lib/active_model/observing.rb | 2 ++ activemodel/lib/active_model/serialization.rb | 1 + activemodel/lib/active_model/validations.rb | 2 ++ activemodel/lib/active_model/validations/validates.rb | 1 + activemodel/lib/active_model/validator.rb | 2 ++ activemodel/test/cases/validations/i18n_validation_test.rb | 1 + activerecord/lib/active_record/aggregations.rb | 2 ++ activerecord/lib/active_record/associations/association.rb | 1 + activerecord/lib/active_record/callbacks.rb | 1 + .../connection_adapters/abstract/schema_definitions.rb | 1 + .../connection_adapters/abstract/schema_statements.rb | 1 + .../lib/active_record/connection_adapters/mysql_adapter.rb | 1 + .../active_record/connection_adapters/postgresql_adapter.rb | 1 + .../active_record/connection_adapters/sqlite3_adapter.rb | 1 + activerecord/lib/active_record/locking/optimistic.rb | 1 + activerecord/lib/active_record/model.rb | 1 + activerecord/lib/active_record/observer.rb | 1 + activerecord/lib/active_record/persistence.rb | 1 + activerecord/lib/active_record/reflection.rb | 6 ++++++ activerecord/lib/active_record/relation/calculations.rb | 1 + activerecord/lib/active_record/relation/finder_methods.rb | 1 + activerecord/lib/active_record/relation/query_methods.rb | 3 +++ activerecord/lib/active_record/relation/spawn_methods.rb | 3 +++ activerecord/lib/active_record/validations/uniqueness.rb | 1 + activerecord/test/cases/attribute_methods_test.rb | 1 + activerecord/test/cases/validations/i18n_validation_test.rb | 1 + activerecord/test/models/subject.rb | 1 + activesupport/lib/active_support/benchmarkable.rb | 1 + activesupport/lib/active_support/callbacks.rb | 1 + activesupport/lib/active_support/concern.rb | 1 + activesupport/lib/active_support/configurable.rb | 2 ++ .../lib/active_support/core_ext/array/conversions.rb | 1 + activesupport/lib/active_support/core_ext/array/uniq_by.rb | 1 + activesupport/lib/active_support/core_ext/enumerable.rb | 2 ++ activesupport/lib/active_support/core_ext/hash/except.rb | 1 + .../lib/active_support/core_ext/hash/indifferent_access.rb | 2 ++ .../lib/active_support/core_ext/integer/inflections.rb | 2 ++ .../lib/active_support/core_ext/kernel/reporting.rb | 2 ++ .../lib/active_support/core_ext/module/anonymous.rb | 1 + .../lib/active_support/core_ext/module/delegation.rb | 1 + .../lib/active_support/core_ext/module/introspection.rb | 2 ++ activesupport/lib/active_support/core_ext/object/blank.rb | 7 +++++++ .../lib/active_support/core_ext/object/duplicable.rb | 5 +++++ .../lib/active_support/core_ext/object/with_options.rb | 1 + .../lib/active_support/core_ext/string/inflections.rb | 1 + .../lib/active_support/core_ext/string/output_safety.rb | 1 + activesupport/lib/active_support/file_update_checker.rb | 1 + .../lib/active_support/hash_with_indifferent_access.rb | 4 ++++ activesupport/lib/active_support/inflector/methods.rb | 1 + activesupport/lib/active_support/lazy_load_hooks.rb | 1 + activesupport/lib/active_support/log_subscriber.rb | 1 + .../lib/active_support/log_subscriber/test_helper.rb | 2 ++ activesupport/lib/active_support/message_encryptor.rb | 1 + activesupport/lib/active_support/notifications.rb | 1 + activesupport/lib/active_support/ordered_options.rb | 1 + activesupport/lib/active_support/string_inquirer.rb | 1 + activesupport/lib/active_support/time_with_zone.rb | 2 ++ railties/lib/rails/application.rb | 1 + railties/lib/rails/configuration.rb | 1 + railties/lib/rails/engine/configuration.rb | 1 + railties/lib/rails/generators/active_model.rb | 1 + railties/lib/rails/generators/base.rb | 1 + railties/lib/rails/generators/named_base.rb | 1 + railties/lib/rails/generators/resource_helpers.rb | 2 ++ railties/lib/rails/generators/test_case.rb | 13 +++++++++++++ railties/lib/rails/railtie.rb | 1 + railties/test/generators/shared_generator_tests.rb | 1 + 105 files changed, 192 insertions(+) diff --git a/Rakefile b/Rakefile index be42c81f1f..21eb60bbe1 100644 --- a/Rakefile +++ b/Rakefile @@ -179,6 +179,7 @@ end # We publish a new version by tagging, and pushing a tag does not trigger # that webhook. Stable docs would be updated by any subsequent regular # push, but if you want that to happen right away just run this. +# desc 'Publishes docs, run this AFTER a new stable tag has been pushed' task :publish_docs do Net::HTTP.new('api.rubyonrails.org', 8080).start do |http| diff --git a/actionmailer/lib/action_mailer/delivery_methods.rb b/actionmailer/lib/action_mailer/delivery_methods.rb index d2ec48b1ab..3b38dbccc7 100644 --- a/actionmailer/lib/action_mailer/delivery_methods.rb +++ b/actionmailer/lib/action_mailer/delivery_methods.rb @@ -50,6 +50,7 @@ module ActionMailer # add_delivery_method :sendmail, Mail::Sendmail, # :location => '/usr/sbin/sendmail', # :arguments => '-i -t' + # def add_delivery_method(symbol, klass, default_options={}) class_attribute(:"#{symbol}_settings") unless respond_to?(:"#{symbol}_settings") send(:"#{symbol}_settings=", default_options) diff --git a/actionmailer/lib/rails/generators/mailer/templates/mailer.rb b/actionmailer/lib/rails/generators/mailer/templates/mailer.rb index 835fc9b148..edcfb4233d 100644 --- a/actionmailer/lib/rails/generators/mailer/templates/mailer.rb +++ b/actionmailer/lib/rails/generators/mailer/templates/mailer.rb @@ -7,6 +7,7 @@ class <%= class_name %> < ActionMailer::Base # with the following lookup: # # en.<%= file_path.tr("/",".") %>.<%= action %>.subject + # def <%= action %> @greeting = "Hi" diff --git a/actionpack/lib/abstract_controller/helpers.rb b/actionpack/lib/abstract_controller/helpers.rb index 529f920e6c..4e0672d590 100644 --- a/actionpack/lib/abstract_controller/helpers.rb +++ b/actionpack/lib/abstract_controller/helpers.rb @@ -90,6 +90,7 @@ module AbstractController # +symbols+, +strings+, +modules+ and blocks. # # helper(:three, BlindHelper) { def mice() 'mice' end } + # def helper(*args, &block) modules_for_helpers(args).each do |mod| add_template_helper(mod) diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 90058245f5..71425cd542 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -167,6 +167,7 @@ module ActionController # redirect_to(:action => "elsewhere") and return if monkeys.nil? # render :action => "overthere" # won't be called if monkeys is nil # end + # class Base < Metal abstract! diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb index 720c0f2258..92433ab462 100644 --- a/actionpack/lib/action_controller/metal.rb +++ b/actionpack/lib/action_controller/metal.rb @@ -9,6 +9,7 @@ module ActionController # class PostsController < ApplicationController # use AuthenticationMiddleware, :except => [:index, :show] # end + # class MiddlewareStack < ActionDispatch::MiddlewareStack #:nodoc: class Middleware < ActionDispatch::MiddlewareStack::Middleware #:nodoc: def initialize(klass, *args, &block) @@ -96,6 +97,7 @@ module ActionController # # You can refer to the modules included in ActionController::Base to see # other features you can bring into your metal controller. + # class Metal < AbstractController::Base abstract! diff --git a/actionpack/lib/action_controller/metal/helpers.rb b/actionpack/lib/action_controller/metal/helpers.rb index 598bc6c5cb..86d061e3b7 100644 --- a/actionpack/lib/action_controller/metal/helpers.rb +++ b/actionpack/lib/action_controller/metal/helpers.rb @@ -47,6 +47,7 @@ module ActionController # # 23 Aug 11:30 | Carolina Railhawks Soccer Match # N/A | Carolina Railhaws Training Workshop + # module Helpers extend ActiveSupport::Concern diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb index d9fc777250..0b800c3c62 100644 --- a/actionpack/lib/action_controller/metal/mime_responds.rb +++ b/actionpack/lib/action_controller/metal/mime_responds.rb @@ -52,6 +52,7 @@ module ActionController #:nodoc: end # Clear all mime types in respond_to. + # def clear_respond_to self.mimes_for_respond_to = Hash.new.freeze end diff --git a/actionpack/lib/action_controller/metal/responder.rb b/actionpack/lib/action_controller/metal/responder.rb index 5aa3b2ca15..83407846dc 100644 --- a/actionpack/lib/action_controller/metal/responder.rb +++ b/actionpack/lib/action_controller/metal/responder.rb @@ -142,11 +142,13 @@ module ActionController #:nodoc: # Initializes a new responder an invoke the proper format. If the format is # not defined, call to_format. + # def self.call(*args) new(*args).respond end # Main entry point for responder responsible to dispatch to the proper format. + # def respond method = "to_#{format}" respond_to?(method) ? send(method) : to_format @@ -154,6 +156,7 @@ module ActionController #:nodoc: # HTML format does not render the resource, it always attempt to render a # template. + # def to_html default_render rescue ActionView::MissingTemplate => e @@ -168,6 +171,7 @@ module ActionController #:nodoc: # All other formats follow the procedure below. First we try to render a # template, if the template is not available, we verify if the resource # responds to :to_format and display it. + # def to_format if get? || !has_errors? || response_overridden? default_render @@ -205,12 +209,14 @@ module ActionController #:nodoc: end # Checks whether the resource responds to the current format or not. + # def resourceful? resource.respond_to?("to_#{format}") end # Returns the resource location by retrieving it from the options or # returning the resources array. + # def resource_location options[:location] || resources end @@ -219,6 +225,7 @@ module ActionController #:nodoc: # If a response block was given, use it, otherwise call render on # controller. + # def default_render if @default_response @default_response.call(options) @@ -243,6 +250,7 @@ module ActionController #:nodoc: # Results in: # # render :xml => @user, :status => :created + # def display(resource, given_options={}) controller.render given_options.merge!(options).merge!(format => resource) end @@ -252,12 +260,14 @@ module ActionController #:nodoc: end # Check whether the resource has errors. + # def has_errors? resource.respond_to?(:errors) && !resource.errors.empty? end # By default, render the :edit action for HTML requests with errors, unless # the verb was POST. + # def default_action @action ||= DEFAULT_ACTIONS_FOR_VERBS[request.request_method_symbol] end diff --git a/actionpack/lib/action_controller/metal/streaming.rb b/actionpack/lib/action_controller/metal/streaming.rb index 0c3caa9514..eeb37db2e7 100644 --- a/actionpack/lib/action_controller/metal/streaming.rb +++ b/actionpack/lib/action_controller/metal/streaming.rb @@ -194,6 +194,7 @@ module ActionController #:nodoc: # ==== Passenger # # To be described. + # module Streaming extend ActiveSupport::Concern diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb b/actionpack/lib/action_dispatch/http/mime_negotiation.rb index ca40ab9502..e31f3b823d 100644 --- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb +++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb @@ -46,6 +46,7 @@ module ActionDispatch # GET /posts/5.xml | request.format => Mime::XML # GET /posts/5.xhtml | request.format => Mime::HTML # GET /posts/5 | request.format => Mime::HTML or MIME::JS, or request.accepts.first + # def format(view_path = []) formats.first end @@ -81,6 +82,7 @@ module ActionDispatch # Receives an array of mimes and return the first user sent mime that # matches the order array. + # def negotiate_mime(order) formats.each do |priority| if priority == Mime::ALL diff --git a/actionpack/lib/action_dispatch/middleware/reloader.rb b/actionpack/lib/action_dispatch/middleware/reloader.rb index 23415dae54..2f6968eb2e 100644 --- a/actionpack/lib/action_dispatch/middleware/reloader.rb +++ b/actionpack/lib/action_dispatch/middleware/reloader.rb @@ -22,6 +22,7 @@ module ActionDispatch # is false. Callbacks may be registered even when it is not included in the # middleware stack, but are executed only when ActionDispatch::Reloader.prepare! # or ActionDispatch::Reloader.cleanup! are called manually. + # class Reloader include ActiveSupport::Callbacks diff --git a/actionpack/lib/action_dispatch/routing.rb b/actionpack/lib/action_dispatch/routing.rb index a2a6fb39dc..38a0270151 100644 --- a/actionpack/lib/action_dispatch/routing.rb +++ b/actionpack/lib/action_dispatch/routing.rb @@ -277,6 +277,7 @@ module ActionDispatch # rake routes # # Target specific controllers by prefixing the command with CONTROLLER=x. + # module Routing autoload :Mapper, 'action_dispatch/routing/mapper' autoload :RouteSet, 'action_dispatch/routing/route_set' diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 79eee21619..67a208263b 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -897,6 +897,7 @@ module ActionDispatch # resources :articles, :id => /[^\/]+/ # # This allows any character other than a slash as part of your +:id+. + # module Resources # CANONICAL_ACTIONS holds all actions that does not need a prefix or # a path appended since they fit properly in their scope level. diff --git a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb index 817cdb2d4e..8fde667108 100644 --- a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb +++ b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb @@ -51,6 +51,7 @@ module ActionDispatch # # polymorphic_url([blog, @post]) # calls blog.post_path(@post) # form_for([blog, @post]) # => "/blog/posts/1" + # module PolymorphicRoutes # Constructs a call to a named RESTful route for the given record and returns the # resulting URL string. For example: @@ -83,6 +84,7 @@ module ActionDispatch # # # the class of a record will also map to the collection # polymorphic_url(Comment) # same as comments_url() + # def polymorphic_url(record_or_hash_or_array, options = {}) if record_or_hash_or_array.kind_of?(Array) record_or_hash_or_array = record_or_hash_or_array.compact diff --git a/actionpack/lib/action_dispatch/routing/redirection.rb b/actionpack/lib/action_dispatch/routing/redirection.rb index d8beba4397..b3823bb496 100644 --- a/actionpack/lib/action_dispatch/routing/redirection.rb +++ b/actionpack/lib/action_dispatch/routing/redirection.rb @@ -121,6 +121,7 @@ module ActionDispatch # a string. # # match 'accounts/:name' => redirect(SubdomainRedirector.new('api')) + # def redirect(*args, &block) options = args.extract_options! status = options.delete(:status) || 301 diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index c5601a82d6..0ae668d42a 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -180,6 +180,7 @@ module ActionDispatch # Also allow options hash, so you can do: # # foo_url(bar, baz, bang, :sort_by => 'baz') + # def define_url_helper(route, name, options) selector = url_helper_name(name, options[:only_path]) diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb index 207f56aaea..fd3bed7e8f 100644 --- a/actionpack/lib/action_dispatch/routing/url_for.rb +++ b/actionpack/lib/action_dispatch/routing/url_for.rb @@ -79,6 +79,7 @@ module ActionDispatch # end # # User.find(1).base_uri # => "/users/1" + # module UrlFor extend ActiveSupport::Concern include PolymorphicRoutes diff --git a/actionpack/lib/action_dispatch/testing/assertions/routing.rb b/actionpack/lib/action_dispatch/testing/assertions/routing.rb index 1539b894c9..567ca0c392 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/routing.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/routing.rb @@ -140,6 +140,7 @@ module ActionDispatch # end # end # end + # def with_routing old_routes, @routes = @routes, ActionDispatch::Routing::RouteSet.new if defined?(@controller) && @controller diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb index d7df9ea0d5..57b0627225 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb @@ -139,6 +139,7 @@ module ActionView # you have too many stylesheets for IE to load. # # stylesheet_link_tag :all, :concat => true + # def stylesheet_link_tag(*sources) @stylesheet_include ||= StylesheetIncludeTag.new(config, asset_paths) @stylesheet_include.include_tag(*sources) diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb index c1f47a2eac..397738dd98 100644 --- a/actionpack/lib/action_view/helpers/capture_helper.rb +++ b/actionpack/lib/action_view/helpers/capture_helper.rb @@ -33,6 +33,7 @@ module ActionView # # <%= @greeting %> # + # def capture(*args) value = nil buffer = with_output_buffer { value = yield(*args) } diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index 12576ecd01..fc81bcea80 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -763,6 +763,7 @@ module ActionView # # text_field(:snippet, :code, :size => 20, :class => 'code_input') # # => + # def text_field(object_name, method, options = {}) Tags::TextField.new(object_name, method, self, options).render end @@ -784,6 +785,7 @@ module ActionView # # password_field(:account, :pin, :size => 20, :class => 'form_input') # # => + # def password_field(object_name, method, options = {}) Tags::PasswordField.new(object_name, method, self, options).render end @@ -822,6 +824,7 @@ module ActionView # # file_field(:attachment, :file, :class => 'file_input') # # => + # def file_field(object_name, method, options = {}) Tags::FileField.new(object_name, method, self, options).render end @@ -910,6 +913,7 @@ module ActionView # check_box("eula", "accepted", { :class => 'eula_check' }, "yes", "no") # # => # # + # def check_box(object_name, method, options = {}, checked_value = "1", unchecked_value = "0") Tags::CheckBox.new(object_name, method, self, checked_value, unchecked_value, options).render end @@ -962,6 +966,7 @@ module ActionView # # telephone_field("user", "phone") # # => + # def telephone_field(object_name, method, options = {}) Tags::TelField.new(object_name, method, self, options).render end @@ -980,6 +985,7 @@ module ActionView # @user.born_on = Date.new(1984, 1, 27) # date_field("user", "born_on", value: "1984-05-12") # # => + # def date_field(object_name, method, options = {}) Tags::DateField.new(object_name, method, self, options).render end @@ -996,6 +1002,7 @@ module ActionView # === Example # time_field("task", "started_at") # # => + # def time_field(object_name, method, options = {}) Tags::TimeField.new(object_name, method, self, options).render end @@ -1004,6 +1011,7 @@ module ActionView # # url_field("user", "homepage") # # => + # def url_field(object_name, method, options = {}) Tags::UrlField.new(object_name, method, self, options).render end @@ -1012,6 +1020,7 @@ module ActionView # # email_field("user", "address") # # => + # def email_field(object_name, method, options = {}) Tags::EmailField.new(object_name, method, self, options).render end @@ -1191,6 +1200,7 @@ module ActionView # submit: # post: # create: "Add %{model}" + # def submit(value=nil, options={}) value, options = nil, value if value.is_a?(Hash) value ||= submit_default_value @@ -1223,6 +1233,7 @@ module ActionView # submit: # post: # create: "Add %{model}" + # def button(value=nil, options={}) value, options = nil, value if value.is_a?(Hash) value ||= submit_default_value diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb index 90fa1f3520..eef426703d 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -98,6 +98,7 @@ module ActionView # # # + # module FormOptionsHelper # ERB::Util can mask some helpers like textilize. Make sure to include them. include TextHelper @@ -153,6 +154,7 @@ module ActionView # key in the query string, that works for ordinary forms. # # In case if you don't want the helper to generate this hidden field you can specify :include_blank => false option. + # def select(object, method, choices, options = {}, html_options = {}) Tags::Select.new(object, method, self, choices, options, html_options).render end @@ -239,6 +241,7 @@ module ActionView # # # + # def grouped_collection_select(object, method, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, html_options = {}) Tags::GroupedCollectionSelect.new(object, method, self, collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options).render end diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index 07453c4b50..e65b4e3e95 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -63,6 +63,7 @@ module ActionView # # form_tag('http://far.away.com/form', :authenticity_token => "cf50faa3fe97702ca1ae") # # form with custom authenticity token + # def form_tag(url_for_options = {}, options = {}, &block) html_options = html_options_for_form(url_for_options, options) if block_given? @@ -408,6 +409,7 @@ module ActionView # # submit_tag "Save", :confirm => "Are you sure?" # # => + # def submit_tag(value = "Save changes", options = {}) options = options.stringify_keys @@ -444,6 +446,7 @@ module ActionView # # => + # def button_tag(content_or_options = nil, options = nil, &block) options = content_or_options if block_given? && content_or_options.is_a?(Hash) options ||= {} diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb index 9e43a1faf1..dfc26acfad 100644 --- a/actionpack/lib/action_view/helpers/number_helper.rb +++ b/actionpack/lib/action_view/helpers/number_helper.rb @@ -514,6 +514,7 @@ module ActionView # number_to_human(343, :units => :distance, :precision => 1) # => "300 meters" # number_to_human(1, :units => :distance) # => "1 meter" # number_to_human(0.34, :units => :distance) # => "34 centimeters" + # def number_to_human(number, options = {}) options = options.symbolize_keys diff --git a/actionpack/lib/action_view/helpers/output_safety_helper.rb b/actionpack/lib/action_view/helpers/output_safety_helper.rb index 891dd859fa..2e7e9dc50c 100644 --- a/actionpack/lib/action_view/helpers/output_safety_helper.rb +++ b/actionpack/lib/action_view/helpers/output_safety_helper.rb @@ -26,6 +26,7 @@ module ActionView #:nodoc: # # safe_join(["

foo

".html_safe, "

bar

".html_safe], "
".html_safe) # # => "

foo


bar

" + # def safe_join(array, sep=$,) sep = ERB::Util.html_escape(sep) diff --git a/actionpack/lib/action_view/helpers/record_tag_helper.rb b/actionpack/lib/action_view/helpers/record_tag_helper.rb index 8734136f39..9b35f076e5 100644 --- a/actionpack/lib/action_view/helpers/record_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/record_tag_helper.rb @@ -29,6 +29,7 @@ module ActionView # #
Joe Bloggs
#
Jane Bloggs
+ # def div_for(record, *args, &block) content_tag_for(:div, record, *args, &block) end @@ -78,6 +79,7 @@ module ActionView # produces: # #
  • ... + # def content_tag_for(tag_name, single_or_multiple_records, prefix = nil, options = nil, &block) options, prefix = prefix, nil if prefix.is_a?(Hash) diff --git a/actionpack/lib/action_view/helpers/rendering_helper.rb b/actionpack/lib/action_view/helpers/rendering_helper.rb index 55fb443929..626e1a1ab7 100644 --- a/actionpack/lib/action_view/helpers/rendering_helper.rb +++ b/actionpack/lib/action_view/helpers/rendering_helper.rb @@ -75,6 +75,7 @@ module ActionView # # Hello David # + # def _layout_for(*args, &block) name = args.first diff --git a/actionpack/lib/action_view/helpers/sanitize_helper.rb b/actionpack/lib/action_view/helpers/sanitize_helper.rb index ba74217c12..a727b910e5 100644 --- a/actionpack/lib/action_view/helpers/sanitize_helper.rb +++ b/actionpack/lib/action_view/helpers/sanitize_helper.rb @@ -55,6 +55,7 @@ module ActionView # resulting markup is valid (conforming to a document type) or even well-formed. # The output may still contain e.g. unescaped '<', '>', '&' characters and # confuse browsers. + # def sanitize(html, options = {}) self.class.white_list_sanitizer.sanitize(html, options).try(:html_safe) end @@ -143,6 +144,7 @@ module ActionView # class Application < Rails::Application # config.action_view.full_sanitizer = MySpecialSanitizer.new # end + # def full_sanitizer @full_sanitizer ||= HTML::FullSanitizer.new end @@ -153,6 +155,7 @@ module ActionView # class Application < Rails::Application # config.action_view.link_sanitizer = MySpecialSanitizer.new # end + # def link_sanitizer @link_sanitizer ||= HTML::LinkSanitizer.new end @@ -163,6 +166,7 @@ module ActionView # class Application < Rails::Application # config.action_view.white_list_sanitizer = MySpecialSanitizer.new # end + # def white_list_sanitizer @white_list_sanitizer ||= HTML::WhiteListSanitizer.new end @@ -172,6 +176,7 @@ module ActionView # class Application < Rails::Application # config.action_view.sanitized_uri_attributes = 'lowsrc', 'target' # end + # def sanitized_uri_attributes=(attributes) HTML::WhiteListSanitizer.uri_attributes.merge(attributes) end @@ -181,6 +186,7 @@ module ActionView # class Application < Rails::Application # config.action_view.sanitized_bad_tags = 'embed', 'object' # end + # def sanitized_bad_tags=(attributes) HTML::WhiteListSanitizer.bad_tags.merge(attributes) end @@ -190,6 +196,7 @@ module ActionView # class Application < Rails::Application # config.action_view.sanitized_allowed_tags = 'table', 'tr', 'td' # end + # def sanitized_allowed_tags=(attributes) HTML::WhiteListSanitizer.allowed_tags.merge(attributes) end @@ -199,6 +206,7 @@ module ActionView # class Application < Rails::Application # config.action_view.sanitized_allowed_attributes = 'onclick', 'longdesc' # end + # def sanitized_allowed_attributes=(attributes) HTML::WhiteListSanitizer.allowed_attributes.merge(attributes) end @@ -208,6 +216,7 @@ module ActionView # class Application < Rails::Application # config.action_view.sanitized_allowed_css_properties = 'expression' # end + # def sanitized_allowed_css_properties=(attributes) HTML::WhiteListSanitizer.allowed_css_properties.merge(attributes) end @@ -217,6 +226,7 @@ module ActionView # class Application < Rails::Application # config.action_view.sanitized_allowed_css_keywords = 'expression' # end + # def sanitized_allowed_css_keywords=(attributes) HTML::WhiteListSanitizer.allowed_css_keywords.merge(attributes) end @@ -226,6 +236,7 @@ module ActionView # class Application < Rails::Application # config.action_view.sanitized_shorthand_css_properties = 'expression' # end + # def sanitized_shorthand_css_properties=(attributes) HTML::WhiteListSanitizer.shorthand_css_properties.merge(attributes) end @@ -235,6 +246,7 @@ module ActionView # class Application < Rails::Application # config.action_view.sanitized_allowed_protocols = 'ssh', 'feed' # end + # def sanitized_allowed_protocols=(attributes) HTML::WhiteListSanitizer.allowed_protocols.merge(attributes) end diff --git a/actionpack/lib/action_view/helpers/tags/select.rb b/actionpack/lib/action_view/helpers/tags/select.rb index 4d94ee2c23..53a108b7e6 100644 --- a/actionpack/lib/action_view/helpers/tags/select.rb +++ b/actionpack/lib/action_view/helpers/tags/select.rb @@ -31,6 +31,7 @@ module ActionView # # [nil, []] # { nil => [] } + # def grouped_choices? !@choices.empty? && @choices.first.respond_to?(:last) && Array === @choices.first.last end diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb index 2e45a2ae0f..7e69547dab 100644 --- a/actionpack/lib/action_view/helpers/url_helper.rb +++ b/actionpack/lib/action_view/helpers/url_helper.rb @@ -586,6 +586,7 @@ module ActionView # # current_page?(:controller => 'product', :action => 'index') # # => false + # def current_page?(options) unless request raise "You cannot use helpers that need to determine the current " \ diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb index d267a8466a..fa2038f78d 100644 --- a/actionpack/lib/action_view/template/resolver.rb +++ b/actionpack/lib/action_view/template/resolver.rb @@ -215,6 +215,7 @@ module ActionView # * :locale - possible locale versions # * :formats - possible request formats (for example html, json, xml...) # * :handlers - possible handlers (for example erb, haml, builder...) + # class FileSystemResolver < PathResolver def initialize(path, pattern=nil) raise ArgumentError, "path already is a Resolver class" if path.is_a?(Resolver) diff --git a/activemodel/lib/active_model/attribute_methods.rb b/activemodel/lib/active_model/attribute_methods.rb index 61985e241b..99918fdb96 100644 --- a/activemodel/lib/active_model/attribute_methods.rb +++ b/activemodel/lib/active_model/attribute_methods.rb @@ -53,6 +53,7 @@ module ActiveModel # hash value. # # Hash keys must be strings. + # module AttributeMethods extend ActiveSupport::Concern diff --git a/activemodel/lib/active_model/callbacks.rb b/activemodel/lib/active_model/callbacks.rb index 50709e5ee1..ebb4b51aa3 100644 --- a/activemodel/lib/active_model/callbacks.rb +++ b/activemodel/lib/active_model/callbacks.rb @@ -83,6 +83,7 @@ module ActiveModel # # obj is the MyModel instance that the callback is being called on # end # end + # def define_model_callbacks(*callbacks) options = callbacks.extract_options! options = { diff --git a/activemodel/lib/active_model/conversion.rb b/activemodel/lib/active_model/conversion.rb index cea11c1a18..d7f30f0920 100644 --- a/activemodel/lib/active_model/conversion.rb +++ b/activemodel/lib/active_model/conversion.rb @@ -22,6 +22,7 @@ module ActiveModel # cm.to_key # => nil # cm.to_param # => nil # cm.to_partial_path # => "contact_messages/contact_message" + # module Conversion extend ActiveSupport::Concern diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb index 7b311a50ff..aba6618b56 100644 --- a/activemodel/lib/active_model/errors.rb +++ b/activemodel/lib/active_model/errors.rb @@ -317,6 +317,7 @@ module ActiveModel # * activemodel.errors.messages.blank # * errors.attributes.title.blank # * errors.messages.blank + # def generate_message(attribute, type = :invalid, options = {}) type = options.delete(:message) if options[:message].is_a?(Symbol) diff --git a/activemodel/lib/active_model/lint.rb b/activemodel/lib/active_model/lint.rb index 2c7f2a9334..88b730626c 100644 --- a/activemodel/lib/active_model/lint.rb +++ b/activemodel/lib/active_model/lint.rb @@ -52,6 +52,7 @@ module ActiveModel # # Returns a string giving a relative path. This is used for looking up # partials. For example, a BlogPost model might return "blog_posts/blog_post" + # def test_to_partial_path assert model.respond_to?(:to_partial_path), "The model should respond to to_partial_path" assert_kind_of String, model.to_partial_path @@ -73,6 +74,7 @@ module ActiveModel # # Model.model_name must return a string with some convenience methods: # :human, :singular, and :plural. Check ActiveModel::Naming for more information. + # def test_model_naming assert model.class.respond_to?(:model_name), "The model should respond to model_name" model_name = model.class.model_name diff --git a/activemodel/lib/active_model/mass_assignment_security.rb b/activemodel/lib/active_model/mass_assignment_security.rb index 50951b28d9..893fbf92c3 100644 --- a/activemodel/lib/active_model/mass_assignment_security.rb +++ b/activemodel/lib/active_model/mass_assignment_security.rb @@ -56,6 +56,8 @@ module ActiveModel # # You can specify your own sanitizer object eg. MySanitizer.new. # See ActiveModel::MassAssignmentSecurity::LoggerSanitizer for example implementation. + # + # module ClassMethods # Attributes named in this macro are protected from mass-assignment # whenever attributes are sanitized before assignment. A role for the diff --git a/activemodel/lib/active_model/observing.rb b/activemodel/lib/active_model/observing.rb index 117c19c412..f5ea285ccb 100644 --- a/activemodel/lib/active_model/observing.rb +++ b/activemodel/lib/active_model/observing.rb @@ -124,6 +124,7 @@ module ActiveModel # # This will call +custom_notification+, passing as arguments # the current object and :foo. + # def notify_observers(method, *extra_args) self.class.notify_observers(method, self, *extra_args) end @@ -191,6 +192,7 @@ module ActiveModel # If you're using an Observer in a Rails application with Active Record, be sure to # read about the necessary configuration in the documentation for # ActiveRecord::Observer. + # class Observer include Singleton extend ActiveSupport::DescendantsTracker diff --git a/activemodel/lib/active_model/serialization.rb b/activemodel/lib/active_model/serialization.rb index 5fabfb7219..6d8fd21814 100644 --- a/activemodel/lib/active_model/serialization.rb +++ b/activemodel/lib/active_model/serialization.rb @@ -115,6 +115,7 @@ module ActiveModel # @data[key] # end # end + # alias :read_attribute_for_serialization :send # Add associations specified via the :include option. diff --git a/activemodel/lib/active_model/validations.rb b/activemodel/lib/active_model/validations.rb index 019d4b22cf..611e9ffd55 100644 --- a/activemodel/lib/active_model/validations.rb +++ b/activemodel/lib/active_model/validations.rb @@ -38,6 +38,7 @@ module ActiveModel # Note that ActiveModel::Validations automatically adds an +errors+ method # to your instances initialized with a new ActiveModel::Errors object, so # there is no need for you to do this manually. + # module Validations extend ActiveSupport::Concern @@ -221,6 +222,7 @@ module ActiveModel # @data[key] # end # end + # alias :read_attribute_for_validation :send protected diff --git a/activemodel/lib/active_model/validations/validates.rb b/activemodel/lib/active_model/validations/validates.rb index b6a1cfcf41..d94c4e3f4f 100644 --- a/activemodel/lib/active_model/validations/validates.rb +++ b/activemodel/lib/active_model/validations/validates.rb @@ -77,6 +77,7 @@ module ActiveModel # Or to all at the same time: # # validates :password, :presence => true, :confirmation => true, :if => :password_required? + # def validates(*attributes) defaults = attributes.extract_options!.dup validations = defaults.slice!(*_validates_default_keys) diff --git a/activemodel/lib/active_model/validator.rb b/activemodel/lib/active_model/validator.rb index de1a271dde..2953126c3c 100644 --- a/activemodel/lib/active_model/validator.rb +++ b/activemodel/lib/active_model/validator.rb @@ -94,6 +94,7 @@ module ActiveModel #:nodoc: # # This setup method is only called when used with validation macros or the # class level validates_with method. + # class Validator attr_reader :options @@ -101,6 +102,7 @@ module ActiveModel #:nodoc: # # PresenceValidator.kind # => :presence # UniquenessValidator.kind # => :uniqueness + # def self.kind @kind ||= name.split('::').last.underscore.sub(/_validator$/, '').to_sym unless anonymous? end diff --git a/activemodel/test/cases/validations/i18n_validation_test.rb b/activemodel/test/cases/validations/i18n_validation_test.rb index 0ea9f5393d..6b6aad3bd1 100644 --- a/activemodel/test/cases/validations/i18n_validation_test.rb +++ b/activemodel/test/cases/validations/i18n_validation_test.rb @@ -65,6 +65,7 @@ class I18nValidationTest < ActiveModel::TestCase # A set of common cases for ActiveModel::Validations message generation that # are used to generate tests to keep things DRY + # COMMON_CASES = [ # [ case, validation_options, generate_message_options] [ "given no options", {}, {}], diff --git a/activerecord/lib/active_record/aggregations.rb b/activerecord/lib/active_record/aggregations.rb index e0392c5a48..6ad16bee2b 100644 --- a/activerecord/lib/active_record/aggregations.rb +++ b/activerecord/lib/active_record/aggregations.rb @@ -166,6 +166,7 @@ module ActiveRecord # finds all customers with +balance_amount+ equal to 20 and +balance_currency+ equal to "USD": # # Customer.where(:balance => Money.new(20, "USD")).all + # module ClassMethods # Adds reader and writer methods for manipulating a value object: # composed_of :address adds address and address=(new_address) methods. @@ -206,6 +207,7 @@ module ActiveRecord # :mapping => %w(ip to_i), # :constructor => Proc.new { |ip| IPAddr.new(ip, Socket::AF_INET) }, # :converter => Proc.new { |ip| ip.is_a?(Integer) ? IPAddr.new(ip, Socket::AF_INET) : IPAddr.new(ip.to_s) } + # def composed_of(part_id, options = {}) options.assert_valid_keys(:class_name, :mapping, :allow_nil, :constructor, :converter) diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb index 57d602fd83..e75003f261 100644 --- a/activerecord/lib/active_record/associations/association.rb +++ b/activerecord/lib/active_record/associations/association.rb @@ -34,6 +34,7 @@ module ActiveRecord # Returns the name of the table of the related class: # # post.comments.aliased_table_name # => "comments" + # def aliased_table_name klass.table_name end diff --git a/activerecord/lib/active_record/callbacks.rb b/activerecord/lib/active_record/callbacks.rb index fe18a5d5aa..a050fabf35 100644 --- a/activerecord/lib/active_record/callbacks.rb +++ b/activerecord/lib/active_record/callbacks.rb @@ -229,6 +229,7 @@ module ActiveRecord # Topic._save_callbacks.select { |cb| cb.kind.eql?(:before) }.collect(&:filter).include?(:rest_when_dead) # # Returns true or false depending on whether the proc is contained in the before_save callback chain on a Topic model. + # module Callbacks # We can't define callbacks directly on ActiveRecord::Model because # it is a module. So we queue up the definitions and execute them diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index 95ab375951..df78ba6c5a 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -339,6 +339,7 @@ module ActiveRecord # t.remove_index # t.remove_timestamps # end + # class Table def initialize(table_name, base) @table_name = table_name diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index e2eb72fdd6..62b0f51bb2 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -380,6 +380,7 @@ module ActiveRecord # CREATE UNIQUE INDEX index_accounts_on_branch_id_and_party_id ON accounts(branch_id, party_id) WHERE active # # Note: only supported by PostgreSQL + # def add_index(table_name, column_name, options = {}) index_name, index_type, index_columns, index_options = add_index_options(table_name, column_name, options) execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{index_columns})#{index_options}" diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index 3d6ab72e07..0b6734b010 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -59,6 +59,7 @@ module ActiveRecord # * :sslcert - Necessary to use MySQL with an SSL connection. # * :sslcapath - Necessary to use MySQL with an SSL connection. # * :sslcipher - Necessary to use MySQL with an SSL connection. + # class MysqlAdapter < AbstractMysqlAdapter class Column < AbstractMysqlAdapter::Column #:nodoc: diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index ad7c4025cf..14bc95abfe 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -684,6 +684,7 @@ module ActiveRecord # -> Seq Scan on posts (cost=0.00..28.88 rows=8 width=4) # Filter: (posts.user_id = 1) # (6 rows) + # def pp(result) header = result.columns.first lines = result.rows.map(&:first) diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index 25ec88c9c5..d4ffa82b17 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -265,6 +265,7 @@ module ActiveRecord # # 0|0|0|SEARCH TABLE users USING INTEGER PRIMARY KEY (rowid=?) (~1 rows) # 0|1|1|SCAN TABLE posts (~100000 rows) + # def pp(result) # :nodoc: result.rows.map do |row| row.join('|') diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb index 604da5a4fd..a3412582fa 100644 --- a/activerecord/lib/active_record/locking/optimistic.rb +++ b/activerecord/lib/active_record/locking/optimistic.rb @@ -46,6 +46,7 @@ module ActiveRecord # class Person < ActiveRecord::Base # self.locking_column = :lock_person # end + # module Optimistic extend ActiveSupport::Concern diff --git a/activerecord/lib/active_record/model.rb b/activerecord/lib/active_record/model.rb index 5906a57828..105d1e0e2b 100644 --- a/activerecord/lib/active_record/model.rb +++ b/activerecord/lib/active_record/model.rb @@ -7,6 +7,7 @@ module ActiveRecord # class Post # include ActiveRecord::Model # end + # module Model module ClassMethods #:nodoc: include ActiveSupport::Callbacks::ClassMethods diff --git a/activerecord/lib/active_record/observer.rb b/activerecord/lib/active_record/observer.rb index 2467edcc53..fdf17c003c 100644 --- a/activerecord/lib/active_record/observer.rb +++ b/activerecord/lib/active_record/observer.rb @@ -87,6 +87,7 @@ module ActiveRecord # If by any chance you are using observed models in the initialization you can still # load their observers by calling ModelObserver.instance before. Observers are # singletons and that call instantiates and registers them. + # class Observer < ActiveModel::Observer protected diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index daf5936a2d..a1bc39a32d 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -158,6 +158,7 @@ module ActiveRecord # * Callbacks are invoked. # * updated_at/updated_on column is updated if that column is available. # * Updates all the attributes that are dirty in this object. + # def update_attribute(name, value) name = name.to_s verify_readonly_attribute(name) diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 17e388a1d4..c380b5c029 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -42,6 +42,7 @@ module ActiveRecord # Returns the AggregateReflection object for the named +aggregation+ (use the symbol). # # Account.reflect_on_aggregation(:balance) # => the balance AggregateReflection + # def reflect_on_aggregation(aggregation) reflection = reflections[aggregation] reflection if reflection.is_a?(AggregateReflection) @@ -56,6 +57,7 @@ module ActiveRecord # # Account.reflect_on_all_associations # returns an array of all associations # Account.reflect_on_all_associations(:has_many) # returns an array of all has_many associations + # def reflect_on_all_associations(macro = nil) association_reflections = reflections.values.grep(AssociationReflection) macro ? association_reflections.select { |reflection| reflection.macro == macro } : association_reflections @@ -65,6 +67,7 @@ module ActiveRecord # # Account.reflect_on_association(:owner) # returns the owner AssociationReflection # Invoice.reflect_on_association(:line_items).macro # returns :has_many + # def reflect_on_association(association) reflection = reflections[association] reflection if reflection.is_a?(AssociationReflection) @@ -383,6 +386,7 @@ module ActiveRecord # has_many :taggings # has_many :tags, :through => :taggings # end + # def source_reflection @source_reflection ||= source_reflection_names.collect { |name| through_reflection.klass.reflect_on_association(name) }.compact.first end @@ -397,6 +401,7 @@ module ActiveRecord # # tags_reflection = Post.reflect_on_association(:tags) # taggings_reflection = tags_reflection.through_reflection + # def through_reflection @through_reflection ||= active_record.reflect_on_association(options[:through]) end @@ -483,6 +488,7 @@ module ActiveRecord # Gets an array of possible :through source reflection names: # # [:singularized, :pluralized] + # def source_reflection_names @source_reflection_names ||= (options[:source] ? [options[:source]] : [name.to_s.singularize, name]).collect { |n| n.to_sym } end diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index 75d983d3b8..31d99f0192 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -138,6 +138,7 @@ module ActiveRecord # Person.pluck('DATEDIFF(updated_at, created_at)') # # SELECT DATEDIFF(updated_at, created_at) FROM people # # => ['0', '27761', '173'] + # def pluck(column_name) if column_name.is_a?(Symbol) && column_names.include?(column_name.to_s) column_name = "#{table_name}.#{column_name}" diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index 9d62e726d4..4fedd33d64 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -49,6 +49,7 @@ module ActiveRecord # # Post.find_by name: 'Spartacus', rating: 4 # Post.find_by "published_at < ?", 2.weeks.ago + # def find_by(*args) where(*args).take end diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index c086386da6..19fe8155d9 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -163,6 +163,7 @@ module ActiveRecord # User.order('email DESC').reorder('id ASC').order('name ASC') # # generates a query with 'ORDER BY id ASC, name ASC'. + # def reorder(*args) args.blank? ? self : spawn.reorder!(*args) end @@ -276,6 +277,7 @@ module ActiveRecord # Post.none # => returning [] instead breaks the previous code # end # end + # def none NullRelation.new(@klass, @table) end @@ -310,6 +312,7 @@ module ActiveRecord # # Topics.select('a.title').from(Topics.approved, :a) # # => SELECT a.title FROM (SELECT * FROM topics WHERE approved = 't') a + # def from(value, subquery_name = nil) spawn.from!(value, subquery_name) end diff --git a/activerecord/lib/active_record/relation/spawn_methods.rb b/activerecord/lib/active_record/relation/spawn_methods.rb index 4fb1cb6726..80d087a9ea 100644 --- a/activerecord/lib/active_record/relation/spawn_methods.rb +++ b/activerecord/lib/active_record/relation/spawn_methods.rb @@ -23,6 +23,7 @@ module ActiveRecord # Post.where(:published => true).merge(recent_posts) # # Returns the intersection of all published posts with the 5 most recently created posts. # # (This is just an example. You'd probably want to do this with a single query!) + # def merge(other) if other.is_a?(Array) to_a & other @@ -44,6 +45,7 @@ module ActiveRecord # # Post.order('id asc').except(:order) # discards the order condition # Post.where('id > 10').order('id asc').except(:where) # discards the where condition but keeps the order + # def except(*skips) result = Relation.new(klass, table, values.except(*skips)) result.default_scoped = default_scoped @@ -57,6 +59,7 @@ module ActiveRecord # # Post.order('id asc').only(:where) # discards the order condition # Post.order('id asc').only(:where, :order) # uses the specified order + # def only(*onlies) result = Relation.new(klass, table, values.slice(*onlies)) result.default_scoped = default_scoped diff --git a/activerecord/lib/active_record/validations/uniqueness.rb b/activerecord/lib/active_record/validations/uniqueness.rb index c1a72ea8b3..9e4b588ac2 100644 --- a/activerecord/lib/active_record/validations/uniqueness.rb +++ b/activerecord/lib/active_record/validations/uniqueness.rb @@ -198,6 +198,7 @@ module ActiveRecord # * ActiveRecord::ConnectionAdapters::Mysql2Adapter # * ActiveRecord::ConnectionAdapters::SQLite3Adapter # * ActiveRecord::ConnectionAdapters::PostgreSQLAdapter + # def validates_uniqueness_of(*attr_names) validates_with UniquenessValidator, _merge_attributes(attr_names) end diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb index eef1366a6d..1093fedea1 100644 --- a/activerecord/test/cases/attribute_methods_test.rb +++ b/activerecord/test/cases/attribute_methods_test.rb @@ -719,6 +719,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase def test_read_attribute_overwrites_private_method_not_considered_implemented # simulate a model with a db column that shares its name an inherited # private method (e.g. Object#system) + # Object.class_eval do private def title; "private!"; end diff --git a/activerecord/test/cases/validations/i18n_validation_test.rb b/activerecord/test/cases/validations/i18n_validation_test.rb index 89b92e0b13..15b97c02c8 100644 --- a/activerecord/test/cases/validations/i18n_validation_test.rb +++ b/activerecord/test/cases/validations/i18n_validation_test.rb @@ -33,6 +33,7 @@ class I18nValidationTest < ActiveRecord::TestCase # A set of common cases for ActiveModel::Validations message generation that # are used to generate tests to keep things DRY + # COMMON_CASES = [ # [ case, validation_options, generate_message_options] [ "given no options", {}, {}], diff --git a/activerecord/test/models/subject.rb b/activerecord/test/models/subject.rb index 6bf45ba5b2..8e28f8b86b 100644 --- a/activerecord/test/models/subject.rb +++ b/activerecord/test/models/subject.rb @@ -1,4 +1,5 @@ # used for OracleSynonymTest, see test/synonym_test_oracle.rb +# class Subject < ActiveRecord::Base # added initialization of author_email_address in the same way as in Topic class diff --git a/activesupport/lib/active_support/benchmarkable.rb b/activesupport/lib/active_support/benchmarkable.rb index a39fa016ec..f149a7f0ed 100644 --- a/activesupport/lib/active_support/benchmarkable.rb +++ b/activesupport/lib/active_support/benchmarkable.rb @@ -44,6 +44,7 @@ module ActiveSupport end # Silence the logger during the execution of the block. + # def silence old_logger_level, logger.level = logger.level, ::Logger::ERROR if logger yield diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 9636bbccb5..a9253c186d 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -341,6 +341,7 @@ module ActiveSupport # This is used internally to append, prepend and skip callbacks to the # CallbackChain. + # def __update_callbacks(name, filters = [], block = nil) #:nodoc: type = filters.first.in?([:before, :after, :around]) ? filters.shift : :before options = filters.last.is_a?(Hash) ? filters.pop : {} diff --git a/activesupport/lib/active_support/concern.rb b/activesupport/lib/active_support/concern.rb index 9450d4ea88..c94a8d99f4 100644 --- a/activesupport/lib/active_support/concern.rb +++ b/activesupport/lib/active_support/concern.rb @@ -94,6 +94,7 @@ module ActiveSupport # class Host # include Bar # works, Bar takes care now of its dependencies # end + # module Concern def self.extended(base) base.instance_variable_set("@_dependencies", []) diff --git a/activesupport/lib/active_support/configurable.rb b/activesupport/lib/active_support/configurable.rb index afd56cb7ce..a8aa53a80f 100644 --- a/activesupport/lib/active_support/configurable.rb +++ b/activesupport/lib/active_support/configurable.rb @@ -48,6 +48,7 @@ module ActiveSupport # user = User.new # user.allowed_access = true # user.allowed_access # => true + # def config_accessor(*names) options = names.extract_options! @@ -78,6 +79,7 @@ module ActiveSupport # # user.config.allowed_access # => true # user.config.level # => 1 + # def config @_config ||= self.class.config.inheritable_copy end diff --git a/activesupport/lib/active_support/core_ext/array/conversions.rb b/activesupport/lib/active_support/core_ext/array/conversions.rb index 193388a158..24aa28b895 100644 --- a/activesupport/lib/active_support/core_ext/array/conversions.rb +++ b/activesupport/lib/active_support/core_ext/array/conversions.rb @@ -136,6 +136,7 @@ class Array # 1 # # + # def to_xml(options = {}) require 'active_support/builder' unless defined?(Builder) diff --git a/activesupport/lib/active_support/core_ext/array/uniq_by.rb b/activesupport/lib/active_support/core_ext/array/uniq_by.rb index c1d5a355a4..3bedfa9a61 100644 --- a/activesupport/lib/active_support/core_ext/array/uniq_by.rb +++ b/activesupport/lib/active_support/core_ext/array/uniq_by.rb @@ -4,6 +4,7 @@ class Array # Returns a unique array based on the criteria in the block. # # [1, 2, 3, 4].uniq_by { |i| i.odd? } # => [1, 2] + # def uniq_by(&block) ActiveSupport::Deprecation.warn 'uniq_by is deprecated. Use Array#uniq instead', caller uniq(&block) diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb index b950826396..02d5a7080f 100644 --- a/activesupport/lib/active_support/core_ext/enumerable.rb +++ b/activesupport/lib/active_support/core_ext/enumerable.rb @@ -17,6 +17,7 @@ module Enumerable # The default sum of an empty list is zero. You can override this default: # # [].sum(Payment.new(0)) { |i| i.amount } # => Payment.new(0) + # def sum(identity = 0, &block) if block_given? map(&block).sum(identity) @@ -31,6 +32,7 @@ module Enumerable # => { "nextangle" => , "chade-" => , ...} # people.index_by { |person| "#{person.first_name} #{person.last_name}" } # => { "Chade- Fowlersburg-e" => , "David Heinemeier Hansson" => , ...} + # def index_by if block_given? Hash[map { |elem| [yield(elem), elem] }] diff --git a/activesupport/lib/active_support/core_ext/hash/except.rb b/activesupport/lib/active_support/core_ext/hash/except.rb index fafd4919b9..5a61906222 100644 --- a/activesupport/lib/active_support/core_ext/hash/except.rb +++ b/activesupport/lib/active_support/core_ext/hash/except.rb @@ -10,6 +10,7 @@ class Hash # # {:a => 1}.with_indifferent_access.except(:a) # => {} # {:a => 1}.with_indifferent_access.except('a') # => {} + # def except(*keys) dup.except!(*keys) end diff --git a/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb b/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb index c1f368d0eb..7d54c9fae6 100644 --- a/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb +++ b/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb @@ -5,6 +5,7 @@ class Hash # Returns an ActiveSupport::HashWithIndifferentAccess out of its receiver: # # {:a => 1}.with_indifferent_access["a"] # => 1 + # def with_indifferent_access ActiveSupport::HashWithIndifferentAccess.new_from_hash_copying_default(self) end @@ -18,5 +19,6 @@ class Hash # # b = {:b => 1} # {:a => b}.with_indifferent_access["a"] # calls b.nested_under_indifferent_access + # alias nested_under_indifferent_access with_indifferent_access end diff --git a/activesupport/lib/active_support/core_ext/integer/inflections.rb b/activesupport/lib/active_support/core_ext/integer/inflections.rb index 56f2ed5985..1e30687166 100644 --- a/activesupport/lib/active_support/core_ext/integer/inflections.rb +++ b/activesupport/lib/active_support/core_ext/integer/inflections.rb @@ -10,6 +10,7 @@ class Integer # 1003.ordinalize # => "1003rd" # -11.ordinalize # => "-11th" # -1001.ordinalize # => "-1001st" + # def ordinalize ActiveSupport::Inflector.ordinalize(self) end @@ -23,6 +24,7 @@ class Integer # 1003.ordinal # => "rd" # -11.ordinal # => "th" # -1001.ordinal # => "st" + # def ordinal ActiveSupport::Inflector.ordinal(self) end diff --git a/activesupport/lib/active_support/core_ext/kernel/reporting.rb b/activesupport/lib/active_support/core_ext/kernel/reporting.rb index 728069a9a8..ad3f9ebec9 100644 --- a/activesupport/lib/active_support/core_ext/kernel/reporting.rb +++ b/activesupport/lib/active_support/core_ext/kernel/reporting.rb @@ -65,6 +65,7 @@ module Kernel # # stream = capture(:stdout) { puts 'Cool' } # stream # => "Cool\n" + # def capture(stream) begin stream = stream.to_s @@ -82,6 +83,7 @@ module Kernel # Silences both STDOUT and STDERR, even for subprocesses. # # quietly { system 'bundle install' } + # def quietly silence_stream(STDOUT) do silence_stream(STDERR) do diff --git a/activesupport/lib/active_support/core_ext/module/anonymous.rb b/activesupport/lib/active_support/core_ext/module/anonymous.rb index b0c7b021db..0a9e791030 100644 --- a/activesupport/lib/active_support/core_ext/module/anonymous.rb +++ b/activesupport/lib/active_support/core_ext/module/anonymous.rb @@ -13,6 +13,7 @@ class Module # m = Module.new # creates an anonymous module # M = m # => m gets a name here as a side-effect # m.name # => "M" + # def anonymous? name.nil? end diff --git a/activesupport/lib/active_support/core_ext/module/delegation.rb b/activesupport/lib/active_support/core_ext/module/delegation.rb index 30acc87c4a..fbef27c76a 100644 --- a/activesupport/lib/active_support/core_ext/module/delegation.rb +++ b/activesupport/lib/active_support/core_ext/module/delegation.rb @@ -100,6 +100,7 @@ class Module # end # # Foo.new.zoo # returns nil + # def delegate(*methods) options = methods.pop unless options.is_a?(Hash) && to = options[:to] diff --git a/activesupport/lib/active_support/core_ext/module/introspection.rb b/activesupport/lib/active_support/core_ext/module/introspection.rb index 649a969149..3c8e811fa4 100644 --- a/activesupport/lib/active_support/core_ext/module/introspection.rb +++ b/activesupport/lib/active_support/core_ext/module/introspection.rb @@ -27,6 +27,7 @@ class Module # # M.parent # => Object # Module.new.parent # => Object + # def parent parent_name ? ActiveSupport::Inflector.constantize(parent_name) : Object end @@ -43,6 +44,7 @@ class Module # M.parents # => [Object] # M::N.parents # => [M, Object] # X.parents # => [M, Object] + # def parents parents = [] if parent_name diff --git a/activesupport/lib/active_support/core_ext/object/blank.rb b/activesupport/lib/active_support/core_ext/object/blank.rb index 09d9af1bde..e238fef5a2 100644 --- a/activesupport/lib/active_support/core_ext/object/blank.rb +++ b/activesupport/lib/active_support/core_ext/object/blank.rb @@ -43,6 +43,7 @@ class NilClass # +nil+ is blank: # # nil.blank? # => true + # def blank? true end @@ -52,6 +53,7 @@ class FalseClass # +false+ is blank: # # false.blank? # => true + # def blank? true end @@ -61,6 +63,7 @@ class TrueClass # +true+ is not blank: # # true.blank? # => false + # def blank? false end @@ -71,6 +74,7 @@ class Array # # [].blank? # => true # [1,2,3].blank? # => false + # alias_method :blank?, :empty? end @@ -79,6 +83,7 @@ class Hash # # {}.blank? # => true # {:key => 'value'}.blank? # => false + # alias_method :blank?, :empty? end @@ -89,6 +94,7 @@ class String # ' '.blank? # => true # ' '.blank? # => true # ' something here '.blank? # => false + # def blank? self !~ /[^[:space:]]/ end @@ -99,6 +105,7 @@ class Numeric #:nodoc: # # 1.blank? # => false # 0.blank? # => false + # def blank? false end diff --git a/activesupport/lib/active_support/core_ext/object/duplicable.rb b/activesupport/lib/active_support/core_ext/object/duplicable.rb index 9cd7485e2e..f1b755c2c4 100644 --- a/activesupport/lib/active_support/core_ext/object/duplicable.rb +++ b/activesupport/lib/active_support/core_ext/object/duplicable.rb @@ -31,6 +31,7 @@ class NilClass # # nil.duplicable? # => false # nil.dup # => TypeError: can't dup NilClass + # def duplicable? false end @@ -41,6 +42,7 @@ class FalseClass # # false.duplicable? # => false # false.dup # => TypeError: can't dup FalseClass + # def duplicable? false end @@ -51,6 +53,7 @@ class TrueClass # # true.duplicable? # => false # true.dup # => TypeError: can't dup TrueClass + # def duplicable? false end @@ -61,6 +64,7 @@ class Symbol # # :my_symbol.duplicable? # => false # :my_symbol.dup # => TypeError: can't dup Symbol + # def duplicable? false end @@ -71,6 +75,7 @@ class Numeric # # 3.duplicable? # => false # 3.dup # => TypeError: can't dup Fixnum + # def duplicable? false end diff --git a/activesupport/lib/active_support/core_ext/object/with_options.rb b/activesupport/lib/active_support/core_ext/object/with_options.rb index 723bf69189..e058367111 100644 --- a/activesupport/lib/active_support/core_ext/object/with_options.rb +++ b/activesupport/lib/active_support/core_ext/object/with_options.rb @@ -36,6 +36,7 @@ class Object # # with_options can also be nested since the call is forwarded to its receiver. # Each nesting level will merge inherited defaults in addition to their own. + # def with_options(options) yield ActiveSupport::OptionMerger.new(self, options) end diff --git a/activesupport/lib/active_support/core_ext/string/inflections.rb b/activesupport/lib/active_support/core_ext/string/inflections.rb index e726a475e0..070bfd7af6 100644 --- a/activesupport/lib/active_support/core_ext/string/inflections.rb +++ b/activesupport/lib/active_support/core_ext/string/inflections.rb @@ -5,6 +5,7 @@ require 'active_support/inflector/transliterate' # For instance, you can figure out the name of a table from the name of a class. # # 'ScaleScore'.tableize # => "scale_scores" +# class String # Returns the plural form of the word in the string. # diff --git a/activesupport/lib/active_support/core_ext/string/output_safety.rb b/activesupport/lib/active_support/core_ext/string/output_safety.rb index d4e1597840..5226ff0cbe 100644 --- a/activesupport/lib/active_support/core_ext/string/output_safety.rb +++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb @@ -64,6 +64,7 @@ class ERB # in Rails templates: # # <%=j @person.to_json %> + # def json_escape(s) result = s.to_s.gsub(JSON_ESCAPE_REGEXP) { |special| JSON_ESCAPE[special] } s.html_safe? ? result.html_safe : result diff --git a/activesupport/lib/active_support/file_update_checker.rb b/activesupport/lib/active_support/file_update_checker.rb index 20dde73abf..8860636168 100644 --- a/activesupport/lib/active_support/file_update_checker.rb +++ b/activesupport/lib/active_support/file_update_checker.rb @@ -28,6 +28,7 @@ module ActiveSupport # ActionDispatch::Reloader.to_prepare do # i18n_reloader.execute_if_updated # end + # class FileUpdateChecker # It accepts two parameters on initialization. The first is an array # of files and the second is an optional hash of directories. The hash must diff --git a/activesupport/lib/active_support/hash_with_indifferent_access.rb b/activesupport/lib/active_support/hash_with_indifferent_access.rb index 3191a3bdc6..91459f3e5b 100644 --- a/activesupport/lib/active_support/hash_with_indifferent_access.rb +++ b/activesupport/lib/active_support/hash_with_indifferent_access.rb @@ -53,6 +53,7 @@ module ActiveSupport # # hash = HashWithIndifferentAccess.new # hash[:key] = "value" + # def []=(key, value) regular_writer(convert_key(key), convert_value(value)) end @@ -68,6 +69,7 @@ module ActiveSupport # hash_2[:key] = "New Value!" # # hash_1.update(hash_2) # => {"key"=>"New Value!"} + # def update(other_hash) if other_hash.is_a? HashWithIndifferentAccess super(other_hash) @@ -85,6 +87,7 @@ module ActiveSupport # hash["key"] = "value" # hash.key? :key # => true # hash.key? "key" # => true + # def key?(key) super(convert_key(key)) end @@ -104,6 +107,7 @@ module ActiveSupport # hash[:a] = "x" # hash[:b] = "y" # hash.values_at("a", "b") # => ["x", "y"] + # def values_at(*indices) indices.collect {|key| self[convert_key(key)]} end diff --git a/activesupport/lib/active_support/inflector/methods.rb b/activesupport/lib/active_support/inflector/methods.rb index 53a1c3f160..48296841aa 100644 --- a/activesupport/lib/active_support/inflector/methods.rb +++ b/activesupport/lib/active_support/inflector/methods.rb @@ -228,6 +228,7 @@ module ActiveSupport # "blargle".safe_constantize # => nil # "UnknownModule".safe_constantize # => nil # "UnknownModule::Foo::Bar".safe_constantize # => nil + # def safe_constantize(camel_cased_word) begin constantize(camel_cased_word) diff --git a/activesupport/lib/active_support/lazy_load_hooks.rb b/activesupport/lib/active_support/lazy_load_hooks.rb index 34450c65d4..c167efc1a7 100644 --- a/activesupport/lib/active_support/lazy_load_hooks.rb +++ b/activesupport/lib/active_support/lazy_load_hooks.rb @@ -17,6 +17,7 @@ module ActiveSupport # The very last line of +activerecord/lib/active_record/base.rb+ is: # # ActiveSupport.run_load_hooks(:active_record, ActiveRecord::Base) + # @load_hooks = Hash.new { |h,k| h[k] = [] } @loaded = Hash.new { |h,k| h[k] = [] } diff --git a/activesupport/lib/active_support/log_subscriber.rb b/activesupport/lib/active_support/log_subscriber.rb index 20ca6ff5f6..d2a6e1bd82 100644 --- a/activesupport/lib/active_support/log_subscriber.rb +++ b/activesupport/lib/active_support/log_subscriber.rb @@ -111,6 +111,7 @@ module ActiveSupport # option is set to true, it also adds bold to the string. This is based # on the Highline implementation and will automatically append CLEAR to the # end of the returned String. + # def color(text, color, bold=false) return text unless colorize_logging color = self.class.const_get(color.to_s.upcase) if color.is_a?(Symbol) diff --git a/activesupport/lib/active_support/log_subscriber/test_helper.rb b/activesupport/lib/active_support/log_subscriber/test_helper.rb index 5c7a238934..b65ea6208c 100644 --- a/activesupport/lib/active_support/log_subscriber/test_helper.rb +++ b/activesupport/lib/active_support/log_subscriber/test_helper.rb @@ -31,6 +31,7 @@ module ActiveSupport # powers (it actually does not send anything to your output), and you can collect them # doing @logger.logged(level), where level is the level used in logging, like info, # debug, warn and so on. + # module TestHelper def setup @logger = MockLogger.new @@ -95,6 +96,7 @@ module ActiveSupport # def logger # ActiveRecord::Base.logger = @logger # end + # def set_logger(logger) ActiveSupport::LogSubscriber.logger = logger end diff --git a/activesupport/lib/active_support/message_encryptor.rb b/activesupport/lib/active_support/message_encryptor.rb index c002b1c02c..ada2e79ccb 100644 --- a/activesupport/lib/active_support/message_encryptor.rb +++ b/activesupport/lib/active_support/message_encryptor.rb @@ -36,6 +36,7 @@ module ActiveSupport # Options: # * :cipher - Cipher to use. Can be any cipher returned by OpenSSL::Cipher.ciphers. Default is 'aes-256-cbc' # * :serializer - Object serializer to use. Default is +Marshal+. + # def initialize(secret, options = {}) @secret = secret @cipher = options[:cipher] || 'aes-256-cbc' diff --git a/activesupport/lib/active_support/notifications.rb b/activesupport/lib/active_support/notifications.rb index 6d89307638..6735c561d3 100644 --- a/activesupport/lib/active_support/notifications.rb +++ b/activesupport/lib/active_support/notifications.rb @@ -133,6 +133,7 @@ module ActiveSupport # # Notifications ships with a queue implementation that consumes and publish events # to log subscribers in a thread. You can use any queue implementation you want. + # module Notifications @instrumenters = Hash.new { |h,k| h[k] = notifier.listening?(k) } diff --git a/activesupport/lib/active_support/ordered_options.rb b/activesupport/lib/active_support/ordered_options.rb index 6bd6f1f2ff..60e6cd55ad 100644 --- a/activesupport/lib/active_support/ordered_options.rb +++ b/activesupport/lib/active_support/ordered_options.rb @@ -13,6 +13,7 @@ # h.girl = 'Mary' # h.boy # => 'John' # h.girl # => 'Mary' +# module ActiveSupport #:nodoc: class OrderedOptions < Hash alias_method :_get, :[] # preserve the original #[] method diff --git a/activesupport/lib/active_support/string_inquirer.rb b/activesupport/lib/active_support/string_inquirer.rb index e059594bfa..f3f3909a90 100644 --- a/activesupport/lib/active_support/string_inquirer.rb +++ b/activesupport/lib/active_support/string_inquirer.rb @@ -8,6 +8,7 @@ module ActiveSupport # you can call this: # # Rails.env.production? + # class StringInquirer < String def method_missing(method_name, *arguments) if method_name[-1, 1] == "?" diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb index f040ee7101..451520ac5c 100644 --- a/activesupport/lib/active_support/time_with_zone.rb +++ b/activesupport/lib/active_support/time_with_zone.rb @@ -31,6 +31,7 @@ module ActiveSupport # t > Time.utc(1999) # => true # t.is_a?(Time) # => true # t.is_a?(ActiveSupport::TimeWithZone) # => true + # class TimeWithZone # Report class name as 'Time' to thwart type checking @@ -126,6 +127,7 @@ module ActiveSupport # # With ActiveSupport::JSON::Encoding.use_standard_json_time_format = false # Time.utc(2005,2,1,15,15,10).in_time_zone.to_json # # => "2005/02/01 15:15:10 +0000" + # def as_json(options = nil) if ActiveSupport::JSON::Encoding.use_standard_json_time_format xmlschema diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index 6cd2c425c3..c4edbae55b 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -48,6 +48,7 @@ module Rails # 10) Build the middleware stack and run to_prepare callbacks # 11) Run config.before_eager_load and eager_load if cache classes is true # 12) Run config.after_initialize callbacks + # class Application < Engine autoload :Bootstrap, 'rails/application/bootstrap' autoload :Configuration, 'rails/application/configuration' diff --git a/railties/lib/rails/configuration.rb b/railties/lib/rails/configuration.rb index 57168eee83..3d66019e5e 100644 --- a/railties/lib/rails/configuration.rb +++ b/railties/lib/rails/configuration.rb @@ -32,6 +32,7 @@ module Rails # And finally they can also be removed from the stack completely: # # config.middleware.delete ActionDispatch::BestStandardsSupport + # class MiddlewareStackProxy def initialize @operations = [] diff --git a/railties/lib/rails/engine/configuration.rb b/railties/lib/rails/engine/configuration.rb index f4de5a4375..d3b42021fc 100644 --- a/railties/lib/rails/engine/configuration.rb +++ b/railties/lib/rails/engine/configuration.rb @@ -28,6 +28,7 @@ module Rails # If you want to disable color in console, do: # # config.generators.colorize_logging = false + # def generators #:nodoc: @generators ||= Rails::Configuration::Generators.new yield(@generators) if block_given? diff --git a/railties/lib/rails/generators/active_model.rb b/railties/lib/rails/generators/active_model.rb index 3d3b50540a..454327f765 100644 --- a/railties/lib/rails/generators/active_model.rb +++ b/railties/lib/rails/generators/active_model.rb @@ -22,6 +22,7 @@ module Rails # # The only exception in ActiveModel for ActiveRecord is the use of self.build # instead of self.new. + # class ActiveModel attr_reader :name diff --git a/railties/lib/rails/generators/base.rb b/railties/lib/rails/generators/base.rb index f2ded6be84..28d7680669 100644 --- a/railties/lib/rails/generators/base.rb +++ b/railties/lib/rails/generators/base.rb @@ -161,6 +161,7 @@ module Rails # hook_for :resource_controller do |instance, controller| # instance.invoke controller, [ instance.name.pluralize ] # end + # def self.hook_for(*names, &block) options = names.extract_options! in_base = options.delete(:in) || base_name diff --git a/railties/lib/rails/generators/named_base.rb b/railties/lib/rails/generators/named_base.rb index e02f19508f..e85d1b8fa2 100644 --- a/railties/lib/rails/generators/named_base.rb +++ b/railties/lib/rails/generators/named_base.rb @@ -168,6 +168,7 @@ module Rails # # If the generator is invoked with class name Admin, it will check for # the presence of "AdminObserver". + # def self.check_class_collision(options={}) define_method :check_class_collision do name = if self.respond_to?(:controller_class_name) # for ScaffoldBase diff --git a/railties/lib/rails/generators/resource_helpers.rb b/railties/lib/rails/generators/resource_helpers.rb index 3c12da359b..48833869e5 100644 --- a/railties/lib/rails/generators/resource_helpers.rb +++ b/railties/lib/rails/generators/resource_helpers.rb @@ -4,6 +4,7 @@ module Rails module Generators # Deal with controller names on scaffold and add some helpers to deal with # ActiveModel. + # module ResourceHelpers mattr_accessor :skip_warn @@ -12,6 +13,7 @@ module Rails end # Set controller variables on initialization. + # def initialize(*args) #:nodoc: super diff --git a/railties/lib/rails/generators/test_case.rb b/railties/lib/rails/generators/test_case.rb index e8f5925ca5..ff9cf0087e 100644 --- a/railties/lib/rails/generators/test_case.rb +++ b/railties/lib/rails/generators/test_case.rb @@ -26,6 +26,7 @@ module Rails # destination File.expand_path("../tmp", File.dirname(__FILE__)) # setup :prepare_destination # end + # class TestCase < ActiveSupport::TestCase include FileUtils @@ -42,6 +43,7 @@ module Rails # Sets which generator should be tested: # # tests AppGenerator + # def self.tests(klass) self.generator_class = klass end @@ -50,6 +52,7 @@ module Rails # invoking it. # # arguments %w(app_name --skip-active-record) + # def self.arguments(array) self.default_arguments = array end @@ -57,6 +60,7 @@ module Rails # Sets the destination of generator files: # # destination File.expand_path("../tmp", File.dirname(__FILE__)) + # def self.destination(path) self.destination_root = path end @@ -79,6 +83,7 @@ module Rails # assert_match(/Product\.all/, index) # end # end + # def assert_file(relative, *contents) absolute = File.expand_path(relative, destination_root) assert File.exists?(absolute), "Expected file #{relative.inspect} to exist, but does not" @@ -101,6 +106,7 @@ module Rails # path relative to the configured destination: # # assert_no_file "config/random.rb" + # def assert_no_file(relative) absolute = File.expand_path(relative, destination_root) assert !File.exists?(absolute), "Expected file #{relative.inspect} to not exist, but does" @@ -118,6 +124,7 @@ module Rails # assert_file "db/migrate/003_create_products.rb" # # Consequently, assert_migration accepts the same arguments has assert_file. + # def assert_migration(relative, *contents, &block) file_name = migration_file_name(relative) assert file_name, "Expected migration #{relative} to exist, but was not found" @@ -128,6 +135,7 @@ module Rails # path relative to the configured destination: # # assert_no_migration "db/migrate/create_products.rb" + # def assert_no_migration(relative) file_name = migration_file_name(relative) assert_nil file_name, "Expected migration #{relative} to not exist, but found #{file_name}" @@ -142,6 +150,7 @@ module Rails # assert_match(/create_table/, up) # end # end + # def assert_class_method(method, content, &block) assert_instance_method "self.#{method}", content, &block end @@ -154,6 +163,7 @@ module Rails # assert_match(/Product\.all/, index) # end # end + # def assert_instance_method(method, content) assert content =~ /def #{method}(\(.+\))?(.*?)\n end/m, "Expected to have method #{method}" yield $2.strip if block_given? @@ -164,6 +174,7 @@ module Rails # properly: # # assert_field_type :date, :date_select + # def assert_field_type(attribute_type, field_type) assert_equal(field_type, create_generated_attribute(attribute_type).field_type) end @@ -171,6 +182,7 @@ module Rails # Asserts the given attribute type gets a proper default value: # # assert_field_default_value :string, "MyString" + # def assert_field_default_value(attribute_type, value) assert_equal(value, create_generated_attribute(attribute_type).default) end @@ -204,6 +216,7 @@ module Rails # attribute type and, optionally, the attribute name: # # create_generated_attribute(:string, 'name') + # def create_generated_attribute(attribute_type, name = 'test', index = nil) Rails::Generators::GeneratedAttribute.parse([name, attribute_type, index].compact.join(':')) end diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb index 8fbf58315a..2102f8a03c 100644 --- a/railties/lib/rails/railtie.rb +++ b/railties/lib/rails/railtie.rb @@ -110,6 +110,7 @@ module Rails # can be used in both. # # Be sure to look at the documentation of those specific classes for more information. + # class Railtie autoload :Configurable, "rails/railtie/configurable" autoload :Configuration, "rails/railtie/configuration" diff --git a/railties/test/generators/shared_generator_tests.rb b/railties/test/generators/shared_generator_tests.rb index 6dc72f0fc0..e78e67725d 100644 --- a/railties/test/generators/shared_generator_tests.rb +++ b/railties/test/generators/shared_generator_tests.rb @@ -1,5 +1,6 @@ # # Tests, setup, and teardown common to the application and plugin generator suites. +# module SharedGeneratorTests def setup Rails.application = TestApp::Application -- cgit v1.2.3 From d31b765628db6aa9ffa9a92bfa2401067e92bb6c Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Wed, 23 May 2012 22:49:39 +0530 Subject: Revert "Remove Obsolute root specifiying short syntax" This reverts commit feaa7b35a0214240eb34780ab51b843571e74904. Reason: Incorrect change. That's a Rails 4 feature and will not obviously work in 3.2.3. [ci skip] --- guides/source/routing.textile | 1 + 1 file changed, 1 insertion(+) diff --git a/guides/source/routing.textile b/guides/source/routing.textile index 6081651364..4a50edbb15 100644 --- a/guides/source/routing.textile +++ b/guides/source/routing.textile @@ -629,6 +629,7 @@ You can specify what Rails should route +"/"+ to with the +root+ method: root :to => 'pages#main' +root 'pages#main' # shortcut for the above You should put the +root+ route at the top of the file, because it is the most popular route and should be matched first. You also need to delete the +public/index.html+ file for the root route to take effect. -- cgit v1.2.3 From 1c94868033c631dcb44d705f70433a64d48e0938 Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Wed, 23 May 2012 23:12:35 +0530 Subject: copy edits in collection proxy docs [ci skip] --- .../active_record/associations/collection_proxy.rb | 43 +++++++++------------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index 6fd5c466f6..100fb38dec 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -92,6 +92,10 @@ module ActiveRecord # # ] # # person.pets.select(:name) { |pet| pet.name =~ /oo/ } + # # => [ + # # #, + # # # + # # ] ## # :method: find @@ -113,7 +117,7 @@ module ActiveRecord # # #, # # # # # ] - # + # # person.pets.find(1) # => # # person.pets.find(4) # => ActiveRecord::RecordNotFound: Couldn't find Pet with id=4 # @@ -231,7 +235,7 @@ module ActiveRecord # # Returns a new object of the collection type that has been instantiated with # attributes, linked to this object and that has already been saved (if it - # passed the validations). + # passes the validations). # # class Person # has_many :pets @@ -255,15 +259,14 @@ module ActiveRecord # # #, # # # # # ] - + ## # :method: create! # # :call-seq: # create!(attributes = {}, options = {}, &block) # - # Like +create+, except that if the record is invalid will - # raise an exception. + # Like +create+, except that if the record is invalid, raises an exception. # # class Person # has_many :pets @@ -340,8 +343,8 @@ module ActiveRecord ## # :method: delete_all # - # Deletes all the records from the collection. For +has_many+ it will do the - # deletion according to the strategy specified by the :dependent + # Deletes all the records from the collection. For +has_many+ asssociations, + # the deletion is done according to the strategy specified by the :dependent # option. Returns an array with the deleted records. # # If no :dependent option is given, then it will follow the @@ -501,7 +504,7 @@ module ActiveRecord # You can pass +Fixnum+ or +String+ values, it finds the records # responding to the +id+ and then deletes them from the database. # - # person.pets.size # => 3 + # person.pets.size # => 3 # person.pets # # => [ # # #, @@ -529,7 +532,7 @@ module ActiveRecord # person.pets # => [] # # Pet.find(4, 5, 6) # => ActiveRecord::RecordNotFound: Couldn't find all Pets with IDs (4, 5, 6) - + ## # :method: size # @@ -541,11 +544,7 @@ module ActiveRecord # end # # person.pets.size # => 3 - # # Executes: - # # - # # SELECT COUNT(*) - # # FROM "pets" - # # WHERE "pets"."person_id" = 1 + # # executes something like SELECT COUNT(*) FROM "pets" WHERE "pets"."person_id" = 1 # # person.pets # This will execute a SELECT * FROM query # # => [ @@ -562,24 +561,18 @@ module ActiveRecord # :method: length # # Returns the size of the collection calling +size+ on the target. - # If the collection has been already loaded +length+ and +size+ are - # equivalent. If not and you are going to need the records anyway this - # method will take one less query because loads the collection. Otherwise - # +size+ is more efficient. + # If the collection has been already loaded, +length+ and +size+ are + # equivalent. # # class Person < ActiveRecord::Base # has_many :pets # end # # person.pets.length # => 3 - # # Executes: - # # - # # SELECT "pets".* - # #  FROM "pets" - # # WHERE "pets"."person_id" = 1 + # # executes something like SELECT "pets".* FROM "pets" WHERE "pets"."person_id" = 1 # # # Because the collection is loaded, you can - # # call the collection without execute a query: + # # call the collection with no additional queries: # person.pets # # => [ # # #, @@ -705,7 +698,7 @@ module ActiveRecord :sum, :count, :size, :length, :empty?, :any?, :many?, :include?, :to => :@association - + def initialize(association) @association = association super association.klass, association.klass.arel_table -- cgit v1.2.3 From c97fb889a6db6c661853ce0612791a26524e7c50 Mon Sep 17 00:00:00 2001 From: Godfrey Chan Date: Tue, 22 May 2012 13:16:39 -0700 Subject: Added instructions for backporting changes to guides. I was looking for instructions on backporting changes the other day and wasn't able to find it anywhere. I updated the contrib guides based on the disccusion in #6420, #6215 and #6447. --- .../source/contributing_to_ruby_on_rails.textile | 29 ++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/guides/source/contributing_to_ruby_on_rails.textile b/guides/source/contributing_to_ruby_on_rails.textile index a2254a550c..72cdea885f 100644 --- a/guides/source/contributing_to_ruby_on_rails.textile +++ b/guides/source/contributing_to_ruby_on_rails.textile @@ -430,6 +430,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: + + +$ git log master..HEAD + + +Then extract the diff: + + +$ git format-patch master --stdout > ~/my_changes.patch + + +Switch over to the target branch and apply your changes: + + +$ git checkout -b my_backport_branch 3-2-stable +$ git apply ~/my_changes.patch + + +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 -- cgit v1.2.3 From 2b5b60fc3c4251536b837937391ebdd028892b15 Mon Sep 17 00:00:00 2001 From: Mark McSpadden Date: Wed, 23 May 2012 12:31:35 -0500 Subject: Add Hash#deep_transform_keys and Hash#deep_transform_keys! Also convert deep_*_keys to use deep_transform_keys. --- activesupport/CHANGELOG.md | 2 +- .../lib/active_support/core_ext/hash/keys.rb | 43 +++++++++++++--------- activesupport/test/core_ext/hash_ext_test.rb | 17 ++++++++- .../source/active_support_core_extensions.textile | 7 ++++ 4 files changed, 50 insertions(+), 19 deletions(-) diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index 0171742347..62b8a789c7 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,6 +1,6 @@ ## Rails 4.0.0 (unreleased) ## -* Add `Hash#transform_keys` and `Hash#transform_keys!`. *Mark McSpadden* +* Add `Hash#transform_keys`, `Hash#transform_keys!`, `Hash#deep_transform_keys`, and `Hash#deep_transform_keys!`. *Mark McSpadden* * Changed xml type `datetime` to `dateTime` (with upper case letter `T`). *Angelo Capilleri* diff --git a/activesupport/lib/active_support/core_ext/hash/keys.rb b/activesupport/lib/active_support/core_ext/hash/keys.rb index 5eb861934d..362d584ba1 100644 --- a/activesupport/lib/active_support/core_ext/hash/keys.rb +++ b/activesupport/lib/active_support/core_ext/hash/keys.rb @@ -65,47 +65,56 @@ class Hash end end - # Return a new hash with all keys converted to strings. + # Return a new hash with all keys converted by the block operation. # This includes the keys from the root hash and from all # nested hashes. - def deep_stringify_keys + # + # { :person => { :name => 'Rob', :years => '28' } }.deep_transform_keys{ |key| key.to_s.upcase } + # # => { "PERSON" => { "NAME" => "Rob", "YEARS" => "28" } } + def deep_transform_keys(&block) result = {} each do |key, value| - result[key.to_s] = value.is_a?(Hash) ? value.deep_stringify_keys : value + result[yield(key)] = value.is_a?(Hash) ? value.deep_transform_keys(&block) : value end result end - # Destructively convert all keys to strings. + # Destructively convert all keys by using the block operation. # This includes the keys from the root hash and from all # nested hashes. - def deep_stringify_keys! + def deep_transform_keys!(&block) keys.each do |key| - val = delete(key) - self[key.to_s] = val.is_a?(Hash) ? val.deep_stringify_keys! : val + value = delete(key) + self[yield(key)] = value.is_a?(Hash) ? value.deep_transform_keys!(&block) : value end self end + # Return a new hash with all keys converted to strings. + # This includes the keys from the root hash and from all + # nested hashes. + def deep_stringify_keys + deep_transform_keys{ |key| key.to_s } + end + + # Destructively convert all keys to strings. + # This includes the keys from the root hash and from all + # nested hashes. + def deep_stringify_keys! + deep_transform_keys!{ |key| key.to_s } + end + # Destructively convert all keys to symbols, as long as they respond # to +to_sym+. This includes the keys from the root hash and from all # nested hashes. def deep_symbolize_keys! - keys.each do |key| - val = delete(key) - self[(key.to_sym rescue key)] = val.is_a?(Hash) ? val.deep_stringify_keys! : val - end - self + deep_transform_keys!{ |key| key.to_sym rescue key } end # Return a new hash with all keys converted to symbols, as long as # they respond to +to_sym+. This includes the keys from the root hash # and from all nested hashes. def deep_symbolize_keys - result = {} - each do |key, value| - result[(key.to_sym rescue key)] = value.is_a?(Hash) ? value.deep_symbolize_keys : value - end - result + deep_transform_keys{ |key| key.to_sym rescue key } end end diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb index e68733db8b..f13fff43d4 100644 --- a/activesupport/test/core_ext/hash_ext_test.rb +++ b/activesupport/test/core_ext/hash_ext_test.rb @@ -32,14 +32,17 @@ class HashExtTest < ActiveSupport::TestCase @fixnums = { 0 => 1, 1 => 2 } @nested_fixnums = { 0 => { 1 => { 2 => 3} } } @illegal_symbols = { [] => 3 } - @upcase_strings = { 'A' => 1, 'B' => 2 } @nested_illegal_symbols = { [] => { [] => 3} } + @upcase_strings = { 'A' => 1, 'B' => 2 } + @nested_upcase_strings = { 'A' => { 'B' => { 'C' => 3 } } } end def test_methods h = {} assert_respond_to h, :transform_keys assert_respond_to h, :transform_keys! + assert_respond_to h, :deep_transform_keys + assert_respond_to h, :deep_transform_keys! assert_respond_to h, :symbolize_keys assert_respond_to h, :symbolize_keys! assert_respond_to h, :deep_symbolize_keys @@ -58,12 +61,24 @@ class HashExtTest < ActiveSupport::TestCase assert_equal @upcase_strings, @mixed.transform_keys{ |key| key.to_s.upcase } end + def test_deep_transform_keys + assert_equal @nested_upcase_strings, @nested_symbols.deep_transform_keys{ |key| key.to_s.upcase } + assert_equal @nested_upcase_strings, @nested_strings.deep_transform_keys{ |key| key.to_s.upcase } + assert_equal @nested_upcase_strings, @nested_mixed.deep_transform_keys{ |key| key.to_s.upcase } + end + def test_transform_keys! assert_equal @upcase_strings, @symbols.dup.transform_keys!{ |key| key.to_s.upcase } assert_equal @upcase_strings, @strings.dup.transform_keys!{ |key| key.to_s.upcase } assert_equal @upcase_strings, @mixed.dup.transform_keys!{ |key| key.to_s.upcase } end + def test_deep_transform_keys! + assert_equal @nested_upcase_strings, @nested_symbols.deep_transform_keys!{ |key| key.to_s.upcase } + assert_equal @nested_upcase_strings, @nested_strings.deep_transform_keys!{ |key| key.to_s.upcase } + assert_equal @nested_upcase_strings, @nested_mixed.deep_transform_keys!{ |key| key.to_s.upcase } + end + def test_symbolize_keys assert_equal @symbols, @symbols.symbolize_keys assert_equal @symbols, @strings.symbolize_keys diff --git a/guides/source/active_support_core_extensions.textile b/guides/source/active_support_core_extensions.textile index e2118e8f61..587f65529e 100644 --- a/guides/source/active_support_core_extensions.textile +++ b/guides/source/active_support_core_extensions.textile @@ -2579,6 +2579,13 @@ end 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: + + +{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}} + + NOTE: Defined in +active_support/core_ext/hash/keys.rb+. h5. +stringify_keys+ and +stringify_keys!+ -- cgit v1.2.3 From 925f6bd546bd719c85b0566157ea5c17cfcd612d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Wed, 23 May 2012 15:30:07 -0300 Subject: PGconn doesn't accepts :checkout_timeout option. This option was added on cb6f839359bd894feb0a1105b79af72b336aa41e renaming the :wait_timeout option. Fix build http://travis-ci.org/#!/rails/rails/jobs/1413405 --- .../lib/active_record/connection_adapters/postgresql_adapter.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 15c3d7be36..8e318a9e94 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -18,7 +18,7 @@ module ActiveRecord # Forward any unused config params to PGconn.connect. [:statement_limit, :encoding, :min_messages, :schema_search_path, - :schema_order, :adapter, :pool, :wait_timeout, :template, + :schema_order, :adapter, :pool, :checkout_timeout, :template, :reaping_frequency, :insert_returning].each do |key| conn_params.delete key end -- cgit v1.2.3 From 82b05fbcf4869517c08fb62398b03f3f133c0a28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Wed, 23 May 2012 15:32:05 -0300 Subject: Whitespaces :scissors: --- .../connection_adapters/abstract/connection_pool.rb | 12 ++++++------ .../active_record/connection_adapters/postgresql_adapter.rb | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb index be36c9695f..c259e46073 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -61,21 +61,21 @@ module ActiveRecord # * +pool+: number indicating size of connection pool (default 5) # * +checkout_timeout+: number of seconds to block and wait for a connection # before giving up and raising a timeout error (default 5 seconds). - # * +reaping_frequency+: frequency in seconds to periodically run the - # Reaper, which attempts to find and close dead connections, which can - # occur if a programmer forgets to close a connection at the end of a + # * +reaping_frequency+: frequency in seconds to periodically run the + # Reaper, which attempts to find and close dead connections, which can + # occur if a programmer forgets to close a connection at the end of a # thread or a thread dies unexpectedly. (Default nil, which means don't - # run the Reaper). + # run the Reaper). # * +dead_connection_timeout+: number of seconds from last checkout # after which the Reaper will consider a connection reapable. (default - # 5 seconds). + # 5 seconds). class ConnectionPool # Every +frequency+ seconds, the reaper will call +reap+ on +pool+. # A reaper instantiated with a nil frequency will never reap the # connection pool. # # Configure the frequency by setting "reaping_frequency" in your - # database yaml file. + # database yaml file. class Reaper attr_reader :pool, :frequency diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 8e318a9e94..d62cf529a4 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -1274,7 +1274,7 @@ module ActiveRecord end when 'integer' return 'integer' unless limit - + case limit when 1, 2; 'smallint' when 3, 4; 'integer' -- cgit v1.2.3 From 03fa7085a958cfd07fe7088a6b83a79d6f0eb602 Mon Sep 17 00:00:00 2001 From: Mikhail Dieterle Date: Thu, 24 May 2012 00:41:13 +0300 Subject: typos --- guides/source/getting_started.textile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/guides/source/getting_started.textile b/guides/source/getting_started.textile index c129aeb2e1..4d099860fa 100644 --- a/guides/source/getting_started.textile +++ b/guides/source/getting_started.textile @@ -500,7 +500,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. @@ -610,7 +610,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 ++ 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 +<table>+ tag: <%= link_to 'New post', :action => :new %> @@ -1129,7 +1129,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 -- cgit v1.2.3 From 4e5175e9570304a5efd148d11b062f15295bb11d Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 23 May 2012 15:44:24 -0700 Subject: use File.join to decrease dependencies on Pathname --- railties/lib/rails/application.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index 5c52235318..d44465e547 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -97,7 +97,7 @@ module Rails # Rails application, you will need to add lib to $LOAD_PATH on your own in case # you need to load files in lib/ during the application configuration as well. def add_lib_to_load_path! #:nodoc: - path = config.root.join('lib').to_s + path = File.join config.root, 'lib' $LOAD_PATH.unshift(path) if File.exists?(path) end -- cgit v1.2.3 From 4001835db00ce44cb75bca33ec02cd76b8ccc790 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 23 May 2012 15:56:49 -0700 Subject: removing more pathnameisms --- railties/lib/rails/engine.rb | 6 +++--- railties/lib/rails/paths.rb | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index e0950c6929..619c76206d 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -416,9 +416,9 @@ module Rails # Finds engine with given path def find(path) - expanded_path = File.expand_path path.to_s + expanded_path = File.expand_path path Rails::Engine::Railties.engines.find { |engine| - File.expand_path(engine.root.to_s) == expanded_path + File.expand_path(engine.root) == expanded_path } end end @@ -652,7 +652,7 @@ module Rails root = File.exist?("#{root_path}/#{flag}") ? root_path : default raise "Could not find root path for #{self}" unless root - Pathname.new File.realpath root + File.realpath root end def default_middleware_stack diff --git a/railties/lib/rails/paths.rb b/railties/lib/rails/paths.rb index b787d91821..6cd9c7bc95 100644 --- a/railties/lib/rails/paths.rb +++ b/railties/lib/rails/paths.rb @@ -1,5 +1,3 @@ -require "pathname" - module Rails module Paths # This object is an extended hash that behaves as root of the Rails::Paths system. @@ -186,7 +184,7 @@ module Rails raise "You need to set a path root" unless @root.path map do |p| - Pathname.new(@root.path).join(p) + File.join @root.path, p end end -- cgit v1.2.3 From d77b576c0330d8b1c6189cb94814382ce32baab6 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 23 May 2012 16:12:51 -0700 Subject: require the constants we use. ensure that root always returns a Pathname --- railties/lib/rails/engine/configuration.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/railties/lib/rails/engine/configuration.rb b/railties/lib/rails/engine/configuration.rb index e31df807a6..f82c1d00fb 100644 --- a/railties/lib/rails/engine/configuration.rb +++ b/railties/lib/rails/engine/configuration.rb @@ -1,4 +1,5 @@ require 'rails/railtie/configuration' +require 'pathname' module Rails class Engine @@ -8,7 +9,7 @@ module Rails def initialize(root=nil) super() - @root = root + @root = root && Pathname.new(root) @generators = app_generators.dup end -- cgit v1.2.3 From 9875574bbfebfdca96a80cf1c29c83adcbbda8f8 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 23 May 2012 16:41:40 -0700 Subject: Revert "require the constants we use. ensure that root always returns a Pathname" This reverts commit d77b576c0330d8b1c6189cb94814382ce32baab6. --- railties/lib/rails/engine/configuration.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/railties/lib/rails/engine/configuration.rb b/railties/lib/rails/engine/configuration.rb index f82c1d00fb..e31df807a6 100644 --- a/railties/lib/rails/engine/configuration.rb +++ b/railties/lib/rails/engine/configuration.rb @@ -1,5 +1,4 @@ require 'rails/railtie/configuration' -require 'pathname' module Rails class Engine @@ -9,7 +8,7 @@ module Rails def initialize(root=nil) super() - @root = root && Pathname.new(root) + @root = root @generators = app_generators.dup end -- cgit v1.2.3 From 880481a355e0017c43d6ff14b2d1a657548d06bf Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 23 May 2012 16:43:16 -0700 Subject: use File.join rather than depend on Pathname --- railties/lib/rails/commands/server.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/lib/rails/commands/server.rb b/railties/lib/rails/commands/server.rb index 4c4caad69f..e68d2e05c5 100644 --- a/railties/lib/rails/commands/server.rb +++ b/railties/lib/rails/commands/server.rb @@ -69,7 +69,7 @@ module Rails #Create required tmp directories if not found %w(cache pids sessions sockets).each do |dir_to_make| - FileUtils.mkdir_p(Rails.root.join('tmp', dir_to_make)) + FileUtils.mkdir_p(File.join(Rails.root, 'tmp', dir_to_make)) end unless options[:daemonize] -- cgit v1.2.3 From 66db0b9440e4db594c951d38f641e1910fd44db3 Mon Sep 17 00:00:00 2001 From: Philip Arndt Date: Thu, 24 May 2012 16:29:08 +1200 Subject: Fixed backward incompatibility for engines. - Many engines rely on being able to join directories to the Rails root: Rails.root.join('somedir') - This was now impossible because Rails.root returned a String: NoMethodError: undefined method `join' for "/code/myrailsapp":String - This was broken in 4001835db00ce44cb75bca33ec02cd76b8ccc790 --- railties/lib/rails/engine.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index 619c76206d..4c7199a2e2 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -652,7 +652,7 @@ module Rails root = File.exist?("#{root_path}/#{flag}") ? root_path : default raise "Could not find root path for #{self}" unless root - File.realpath root + Pathname.new File.realpath root end def default_middleware_stack -- cgit v1.2.3 From aa54d29f9b3068a40b67f055726696fa51a3baef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rory=20O=E2=80=99Kane?= Date: Thu, 24 May 2012 11:39:31 -0300 Subject: grammar fixes in a tip in Rails routing guide --- guides/source/routing.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/source/routing.textile b/guides/source/routing.textile index 4a50edbb15..d77b3bc7cd 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\/[^\/]+/ -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 -- cgit v1.2.3 From f1c2727d2a6ac492b799b7d79168e32c412d3c78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rory=20O=E2=80=99Kane?= Date: Thu, 24 May 2012 11:39:55 -0400 Subject: capitalize HTML5 in Getting Started Guide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit these pages capitalize “HTML5”: http://en.wikipedia.org/wiki/HTML5 http://dev.w3.org/html5/spec/ http://www.html5rocks.com/en/ --- guides/source/getting_started.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/source/getting_started.textile b/guides/source/getting_started.textile index 4d099860fa..1979d87a06 100644 --- a/guides/source/getting_started.textile +++ b/guides/source/getting_started.textile @@ -1129,7 +1129,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 link is clicked, +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 -- cgit v1.2.3 From f2c60c79416e449adb0abd663be3a5579615f722 Mon Sep 17 00:00:00 2001 From: Oscar Del Ben Date: Thu, 24 May 2012 08:26:59 -0700 Subject: [Guides] Add sprockets to list of loaded frameworks --- guides/source/initialization.textile | 1 + 1 file changed, 1 insertion(+) diff --git a/guides/source/initialization.textile b/guides/source/initialization.textile index 12b2eb7458..097e577cca 100644 --- a/guides/source/initialization.textile +++ b/guides/source/initialization.textile @@ -531,6 +531,7 @@ require "rails" action_controller action_mailer rails/test_unit + sprockets/rails ).each do |framework| begin require "#{framework}/railtie" -- cgit v1.2.3 From f819b90a13fab93b5ea819fb8d9e2dd1b33780e4 Mon Sep 17 00:00:00 2001 From: Oscar Del Ben Date: Thu, 24 May 2012 08:29:33 -0700 Subject: [Guides] Update ruby version check --- guides/source/initialization.textile | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/guides/source/initialization.textile b/guides/source/initialization.textile index 097e577cca..d627c37400 100644 --- a/guides/source/initialization.textile +++ b/guides/source/initialization.textile @@ -544,13 +544,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 1.9.3 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. -- cgit v1.2.3 From 27874a8e436b20405bcaad75536a3b15ab0cd22a Mon Sep 17 00:00:00 2001 From: Oscar Del Ben Date: Thu, 24 May 2012 08:35:05 -0700 Subject: [Guides] Add extract_options section --- guides/source/initialization.textile | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/guides/source/initialization.textile b/guides/source/initialization.textile index d627c37400..fb205bd658 100644 --- a/guides/source/initialization.textile +++ b/guides/source/initialization.textile @@ -572,11 +572,34 @@ 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+ +h4. +active_support/core_ext/array/extract_options.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. +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. -For more information see the "Extensions to Logger":active_support_core_extensions.html#extensions-to-logger section from the Active Support Core Extensions Guide. + +class Array + # Extracts options from a set of arguments. Removes and returns the + # last + # element in the array if it's a hash, otherwise returns a blank hash. + # + # def options(*args) + # args.extract_options! + # end + # + # options(1, 2) # => {} + # options(1, 2, :a => :b) # => {:a=>:b} + def extract_options! + if last.is_a?(Hash) && last.extractable_options? + pop + else + {} + end + end +end + h4. +railties/lib/rails/application.rb+ -- cgit v1.2.3 From cd6aa9f0952904437c7ecf9f153a3eb3860f3384 Mon Sep 17 00:00:00 2001 From: Oscar Del Ben Date: Thu, 24 May 2012 08:43:29 -0700 Subject: [Guides] Rewrite Rails application section --- guides/source/initialization.textile | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/guides/source/initialization.textile b/guides/source/initialization.textile index fb205bd658..be33f795d3 100644 --- a/guides/source/initialization.textile +++ b/guides/source/initialization.textile @@ -603,27 +603,20 @@ end 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 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. -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. +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. -h4. +active_support/file_update_checker.rb+ +TIP: You can read more about engines in the "Getting Started with Engines":engines.html +guide. -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. - -h4. +railties/lib/rails/plugin.rb+ - -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. - -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+ -- cgit v1.2.3 From 2ccc2109b7af1d656df0972747ed3c0363528e06 Mon Sep 17 00:00:00 2001 From: Oscar Del Ben Date: Thu, 24 May 2012 08:51:32 -0700 Subject: [Guides] Add core_ext/object section --- guides/source/initialization.textile | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/guides/source/initialization.textile b/guides/source/initialization.textile index be33f795d3..add3f44b1c 100644 --- a/guides/source/initialization.textile +++ b/guides/source/initialization.textile @@ -687,7 +687,31 @@ 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 core extensions: + + +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' + + +The Rails "api documentation":http://api.rubyonrails.org/ 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+ -- cgit v1.2.3 From 0b11840d1b3b0e17f4e26c3e6d499622b6c4fe9f Mon Sep 17 00:00:00 2001 From: Oscar Del Ben Date: Thu, 24 May 2012 08:52:46 -0700 Subject: [Guides] Update rack example --- guides/source/initialization.textile | 1 - 1 file changed, 1 deletion(-) diff --git a/guides/source/initialization.textile b/guides/source/initialization.textile index add3f44b1c..fe777d063b 100644 --- a/guides/source/initialization.textile +++ b/guides/source/initialization.textile @@ -727,7 +727,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 -- cgit v1.2.3 From cb44e0fed97d7cef024e9dd9cc113a75cc7d6f20 Mon Sep 17 00:00:00 2001 From: schneems Date: Tue, 22 May 2012 18:23:17 -0500 Subject: /rails/info/routes path shows routing information Will show similar contents to the output of `$ rake routes` in the browser in development. This speeds the time required to generate routes, since the application is already initialized. --- railties/CHANGELOG.md | 2 ++ railties/lib/rails/application/finisher.rb | 2 ++ railties/lib/rails/application/route_inspector.rb | 2 +- railties/lib/rails/info_controller.rb | 32 +++++++++++++++++----- .../rails/templates/layouts/application.html.erb | 32 ++++++++++++++++++++++ .../rails/templates/rails/info/properties.html.erb | 1 + .../lib/rails/templates/rails/info/routes.html.erb | 9 ++++++ 7 files changed, 72 insertions(+), 8 deletions(-) create mode 100644 railties/lib/rails/templates/layouts/application.html.erb create mode 100644 railties/lib/rails/templates/rails/info/properties.html.erb create mode 100644 railties/lib/rails/templates/rails/info/routes.html.erb diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index ccccc178c5..787bafea04 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -1,5 +1,7 @@ ## Rails 4.0.0 (unreleased) ## +* Add `/rails/info/routes` path, displays same information as `rake routes` *Richard Schneeman & Andrew White* + * Improved `rake routes` output for redirects *Łukasz Strzałkowski & Andrew White* * Load all environments available in `config.paths["config/environments"]`. *Piotr Sarnacki* diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb index 84f2601f28..60aa40b92f 100644 --- a/railties/lib/rails/application/finisher.rb +++ b/railties/lib/rails/application/finisher.rb @@ -23,6 +23,8 @@ module Rails if Rails.env.development? app.routes.append do get '/rails/info/properties' => "rails/info#properties" + get '/rails/info/routes' => "rails/info#routes" + get '/rails/info' => "rails/info#index" end end end diff --git a/railties/lib/rails/application/route_inspector.rb b/railties/lib/rails/application/route_inspector.rb index b23fb3e920..942c4f4789 100644 --- a/railties/lib/rails/application/route_inspector.rb +++ b/railties/lib/rails/application/route_inspector.rb @@ -51,7 +51,7 @@ module Rails end def internal? - path =~ %r{/rails/info/properties|^#{Rails.application.config.assets.prefix}} + path =~ %r{/rails/info.*|^#{Rails.application.config.assets.prefix}} end def engine? diff --git a/railties/lib/rails/info_controller.rb b/railties/lib/rails/info_controller.rb index 6b4bdb2921..5081074395 100644 --- a/railties/lib/rails/info_controller.rb +++ b/railties/lib/rails/info_controller.rb @@ -1,15 +1,33 @@ +require 'rails/application/route_inspector' + class Rails::InfoController < ActionController::Base + self.view_paths = File.join(File.dirname(__FILE__), 'templates') + layout 'application' + + before_filter :require_local! + + def index + redirect_to '/rails/info/routes' + end + def properties - if consider_all_requests_local? || request.local? - render :inline => Rails::Info.to_html - else - render :text => '

    For security purposes, this information is only available to local requests.

    ', :status => :forbidden - end + @info = Rails::Info.to_html + end + + def routes + inspector = Rails::Application::RouteInspector.new + @info = inspector.format(_routes.routes).join("\n") end protected - def consider_all_requests_local? - Rails.application.config.consider_all_requests_local + def require_local! + unless local_request? + render :text => '

    For security purposes, this information is only available to local requests.

    ', :status => :forbidden + end + end + + def local_request? + Rails.application.config.consider_all_requests_local || request.local? end end diff --git a/railties/lib/rails/templates/layouts/application.html.erb b/railties/lib/rails/templates/layouts/application.html.erb new file mode 100644 index 0000000000..53276d3e7c --- /dev/null +++ b/railties/lib/rails/templates/layouts/application.html.erb @@ -0,0 +1,32 @@ + + + + + Routes + + + +

    Your App: <%= link_to 'properties', '/rails/info/properties' %> | <%= link_to 'routes', '/rails/info/routes' %>

    +<%= yield %> + + + diff --git a/railties/lib/rails/templates/rails/info/properties.html.erb b/railties/lib/rails/templates/rails/info/properties.html.erb new file mode 100644 index 0000000000..d47cbab202 --- /dev/null +++ b/railties/lib/rails/templates/rails/info/properties.html.erb @@ -0,0 +1 @@ +<%= @info.html_safe %> \ No newline at end of file diff --git a/railties/lib/rails/templates/rails/info/routes.html.erb b/railties/lib/rails/templates/rails/info/routes.html.erb new file mode 100644 index 0000000000..890f6f5b03 --- /dev/null +++ b/railties/lib/rails/templates/rails/info/routes.html.erb @@ -0,0 +1,9 @@ +

    + Routes +

    + +

    + Routes match in priority from top to bottom +

    + +

    <%= @info %>

    \ No newline at end of file -- cgit v1.2.3 From c3e3102904c98a6e05bee33616288323278692b8 Mon Sep 17 00:00:00 2001 From: schneems Date: Wed, 23 May 2012 14:42:28 -0500 Subject: Rails::InfoController tests passing This includes new tests for /rails/info/routes --- railties/test/application/route_inspect_test.rb | 9 +++++++++ railties/test/application/routing_test.rb | 12 ++++++++++++ railties/test/rails_info_controller_test.rb | 17 +++++++++++------ 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/railties/test/application/route_inspect_test.rb b/railties/test/application/route_inspect_test.rb index 3b8c874b5b..e453cdb074 100644 --- a/railties/test/application/route_inspect_test.rb +++ b/railties/test/application/route_inspect_test.rb @@ -164,5 +164,14 @@ module ApplicationTests assert_equal " bar GET /bar(.:format) redirect(307, path: /foo/bar)", output[1] assert_equal "foobar GET /foobar(.:format) redirect(301)", output[2] end + + def test_presenter + output = draw do + get "/foo" => redirect("/foo/bar"), :constraints => { :subdomain => "admin" } + get "/bar" => redirect(path: "/foo/bar", status: 307) + get "/foobar" => redirect{ "/foo/bar" } + end + assert_equal output.join("\n"), Rails::Application::RoutePresenter.display_routes(@set.routes) + end end end diff --git a/railties/test/application/routing_test.rb b/railties/test/application/routing_test.rb index 977a5fc7e8..d1373ba202 100644 --- a/railties/test/application/routing_test.rb +++ b/railties/test/application/routing_test.rb @@ -15,12 +15,24 @@ module ApplicationTests teardown_app end + test "rails/info/routes in development" do + app("development") + get "/rails/info/routes" + assert_equal 200, last_response.status + end + test "rails/info/properties in development" do app("development") get "/rails/info/properties" assert_equal 200, last_response.status end + test "rails/info/routes in production" do + app("production") + get "/rails/info/routes" + assert_equal 404, last_response.status + end + test "rails/info/properties in production" do app("production") get "/rails/info/properties" diff --git a/railties/test/rails_info_controller_test.rb b/railties/test/rails_info_controller_test.rb index f7a30a16d2..cfb32b7d35 100644 --- a/railties/test/rails_info_controller_test.rb +++ b/railties/test/rails_info_controller_test.rb @@ -12,29 +12,28 @@ class InfoControllerTest < ActionController::TestCase def setup Rails.application.routes.draw do get '/rails/info/properties' => "rails/info#properties" + get '/rails/info/routes' => "rails/info#routes" end - @request.stubs(:local? => true) - @controller.stubs(:consider_all_requests_local? => false) + @controller.stubs(:local_request? => true) @routes = Rails.application.routes Rails::InfoController.send(:include, @routes.url_helpers) end test "info controller does not allow remote requests" do - @request.stubs(:local? => false) + @controller.stubs(:local_request? => false) get :properties assert_response :forbidden end test "info controller renders an error message when request was forbidden" do - @request.stubs(:local? => false) + @controller.stubs(:local_request? => false) get :properties assert_select 'p' end test "info controller allows requests when all requests are considered local" do - @request.stubs(:local? => false) - @controller.stubs(:consider_all_requests_local? => true) + @controller.stubs(:local_request? => true) get :properties assert_response :success end @@ -48,4 +47,10 @@ class InfoControllerTest < ActionController::TestCase get :properties assert_select 'table' end + + test "info controller renders with routes" do + get :routes + assert_select 'pre' + end + end -- cgit v1.2.3 From b0ebdf3e744baa935c0d9325780121e7fcac9d9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Thu, 24 May 2012 17:23:26 -0300 Subject: Use deep_dup in the deep_transform_keys tests. Using only dup make some tests to not catch up an implementation error because the methods were changing the nested hashes. Related to: https://github.com/rails/rails/commit/541429fbe49b0671adb3842ab1818230d670ef9f#L1R96 --- activesupport/test/core_ext/hash_ext_test.rb | 118 ++++++++++++++++++++++----- 1 file changed, 98 insertions(+), 20 deletions(-) diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb index f13fff43d4..e8fc94e6d6 100644 --- a/activesupport/test/core_ext/hash_ext_test.rb +++ b/activesupport/test/core_ext/hash_ext_test.rb @@ -61,23 +61,49 @@ class HashExtTest < ActiveSupport::TestCase assert_equal @upcase_strings, @mixed.transform_keys{ |key| key.to_s.upcase } end + def test_transform_keys_not_mutates + transformed_hash = @mixed.dup + transformed_hash.transform_keys{ |key| key.to_s.upcase } + assert_equal @mixed, transformed_hash + end + def test_deep_transform_keys assert_equal @nested_upcase_strings, @nested_symbols.deep_transform_keys{ |key| key.to_s.upcase } assert_equal @nested_upcase_strings, @nested_strings.deep_transform_keys{ |key| key.to_s.upcase } assert_equal @nested_upcase_strings, @nested_mixed.deep_transform_keys{ |key| key.to_s.upcase } end + def test_deep_transform_keys_not_mutates + transformed_hash = @nested_mixed.deep_dup + transformed_hash.deep_transform_keys{ |key| key.to_s.upcase } + assert_equal @nested_mixed, transformed_hash + end + def test_transform_keys! assert_equal @upcase_strings, @symbols.dup.transform_keys!{ |key| key.to_s.upcase } assert_equal @upcase_strings, @strings.dup.transform_keys!{ |key| key.to_s.upcase } assert_equal @upcase_strings, @mixed.dup.transform_keys!{ |key| key.to_s.upcase } end + def test_transform_keys_with_bang_mutates + transformed_hash = @mixed.dup + transformed_hash.transform_keys!{ |key| key.to_s.upcase } + assert_equal @upcase_strings, transformed_hash + assert_equal @mixed, { :a => 1, "b" => 2 } + end + def test_deep_transform_keys! - assert_equal @nested_upcase_strings, @nested_symbols.deep_transform_keys!{ |key| key.to_s.upcase } - assert_equal @nested_upcase_strings, @nested_strings.deep_transform_keys!{ |key| key.to_s.upcase } - assert_equal @nested_upcase_strings, @nested_mixed.deep_transform_keys!{ |key| key.to_s.upcase } - end + assert_equal @nested_upcase_strings, @nested_symbols.deep_dup.deep_transform_keys!{ |key| key.to_s.upcase } + assert_equal @nested_upcase_strings, @nested_strings.deep_dup.deep_transform_keys!{ |key| key.to_s.upcase } + assert_equal @nested_upcase_strings, @nested_mixed.deep_dup.deep_transform_keys!{ |key| key.to_s.upcase } + end + + def test_deep_transform_keys_with_bang_mutates + transformed_hash = @nested_mixed.deep_dup + transformed_hash.deep_transform_keys!{ |key| key.to_s.upcase } + assert_equal @nested_upcase_strings, transformed_hash + assert_equal @nested_mixed, { 'a' => { :b => { 'c' => 3 } } } + end def test_symbolize_keys assert_equal @symbols, @symbols.symbolize_keys @@ -85,22 +111,48 @@ class HashExtTest < ActiveSupport::TestCase assert_equal @symbols, @mixed.symbolize_keys end + def test_symbolize_keys_not_mutates + transformed_hash = @mixed.dup + transformed_hash.symbolize_keys + assert_equal @mixed, transformed_hash + end + def test_deep_symbolize_keys assert_equal @nested_symbols, @nested_symbols.deep_symbolize_keys assert_equal @nested_symbols, @nested_strings.deep_symbolize_keys assert_equal @nested_symbols, @nested_mixed.deep_symbolize_keys end + def test_deep_symbolize_keys_not_mutates + transformed_hash = @nested_mixed.deep_dup + transformed_hash.deep_symbolize_keys + assert_equal @nested_mixed, transformed_hash + end + def test_symbolize_keys! assert_equal @symbols, @symbols.dup.symbolize_keys! assert_equal @symbols, @strings.dup.symbolize_keys! assert_equal @symbols, @mixed.dup.symbolize_keys! end + def test_symbolize_keys_with_bang_mutates + transformed_hash = @mixed.dup + transformed_hash.deep_symbolize_keys! + assert_equal @symbols, transformed_hash + assert_equal @mixed, { :a => 1, "b" => 2 } + end + def test_deep_symbolize_keys! - assert_equal @nested_symbols, @nested_symbols.dup.deep_symbolize_keys! - assert_equal @nested_symbols, @nested_strings.dup.deep_symbolize_keys! - assert_equal @nested_symbols, @nested_mixed.dup.deep_symbolize_keys! + assert_equal @nested_symbols, @nested_symbols.deep_dup.deep_symbolize_keys! + assert_equal @nested_symbols, @nested_strings.deep_dup.deep_symbolize_keys! + assert_equal @nested_symbols, @nested_mixed.deep_dup.deep_symbolize_keys! + end + + def test_deep_symbolize_keys_with_bang_mutates + transformed_hash = @nested_mixed.deep_dup + transformed_hash.deep_symbolize_keys! + assert_equal @nested_symbols, transformed_hash + assert_equal @nested_mixed, { 'a' => { :b => { 'c' => 3 } } } end def test_symbolize_keys_preserves_keys_that_cant_be_symbolized @@ -110,7 +162,7 @@ class HashExtTest < ActiveSupport::TestCase def test_deep_symbolize_keys_preserves_keys_that_cant_be_symbolized assert_equal @nested_illegal_symbols, @nested_illegal_symbols.deep_symbolize_keys - assert_equal @nested_illegal_symbols, @nested_illegal_symbols.dup.deep_symbolize_keys! + assert_equal @nested_illegal_symbols, @nested_illegal_symbols.deep_dup.deep_symbolize_keys! end def test_symbolize_keys_preserves_fixnum_keys @@ -120,7 +172,7 @@ class HashExtTest < ActiveSupport::TestCase def test_deep_symbolize_keys_preserves_fixnum_keys assert_equal @nested_fixnums, @nested_fixnums.deep_symbolize_keys - assert_equal @nested_fixnums, @nested_fixnums.dup.deep_symbolize_keys! + assert_equal @nested_fixnums, @nested_fixnums.deep_dup.deep_symbolize_keys! end def test_stringify_keys @@ -129,22 +181,48 @@ class HashExtTest < ActiveSupport::TestCase assert_equal @strings, @mixed.stringify_keys end + def test_stringify_keys_not_mutates + transformed_hash = @mixed.dup + transformed_hash.stringify_keys + assert_equal @mixed, transformed_hash + end + def test_deep_stringify_keys assert_equal @nested_strings, @nested_symbols.deep_stringify_keys assert_equal @nested_strings, @nested_strings.deep_stringify_keys assert_equal @nested_strings, @nested_mixed.deep_stringify_keys end + def test_deep_stringify_keys_not_mutates + transformed_hash = @nested_mixed.deep_dup + transformed_hash.deep_stringify_keys + assert_equal @nested_mixed, transformed_hash + end + def test_stringify_keys! assert_equal @strings, @symbols.dup.stringify_keys! assert_equal @strings, @strings.dup.stringify_keys! assert_equal @strings, @mixed.dup.stringify_keys! end + def test_stringify_keys_with_bang_mutates + transformed_hash = @mixed.dup + transformed_hash.stringify_keys! + assert_equal @strings, transformed_hash + assert_equal @mixed, { :a => 1, "b" => 2 } + end + def test_deep_stringify_keys! - assert_equal @nested_strings, @nested_symbols.dup.deep_stringify_keys! - assert_equal @nested_strings, @nested_strings.dup.deep_stringify_keys! - assert_equal @nested_strings, @nested_mixed.dup.deep_stringify_keys! + assert_equal @nested_strings, @nested_symbols.deep_dup.deep_stringify_keys! + assert_equal @nested_strings, @nested_strings.deep_dup.deep_stringify_keys! + assert_equal @nested_strings, @nested_mixed.deep_dup.deep_stringify_keys! + end + + def test_deep_stringify_keys_with_bang_mutates + transformed_hash = @nested_mixed.deep_dup + transformed_hash.deep_stringify_keys! + assert_equal @nested_strings, transformed_hash + assert_equal @nested_mixed, { 'a' => { :b => { 'c' => 3 } } } end def test_symbolize_keys_for_hash_with_indifferent_access @@ -169,9 +247,9 @@ class HashExtTest < ActiveSupport::TestCase end def test_deep_symbolize_keys_bang_for_hash_with_indifferent_access - assert_raise(NoMethodError) { @nested_symbols.with_indifferent_access.dup.deep_symbolize_keys! } - assert_raise(NoMethodError) { @nested_strings.with_indifferent_access.dup.deep_symbolize_keys! } - assert_raise(NoMethodError) { @nested_mixed.with_indifferent_access.dup.deep_symbolize_keys! } + assert_raise(NoMethodError) { @nested_symbols.with_indifferent_access.deep_dup.deep_symbolize_keys! } + assert_raise(NoMethodError) { @nested_strings.with_indifferent_access.deep_dup.deep_symbolize_keys! } + assert_raise(NoMethodError) { @nested_mixed.with_indifferent_access.deep_dup.deep_symbolize_keys! } end def test_symbolize_keys_preserves_keys_that_cant_be_symbolized_for_hash_with_indifferent_access @@ -181,7 +259,7 @@ class HashExtTest < ActiveSupport::TestCase def test_deep_symbolize_keys_preserves_keys_that_cant_be_symbolized_for_hash_with_indifferent_access assert_equal @nested_illegal_symbols, @nested_illegal_symbols.with_indifferent_access.deep_symbolize_keys - assert_raise(NoMethodError) { @nested_illegal_symbols.with_indifferent_access.dup.deep_symbolize_keys! } + assert_raise(NoMethodError) { @nested_illegal_symbols.with_indifferent_access.deep_dup.deep_symbolize_keys! } end def test_symbolize_keys_preserves_fixnum_keys_for_hash_with_indifferent_access @@ -191,7 +269,7 @@ class HashExtTest < ActiveSupport::TestCase def test_deep_symbolize_keys_preserves_fixnum_keys_for_hash_with_indifferent_access assert_equal @nested_fixnums, @nested_fixnums.with_indifferent_access.deep_symbolize_keys - assert_raise(NoMethodError) { @nested_fixnums.with_indifferent_access.dup.deep_symbolize_keys! } + assert_raise(NoMethodError) { @nested_fixnums.with_indifferent_access.deep_dup.deep_symbolize_keys! } end def test_stringify_keys_for_hash_with_indifferent_access @@ -217,9 +295,9 @@ class HashExtTest < ActiveSupport::TestCase def test_deep_stringify_keys_bang_for_hash_with_indifferent_access assert_instance_of ActiveSupport::HashWithIndifferentAccess, @nested_symbols.with_indifferent_access.dup.deep_stringify_keys! - assert_equal @nested_strings, @nested_symbols.with_indifferent_access.dup.deep_stringify_keys! - assert_equal @nested_strings, @nested_strings.with_indifferent_access.dup.deep_stringify_keys! - assert_equal @nested_strings, @nested_mixed.with_indifferent_access.dup.deep_stringify_keys! + assert_equal @nested_strings, @nested_symbols.with_indifferent_access.deep_dup.deep_stringify_keys! + assert_equal @nested_strings, @nested_strings.with_indifferent_access.deep_dup.deep_stringify_keys! + assert_equal @nested_strings, @nested_mixed.with_indifferent_access.deep_dup.deep_stringify_keys! end def test_nested_under_indifferent_access -- cgit v1.2.3 From 6775ad8c61b18e0df2df7c7103478d4f315c0cb3 Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Thu, 24 May 2012 15:12:11 -0700 Subject: Merge pull request #5925 from Juanmcuello/pg_structure_dump Quote arguments in db:structure:dump for PostgreSQL. --- activerecord/lib/active_record/railties/databases.rake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index f26e18b1e0..791a22958c 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -406,9 +406,9 @@ db_namespace = namespace :db do set_psql_env(abcs[Rails.env]) search_path = abcs[Rails.env]['schema_search_path'] unless search_path.blank? - search_path = search_path.split(",").map{|search_path_part| "--schema=#{search_path_part.strip}" }.join(" ") + search_path = search_path.split(",").map{|search_path_part| "--schema=#{Shellwords.escape(search_path_part.strip)}" }.join(" ") end - `pg_dump -i -s -x -O -f #{filename} #{search_path} #{abcs[Rails.env]['database']}` + `pg_dump -i -s -x -O -f #{Shellwords.escape(filename)} #{search_path} #{Shellwords.escape(abcs[Rails.env]['database'])}` raise 'Error dumping database' if $?.exitstatus == 1 when /sqlite/ dbfile = abcs[Rails.env]['database'] -- cgit v1.2.3 From 317f49493afc92c7aab1b9b43a1214a1966106e2 Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Thu, 24 May 2012 19:18:28 -0300 Subject: Add missing requires for deep_dup and hash ext test --- activesupport/lib/active_support/core_ext/object/deep_dup.rb | 2 ++ activesupport/test/core_ext/hash_ext_test.rb | 1 + 2 files changed, 3 insertions(+) diff --git a/activesupport/lib/active_support/core_ext/object/deep_dup.rb b/activesupport/lib/active_support/core_ext/object/deep_dup.rb index 883f5f556c..f55fbc282e 100644 --- a/activesupport/lib/active_support/core_ext/object/deep_dup.rb +++ b/activesupport/lib/active_support/core_ext/object/deep_dup.rb @@ -1,3 +1,5 @@ +require 'active_support/core_ext/object/duplicable' + class Object # Returns a deep copy of object if it's duplicable. If it's # not duplicable, returns +self+. diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb index e8fc94e6d6..5d422ce5ad 100644 --- a/activesupport/test/core_ext/hash_ext_test.rb +++ b/activesupport/test/core_ext/hash_ext_test.rb @@ -4,6 +4,7 @@ require 'bigdecimal' require 'active_support/core_ext/string/access' require 'active_support/ordered_hash' require 'active_support/core_ext/object/conversions' +require 'active_support/core_ext/object/deep_dup' require 'active_support/inflections' class HashExtTest < ActiveSupport::TestCase -- cgit v1.2.3 From d5dc462cd28c7787735ff9f571869eeb097e25f7 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 24 May 2012 14:55:38 -0700 Subject: `name` should be public. --- .../rails/plugin_new/plugin_new_generator.rb | 24 +++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb index 7088367462..ab0e440bc4 100644 --- a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +++ b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb @@ -232,6 +232,18 @@ task :default => :test public_task :apply_rails_template, :run_bundle + def name + @name ||= begin + # same as ActiveSupport::Inflector#underscore except not replacing '-' + underscored = original_name.dup + underscored.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2') + underscored.gsub!(/([a-z\d])([A-Z])/,'\1_\2') + underscored.downcase! + + underscored + end + end + protected def app_templates_dir @@ -268,18 +280,6 @@ task :default => :test @original_name ||= File.basename(destination_root) end - def name - @name ||= begin - # same as ActiveSupport::Inflector#underscore except not replacing '-' - underscored = original_name.dup - underscored.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2') - underscored.gsub!(/([a-z\d])([A-Z])/,'\1_\2') - underscored.downcase! - - underscored - end - end - def camelized @camelized ||= name.gsub(/\W/, '_').squeeze('_').camelize end -- cgit v1.2.3 From d476129691b1dd1e356f386af0532dcb2cd885ee Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 24 May 2012 15:54:30 -0700 Subject: do not set the ENGINE_PATH to nil --- railties/lib/rails/tasks/engine.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/railties/lib/rails/tasks/engine.rake b/railties/lib/rails/tasks/engine.rake index eea8abe7d2..70370be3f5 100644 --- a/railties/lib/rails/tasks/engine.rake +++ b/railties/lib/rails/tasks/engine.rake @@ -60,7 +60,7 @@ namespace :db do end def find_engine_path(path) - return if path == "/" + return File.expand_path(Dir.pwd) if path == "/" if Rails::Engine.find(path) path -- cgit v1.2.3 From 44591250189fd2dadc8303d094b72552d7d06543 Mon Sep 17 00:00:00 2001 From: schneems Date: Thu, 24 May 2012 21:31:09 -0500 Subject: remove unnecessary test from route_inspect_test --- railties/test/application/route_inspect_test.rb | 9 --------- 1 file changed, 9 deletions(-) diff --git a/railties/test/application/route_inspect_test.rb b/railties/test/application/route_inspect_test.rb index e453cdb074..3b8c874b5b 100644 --- a/railties/test/application/route_inspect_test.rb +++ b/railties/test/application/route_inspect_test.rb @@ -164,14 +164,5 @@ module ApplicationTests assert_equal " bar GET /bar(.:format) redirect(307, path: /foo/bar)", output[1] assert_equal "foobar GET /foobar(.:format) redirect(301)", output[2] end - - def test_presenter - output = draw do - get "/foo" => redirect("/foo/bar"), :constraints => { :subdomain => "admin" } - get "/bar" => redirect(path: "/foo/bar", status: 307) - get "/foobar" => redirect{ "/foo/bar" } - end - assert_equal output.join("\n"), Rails::Application::RoutePresenter.display_routes(@set.routes) - end end end -- cgit v1.2.3 From baa336364da932ccaee6bb724ab615145e63c4d3 Mon Sep 17 00:00:00 2001 From: Waseem Ahmad Date: Fri, 25 May 2012 09:49:34 +0530 Subject: Fixes build 4008.1 This fixex build 4008.1[1] because of the changes made in 4001835db00ce44cb75bca33ec02cd76b8ccc790 [1] http://travis-ci.org/#!/rails/rails/jobs/1429671 --- railties/test/paths_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/railties/test/paths_test.rb b/railties/test/paths_test.rb index aa04cad033..5d6b6f9f72 100644 --- a/railties/test/paths_test.rb +++ b/railties/test/paths_test.rb @@ -29,7 +29,7 @@ class PathsTest < ActiveSupport::TestCase test "creating a root level path" do @root.add "app" assert_equal ["/foo/bar/app"], @root["app"].to_a - assert_equal [Pathname.new("/foo/bar/app")], @root["app"].paths + assert_equal ["/foo/bar/app"], @root["app"].paths end test "creating a root level path with options" do @@ -192,7 +192,7 @@ class PathsTest < ActiveSupport::TestCase @root["app"] = "/app" @root["app"].glob = "*.rb" assert_equal "*.rb", @root["app"].glob - assert_equal [Pathname.new("/app")], @root["app"].paths + assert_equal ["/foo/bar/app"], @root["app"].paths end test "it should be possible to override a path's default glob without assignment" do -- cgit v1.2.3 From 05ae220d2e3de751486951a88800e98f0c1014fa Mon Sep 17 00:00:00 2001 From: Alexey Vakhov Date: Fri, 25 May 2012 10:23:44 +0400 Subject: Fix ActiveSupport Cache decrement method description --- activesupport/lib/active_support/cache.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb index 55791bfa56..a62214d604 100644 --- a/activesupport/lib/active_support/cache.rb +++ b/activesupport/lib/active_support/cache.rb @@ -405,7 +405,7 @@ module ActiveSupport raise NotImplementedError.new("#{self.class.name} does not support increment") end - # Increment an integer value in the cache. + # Decrement an integer value in the cache. # # Options are passed to the underlying cache implementation. # -- cgit v1.2.3 From 73db73fee931e087317261fe9373228b5c0f1ed1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Fri, 25 May 2012 09:27:39 +0200 Subject: Remove implicit dependency on pathname --- actionpack/lib/action_dispatch/routing/mapper.rb | 6 +++--- actionpack/test/dispatch/routing_test.rb | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 67a208263b..e43e897783 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -1318,7 +1318,7 @@ module ActionDispatch def draw(name) path = @draw_paths.find do |_path| - _path.join("#{name}.rb").file? + File.exists? "#{_path}/#{name}.rb" end unless path @@ -1328,8 +1328,8 @@ module ActionDispatch raise ArgumentError, msg end - route_path = path.join("#{name}.rb") - instance_eval(route_path.read, route_path.to_s) + route_path = "#{path}/#{name}.rb" + instance_eval(File.read(route_path), route_path.to_s) end # match 'path' => 'controller#action' diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index 00d09282ca..fa4cb301eb 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -2331,7 +2331,7 @@ class TestDrawExternalFile < ActionDispatch::IntegrationTest end end - DRAW_PATH = Pathname.new(File.expand_path('../../fixtures/routes', __FILE__)) + DRAW_PATH = File.expand_path('../../fixtures/routes', __FILE__) DefaultScopeRoutes = ActionDispatch::Routing::RouteSet.new.tap do |app| app.draw_paths << DRAW_PATH -- cgit v1.2.3 From d83411134b3a207b767b1f6759cbe964e0088e27 Mon Sep 17 00:00:00 2001 From: Alexey Vakhov Date: Fri, 25 May 2012 16:47:00 +0400 Subject: Update examples of Array #in_groups and #in_groups_of Examples should be not square to visually underline a difference between Array#in_groups and Array#in_groups_of. --- .../lib/active_support/core_ext/array/grouping.rb | 23 ++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/activesupport/lib/active_support/core_ext/array/grouping.rb b/activesupport/lib/active_support/core_ext/array/grouping.rb index ac1ae53db0..a184eb492a 100644 --- a/activesupport/lib/active_support/core_ext/array/grouping.rb +++ b/activesupport/lib/active_support/core_ext/array/grouping.rb @@ -2,18 +2,21 @@ class Array # Splits or iterates over the array in groups of size +number+, # padding any remaining slots with +fill_with+ unless it is +false+. # - # %w(1 2 3 4 5 6 7).in_groups_of(3) {|group| p group} + # %w(1 2 3 4 5 6 7 8 9 10).in_groups_of(3) {|group| p group} # ["1", "2", "3"] # ["4", "5", "6"] - # ["7", nil, nil] + # ["7", "8", "9"] + # ["10", nil, nil] # - # %w(1 2 3).in_groups_of(2, ' ') {|group| p group} + # %w(1 2 3 4 5).in_groups_of(2, ' ') {|group| p group} # ["1", "2"] - # ["3", " "] + # ["3", "4"] + # ["5", " "] # - # %w(1 2 3).in_groups_of(2, false) {|group| p group} + # %w(1 2 3 4 5).in_groups_of(2, false) {|group| p group} # ["1", "2"] - # ["3"] + # ["3", "4"] + # ["5"] def in_groups_of(number, fill_with = nil) if fill_with == false collection = self @@ -42,10 +45,10 @@ class Array # ["5", "6", "7", nil] # ["8", "9", "10", nil] # - # %w(1 2 3 4 5 6 7).in_groups(3, ' ') {|group| p group} - # ["1", "2", "3"] - # ["4", "5", " "] - # ["6", "7", " "] + # %w(1 2 3 4 5 6 7 8 9 10).in_groups(3, ' ') {|group| p group} + # ["1", "2", "3", "4"] + # ["5", "6", "7", " "] + # ["8", "9", "10", " "] # # %w(1 2 3 4 5 6 7).in_groups(3, false) {|group| p group} # ["1", "2", "3"] -- cgit v1.2.3 From 17eedd8e07d01a72ea11b9ee616c7dfdea4dc9ef Mon Sep 17 00:00:00 2001 From: Mikhail Vaysman <9996113+github@gmail.com> Date: Fri, 25 May 2012 16:58:43 +0400 Subject: references to the old behavior removed --- actionpack/lib/action_dispatch/testing/integration.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb index 08fd28d72d..3fdc6688c2 100644 --- a/actionpack/lib/action_dispatch/testing/integration.rb +++ b/actionpack/lib/action_dispatch/testing/integration.rb @@ -17,8 +17,8 @@ module ActionDispatch # a Hash, or a String that is appropriately encoded # (application/x-www-form-urlencoded or # multipart/form-data). - # - +headers+: Additional HTTP headers to pass, as a Hash. The keys will - # automatically be upcased, with the prefix 'HTTP_' added if needed. + # - +headers+: Additional headers to pass, as a Hash. The headers will be + # merged into the Rack env hash. # # This method returns an Response object, which one can use to # inspect the details of the response. Furthermore, if this method was @@ -73,8 +73,7 @@ module ActionDispatch # # The request_method is +:get+, +:post+, +:patch+, +:put+, +:delete+ or # +:head+; the parameters are +nil+, a hash, or a url-encoded or multipart - # string; the headers are a hash. Keys are automatically upcased and - # prefixed with 'HTTP_' if not already. + # string; the headers are a hash. def xml_http_request(request_method, path, parameters = nil, headers = nil) headers ||= {} headers['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest' -- cgit v1.2.3 From a1a16de49bd223086002a4dab899ed441bb9c956 Mon Sep 17 00:00:00 2001 From: Alexey Vakhov Date: Fri, 25 May 2012 17:00:51 +0400 Subject: Clean Date#beginning_of_month description Unnecessary peace of text was injected at 507da04a149b44e20c5a0ba72a218fe1762b6baf by mistake. --- activesupport/lib/active_support/core_ext/date/calculations.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activesupport/lib/active_support/core_ext/date/calculations.rb b/activesupport/lib/active_support/core_ext/date/calculations.rb index 3e36c54eba..8a7eb6bc6b 100644 --- a/activesupport/lib/active_support/core_ext/date/calculations.rb +++ b/activesupport/lib/active_support/core_ext/date/calculations.rb @@ -202,7 +202,7 @@ class Date acts_like?(:time) ? result.change(:hour => 0) : result end - # Returns a new ; DateTime objects will have time set to 0:00DateTime representing the start of the month (1st of the month; DateTime objects will have time set to 0:00) + # Returns a new Date/DateTime representing the start of the month (1st of the month; DateTime objects will have time set to 0:00) def beginning_of_month acts_like?(:time) ? change(:day => 1, :hour => 0) : change(:day => 1) end -- cgit v1.2.3 From b4167d3f3e4d25be16e06e71afd1c64a47ca54d7 Mon Sep 17 00:00:00 2001 From: Alexey Vakhov Date: Fri, 25 May 2012 17:46:53 +0400 Subject: Fix Range#sum optimized version At 1bd4d1c67459a91415ee73a8f55d2309c0d62a87 was added Range#sum optimized version for arithmetic progressions. This improvment injected a defect with not integer range boundaries. The defect was fixed by e0adfa82c05f9c975005f102b4bcaebfcd17d241. The second commit really disabled optimization at all because in Ruby integer-valued numbers are instances of Fixnum and Bignum classes. We should #use is_a? (#kind_of?) method instead #instance_of? to check if value is numerical: 1.class # => Fixnum 1.instance_of?(Integer) # => false 1.is_a?(Integer) # => true -100_000_000_000.class # => Bignum -100_000_000_000.instance_of?(Integer) # => false -100_000_000_000.is_a?(Integer) # => true Moreover original implementation of Range#sum has a defect with reverse range boundaries. If the first boundary is less than the second range is empty. Current commit fixes and tests this case too. --- activesupport/lib/active_support/core_ext/enumerable.rb | 8 ++++++-- activesupport/test/core_ext/enumerable_test.rb | 5 +++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb index 02d5a7080f..03efe6a19a 100644 --- a/activesupport/lib/active_support/core_ext/enumerable.rb +++ b/activesupport/lib/active_support/core_ext/enumerable.rb @@ -65,11 +65,15 @@ class Range #:nodoc: # Optimize range sum to use arithmetic progression if a block is not given and # we have a range of numeric values. def sum(identity = 0) - if block_given? || !(first.instance_of?(Integer) && last.instance_of?(Integer)) + if block_given? || !(first.is_a?(Integer) && last.is_a?(Integer)) super else actual_last = exclude_end? ? (last - 1) : last - (actual_last - first + 1) * (actual_last + first) / 2 + if actual_last >= first + (actual_last - first + 1) * (actual_last + first) / 2 + else + identity + end end end end diff --git a/activesupport/test/core_ext/enumerable_test.rb b/activesupport/test/core_ext/enumerable_test.rb index 0bf48dd378..0a1abac767 100644 --- a/activesupport/test/core_ext/enumerable_test.rb +++ b/activesupport/test/core_ext/enumerable_test.rb @@ -84,6 +84,11 @@ class EnumerableTests < ActiveSupport::TestCase assert_equal 10, (1..4.5).sum assert_equal 6, (1...4).sum assert_equal 'abc', ('a'..'c').sum + assert_equal 50_000_005_000_000, (0..10_000_000).sum + assert_equal 0, (10..0).sum + assert_equal 5, (10..0).sum(5) + assert_equal 10, (10..10).sum + assert_equal 42, (10...10).sum(42) end def test_index_by -- cgit v1.2.3 From cb25bce26f44806fca780cd8ddd3d18c3b999dc0 Mon Sep 17 00:00:00 2001 From: Alexey Vakhov Date: Fri, 25 May 2012 18:30:56 +0400 Subject: Fix unbalanced braces in Hash#typecast_xml_value internal comment --- activesupport/lib/active_support/core_ext/hash/conversions.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activesupport/lib/active_support/core_ext/hash/conversions.rb b/activesupport/lib/active_support/core_ext/hash/conversions.rb index 43ba05a256..7c72ead36c 100644 --- a/activesupport/lib/active_support/core_ext/hash/conversions.rb +++ b/activesupport/lib/active_support/core_ext/hash/conversions.rb @@ -129,7 +129,7 @@ class Hash else xml_value = Hash[value.map { |k,v| [k, typecast_xml_value(v)] }] - # Turn { :files => { :file => # } into { :files => # } so it is compatible with + # Turn { :files => { :file => # } } into { :files => # } so it is compatible with # how multipart uploaded files from HTML appear xml_value['file'].is_a?(StringIO) ? xml_value['file'] : xml_value end -- cgit v1.2.3 From b98a343da5b9fd6a6ffa7eeac42c141f5b64e961 Mon Sep 17 00:00:00 2001 From: Edward Tsech Date: Fri, 25 May 2012 16:34:34 +0200 Subject: Add comment for attr_accessible/attr_protected :as option. [ci skip] --- activemodel/lib/active_model/mass_assignment_security.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/activemodel/lib/active_model/mass_assignment_security.rb b/activemodel/lib/active_model/mass_assignment_security.rb index 893fbf92c3..cfce1542b1 100644 --- a/activemodel/lib/active_model/mass_assignment_security.rb +++ b/activemodel/lib/active_model/mass_assignment_security.rb @@ -62,7 +62,7 @@ module ActiveModel # Attributes named in this macro are protected from mass-assignment # whenever attributes are sanitized before assignment. A role for the # attributes is optional, if no role is provided then :default is used. - # A role can be defined by using the :as option. + # A role can be defined by using the :as option with a symbol or an array of symbols as the value. # # Mass-assignment to these attributes will simply be ignored, to assign # to them you can use direct writer methods. This is meant to protect @@ -128,7 +128,7 @@ module ActiveModel # # Like +attr_protected+, a role for the attributes is optional, # if no role is provided then :default is used. A role can be defined by - # using the :as option. + # using the :as option with a symbol or an array of symbols as the value. # # This is the opposite of the +attr_protected+ macro: Mass-assignment # will only set attributes in this list, to assign to the rest of -- cgit v1.2.3 From 470c1516b384f0ae710cdcf4f5a83a81f909252c Mon Sep 17 00:00:00 2001 From: Rafael Magana Date: Fri, 25 May 2012 11:01:03 -0500 Subject: [getting started] specify that rails new blog executes bundle install --- guides/source/getting_started.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/source/getting_started.textile b/guides/source/getting_started.textile index 1979d87a06..628010697f 100644 --- a/guides/source/getting_started.textile +++ b/guides/source/getting_started.textile @@ -108,7 +108,7 @@ To use this generator, open a terminal, navigate to a directory where you have r $ rails new blog -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 specified 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+. -- cgit v1.2.3 From 3e7d43b43c71a4b4bfc53a51f2383a1d5a75e71f Mon Sep 17 00:00:00 2001 From: Rafael Magana Date: Fri, 25 May 2012 11:10:48 -0500 Subject: [getting started] specify what # and $ denotes in the prompt in unix-like OSs --- guides/source/getting_started.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/source/getting_started.textile b/guides/source/getting_started.textile index 628010697f..35ae52e1d5 100644 --- a/guides/source/getting_started.textile +++ b/guides/source/getting_started.textile @@ -75,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 -- cgit v1.2.3 From 26149260bfe5aaee162586e6d1fa54365f8a773e Mon Sep 17 00:00:00 2001 From: Oscar Del Ben Date: Fri, 25 May 2012 08:59:00 -0700 Subject: [Guides] Add inflector example --- guides/source/initialization.textile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/guides/source/initialization.textile b/guides/source/initialization.textile index fe777d063b..89bb0bba84 100644 --- a/guides/source/initialization.textile +++ b/guides/source/initialization.textile @@ -752,6 +752,10 @@ 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". + +inflect.irregular('zombie', 'zombies') + + 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. -- cgit v1.2.3 From 4ce51e3d76f1d976d235d6be1c9252ef969ba423 Mon Sep 17 00:00:00 2001 From: Oscar Del Ben Date: Fri, 25 May 2012 09:15:31 -0700 Subject: [Guides] Add missing file descriptions --- guides/source/initialization.textile | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/guides/source/initialization.textile b/guides/source/initialization.textile index 89bb0bba84..ebeed52160 100644 --- a/guides/source/initialization.textile +++ b/guides/source/initialization.textile @@ -758,7 +758,23 @@ inflect.irregular('zombie', 'zombies') 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. +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. + + +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+ -- cgit v1.2.3 From 10f16e6e390f16979e2b8a26c8b98e286a17f152 Mon Sep 17 00:00:00 2001 From: Rafael Magana Date: Fri, 25 May 2012 11:17:14 -0500 Subject: [getting started] specify which kind of temporary files are stored in the /tmp folder --- guides/source/getting_started.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/source/getting_started.textile b/guides/source/getting_started.textile index 35ae52e1d5..6ba70fa58e 100644 --- a/guides/source/getting_started.textile +++ b/guides/source/getting_started.textile @@ -138,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! -- cgit v1.2.3 From 12111e2391598d9519bc29e1a68e11f1c191183e Mon Sep 17 00:00:00 2001 From: Rafael Magana Date: Fri, 25 May 2012 12:23:04 -0500 Subject: [getting started] Update Setting the Application Home Page to show the get "welcome/index" route --- guides/source/getting_started.textile | 42 ++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/guides/source/getting_started.textile b/guides/source/getting_started.textile index c129aeb2e1..1799d55a7a 100644 --- a/guides/source/getting_started.textile +++ b/guides/source/getting_started.textile @@ -177,7 +177,28 @@ To create a new controller, you will need to run the "controller" generator and $ rails generate controller welcome index -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. + + +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 + + +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: @@ -195,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. 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" + + +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: + + +root :to => "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. 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. -- cgit v1.2.3 From 096cc0e39d53355d91f485341ed52c6554ac8745 Mon Sep 17 00:00:00 2001 From: Tadas Tamosauskas Date: Fri, 25 May 2012 18:25:59 +0100 Subject: Update paths in action_view_overview raislguide to reflect asset pipeline conventions. --- guides/source/action_view_overview.textile | 50 +++++++++++++++++------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/guides/source/action_view_overview.textile b/guides/source/action_view_overview.textile index bde30ba21c..734fdd895b 100644 --- a/guides/source/action_view_overview.textile +++ b/guides/source/action_view_overview.textile @@ -542,28 +542,28 @@ image_tag("rails.png") # => - - - + + + 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+. ActionView::Helpers::AssetTagHelper.register_stylesheet_expansion :monkey => ["head", "body", "tail"] stylesheet_link_tag :monkey # => - - - + + + h5. auto_discovery_link_tag @@ -577,15 +577,21 @@ 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. image_path("edit.png") # => /images/edit.png +Fingerprint will be added to the filename if config.assets.digest is set to true. + + +image_path("edit.png") # => /images/edit-2d1a2db63fc738690021fedb5a65b68e.png + + 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. image_url("edit.png") # => http://www.example.com/images/edit.png @@ -593,7 +599,7 @@ image_url("edit.png") # => http://www.example.com/images/edit.png 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. image_tag("icon.png") # => Icon @@ -601,20 +607,20 @@ image_tag("icon.png") # => Icon 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. javascript_include_tag "common" # => -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. javascript_include_tag :defaults -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. javascript_include_tag :all @@ -629,7 +635,7 @@ 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. javascript_path "common" # => /javascripts/common.js @@ -637,7 +643,7 @@ javascript_path "common" # => /javascripts/common.js 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. javascript_url "common" # => http://www.example.com/javascripts/common.js @@ -649,7 +655,7 @@ Returns a stylesheet link tag for the sources specified as arguments. If you don stylesheet_link_tag "application" # => - + You can also include all styles in the stylesheet directory using :all as the source: @@ -662,23 +668,23 @@ You can also cache multiple stylesheets into one file, which requires less HTTP stylesheet_link_tag :all, :cache => true - + 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. -stylesheet_path "application" # => /stylesheets/application.css +stylesheet_path "application" # => /assets/application.css 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. -stylesheet_url "application" # => http://www.example.com/stylesheets/application.css +stylesheet_url "application" # => http://www.example.com/assets/application.css h4. AtomFeedHelper -- cgit v1.2.3 From 1d485d51f8cd6e122a66d754f95918d378a9bb33 Mon Sep 17 00:00:00 2001 From: Mark McSpadden Date: Fri, 25 May 2012 15:29:01 -0500 Subject: Reorder deep_symbolize_keys methods --- activesupport/lib/active_support/core_ext/hash/keys.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/activesupport/lib/active_support/core_ext/hash/keys.rb b/activesupport/lib/active_support/core_ext/hash/keys.rb index 362d584ba1..e5e77bcef4 100644 --- a/activesupport/lib/active_support/core_ext/hash/keys.rb +++ b/activesupport/lib/active_support/core_ext/hash/keys.rb @@ -104,17 +104,17 @@ class Hash deep_transform_keys!{ |key| key.to_s } end - # Destructively convert all keys to symbols, as long as they respond - # to +to_sym+. This includes the keys from the root hash and from all - # nested hashes. - def deep_symbolize_keys! - deep_transform_keys!{ |key| key.to_sym rescue key } - end - # Return a new hash with all keys converted to symbols, as long as # they respond to +to_sym+. This includes the keys from the root hash # and from all nested hashes. def deep_symbolize_keys deep_transform_keys{ |key| key.to_sym rescue key } end + + # Destructively convert all keys to symbols, as long as they respond + # to +to_sym+. This includes the keys from the root hash and from all + # nested hashes. + def deep_symbolize_keys! + deep_transform_keys!{ |key| key.to_sym rescue key } + end end -- cgit v1.2.3 From 29463aa15dd670621ad0de861b5aa66feeb09ffa Mon Sep 17 00:00:00 2001 From: Francesco Rodriguez Date: Fri, 25 May 2012 22:08:59 -0500 Subject: add CollectionProxy#delete documentation --- .../active_record/associations/collection_proxy.rb | 105 ++++++++++++++++++++- 1 file changed, 104 insertions(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index 100fb38dec..2b59b07eb2 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -343,6 +343,9 @@ module ActiveRecord ## # :method: delete_all # + # :call-seq: + # delete_all() + # # Deletes all the records from the collection. For +has_many+ asssociations, # the deletion is done according to the strategy specified by the :dependent # option. Returns an array with the deleted records. @@ -435,6 +438,9 @@ module ActiveRecord ## # :method: destroy_all # + # :call-seq: + # destroy_all() + # # Deletes the records of the collection directly from the database. # This will _always_ remove the records ignoring the +:dependent+ # option. @@ -458,13 +464,110 @@ module ActiveRecord # # Pet.find(1) # => Couldn't find Pet with id=1 + ## + # :method: delete + # + # :call-seq: + # delete(*records) + # + # Deletes the +records+ supplied and remove them from the collection. For + # +has_many+ associations, the deletion is done according to the strategy + # specified by the :dependent option. Returns an array with the + # deleted records. + # + # If no :dependent option is given, then it will follow the default + # strategy. The default strategy is :nullify. This sets the foreign + # keys to NULL. For, +has_many+ :through, the default + # strategy is +delete_all+. + # + # class Person < ActiveRecord::Base + # has_many :pets # dependent: :nullify option by default + # end + # + # person.pets.size # => 3 + # person.pets + # # => [ + # # #, + # # #, + # # # + # # ] + # + # person.pets.delete(Pet.find(1)) + # # => [#] + # + # person.pets.size # => 2 + # person.pets + # # => [ + # # #, + # # # + # # ] + # + # Pet.find(1) + # # => # + # + # If it is set to :destroy all the +records+ are removed by calling + # their +destroy+ method. See +destroy+ for more information. + # + # class Person < ActiveRecord::Base + # has_many :pets, dependent: :destroy + # end + # + # person.pets.size # => 3 + # person.pets + # # => [ + # # #, + # # #, + # # # + # # ] + # + # person.pets.delete([Pet.find(1), Pet.find(3)]) + # # => [ + # # #, + # # # + # # ] + # + # person.pets.size # => 1 + # person.pets + # # => [#] + # + # Pet.find(1, 3) + # # => ActiveRecord::RecordNotFound: Couldn't find all Pets with IDs (1, 3) + # + # If it is set to :delete_all, all the +records+ are deleted + # *without* calling their +destroy+ method. + # + # class Person < ActiveRecord::Base + # has_many :pets, dependent: :delete_all + # end + # + # person.pets.size # => 3 + # person.pets + # # => [ + # # #, + # # #, + # # # + # # ] + # + # person.pets.delete(Pet.find(1)) + # # => [#] + # + # person.pets.size # => 2 + # person.pets + # # => [ + # # #, + # # # + # # ] + # + # Pet.find(1) + # # => ActiveRecord::RecordNotFound: Couldn't find Pet with id=1 + ## # :method: destroy # # :call-seq: # destroy(*records) # - # Destroy the +records+ supplied and remove them from the collection. + # Destroys the +records+ supplied and remove them from the collection. # This method will _always_ remove record from the database ignoring # the +:dependent+ option. Returns an array with the removed records. # -- cgit v1.2.3 From 390d86ae899f6aba735d8efa0f7f23e05c6957a5 Mon Sep 17 00:00:00 2001 From: Francesco Rodriguez Date: Fri, 25 May 2012 22:18:56 -0500 Subject: add CollectionProxy#to_ary documentation --- .../active_record/associations/collection_proxy.rb | 37 ++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index 2b59b07eb2..5b5aef070d 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -470,7 +470,7 @@ module ActiveRecord # :call-seq: # delete(*records) # - # Deletes the +records+ supplied and remove them from the collection. For + # Deletes the +records+ supplied and removes them from the collection. For # +has_many+ associations, the deletion is done according to the strategy # specified by the :dependent option. Returns an array with the # deleted records. @@ -567,7 +567,7 @@ module ActiveRecord # :call-seq: # destroy(*records) # - # Destroys the +records+ supplied and remove them from the collection. + # Destroys the +records+ supplied and removes them from the collection. # This method will _always_ remove record from the database ignoring # the +:dependent+ option. Returns an array with the removed records. # @@ -838,6 +838,39 @@ module ActiveRecord load_target == other end + # Returns a new array of objects from the collection. If the collection + # hasn't been loaded, it fetches the records from the database. + # + # class Person < ActiveRecord::Base + # has_many :pets + # end + # + # person.pets + # # => [ + # # #, + # # #, + # # # + # # ] + # + # other_pets = person.pets.to_ary + # # => [ + # # #, + # # #, + # # # + # # ] + # + # other_pets.replace([Pet.new(name: 'BooGoo')]) + # + # other_pets + # # => [#] + # + # person.pets + # # This is not affected by replace + # # => [ + # # #, + # # #, + # # # + # # ] def to_ary load_target.dup end -- cgit v1.2.3 From f81798d06415c538f5b1c5acfd4889b45473e62d Mon Sep 17 00:00:00 2001 From: Francesco Rodriguez Date: Fri, 25 May 2012 22:45:22 -0500 Subject: add CollectionProxy#count documentation --- .../active_record/associations/collection_proxy.rb | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index 5b5aef070d..93ed2e5a56 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -636,9 +636,32 @@ module ActiveRecord # # Pet.find(4, 5, 6) # => ActiveRecord::RecordNotFound: Couldn't find all Pets with IDs (4, 5, 6) + ## + # :method: count + # + # :call-seq: + # count() + # + # Count all records using SQL. + # + # class Person < ActiveRecord::Base + # has_many :pets + # end + # + # person.pets.count # => 3 + # person.pets + # # => [ + # # #, + # # #, + # # # + # # ] + ## # :method: size # + # :call-seq: + # size() + # # Returns the size of the collection. If the collection hasn't been loaded, # it executes a SELECT COUNT(*) query. # @@ -663,6 +686,9 @@ module ActiveRecord ## # :method: length # + # :call-seq: + # length() + # # Returns the size of the collection calling +size+ on the target. # If the collection has been already loaded, +length+ and +size+ are # equivalent. -- cgit v1.2.3 From bb55f52ee8ae0eb932eec4eace8adb81b05d13ad Mon Sep 17 00:00:00 2001 From: Francesco Rodriguez Date: Fri, 25 May 2012 23:01:38 -0500 Subject: add CollectionProxy#== documentation --- .../active_record/associations/collection_proxy.rb | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index 93ed2e5a56..44f5041bd8 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -860,6 +860,30 @@ module ActiveRecord end end + # Equivalent to Array#==. Returns +true+ if the two arrays + # contain the same number of elements and if each element is equal + # to the corresponding element in the other array, otherwise returns + # +false+. + # + # class Person < ActiveRecord::Base + # has_many :pets + # end + # + # person.pets + # # => [ + # # #, + # # # + # # ] + # + # other = person.pets.to_ary + # + # person.pets == other + # # => true + # + # other = [Pet.new(id: 1), Pet.new(id: 2)] + # + # person.pets == other + # # => false def ==(other) load_target == other end -- cgit v1.2.3 From 7a323e2ed15e06f468d783340c4680c5ad235e87 Mon Sep 17 00:00:00 2001 From: Francesco Rodriguez Date: Fri, 25 May 2012 23:09:47 -0500 Subject: add :nodoc: to CollectionProxy#initialize --- activerecord/lib/active_record/associations/collection_proxy.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index 44f5041bd8..7408428493 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -828,7 +828,7 @@ module ActiveRecord :any?, :many?, :include?, :to => :@association - def initialize(association) + def initialize(association) #:nodoc: @association = association super association.klass, association.klass.arel_table merge! association.scoped -- cgit v1.2.3 From 9122143767b419c3be6b8ec86fd9b90ba7c39fe6 Mon Sep 17 00:00:00 2001 From: Ryan Bigg Date: Sat, 26 May 2012 16:12:06 +1000 Subject: [routing guide] Add mention of get '/:username' route This is fairly common in Rails applications and is requested a lot of the time on Stack Overflow and #rubyonrails --- guides/source/routing.textile | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/guides/source/routing.textile b/guides/source/routing.textile index d77b3bc7cd..0773a96c67 100644 --- a/guides/source/routing.textile +++ b/guides/source/routing.textile @@ -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: + + +get ':username', :to => "users#show", :as => :user + + +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: -- cgit v1.2.3 From 6999b36c1b76393e68b0b67540f34d18b37e7957 Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Sat, 26 May 2012 17:45:58 +0530 Subject: make it explicit that bundle install at the time of app creation installs only the gems that are already in the gemfile [ci skip] --- guides/source/getting_started.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/source/getting_started.textile b/guides/source/getting_started.textile index 6ba70fa58e..342e7284b0 100644 --- a/guides/source/getting_started.textile +++ b/guides/source/getting_started.textile @@ -108,7 +108,7 @@ To use this generator, open a terminal, navigate to a directory where you have r $ rails new blog -This will create a Rails application called Blog in a directory called blog and install the gem dependencies specified in +Gemfile+ using +bundle install+. +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+. -- cgit v1.2.3 From 06731530ff4f13facdfa60e4db55ea9c081cd055 Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Sat, 26 May 2012 17:48:40 +0530 Subject: fix mention of ruby versions that rails 4 won't run on [ci skip] --- guides/source/initialization.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guides/source/initialization.textile b/guides/source/initialization.textile index ebeed52160..85a9966c20 100644 --- a/guides/source/initialization.textile +++ b/guides/source/initialization.textile @@ -556,7 +556,7 @@ h4. +railties/lib/rails/ruby_version_check.rb+ 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 1.9.3 +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. -- cgit v1.2.3 From 2114e2187dd8cbdcc0ab304ec0adf1a1bf5cc09a Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Sat, 26 May 2012 18:07:17 +0530 Subject: some small corrections & wrapping changes in the initialization guide This guide is currently a wip and pending reviews. [ci skip] --- guides/source/initialization.textile | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/guides/source/initialization.textile b/guides/source/initialization.textile index 85a9966c20..913ff24290 100644 --- a/guides/source/initialization.textile +++ b/guides/source/initialization.textile @@ -708,10 +708,9 @@ require 'active_support/core_ext/object/to_query' require 'active_support/core_ext/object/with_options' -The Rails "api documentation":http://api.rubyonrails.org/ covers them in -great detail, so we're not going to explain each of them. +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+ +The file that is required next from +rails/configuration+ is +rails/paths+. h4. +railties/lib/rails/paths.rb+ @@ -758,10 +757,7 @@ inflect.irregular('zombie', 'zombies') 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+ @@ -771,10 +767,7 @@ extension, which extends +Module+ with methods like +parent_name+, +parent+ and 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. +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+ -- cgit v1.2.3 From 38813da6dc6611d6b68dd4d584012c19e86a218a Mon Sep 17 00:00:00 2001 From: Li Ellis Gallardo Date: Sat, 28 Apr 2012 01:48:28 -0500 Subject: Truncate now has the ability to receive a html option that allows it to call rails helpers. This way if my text is long I don't have to do something like this: .text = truncate(@text, :length => 27) if @text.size >= 27 = link_to "continue", notes_path, ....."") --- actionpack/lib/action_view/helpers/text_helper.rb | 14 +++++++-- actionpack/test/template/text_helper_test.rb | 37 ++++++++++++++++++----- activesupport/test/core_ext/string_ext_test.rb | 4 +++ 3 files changed, 45 insertions(+), 10 deletions(-) diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb index 8cd7cf0052..515bd78101 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionpack/lib/action_view/helpers/text_helper.rb @@ -80,8 +80,18 @@ module ActionView # # truncate("

    Once upon a time in a world far far away

    ") # # => "

    Once upon a time in a wo..." - def truncate(text, options = {}) - text.truncate(options.fetch(:length, 30), options) if text + # + # truncate("Once upon a time in a world far far away") { link_to "Continue", "#" } + # # => "Once upon a time in a wo...Continue" + def truncate(text, options = {}, &block) + return unless text + + options = { :length => 30 }.merge!(options) + length = options.delete(:length) + + content = ERB::Util.html_escape(text.truncate(length, options)) + content << capture(&block) if block_given? && text.length > length + content end # Highlights one or more +phrases+ everywhere in +text+ by inserting it into diff --git a/actionpack/test/template/text_helper_test.rb b/actionpack/test/template/text_helper_test.rb index f58e474759..a7333a3af9 100644 --- a/actionpack/test/template/text_helper_test.rb +++ b/actionpack/test/template/text_helper_test.rb @@ -75,19 +75,11 @@ class TextHelperTest < ActionView::TestCase assert_equal options, passed_options end - def test_truncate_should_not_be_html_safe - assert !truncate("Hello World!", :length => 12).html_safe? - end - def test_truncate assert_equal "Hello World!", truncate("Hello World!", :length => 12) assert_equal "Hello Wor...", truncate("Hello World!!", :length => 12) end - def test_truncate_should_not_escape_input - assert_equal "Hello code!World!!", :length => 12) - end - def test_truncate_should_use_default_length_of_30 str = "This is a string that will go longer then the default truncate length of 30" assert_equal str[0...27] + "...", truncate(str) @@ -114,6 +106,35 @@ class TextHelperTest < ActionView::TestCase assert_equal options, passed_options end + def test_truncate_with_link_options + assert_equal "Here's a long test and I...Continue", + truncate("Here's a long test and I need a continue to read link", :length => 27) { link_to 'Continue', '#' } + end + + def test_truncate_should_not_mutate_the_options_hash + options = { :length => 27 } + truncate("Here's a long test and I need a continue to read link", options) { link_to 'Continue', '#' } + assert_equal({ :length => 27 }, options) + end + + def test_truncate_should_be_html_safe + assert truncate("Hello World!", :length => 12).html_safe? + end + + def test_truncate_should_escape_the_input + assert_equal "Hello <sc...", truncate("Hello World!!", :length => 12) + end + + def test_truncate_with_block_should_be_html_safe + truncated = truncate("Here's a long test and I need a continue to read link", :length => 27) { link_to 'Continue', '#' } + assert truncated.html_safe? + end + + def test_truncate_with_block_should_escape_the_input + assert_equal "<script>code!</script>He...Continue", + truncate("Here's a long test and I need a continue to read link", :length => 27) { link_to 'Continue', '#' } + end + def test_highlight_should_be_html_safe assert highlight("This is a beautiful morning", "beautiful").html_safe? end diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb index 8437ef1347..e5b774425e 100644 --- a/activesupport/test/core_ext/string_ext_test.rb +++ b/activesupport/test/core_ext/string_ext_test.rb @@ -290,6 +290,10 @@ class StringInflectionsTest < ActiveSupport::TestCase "\354\225\204\353\246\254\353\236\221 \354\225\204\353\246\254 \354\225\204\353\235\274\353\246\254\354\230\244".force_encoding('UTF-8').truncate(10) end + def test_truncate_should_not_be_html_safe + assert !"Hello World!".truncate(12).html_safe? + end + def test_constantize run_constantize_tests_on do |string| string.constantize -- cgit v1.2.3 From dc8957a077396e419f5e1ec4dfddf65b1aa52227 Mon Sep 17 00:00:00 2001 From: Les Nightingill Date: Sat, 26 May 2012 09:53:16 -0700 Subject: add small note about how to get the full list of options for rails plugin new --- guides/source/engines.textile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/guides/source/engines.textile b/guides/source/engines.textile index c35305a822..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 +The full list of options for the plugin generator may be seen by typing: + + +$ rails plugin --help + + 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: -- cgit v1.2.3 From 4ce3b5d6fe6451a7e6951f366d3e3f9324f75fdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Sat, 26 May 2012 13:44:30 -0300 Subject: Test that the block used in truncate is escaped if it is not HTML safe Refactoring the truncate method to not do a sort-circuit return --- actionpack/lib/action_view/helpers/text_helper.rb | 25 +++++++++++------------ actionpack/test/template/text_helper_test.rb | 23 ++++++++++----------- 2 files changed, 23 insertions(+), 25 deletions(-) diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb index 515bd78101..73c3c61a41 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionpack/lib/action_view/helpers/text_helper.rb @@ -84,14 +84,13 @@ module ActionView # truncate("Once upon a time in a world far far away") { link_to "Continue", "#" } # # => "Once upon a time in a wo...Continue" def truncate(text, options = {}, &block) - return unless text + if text + length = options.fetch(:length, 30) - options = { :length => 30 }.merge!(options) - length = options.delete(:length) - - content = ERB::Util.html_escape(text.truncate(length, options)) - content << capture(&block) if block_given? && text.length > length - content + content = ERB::Util.html_escape(text.truncate(length, options)) + content << capture(&block) if block_given? && text.length > length + content + end end # Highlights one or more +phrases+ everywhere in +text+ by inserting it into @@ -112,7 +111,7 @@ module ActionView # # => You searched for: rails def highlight(text, phrases, options = {}) highlighter = options.fetch(:highlighter, '\1') - + text = sanitize(text) if options.fetch(:sanitize, true) if text.blank? || phrases.blank? text @@ -175,12 +174,12 @@ module ActionView # pluralize(0, 'person') # # => 0 people def pluralize(count, singular, plural = nil) - word = if (count == 1 || count =~ /^1(\.0+)?$/) - singular + word = if (count == 1 || count =~ /^1(\.0+)?$/) + singular else plural || singular.pluralize end - + "#{count || 0} #{word}" end @@ -225,7 +224,7 @@ module ActionView # # simple_format(my_text) # # => "

    Here is some basic text...\n
    ...with a line break.

    " - # + # # simple_format(my_text, {}, :wrapper_tag => "div") # # => "
    Here is some basic text...\n
    ...with a line break.
    " # @@ -241,7 +240,7 @@ module ActionView # # => "

    I'm allowed! It's true.

    " def simple_format(text, html_options = {}, options = {}) wrapper_tag = options.fetch(:wrapper_tag, :p) - + text = sanitize(text) if options.fetch(:sanitize, true) paragraphs = split_paragraphs(text) diff --git a/actionpack/test/template/text_helper_test.rb b/actionpack/test/template/text_helper_test.rb index a7333a3af9..4b1c1ef78b 100644 --- a/actionpack/test/template/text_helper_test.rb +++ b/actionpack/test/template/text_helper_test.rb @@ -60,14 +60,14 @@ class TextHelperTest < ActionView::TestCase simple_format(text) assert_equal text_clone, text end - + def test_simple_format_does_not_modify_the_html_options_hash options = { :class => "foobar"} passed_options = options.dup simple_format("some text", passed_options) assert_equal options, passed_options end - + def test_simple_format_does_not_modify_the_options_hash options = { :wrapper_tag => :div, :sanitize => false } passed_options = options.dup @@ -98,7 +98,7 @@ class TextHelperTest < ActionView::TestCase assert_equal "\354\225\204\353\246\254\353\236\221 \354\225\204\353\246\254 ...".force_encoding('UTF-8'), truncate("\354\225\204\353\246\254\353\236\221 \354\225\204\353\246\254 \354\225\204\353\235\274\353\246\254\354\230\244".force_encoding('UTF-8'), :length => 10) end - + def test_truncate_does_not_modify_the_options_hash options = { :length => 10 } passed_options = options.dup @@ -111,12 +111,6 @@ class TextHelperTest < ActionView::TestCase truncate("Here's a long test and I need a continue to read link", :length => 27) { link_to 'Continue', '#' } end - def test_truncate_should_not_mutate_the_options_hash - options = { :length => 27 } - truncate("Here's a long test and I need a continue to read link", options) { link_to 'Continue', '#' } - assert_equal({ :length => 27 }, options) - end - def test_truncate_should_be_html_safe assert truncate("Hello World!", :length => 12).html_safe? end @@ -135,6 +129,11 @@ class TextHelperTest < ActionView::TestCase truncate("Here's a long test and I need a continue to read link", :length => 27) { link_to 'Continue', '#' } end + def test_truncate_with_block_should_escape_the_block + assert_equal "Here's a long test and I...<script>alert('foo');</script>", + truncate("Here's a long test and I need a continue to read link", :length => 27) { "" } + end + def test_highlight_should_be_html_safe assert highlight("This is a beautiful morning", "beautiful").html_safe? end @@ -224,7 +223,7 @@ class TextHelperTest < ActionView::TestCase highlight("
    abc div
    ", "div", :highlighter => '\1') ) end - + def test_highlight_does_not_modify_the_options_hash options = { :highlighter => '\1', :sanitize => false } passed_options = options.dup @@ -277,7 +276,7 @@ class TextHelperTest < ActionView::TestCase def test_excerpt_with_utf8 assert_equal("...\357\254\203ciency could not be...".force_encoding('UTF-8'), excerpt("That's why e\357\254\203ciency could not be helped".force_encoding('UTF-8'), 'could', :radius => 8)) end - + def test_excerpt_does_not_modify_the_options_hash options = { :omission => "[...]",:radius => 5 } passed_options = options.dup @@ -292,7 +291,7 @@ class TextHelperTest < ActionView::TestCase def test_word_wrap_with_extra_newlines assert_equal("my very very\nvery long\nstring\n\nwith another\nline", word_wrap("my very very very long string\n\nwith another line", :line_width => 15)) end - + def test_word_wrap_does_not_modify_the_options_hash options = { :line_width => 15 } passed_options = options.dup -- cgit v1.2.3 From 0cfbaa030a0684aaa89d3d3c85528e80c1995836 Mon Sep 17 00:00:00 2001 From: Deepak Kannan Date: Sat, 26 May 2012 22:28:03 +0530 Subject: Small correction to contributing_to_rails in the section for testing ActiveRecord Initially the guide suggests to install gems via "bundle install --without db" But tests for ActiveRecord need to install the gems in db group also, like mysql. The patch clears the bundler options in ".bundle/config" and installs all the gems in Gemfile --- guides/source/contributing_to_ruby_on_rails.textile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/guides/source/contributing_to_ruby_on_rails.textile b/guides/source/contributing_to_ruby_on_rails.textile index 72cdea885f..8f36511d7d 100644 --- a/guides/source/contributing_to_ruby_on_rails.textile +++ b/guides/source/contributing_to_ruby_on_rails.textile @@ -128,6 +128,12 @@ The test suite of Active Record attempts to run four times: once for SQLite3, on WARNING: If you're working with Active Record code, you _must_ ensure that the tests pass for at least MySQL, PostgreSQL, and SQLite3. Subtle differences between the various adapters have been behind the rejection of many patches that looked OK when tested only against MySQL. +NOTE: need to install gems in the db group: + + +$ bundle install --without "" + + h5. Database Configuration The Active Record test suite requires a custom config file: +activerecord/test/config.yml+. An example is provided in +activerecord/test/config.example.yml+ which can be copied and used as needed for your environment. -- cgit v1.2.3 From eedc513503785490a7caed23cd0a0aef3536759f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Sat, 26 May 2012 13:56:42 -0300 Subject: Update the documentation and add CHANGELOG entry --- actionpack/CHANGELOG.md | 2 ++ actionpack/lib/action_view/helpers/text_helper.rb | 6 +++--- activesupport/lib/active_support/core_ext/string/filters.rb | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index 920858d8c0..db5e40b07c 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,5 +1,7 @@ ## Rails 4.0.0 (unreleased) ## +* `truncate` now accepts a block to show extra content when the text is truncated. *Li Ellis Gallardo* + * Add `week_field`, `week_field_tag`, `month_field`, `month_field_tag`, `datetime_local_field`, `datetime_local_field_tag`, `datetime_field` and `datetime_field_tag` helpers. *Carlos Galdino* diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb index 73c3c61a41..72f9dd2cef 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionpack/lib/action_view/helpers/text_helper.rb @@ -62,9 +62,9 @@ module ActionView # # Pass a :separator to truncate +text+ at a natural break. # - # The result is not marked as HTML-safe, so will be subject to the default escaping when - # used in views, unless wrapped by raw(). Care should be taken if +text+ contains HTML tags - # or entities, because truncation may produce invalid HTML (such as unbalanced or incomplete tags). + # Pass a block if you want to show extra content when the text is truncated. + # + # The result is marked as HTML-safe, but the it is escaped first. # # truncate("Once upon a time in a world far far away") # # => "Once upon a time in a world..." diff --git a/activesupport/lib/active_support/core_ext/string/filters.rb b/activesupport/lib/active_support/core_ext/string/filters.rb index 2478f42290..70f2dcb562 100644 --- a/activesupport/lib/active_support/core_ext/string/filters.rb +++ b/activesupport/lib/active_support/core_ext/string/filters.rb @@ -33,7 +33,7 @@ class String # # => "Once upon a time in a..." # # The last characters will be replaced with the :omission string (defaults to "...") - # for a total length not exceeding :length: + # for a total length not exceeding length: # # 'And they found that many people were sleeping better.'.truncate(25, :omission => '... (continued)') # # => "And they f... (continued)" -- cgit v1.2.3 From 2c2b0beaf46c997773b9adc8ef9ff57547a770a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Sat, 26 May 2012 14:11:28 -0300 Subject: Add `:escape` option for `truncate` This options can be used to not escape the result by default. --- actionpack/CHANGELOG.md | 5 +++++ actionpack/lib/action_view/helpers/text_helper.rb | 7 +++++-- actionpack/test/template/text_helper_test.rb | 19 +++++++++++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index db5e40b07c..ba66b525bc 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,5 +1,10 @@ ## Rails 4.0.0 (unreleased) ## +* `truncate` now always returns an escaped HTMl-safe string. The option `:escape` can be used as + false to not escape the result. + + *Li Ellis Gallardo + Rafael Mendonça França* + * `truncate` now accepts a block to show extra content when the text is truncated. *Li Ellis Gallardo* * Add `week_field`, `week_field_tag`, `month_field`, `month_field_tag`, `datetime_local_field`, diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb index 72f9dd2cef..0cc0d069ea 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionpack/lib/action_view/helpers/text_helper.rb @@ -64,7 +64,9 @@ module ActionView # # Pass a block if you want to show extra content when the text is truncated. # - # The result is marked as HTML-safe, but the it is escaped first. + # The result is marked as HTML-safe, but it is escaped by default, unless :escape is + # +false+. Care should be taken if +text+ contains HTML tags or entities, because truncation + # may produce invalid HTML (such as unbalanced or incomplete tags). # # truncate("Once upon a time in a world far far away") # # => "Once upon a time in a world..." @@ -87,7 +89,8 @@ module ActionView if text length = options.fetch(:length, 30) - content = ERB::Util.html_escape(text.truncate(length, options)) + content = text.truncate(length, options) + content = options[:escape] == false ? content.html_safe : ERB::Util.html_escape(content) content << capture(&block) if block_given? && text.length > length content end diff --git a/actionpack/test/template/text_helper_test.rb b/actionpack/test/template/text_helper_test.rb index 4b1c1ef78b..a3ab091c6c 100644 --- a/actionpack/test/template/text_helper_test.rb +++ b/actionpack/test/template/text_helper_test.rb @@ -119,6 +119,15 @@ class TextHelperTest < ActionView::TestCase assert_equal "Hello <sc...", truncate("Hello World!!", :length => 12) end + def test_truncate_should_not_escape_the_input_with_escape_false + assert_equal "Hello code!World!!", :length => 12, :escape => false) + end + + def test_truncate_with_escape_false_should_be_html_safe + truncated = truncate("Hello World!!", :length => 12, :escape => false) + assert truncated.html_safe? + end + def test_truncate_with_block_should_be_html_safe truncated = truncate("Here's a long test and I need a continue to read link", :length => 27) { link_to 'Continue', '#' } assert truncated.html_safe? @@ -129,6 +138,16 @@ class TextHelperTest < ActionView::TestCase truncate("Here's a long test and I need a continue to read link", :length => 27) { link_to 'Continue', '#' } end + def test_truncate_with_block_should_not_escape_the_input_with_escape_false + assert_equal "He...Continue", + truncate("Here's a long test and I need a continue to read link", :length => 27, :escape => false) { link_to 'Continue', '#' } + end + + def test_truncate_with_block_with_escape_false_should_be_html_safe + truncated = truncate("Here's a long test and I need a continue to read link", :length => 27, :escape => false) { link_to 'Continue', '#' } + assert truncated.html_safe? + end + def test_truncate_with_block_should_escape_the_block assert_equal "Here's a long test and I...<script>alert('foo');</script>", truncate("Here's a long test and I need a continue to read link", :length => 27) { "" } -- cgit v1.2.3 From ef4b3eef50f0d2526854ac1551d0f36b8eb82347 Mon Sep 17 00:00:00 2001 From: Deepak Kannan Date: Sat, 26 May 2012 23:05:48 +0530 Subject: Revert "Small correction to contributing_to_rails in the section for testing ActiveRecord " This reverts commit 0cfbaa030a0684aaa89d3d3c85528e80c1995836. Sorry did not see the section on MySql and PostgreSQL # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # On branch master # Changes to be committed: # (use "git reset HEAD ..." to unstage) # # modified: guides/source/contributing_to_ruby_on_rails.textile # --- guides/source/contributing_to_ruby_on_rails.textile | 6 ------ 1 file changed, 6 deletions(-) diff --git a/guides/source/contributing_to_ruby_on_rails.textile b/guides/source/contributing_to_ruby_on_rails.textile index 8f36511d7d..72cdea885f 100644 --- a/guides/source/contributing_to_ruby_on_rails.textile +++ b/guides/source/contributing_to_ruby_on_rails.textile @@ -128,12 +128,6 @@ The test suite of Active Record attempts to run four times: once for SQLite3, on WARNING: If you're working with Active Record code, you _must_ ensure that the tests pass for at least MySQL, PostgreSQL, and SQLite3. Subtle differences between the various adapters have been behind the rejection of many patches that looked OK when tested only against MySQL. -NOTE: need to install gems in the db group: - - -$ bundle install --without "" - - h5. Database Configuration The Active Record test suite requires a custom config file: +activerecord/test/config.yml+. An example is provided in +activerecord/test/config.example.yml+ which can be copied and used as needed for your environment. -- cgit v1.2.3 From 4c34cb31fab087217a666a0dd7b1363128acd3a6 Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Sun, 27 May 2012 01:39:54 +0530 Subject: Update initialization guide [ci skip] * update rails versions * remove outdated code snippets * few more corrections --- guides/source/initialization.textile | 96 ++++++++++++------------------------ 1 file changed, 32 insertions(+), 64 deletions(-) diff --git a/guides/source/initialization.textile b/guides/source/initialization.textile index 913ff24290..48d4373afe 100644 --- a/guides/source/initialization.textile +++ b/guides/source/initialization.textile @@ -57,7 +57,7 @@ else end
    -The +rbconfig+ file from the Ruby standard library provides us with the +RbConfig+ class which contains detailed information about the Ruby environment, including how Ruby was compiled. We can see thisin use in +railties/lib/rails/script_rails_loader+. +The +rbconfig+ file from the Ruby standard library provides us with the +RbConfig+ class which contains detailed information about the Ruby environment, including how Ruby was compiled. We can see this in use in +railties/lib/rails/script_rails_loader+. require 'pathname' @@ -157,11 +157,11 @@ 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) @@ -174,8 +174,8 @@ TODO: change these when the Rails 4 release is near. * 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) @@ -191,6 +191,7 @@ ARGV << '--help' if ARGV.empty? aliases = { "g" => "generate", + "d" => "destroy", "c" => "console", "s" => "server", "db" => "dbconsole", @@ -579,28 +580,6 @@ this time to the +Array+ and +Hash+ classes. This file defines an +extract_options!+ method which Rails uses to extract options from parameters. - -class Array - # Extracts options from a set of arguments. Removes and returns the - # last - # element in the array if it's a hash, otherwise returns a blank hash. - # - # def options(*args) - # args.extract_options! - # end - # - # options(1, 2) # => {} - # options(1, 2, :a => :b) # => {:a=>:b} - def extract_options! - if last.is_a?(Hash) && last.extractable_options? - pop - else - {} - end - end -end - - h4. +railties/lib/rails/application.rb+ The next file required by +railties/lib/rails.rb+ is +application.rb+. @@ -612,8 +591,7 @@ 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. -TIP: You can read more about engines in the "Getting Started with Engines":engines.html -guide. +TIP: You can read more about engines in the "Getting Started with Engines":engines.html guide. Among other things, Rails Engine is also responsible for loading the Railtie class. @@ -678,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: - BadConstant is deprecated! Use GoodConstant instead. +BadConstant is deprecated! Use GoodConstant instead. h4. +active_support/ordered_options+ @@ -689,7 +667,7 @@ The next file required is +active_support/core_ext/hash/deep_dup+ which is cover h4. +active_support/core_ext/object+ -This file is responsible for requiring many more core extensions: +This file is responsible for requiring many more Active Support core extensions: require 'active_support/core_ext/object/acts_like' @@ -947,7 +925,7 @@ The +initializers_chain+ method referenced in the +initializers_for+ method is d 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 @@ -1010,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. - - -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) - - -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: require 'active_support' require 'active_support/dependencies/autoload' +require 'active_support/core_ext/module/attribute_accessors' -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: module ActionPack module VERSION #:nodoc: - MAJOR = 3 - MINOR = 1 + MAJOR = 4 + MINOR = 0 TINY = 0 PRE = "beta" @@ -1067,8 +1034,8 @@ This file makes a require to +active_model/version+ which defines the version fo module ActiveModel module VERSION #:nodoc: - MAJOR = 3 - MINOR = 1 + MAJOR = 4 + MINOR = 0 TINY = 0 PRE = "beta" @@ -1105,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: @@ -1119,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+. @@ -1141,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. require 'active_support' -require 'active_support/i18n' require 'active_model' require 'arel' -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: module ActiveRecord module VERSION #:nodoc: - MAJOR = 3 - MINOR = 1 + MAJOR = 4 + MINOR = 0 TINY = 0 PRE = "beta" @@ -1180,7 +1146,9 @@ This will set the engine for +Arel::Table+ to be +ActiveRecord::Base+. The file then finishes with this line: -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 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. -- cgit v1.2.3 From 7d8474e20a7c3ee720c2659e52d1862dcd8b368d Mon Sep 17 00:00:00 2001 From: Erich Menge Date: Sat, 26 May 2012 16:39:18 -0500 Subject: Add some information about handle_unverified_request to guides. --- guides/source/security.textile | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/guides/source/security.textile b/guides/source/security.textile index ac55d60368..14038a9bcd 100644 --- a/guides/source/security.textile +++ b/guides/source/security.textile @@ -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 ActionController::InvalidAuthenticityToken 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: + + +def handle_unverified_request + super + sign_out_user # Example method that will destroy the user cookies. +end + + +The above method could be placed in the +ApplicationController+ and will be called when a CSRF token is not present on a POST 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 more about XSS later. h3. Redirection and Files -- cgit v1.2.3 From ac50b633d4b9fd12bf0212a5cf8ebc5ab3ee8f37 Mon Sep 17 00:00:00 2001 From: Francesco Rodriguez Date: Sat, 26 May 2012 22:24:06 -0500 Subject: add examples to Hash#deep_stringify_keys and Hash#deep_symbolize_keys [ci skip] --- activesupport/lib/active_support/core_ext/hash/keys.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/activesupport/lib/active_support/core_ext/hash/keys.rb b/activesupport/lib/active_support/core_ext/hash/keys.rb index e5e77bcef4..988a0b5949 100644 --- a/activesupport/lib/active_support/core_ext/hash/keys.rb +++ b/activesupport/lib/active_support/core_ext/hash/keys.rb @@ -93,6 +93,11 @@ class Hash # Return a new hash with all keys converted to strings. # This includes the keys from the root hash and from all # nested hashes. + # + # hash = { person: { name: 'Rob', age: '28' } } + # + # hash.deep_stringify_keys + # # => { "person" => { "name" => "Rob", "age" => "28" } } def deep_stringify_keys deep_transform_keys{ |key| key.to_s } end @@ -107,6 +112,11 @@ class Hash # Return a new hash with all keys converted to symbols, as long as # they respond to +to_sym+. This includes the keys from the root hash # and from all nested hashes. + # + # hash = { 'person' => { 'name' => 'Rob', 'age' => '28' } } + # + # hash.deep_symbolize_keys + # # => { person: { name: "Rob", age: "28" } } def deep_symbolize_keys deep_transform_keys{ |key| key.to_sym rescue key } end -- cgit v1.2.3 From 29713d7f3bca4267343a0bcaf8f1ee0ea3fe02ae Mon Sep 17 00:00:00 2001 From: Francesco Rodriguez Date: Sat, 26 May 2012 22:28:49 -0500 Subject: update Hash documentation with 1.9 syntax [ci skip] --- .../lib/active_support/core_ext/hash/keys.rb | 24 ++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/activesupport/lib/active_support/core_ext/hash/keys.rb b/activesupport/lib/active_support/core_ext/hash/keys.rb index 988a0b5949..8e728691c6 100644 --- a/activesupport/lib/active_support/core_ext/hash/keys.rb +++ b/activesupport/lib/active_support/core_ext/hash/keys.rb @@ -1,8 +1,10 @@ class Hash # Return a new hash with all keys converted using the block operation. # - # { :name => 'Rob', :years => '28' }.transform_keys{ |key| key.to_s.upcase } - # # => { "NAME" => "Rob", "YEARS" => "28" } + # hash = { name: 'Rob', age: '28' } + # + # hash.transform_keys{ |key| key.to_s.upcase } + # # => { "NAME" => "Rob", "AGE" => "28" } def transform_keys result = {} keys.each do |key| @@ -22,8 +24,10 @@ class Hash # Return a new hash with all keys converted to strings. # - # { :name => 'Rob', :years => '28' }.stringify_keys - # #=> { "name" => "Rob", "years" => "28" } + # hash = { name: 'Rob', age: '28' } + # + # hash.stringify_keys + # #=> { "name" => "Rob", "age" => "28" } def stringify_keys transform_keys{ |key| key.to_s } end @@ -37,8 +41,10 @@ class Hash # Return a new hash with all keys converted to symbols, as long as # they respond to +to_sym+. # - # { 'name' => 'Rob', 'years' => '28' }.symbolize_keys - # #=> { :name => "Rob", :years => "28" } + # hash = { 'name' => 'Rob', 'age' => '28' } + # + # hash.symbolize_keys + # #=> { name: "Rob", age: "28" } def symbolize_keys transform_keys{ |key| key.to_sym rescue key } end @@ -69,8 +75,10 @@ class Hash # This includes the keys from the root hash and from all # nested hashes. # - # { :person => { :name => 'Rob', :years => '28' } }.deep_transform_keys{ |key| key.to_s.upcase } - # # => { "PERSON" => { "NAME" => "Rob", "YEARS" => "28" } } + # hash = { person: { name: 'Rob', age: '28' } } + # + # hash.deep_transform_keys{ |key| key.to_s.upcase } + # # => { "PERSON" => { "NAME" => "Rob", "AGE" => "28" } } def deep_transform_keys(&block) result = {} each do |key, value| -- cgit v1.2.3 From 55c05276c71548f158cb9ae28fe2a154de9f8349 Mon Sep 17 00:00:00 2001 From: Francesco Rodriguez Date: Sat, 26 May 2012 22:43:24 -0500 Subject: add CollectionProxy#uniq documentation --- .../active_record/associations/collection_proxy.rb | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index 7408428493..294aa63f75 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -636,6 +636,27 @@ module ActiveRecord # # Pet.find(4, 5, 6) # => ActiveRecord::RecordNotFound: Couldn't find all Pets with IDs (4, 5, 6) + ## + # :method: uniq + # + # :call-seq: + # uniq() + # + # Specifies whether the records should be unique or not. + # + # class Person < ActiveRecord::Base + # has_many :pets + # end + # + # person.pets.select(:name) + # # => [ + # # #, + # # # + # # ] + # + # person.pets.select(:name).uniq + # # => [#] + ## # :method: count # -- cgit v1.2.3 From 4df16f3f3d2e2f806532ef2f698ae29f26df44db Mon Sep 17 00:00:00 2001 From: Francesco Rodriguez Date: Sat, 26 May 2012 22:51:26 -0500 Subject: remove unnecessary ruby 1.8 reference from active_record/core [ci skip] --- activerecord/lib/active_record/core.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb index f2833fbf3c..80c6f20b1a 100644 --- a/activerecord/lib/active_record/core.rb +++ b/activerecord/lib/active_record/core.rb @@ -10,9 +10,10 @@ module ActiveRecord included do ## # :singleton-method: - # Accepts a logger conforming to the interface of Log4r or the default Ruby 1.8+ Logger class, - # which is then passed on to any new database connections made and which can be retrieved on both - # a class and instance level by calling +logger+. + # + # Accepts a logger conforming to the interface of Log4r which is then + # passed on to any new database connections made and which can be + # retrieved on both a class and instance level by calling +logger+. config_attribute :logger, :global => true ## -- cgit v1.2.3 From 4f031c8350b08eb0b1eb8abf7eb380654d284abc Mon Sep 17 00:00:00 2001 From: Francesco Rodriguez Date: Sat, 26 May 2012 23:07:37 -0500 Subject: update Module#mattr_accessor documentation [ci skip] --- .../active_support/core_ext/module/attribute_accessors.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb index f914425827..b8cb2e347f 100644 --- a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb +++ b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb @@ -48,17 +48,17 @@ class Module # # module AppConfiguration # mattr_accessor :google_api_key - # self.google_api_key = "123456789" # - # mattr_accessor :paypal_url - # self.paypal_url = "www.sandbox.paypal.com" + # self.google_api_key = "123456789" # end # + # AppConfiguration.google_api_key # => "123456789" # AppConfiguration.google_api_key = "overriding the api key!" + # AppConfiguration.google_api_key # => "overriding the api key!" # - # To opt out of the instance writer method, pass :instance_writer => false. - # To opt out of the instance reader method, pass :instance_reader => false. - # To opt out of both instance methods, pass :instance_accessor => false. + # To opt out of the instance writer method, pass instance_writer: false. + # To opt out of the instance reader method, pass instance_reader: false. + # To opt out of both instance methods, pass instance_accessor: false. def mattr_accessor(*syms) mattr_reader(*syms) mattr_writer(*syms) -- cgit v1.2.3 From cf992fba95eb5d6282b0d04a52a3595f1c089512 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Sun, 27 May 2012 12:28:26 +0200 Subject: Fix railties_order when application object is passed railites_order method, introduced in 40b19e0, had a bug that was causing loading application instance twice in initializers if railties_order already included application instance. So for example railties_order = [Foo::Engine, :main_app, Bar::Engine] would result in such railties array: [MyApp::Application, Foo::Engine, MyAppApplication, Bar::Engine] In order to fix it, we need to check for existence of application in both railties_order and railties arrays. --- railties/lib/rails/application.rb | 2 +- railties/test/railties/engine_test.rb | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index d44465e547..660e864d2a 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -185,7 +185,7 @@ module Rails end all = (railties.all - order) - all.push(self) unless all.include?(self) + all.push(self) unless (all + order).include?(self) order.push(:all) unless order.include?(:all) index = order.index(:all) diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb index 7a047ef93a..4437e2c8af 100644 --- a/railties/test/railties/engine_test.rb +++ b/railties/test/railties/engine_test.rb @@ -1098,6 +1098,10 @@ YAML get("/assets/bar.js") assert_equal "// App's bar js\n;", last_response.body.strip + + # ensure that railties are not added twice + railties = Rails.application.ordered_railties.map(&:class) + assert_equal railties, railties.uniq end test "railties_order adds :all with lowest priority if not given" do -- cgit v1.2.3 From 903a9d51c0f736de3d5a82334190abe04f79b037 Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Sun, 27 May 2012 19:45:52 +0530 Subject: copy edits [ci skip] --- guides/source/security.textile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/guides/source/security.textile b/guides/source/security.textile index 14038a9bcd..cc0894fc77 100644 --- a/guides/source/security.textile +++ b/guides/source/security.textile @@ -240,12 +240,12 @@ It is common to use persistent cookies to store user information, with +cookies. def handle_unverified_request - super - sign_out_user # Example method that will destroy the user cookies. + super + sign_out_user # Example method that will destroy the user cookies. end -The above method could be placed in the +ApplicationController+ and will be called when a CSRF token is not present on a POST request. +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 more about XSS later. -- cgit v1.2.3 From 490b52ee8e9110d2cc484c3ef420af37c381e94b Mon Sep 17 00:00:00 2001 From: Vijay Dev Date: Sun, 27 May 2012 20:01:55 +0530 Subject: some asset path changes and formatting fixes in AV overview [ci skip] --- guides/source/action_view_overview.textile | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/guides/source/action_view_overview.textile b/guides/source/action_view_overview.textile index 734fdd895b..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 +
    +, 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 @@ -580,13 +580,13 @@ h5. 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. -image_path("edit.png") # => /images/edit.png +image_path("edit.png") # => /assets/edit.png Fingerprint will be added to the filename if config.assets.digest is set to true. -image_path("edit.png") # => /images/edit-2d1a2db63fc738690021fedb5a65b68e.png +image_path("edit.png") # => /assets/edit-2d1a2db63fc738690021fedb5a65b68e.png h5. image_url @@ -594,7 +594,7 @@ h5. image_url 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. -image_url("edit.png") # => http://www.example.com/images/edit.png +image_url("edit.png") # => http://www.example.com/assets/edit.png h5. image_tag @@ -602,7 +602,7 @@ 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 +app/assets/images+ directory. -image_tag("icon.png") # => Icon +image_tag("icon.png") # => Icon h5. javascript_include_tag @@ -610,8 +610,7 @@ 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 +app/assets/javascripts+ directory for inclusion into the current page or you can pass the full path relative to your document root. -javascript_include_tag "common" # => - +javascript_include_tag "common" # => 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. @@ -638,7 +637,7 @@ h5. javascript_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. -javascript_path "common" # => /javascripts/common.js +javascript_path "common" # => /assets/common.js h5. javascript_url @@ -646,7 +645,7 @@ h5. javascript_url 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. -javascript_url "common" # => http://www.example.com/javascripts/common.js +javascript_url "common" # => http://www.example.com/assets/common.js h5. stylesheet_link_tag @@ -654,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. -stylesheet_link_tag "application" # => - +stylesheet_link_tag "application" # => You can also include all styles in the stylesheet directory using :all as the source: @@ -668,7 +666,7 @@ You can also cache multiple stylesheets into one file, which requires less HTTP stylesheet_link_tag :all, :cache => true - +# => h5. stylesheet_path -- cgit v1.2.3 From d138921cece0c4923849ff61100fcce56e98e967 Mon Sep 17 00:00:00 2001 From: Mark Rushakoff Date: Sun, 27 May 2012 08:25:00 -0700 Subject: "a sql" -> "an SQL" per API documentation guidelines --- activerecord/lib/active_record/relation/calculations.rb | 2 +- guides/source/active_support_instrumentation.textile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index 31d99f0192..ab32bfe70a 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -118,7 +118,7 @@ module ActiveRecord # Person.all.map(&:name) # # Pluck returns an Array of attribute values type-casted to match - # the plucked column name, if it can be deduced. Plucking a SQL fragment + # the plucked column name, if it can be deduced. Plucking an SQL fragment # returns String values by default. # # Examples: diff --git a/guides/source/active_support_instrumentation.textile b/guides/source/active_support_instrumentation.textile index 430549fba4..666110495c 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 . 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. -- cgit v1.2.3 From ef498057bbb68d12f930533f455e21aae2056c3e Mon Sep 17 00:00:00 2001 From: Rafael Magana Date: Mon, 28 May 2012 00:17:20 -0500 Subject: [security guide] use info, note and warning where applicable --- guides/source/security.textile | 68 +++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/guides/source/security.textile b/guides/source/security.textile index cc0894fc77..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: @@ -255,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: @@ -283,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. @@ -308,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. @@ -316,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: @@ -338,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.
 @@ -370,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: @@ -482,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. @@ -509,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. @@ -521,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 @@ -537,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. @@ -564,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 config.filter_parameters in the application configuration. These parameters will be marked [FILTERED] in the log. @@ -574,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 below. It turns out that most of the passwords are quite easy to crack. The 20 most common passwords are: @@ -586,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: @@ -610,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: @@ -630,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_: @@ -651,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 @@ -730,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 @@ -858,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. @@ -898,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 <em>test<em>, 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: @@ -927,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 (|). @@ -947,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. -- cgit v1.2.3 From b4f0beb68a051495e51dd4a44a08d8a8d53f6998 Mon Sep 17 00:00:00 2001 From: Francesco Rodriguez Date: Mon, 28 May 2012 00:32:17 -0500 Subject: update documentation of array/access methods [ci skip] --- .../lib/active_support/core_ext/array/access.rb | 24 ++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/activesupport/lib/active_support/core_ext/array/access.rb b/activesupport/lib/active_support/core_ext/array/access.rb index 44d90ef732..a8f9dddae5 100644 --- a/activesupport/lib/active_support/core_ext/array/access.rb +++ b/activesupport/lib/active_support/core_ext/array/access.rb @@ -1,40 +1,48 @@ class Array # Returns the tail of the array from +position+. # - # %w( a b c d ).from(0) # => %w( a b c d ) - # %w( a b c d ).from(2) # => %w( c d ) - # %w( a b c d ).from(10) # => %w() - # %w().from(0) # => %w() + # %w( a b c d ).from(0) # => ["a", "b", "c", "d"] + # %w( a b c d ).from(2) # => ["c", "d"] + # %w( a b c d ).from(10) # => [] + # %w().from(0) # => [] def from(position) self[position, length] || [] end # Returns the beginning of the array up to +position+. # - # %w( a b c d ).to(0) # => %w( a ) - # %w( a b c d ).to(2) # => %w( a b c ) - # %w( a b c d ).to(10) # => %w( a b c d ) - # %w().to(0) # => %w() + # %w( a b c d ).to(0) # => ["a"] + # %w( a b c d ).to(2) # => ["a", "b", "c"] + # %w( a b c d ).to(10) # => ["a", "b", "c", "d"] + # %w().to(0) # => [] def to(position) first position + 1 end # Equal to self[1]. + # + # %w( a b c d e).second # => "b" def second self[1] end # Equal to self[2]. + # + # %w( a b c d e).third # => "c" def third self[2] end # Equal to self[3]. + # + # %w( a b c d e).fourth # => "d" def fourth self[3] end # Equal to self[4]. + # + # %w( a b c d e).fifth # => "e" def fifth self[4] end -- cgit v1.2.3 From 1e1d1da3ad71ed43fcff73bc3956579b69a1563d Mon Sep 17 00:00:00 2001 From: Francesco Rodriguez Date: Mon, 28 May 2012 01:23:38 -0500 Subject: add examples to Array#to_sentence [ci skip] --- .../active_support/core_ext/array/conversions.rb | 28 ++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/activesupport/lib/active_support/core_ext/array/conversions.rb b/activesupport/lib/active_support/core_ext/array/conversions.rb index 24aa28b895..d794713ed5 100644 --- a/activesupport/lib/active_support/core_ext/array/conversions.rb +++ b/activesupport/lib/active_support/core_ext/array/conversions.rb @@ -4,10 +4,30 @@ require 'active_support/core_ext/hash/reverse_merge' require 'active_support/core_ext/string/inflections' class Array - # Converts the array to a comma-separated sentence where the last element is joined by the connector word. Options: - # * :words_connector - The sign or word used to join the elements in arrays with two or more elements (default: ", ") - # * :two_words_connector - The sign or word used to join the elements in arrays with two elements (default: " and ") - # * :last_word_connector - The sign or word used to join the last element in arrays with three or more elements (default: ", and ") + # Converts the array to a comma-separated sentence where the last element is + # joined by the connector word. + # + # Options: + # + # * :words_connector - The sign or word used to join the elements + # in arrays with two or more elements (default: ", "). + # * :two_words_connector - The sign or word used to join the elements + # in arrays with two elements (default: " and "). + # * :last_word_connector - The sign or word used to join the last element + # in arrays with three or more elements (default: ", and "). + # + # Examples: + # + # [].to_sentence # => "" + # ['one'].to_sentence # => "one" + # ['one', 'two'].to_sentence # => "one and two" + # ['one', 'two', 'three'].to_sentence # => "one, two, and three" + # + # ['one', 'two'].to_sentence(two_words_connector: '-') + # # => "one-two" + # + # ['one', 'two', 'three'].to_sentence(words_connector: ' or ', last_word_connector: ' or at least ') + # # => "one or two or at least three" def to_sentence(options = {}) options.assert_valid_keys(:words_connector, :two_words_connector, :last_word_connector, :locale) -- cgit v1.2.3 From c6219b021574c4da69fbe0687726763fced9e492 Mon Sep 17 00:00:00 2001 From: Francesco Rodriguez Date: Mon, 28 May 2012 01:24:34 -0500 Subject: add :locale option to Array#to_sentence documentation [ci skip] --- .../active_support/core_ext/array/conversions.rb | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/activesupport/lib/active_support/core_ext/array/conversions.rb b/activesupport/lib/active_support/core_ext/array/conversions.rb index d794713ed5..74b5c73664 100644 --- a/activesupport/lib/active_support/core_ext/array/conversions.rb +++ b/activesupport/lib/active_support/core_ext/array/conversions.rb @@ -7,6 +7,10 @@ class Array # Converts the array to a comma-separated sentence where the last element is # joined by the connector word. # + # You can pass the following options to change the default behaviour. If you + # pass an option key that doesn't exist in the next list, it will raise an + # "Unknow key" error. + # # Options: # # * :words_connector - The sign or word used to join the elements @@ -15,6 +19,9 @@ class Array # in arrays with two elements (default: " and "). # * :last_word_connector - The sign or word used to join the last element # in arrays with three or more elements (default: ", and "). + # * :locale - If +i18n+ is available, you can set a locale and use + # the connector options defined on the 'support.array' namespace in the + # corresponding dictionary file. # # Examples: # @@ -23,11 +30,31 @@ class Array # ['one', 'two'].to_sentence # => "one and two" # ['one', 'two', 'three'].to_sentence # => "one, two, and three" # + # ['one', 'two'].to_sentence(passing: 'invalid option') + # # => ArgumentError: Unknown key :passing + # # ['one', 'two'].to_sentence(two_words_connector: '-') # # => "one-two" # # ['one', 'two', 'three'].to_sentence(words_connector: ' or ', last_word_connector: ' or at least ') # # => "one or two or at least three" + # + # Examples using :locale option: + # + # # With the next locale dictionary: + # #  + # # es: + # # support: + # # array: + # # words_connector: " o " + # # two_words_connector: " y " + # # last_word_connector: " o al menos " + # + # ['uno', 'dos'].to_sentence(locale: :es) + # # => "uno y dos" + # + # ['uno', 'dos', 'tres'].to_sentence(locale: :es) + # # => "uno o dos o al menos tres" def to_sentence(options = {}) options.assert_valid_keys(:words_connector, :two_words_connector, :last_word_connector, :locale) -- cgit v1.2.3 From ca65dcbbb2eca975782ea007a308000f1fbaf57f Mon Sep 17 00:00:00 2001 From: Rafael Magana Date: Mon, 28 May 2012 01:47:48 -0500 Subject: [command line guide] Use actual output of a Rails 3.2.x app --- guides/source/command_line.textile | 198 ++++++++++++++++++------------------- 1 file changed, 96 insertions(+), 102 deletions(-) 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. $ 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 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 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: rails s. +INFO: You can also use the alias "s" to start the server: rails s. 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: rails g. +INFO: You can also use the alias "g" to invoke the generator command: rails g. $ 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 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 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. $ 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. 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 $ 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 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. $ 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) ====================================== 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: rails c. +INFO: You can also use the alias "c" to invoke the console: rails c. -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. -$ rails console -e staging +$ rails console staging If you wish to test out some code without changing any data, you can do that by invoking +rails console --sandbox+. $ 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> @@ -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: rails db. +INFO: You can also use the alias "db" to invoke the dbconsole: rails db. h4. +rails runner+ @@ -305,7 +305,7 @@ h4. +rails runner+ $ rails runner "Model.long_running_method" -You can also use the alias "r" to invoke the runner: rails r. +INFO: You can also use the alias "r" to invoke the runner: rails r. 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: rails d. +INFO: You can also use the alias "d" to invoke the destroy command: rails d. $ 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 + + $ 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 h3. Rake @@ -352,16 +346,16 @@ You can get a list of Rake tasks available to you, which will often depend on yo $ 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 h4. +about+ -- cgit v1.2.3 From 0ad2146ccf45b3a26924e729a92cd2ff98356413 Mon Sep 17 00:00:00 2001 From: Francesco Rodriguez Date: Mon, 28 May 2012 02:18:35 -0500 Subject: remove :nodoc: from Class#subclasses [ci skip] --- .../lib/active_support/core_ext/class/subclasses.rb | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/activesupport/lib/active_support/core_ext/class/subclasses.rb b/activesupport/lib/active_support/core_ext/class/subclasses.rb index 74ea047c24..c2e0ebb3d4 100644 --- a/activesupport/lib/active_support/core_ext/class/subclasses.rb +++ b/activesupport/lib/active_support/core_ext/class/subclasses.rb @@ -1,11 +1,11 @@ require 'active_support/core_ext/module/anonymous' require 'active_support/core_ext/module/reachable' -class Class #:nodoc: +class Class begin ObjectSpace.each_object(Class.new) {} - def descendants + def descendants # :nodoc: descendants = [] ObjectSpace.each_object(singleton_class) do |k| descendants.unshift k unless k == self @@ -13,7 +13,7 @@ class Class #:nodoc: descendants end rescue StandardError # JRuby - def descendants + def descendants # :nodoc: descendants = [] ObjectSpace.each_object(Class) do |k| descendants.unshift k if k < self @@ -25,7 +25,13 @@ class Class #:nodoc: # Returns an array with the direct children of +self+. # - # Integer.subclasses # => [Bignum, Fixnum] + # Integer.subclasses # => [Fixnum, Bignum] + # + # class Foo; end + # class Bar < Foo; end + # class Baz < Foo; end + # + # Foo.subclasses # => [Baz, Bar] def subclasses subclasses, chain = [], descendants chain.each do |k| -- cgit v1.2.3