aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile2
-rw-r--r--actionmailer/CHANGELOG30
-rw-r--r--actionmailer/README.rdoc2
-rw-r--r--actionmailer/lib/rails/generators/mailer/templates/mailer.rb4
-rw-r--r--actionpack/CHANGELOG57
-rw-r--r--actionpack/README.rdoc2
-rw-r--r--actionpack/actionpack.gemspec4
-rw-r--r--actionpack/lib/abstract_controller/url_for.rb6
-rw-r--r--actionpack/lib/action_controller/metal/params_wrapper.rb29
-rw-r--r--actionpack/lib/action_controller/metal/request_forgery_protection.rb5
-rw-r--r--actionpack/lib/action_controller/metal/url_for.rb21
-rw-r--r--actionpack/lib/action_controller/test_case.rb7
-rw-r--r--actionpack/lib/action_dispatch/http/cache.rb26
-rw-r--r--actionpack/lib/action_dispatch/http/response.rb56
-rw-r--r--actionpack/lib/action_dispatch/http/url.rb2
-rw-r--r--actionpack/lib/action_dispatch/routing.rb6
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb51
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb9
-rw-r--r--actionpack/lib/action_dispatch/routing/url_for.rb8
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/selector.rb2
-rw-r--r--actionpack/lib/action_dispatch/testing/test_process.rb2
-rw-r--r--actionpack/lib/action_view.rb1
-rw-r--r--actionpack/lib/action_view/base.rb10
-rw-r--r--actionpack/lib/action_view/helpers/atom_feed_helper.rb8
-rw-r--r--actionpack/lib/action_view/helpers/cache_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/capture_helper.rb8
-rw-r--r--actionpack/lib/action_view/helpers/date_helper.rb143
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb62
-rw-r--r--actionpack/lib/action_view/helpers/form_options_helper.rb4
-rw-r--r--actionpack/lib/action_view/helpers/form_tag_helper.rb12
-rw-r--r--actionpack/lib/action_view/helpers/translation_helper.rb8
-rw-r--r--actionpack/lib/action_view/helpers/url_helper.rb2
-rw-r--r--actionpack/lib/action_view/path_set.rb2
-rw-r--r--actionpack/lib/action_view/template.rb10
-rw-r--r--actionpack/lib/action_view/template/error.rb2
-rw-r--r--actionpack/lib/action_view/template/resolver.rb62
-rw-r--r--actionpack/lib/sprockets/railtie.rb6
-rw-r--r--actionpack/test/activerecord/controller_runtime_test.rb15
-rw-r--r--actionpack/test/activerecord/render_partial_with_record_identification_test.rb2
-rw-r--r--actionpack/test/controller/params_wrapper_test.rb119
-rw-r--r--actionpack/test/controller/request_forgery_protection_test.rb25
-rw-r--r--actionpack/test/dispatch/request_test.rb7
-rw-r--r--actionpack/test/dispatch/response_body_is_proc_test.rb37
-rw-r--r--actionpack/test/template/capture_helper_test.rb16
-rw-r--r--actionpack/test/template/form_helper_test.rb14
-rw-r--r--actionpack/test/template/lookup_context_test.rb9
-rw-r--r--actionpack/test/template/render_test.rb2
-rw-r--r--activemodel/CHANGELOG31
-rw-r--r--activemodel/lib/active_model/conversion.rb8
-rw-r--r--activemodel/lib/active_model/mass_assignment_security.rb46
-rw-r--r--activemodel/lib/active_model/serializers/xml.rb1
-rw-r--r--activemodel/lib/active_model/validations/length.rb4
-rw-r--r--activemodel/lib/active_model/validations/numericality.rb4
-rw-r--r--activemodel/test/cases/mass_assignment_security_test.rb4
-rw-r--r--activemodel/test/cases/serializers/xml_serialization_test.rb4
-rw-r--r--activemodel/test/cases/validations/conditional_validation_test.rb24
-rw-r--r--activemodel/test/cases/validations/format_validation_test.rb2
-rw-r--r--activemodel/test/cases/validations/inclusion_validation_test.rb2
-rw-r--r--activemodel/test/cases/validations/length_validation_test.rb30
-rw-r--r--activemodel/test/models/contact.rb4
-rw-r--r--activerecord/CHANGELOG122
-rw-r--r--activerecord/README.rdoc2
-rw-r--r--activerecord/lib/active_record/associations.rb2
-rw-r--r--activerecord/lib/active_record/associations/alias_tracker.rb2
-rw-r--r--activerecord/lib/active_record/associations/builder/singular_association.rb25
-rw-r--r--activerecord/lib/active_record/associations/collection_association.rb113
-rw-r--r--activerecord/lib/active_record/associations/has_one_association.rb2
-rw-r--r--activerecord/lib/active_record/associations/singular_association.rb27
-rw-r--r--activerecord/lib/active_record/associations/through_association.rb5
-rw-r--r--activerecord/lib/active_record/base.rb34
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb10
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb11
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb13
-rw-r--r--activerecord/lib/active_record/fixtures.rb58
-rw-r--r--activerecord/lib/active_record/identity_map.rb32
-rw-r--r--activerecord/lib/active_record/locking/optimistic.rb2
-rw-r--r--activerecord/lib/active_record/persistence.rb2
-rw-r--r--activerecord/lib/active_record/railties/controller_runtime.rb10
-rw-r--r--activerecord/lib/active_record/railties/databases.rake12
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb11
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb7
-rw-r--r--activerecord/lib/active_record/session_store.rb6
-rw-r--r--activerecord/lib/active_record/test_case.rb7
-rw-r--r--activerecord/lib/active_record/validations.rb6
-rw-r--r--activerecord/test/cases/adapters/mysql2/bind_parameter_test.rb50
-rw-r--r--activerecord/test/cases/associations/belongs_to_associations_test.rb21
-rw-r--r--activerecord/test/cases/associations/cascaded_eager_loading_test.rb4
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb80
-rw-r--r--activerecord/test/cases/associations/has_one_associations_test.rb88
-rw-r--r--activerecord/test/cases/associations/has_one_through_associations_test.rb4
-rw-r--r--activerecord/test/cases/associations/inner_join_association_test.rb3
-rw-r--r--activerecord/test/cases/associations/join_model_test.rb12
-rw-r--r--activerecord/test/cases/associations_test.rb2
-rw-r--r--activerecord/test/cases/base_test.rb24
-rw-r--r--activerecord/test/cases/calculations_test.rb11
-rw-r--r--activerecord/test/cases/finder_test.rb21
-rw-r--r--activerecord/test/cases/fixtures_test.rb4
-rw-r--r--activerecord/test/cases/locking_test.rb36
-rw-r--r--activerecord/test/cases/mass_assignment_security_test.rb82
-rw-r--r--activerecord/test/cases/method_scoping_test.rb22
-rw-r--r--activerecord/test/cases/named_scope_test.rb2
-rw-r--r--activerecord/test/cases/persistence_test.rb4
-rw-r--r--activerecord/test/cases/relation_scoping_test.rb4
-rw-r--r--activerecord/test/cases/session_store/session_test.rb6
-rw-r--r--activerecord/test/cases/timestamp_test.rb26
-rw-r--r--activerecord/test/cases/xml_serialization_test.rb5
-rw-r--r--activerecord/test/fixtures/all/people.yml (renamed from activerecord/test/fixtures/all/people.csv)0
-rw-r--r--activerecord/test/fixtures/memberships.yml7
-rw-r--r--activerecord/test/fixtures/string_key_objects.yml7
-rw-r--r--activerecord/test/models/aircraft.rb3
-rw-r--r--activerecord/test/models/bulb.rb19
-rw-r--r--activerecord/test/models/car.rb5
-rw-r--r--activerecord/test/models/member.rb2
-rw-r--r--activerecord/test/models/membership.rb6
-rw-r--r--activerecord/test/models/string_key_object.rb3
-rw-r--r--activerecord/test/schema/schema.rb12
-rw-r--r--activeresource/CHANGELOG30
-rw-r--r--activeresource/lib/active_resource.rb2
-rw-r--r--activeresource/test/cases/format_test.rb2
-rw-r--r--activesupport/CHANGELOG34
-rw-r--r--activesupport/README.rdoc2
-rw-r--r--activesupport/lib/active_support.rb2
-rw-r--r--activesupport/lib/active_support/buffered_logger.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/array/conversions.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/array/random_access.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/array/uniq_by.rb5
-rw-r--r--activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/date/calculations.rb6
-rw-r--r--activesupport/lib/active_support/core_ext/date/conversions.rb5
-rw-r--r--activesupport/lib/active_support/core_ext/date_time/conversions.rb16
-rw-r--r--activesupport/lib/active_support/core_ext/hash/indifferent_access.rb12
-rw-r--r--activesupport/lib/active_support/core_ext/hash/slice.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/integer/inflections.rb11
-rw-r--r--activesupport/lib/active_support/core_ext/kernel/reporting.rb14
-rw-r--r--activesupport/lib/active_support/core_ext/module/attr_accessor_with_default.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/module/deprecation.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/object/blank.rb6
-rw-r--r--activesupport/lib/active_support/core_ext/object/with_options.rb13
-rw-r--r--activesupport/lib/active_support/core_ext/string/behavior.rb3
-rw-r--r--activesupport/lib/active_support/core_ext/string/exclude.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/string/inquiry.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/time/calculations.rb6
-rw-r--r--activesupport/lib/active_support/hash_with_indifferent_access.rb16
-rw-r--r--activesupport/lib/active_support/inflector/methods.rb4
-rw-r--r--activesupport/lib/active_support/json/encoding.rb1
-rw-r--r--activesupport/lib/active_support/log_subscriber/test_helper.rb1
-rw-r--r--activesupport/lib/active_support/ordered_hash.rb4
-rw-r--r--activesupport/lib/active_support/secure_random.rb205
-rw-r--r--activesupport/lib/active_support/xml_mini.rb4
-rw-r--r--activesupport/test/buffered_logger_test.rb39
-rw-r--r--activesupport/test/core_ext/hash_ext_test.rb20
-rw-r--r--activesupport/test/core_ext/module/attr_accessor_with_default_test.rb16
-rw-r--r--activesupport/test/ordered_hash_test.rb6
-rw-r--r--activesupport/test/xml_mini_test.rb10
-rw-r--r--railties/CHANGELOG36
-rw-r--r--railties/guides/rails_guides/generator.rb9
-rw-r--r--railties/guides/source/action_controller_overview.textile26
-rw-r--r--railties/guides/source/active_support_core_extensions.textile10
-rw-r--r--railties/guides/source/association_basics.textile4
-rw-r--r--railties/guides/source/caching_with_rails.textile31
-rw-r--r--railties/guides/source/configuring.textile85
-rw-r--r--railties/guides/source/contributing_to_ruby_on_rails.textile31
-rw-r--r--railties/guides/source/generators.textile47
-rw-r--r--railties/guides/source/getting_started.textile8
-rw-r--r--railties/guides/source/rails_on_rack.textile6
-rw-r--r--railties/guides/source/security.textile10
-rw-r--r--railties/guides/source/testing.textile6
-rw-r--r--railties/lib/rails/application.rb6
-rw-r--r--railties/lib/rails/application/configuration.rb2
-rw-r--r--railties/lib/rails/commands.rb3
-rw-r--r--railties/lib/rails/commands/runner.rb2
-rw-r--r--railties/lib/rails/engine.rb1
-rw-r--r--railties/lib/rails/engine/configuration.rb1
-rw-r--r--railties/lib/rails/generators/app_base.rb18
-rw-r--r--railties/lib/rails/generators/base.rb4
-rw-r--r--railties/lib/rails/generators/generated_attribute.rb13
-rw-r--r--railties/lib/rails/generators/rails/app/app_generator.rb21
-rw-r--r--railties/lib/rails/generators/rails/app/templates/Gemfile4
-rw-r--r--railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt7
-rw-r--r--railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css4
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/application.rb5
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/databases/frontbase.yml5
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/databases/ibm_db.yml3
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml3
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml4
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml5
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml4
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml4
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml3
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt1
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/db/seeds.rb.tt2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/gitignore1
-rw-r--r--railties/lib/rails/generators/rails/assets/USAGE6
-rw-r--r--railties/lib/rails/generators/rails/assets/assets_generator.rb8
-rw-r--r--railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb2
-rw-r--r--railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb4
-rw-r--r--railties/lib/rails/tasks/framework.rake9
-rw-r--r--railties/test/application/assets_test.rb58
-rw-r--r--railties/test/application/configuration_test.rb19
-rw-r--r--railties/test/application/initializers/frameworks_test.rb2
-rw-r--r--railties/test/application/middleware_test.rb6
-rw-r--r--railties/test/application/rack/logger_test.rb40
-rw-r--r--railties/test/application/routing_test.rb4
-rw-r--r--railties/test/generators/app_generator_test.rb11
-rw-r--r--railties/test/generators/generated_attribute_test.rb6
-rw-r--r--railties/test/generators/mailer_generator_test.rb28
-rw-r--r--railties/test/generators/namespaced_generators_test.rb6
-rw-r--r--railties/test/generators/plugin_new_generator_test.rb6
-rw-r--r--railties/test/generators/shared_generator_tests.rb53
-rw-r--r--railties/test/railties/engine_test.rb28
-rw-r--r--railties/test/railties/shared_tests.rb3
213 files changed, 2340 insertions, 1091 deletions
diff --git a/Gemfile b/Gemfile
index 23b1a1096b..7199301b90 100644
--- a/Gemfile
+++ b/Gemfile
@@ -10,7 +10,7 @@ end
gem "coffee-script"
gem "sass"
-gem "uglifier"
+gem "uglifier", :git => 'git://github.com/lautis/uglifier.git'
gem "rake", ">= 0.8.7"
gem "mocha", ">= 0.9.8"
diff --git a/actionmailer/CHANGELOG b/actionmailer/CHANGELOG
index 167c1da9c5..d4475bc951 100644
--- a/actionmailer/CHANGELOG
+++ b/actionmailer/CHANGELOG
@@ -2,14 +2,42 @@
* No changes
-*Rails 3.0.2 (unreleased)*
+
+*Rails 3.0.7 (April 18, 2011)*
+
+* remove AM delegating register_observer and register_interceptor to Mail [Josh Kalderimis]
+
+
+*Rails 3.0.6 (April 5, 2011)
+
+* Don't allow i18n to change the minor version, version now set to ~> 0.5.0 [Santiago Pastorino]
+
+
+*Rails 3.0.5 (February 26, 2011)*
+
+* No changes.
+
+
+*Rails 3.0.4 (February 8, 2011)*
+
+* No changes.
+
+
+*Rails 3.0.3 (November 16, 2010)*
+
+* No changes.
+
+
+*Rails 3.0.2 (November 15, 2010)*
* No changes
+
*Rails 3.0.1 (October 15, 2010)*
* No Changes, just a version bump.
+
*Rails 3.0.0 (August 29, 2010)*
* subject is automatically looked up on I18n using mailer_name and action_name as scope as in t(".subject") [JK]
diff --git a/actionmailer/README.rdoc b/actionmailer/README.rdoc
index 9b206fbcc7..af9bf40f9e 100644
--- a/actionmailer/README.rdoc
+++ b/actionmailer/README.rdoc
@@ -157,5 +157,5 @@ API documentation is at
Bug reports and feature requests can be filed with the rest for the Ruby on Rails project here:
-* https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets
+* https://github.com/rails/rails/issues
diff --git a/actionmailer/lib/rails/generators/mailer/templates/mailer.rb b/actionmailer/lib/rails/generators/mailer/templates/mailer.rb
index 370a508cad..88b074cef5 100644
--- a/actionmailer/lib/rails/generators/mailer/templates/mailer.rb
+++ b/actionmailer/lib/rails/generators/mailer/templates/mailer.rb
@@ -1,6 +1,6 @@
<% module_namespacing do -%>
class <%= class_name %> < ActionMailer::Base
- default :from => "from@example.com"
+ default <%= key_value :from, '"from@example.com"' %>
<% for action in actions -%>
# Subject can be set in your I18n file at config/locales/en.yml
@@ -11,7 +11,7 @@ class <%= class_name %> < ActionMailer::Base
def <%= action %>
@greeting = "Hi"
- mail :to => "to@example.org"
+ mail <%= key_value :to, '"to@example.org"' %>
end
<% end -%>
end
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG
index 428a5d0e1a..15abfb8369 100644
--- a/actionpack/CHANGELOG
+++ b/actionpack/CHANGELOG
@@ -1,5 +1,7 @@
*Rails 3.1.0 (unreleased)*
+* Warn if we cannot verify CSRF token authenticity [José Valim]
+
* Allow AM/PM format in datetime selectors [Aditya Sanghi]
* Only show dump of regular env methods on exception screen (not all the rack crap) [DHH]
@@ -15,7 +17,7 @@
class PostsController < ActionController::Base
stream :only => :index
end
-
+
Please read the docs at `ActionController::Streaming` for more information.
* Added `ActionDispatch::Request.ignore_accept_header` to ignore accept headers and only consider the format given as parameter [José Valim]
@@ -131,7 +133,58 @@ tested.
* Add Rack::Cache to the default stack. Create a Rails store that delegates to the Rails cache, so by default, whatever caching layer you are using will be used for HTTP caching. Note that Rack::Cache will be used if you use #expires_in, #fresh_when or #stale with :public => true. Otherwise, the caching rules will apply to the browser only. [Yehuda Katz, Carl Lerche]
-*Rails 3.0.2 (unreleased)*
+*Rails 3.0.7 (April 18, 2011)*
+
+*No changes.
+
+
+*Rails 3.0.6 (April 5, 2011)
+
+* Fixed XSS vulnerability in `auto_link`. `auto_link` no longer marks input as
+ html safe. Please make sure that calls to auto_link() are wrapped in a
+ sanitize(), or a raw() depending on the type of input passed to auto_link().
+ For example:
+
+ <%= sanitize(auto_link(some_user_input)) %>
+
+ Thanks to Torben Schulz for reporting this. The fix can be found here:
+ 61ee3449674c591747db95f9b3472c5c3bd9e84d
+
+* Fixes the output of `rake routes` to be correctly match to the behavior of the application, as the regular expression used to match the path is greedy and won't capture the format part by default [Prem Sichanugrist]
+
+* Fixes an issue with number_to_human when converting values which are less than 1 but greater than -1 [Josh Kalderimis]
+
+* Sensitive query string parameters (specified in config.filter_parameters) will now be filtered out from the request paths in the log file. [Prem Sichanugrist, fxn]
+
+* URL parameters which return nil for to_param are now removed from the query string [Andrew White]
+
+* Don't allow i18n to change the minor version, version now set to ~> 0.5.0 [Santiago Pastorino]
+
+* Make TranslationHelper#translate use the :rescue_format option in I18n 0.5.0 [Sven Fuchs]
+
+* Fix regression: javascript_include_tag shouldn't raise if you register an expansion key with nil or [] value [Santiago Pastorino]
+
+* Fix Action caching bug where an action that has a non-cacheable response always renders a nil response body. It now correctly renders the response body. [Cheah Chu Yeow]
+
+
+*Rails 3.0.5 (February 26, 2011)*
+
+* No changes.
+
+
+*Rails 3.0.4 (February 8, 2011)*
+
+* No changes.
+
+
+*Rails 3.0.3 (November 16, 2010)*
+
+* When ActiveRecord::Base objects are sent to predicate methods, the id of the object should be sent to ARel, not the ActiveRecord::Base object.
+
+* :constraints routing should only do sanity checks against regular expressions. String arguments are OK.
+
+
+*Rails 3.0.2 (November 15, 2010)*
* The helper number_to_currency accepts a new :negative_format option to be able to configure how to render negative amounts. [Don Wilson]
diff --git a/actionpack/README.rdoc b/actionpack/README.rdoc
index 1a56c44db5..5db4cff66b 100644
--- a/actionpack/README.rdoc
+++ b/actionpack/README.rdoc
@@ -338,4 +338,4 @@ API documentation is at
Bug reports and feature requests can be filed with the rest for the Ruby on Rails project here:
-* https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets
+* https://github.com/rails/rails/issues
diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec
index fdd894fe63..f623d6d487 100644
--- a/actionpack/actionpack.gemspec
+++ b/actionpack/actionpack.gemspec
@@ -24,8 +24,8 @@ Gem::Specification.new do |s|
s.add_dependency('i18n', '~> 0.6.0beta1')
s.add_dependency('rack', '~> 1.3.0.beta')
s.add_dependency('rack-test', '~> 0.6.0')
- s.add_dependency('rack-mount', '~> 0.7.2')
- s.add_dependency('sprockets', '~> 2.0.0.beta.2')
+ s.add_dependency('rack-mount', '~> 0.8.0')
+ s.add_dependency('sprockets', '~> 2.0.0.beta.3')
s.add_dependency('tzinfo', '~> 0.3.27')
s.add_dependency('erubis', '~> 2.7.0')
end
diff --git a/actionpack/lib/abstract_controller/url_for.rb b/actionpack/lib/abstract_controller/url_for.rb
index e5d5bef6b4..e4261068d8 100644
--- a/actionpack/lib/abstract_controller/url_for.rb
+++ b/actionpack/lib/abstract_controller/url_for.rb
@@ -1,3 +1,9 @@
+# Includes +url_for+ into the host class (e.g. an abstract controller or mailer). The class
+# has to provide a +RouteSet+ by implementing the <tt>_routes</tt> methods. Otherwise, an
+# exception will be raised.
+#
+# Note that this module is completely decoupled from HTTP - the only requirement is a valid
+# <tt>_routes</tt> implementation.
module AbstractController
module UrlFor
extend ActiveSupport::Concern
diff --git a/actionpack/lib/action_controller/metal/params_wrapper.rb b/actionpack/lib/action_controller/metal/params_wrapper.rb
index 881af74147..93241fc056 100644
--- a/actionpack/lib/action_controller/metal/params_wrapper.rb
+++ b/actionpack/lib/action_controller/metal/params_wrapper.rb
@@ -2,6 +2,7 @@ require 'active_support/core_ext/class/attribute'
require 'active_support/core_ext/hash/slice'
require 'active_support/core_ext/hash/except'
require 'active_support/core_ext/array/wrap'
+require 'active_support/core_ext/module/anonymous'
require 'action_dispatch/http/mime_types'
module ActionController
@@ -136,15 +137,25 @@ module ActionController
# this could be done by trying to find the defined model that has the
# same singularize name as the controller. For example, +UsersController+
# will try to find if the +User+ model exists.
- def _default_wrap_model
+ #
+ # This method also does namespace lookup. Foo::Bar::UsersController will
+ # try to find Foo::Bar::User, Foo::User and finally User.
+ def _default_wrap_model #:nodoc:
+ return nil if self.anonymous?
+
model_name = self.name.sub(/Controller$/, '').singularize
begin
model_klass = model_name.constantize
- rescue NameError => e
- unscoped_model_name = model_name.split("::", 2).last
- break if unscoped_model_name == model_name
- model_name = unscoped_model_name
+ rescue NameError, ArgumentError => e
+ if e.message =~ /is not missing constant|uninitialized constant #{model_name}/
+ namespaces = model_name.split("::")
+ namespaces.delete_at(-2)
+ break if namespaces.last == model_name
+ model_name = namespaces.join("::")
+ else
+ raise
+ end
end until model_klass
model_klass
@@ -155,12 +166,12 @@ module ActionController
unless options[:only] || options[:except]
model ||= _default_wrap_model
- if model.respond_to?(:column_names)
- options[:only] = model.column_names
+ if model.respond_to?(:attribute_names) && model.attribute_names.present?
+ options[:only] = model.attribute_names
end
end
- unless options[:name]
+ unless options[:name] || self.anonymous?
model ||= _default_wrap_model
options[:name] = model ? model.to_s.demodulize.underscore :
controller_name.singularize
@@ -218,7 +229,7 @@ module ActionController
# Checks if we should perform parameters wrapping.
def _wrapper_enabled?
ref = request.content_mime_type.try(:ref)
- _wrapper_formats.include?(ref) && !request.request_parameters[_wrapper_key]
+ _wrapper_formats.include?(ref) && _wrapper_key && !request.request_parameters[_wrapper_key]
end
end
end
diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
index 1cd93a188c..13044a7450 100644
--- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
@@ -73,7 +73,10 @@ module ActionController #:nodoc:
protected
# The actual before_filter that is used. Modify this to change how you handle unverified requests.
def verify_authenticity_token
- verified_request? || handle_unverified_request
+ unless verified_request?
+ logger.debug "WARNING: Can't verify CSRF token authenticity" if logger
+ handle_unverified_request
+ end
end
def handle_unverified_request
diff --git a/actionpack/lib/action_controller/metal/url_for.rb b/actionpack/lib/action_controller/metal/url_for.rb
index 6fc0cf1fb8..08132b1900 100644
--- a/actionpack/lib/action_controller/metal/url_for.rb
+++ b/actionpack/lib/action_controller/metal/url_for.rb
@@ -1,3 +1,24 @@
+# Includes +url_for+ into the host class. The class has to provide a +RouteSet+ by implementing
+# the <tt>_routes</tt> method. Otherwise, an exception will be raised.
+#
+# In addition to <tt>AbstractController::UrlFor</tt>, this module accesses the HTTP layer to define
+# url options like the +host+. In order to do so, this module requires the host class
+# to implement +env+ and +request+, which need to be a Rack-compatible.
+#
+# Example:
+#
+# class RootUrl
+# include ActionController::UrlFor
+# include Rails.application.routes.url_helpers
+#
+# delegate :env, :request, :to => :controller
+#
+# def initialize(controller)
+# @controller = controller
+# @url = root_path # named route from the application.
+# end
+# end
+# =>
module ActionController
module UrlFor
extend ActiveSupport::Concern
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index 0085f542aa..89ff5ba174 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -2,6 +2,7 @@ require 'rack/session/abstract/id'
require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/object/to_query'
require 'active_support/core_ext/class/attribute'
+require 'active_support/core_ext/module/anonymous'
module ActionController
module TemplateAssertions
@@ -413,7 +414,11 @@ module ActionController
@request.env['REQUEST_METHOD'] = http_method
parameters ||= {}
- @request.assign_parameters(@routes, @controller.class.name.underscore.sub(/_controller$/, ''), action.to_s, parameters)
+ controller_class_name = @controller.class.anonymous? ?
+ "anonymous_controller" :
+ @controller.class.name.underscore.sub(/_controller$/, '')
+
+ @request.assign_parameters(@routes, controller_class_name, action.to_s, parameters)
@request.session = ActionController::TestSession.new(session) if session
@request.session["flash"] = @request.flash.update(flash || {})
diff --git a/actionpack/lib/action_dispatch/http/cache.rb b/actionpack/lib/action_dispatch/http/cache.rb
index 4f4cb96a74..aaed0d750f 100644
--- a/actionpack/lib/action_dispatch/http/cache.rb
+++ b/actionpack/lib/action_dispatch/http/cache.rb
@@ -42,20 +42,6 @@ module ActionDispatch
attr_reader :cache_control, :etag
alias :etag? :etag
- def initialize(*)
- super
-
- @cache_control = {}
- @etag = self["ETag"]
-
- if cache_control = self["Cache-Control"]
- cache_control.split(/,\s*/).each do |segment|
- first, last = segment.split("=")
- @cache_control[first.to_sym] = last || true
- end
- end
- end
-
def last_modified
if last = headers['Last-Modified']
Time.httpdate(last)
@@ -77,6 +63,18 @@ module ActionDispatch
private
+ def prepare_cache_control!
+ @cache_control = {}
+ @etag = self["ETag"]
+
+ if cache_control = self["Cache-Control"]
+ cache_control.split(/,\s*/).each do |segment|
+ first, last = segment.split("=")
+ @cache_control[first.to_sym] = last || true
+ end
+ end
+ end
+
def handle_conditional_get!
if etag? || last_modified? || !@cache_control.empty?
set_conditional_cache_control!
diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb
index 1f4f3ac0da..3a6b1da4fd 100644
--- a/actionpack/lib/action_dispatch/http/response.rb
+++ b/actionpack/lib/action_dispatch/http/response.rb
@@ -56,26 +56,25 @@ module ActionDispatch # :nodoc:
cattr_accessor(:default_charset) { "utf-8" }
- module Setup
- def initialize(status = 200, header = {}, body = [])
- self.body, self.header, self.status = body, header, status
+ include Rack::Response::Helpers
+ include ActionDispatch::Http::Cache::Response
- @sending_file = false
- @blank = false
+ def initialize(status = 200, header = {}, body = [])
+ self.body, self.header, self.status = body, header, status
- if content_type = self["Content-Type"]
- type, charset = content_type.split(/;\s*charset=/)
- @content_type = Mime::Type.lookup(type)
- @charset = charset || "UTF-8"
- end
+ @sending_file = false
+ @blank = false
- yield self if block_given?
+ if content_type = self["Content-Type"]
+ type, charset = content_type.split(/;\s*charset=/)
+ @content_type = Mime::Type.lookup(type)
+ @charset = charset || "UTF-8"
end
- end
- include Rack::Response::Helpers
- include Setup
- include ActionDispatch::Http::Cache::Response
+ prepare_cache_control!
+
+ yield self if block_given?
+ end
def status=(status)
@status = Rack::Utils.status_code(status)
@@ -116,9 +115,32 @@ module ActionDispatch # :nodoc:
EMPTY = " "
+ class BodyBuster #:nodoc:
+ def initialize(response)
+ @response = response
+ @body = ""
+ end
+
+ def bust(body)
+ body.call(@response, self)
+ body.close if body.respond_to?(:close)
+ @body
+ end
+
+ def write(string)
+ @body << string.to_s
+ end
+ end
+
def body=(body)
@blank = true if body == EMPTY
+ if body.respond_to?(:call)
+ ActiveSupport::Deprecation.warn "Setting a Proc or an object that responds to call " \
+ "in response_body is no longer supported", caller
+ body = BodyBuster.new(self).bust(body)
+ end
+
# Explicitly check for strings. This is *wrong* theoretically
# but if we don't check this, the performance on string bodies
# is bad on Ruby 1.8 (because strings responds to each then).
@@ -150,6 +172,10 @@ module ActionDispatch # :nodoc:
headers['Location'] = url
end
+ def close
+ @body.close if @body.respond_to?(:close)
+ end
+
def to_a
assign_default_content_type_and_charset!
handle_conditional_get!
diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb
index d9c07d6ca3..8487b0fc8c 100644
--- a/actionpack/lib/action_dispatch/http/url.rb
+++ b/actionpack/lib/action_dispatch/http/url.rb
@@ -162,7 +162,7 @@ module ActionDispatch
# Returns all the \subdomains as a string, so <tt>"dev.www"</tt> would be
# returned for "dev.www.rubyonrails.org". You can specify a different <tt>tld_length</tt>,
- # such as 2 to catch <tt>["www"]</tt> instead of <tt>"www.rubyonrails"</tt>
+ # such as 2 to catch <tt>"www"</tt> instead of <tt>"www.rubyonrails"</tt>
# in "www.rubyonrails.co.uk".
def subdomain(tld_length = @@tld_length)
subdomains(tld_length).join(".")
diff --git a/actionpack/lib/action_dispatch/routing.rb b/actionpack/lib/action_dispatch/routing.rb
index 43fd93adf6..74c090f260 100644
--- a/actionpack/lib/action_dispatch/routing.rb
+++ b/actionpack/lib/action_dispatch/routing.rb
@@ -49,8 +49,8 @@ module ActionDispatch
# You may wish to organize groups of controllers under a namespace. Most
# commonly, you might group a number of administrative controllers under
# an +admin+ namespace. You would place these controllers under the
- # app/controllers/admin directory, and you can group them together in your
- # router:
+ # <tt>app/controllers/admin</tt> directory, and you can group them together
+ # in your router:
#
# namespace "admin" do
# resources :posts, :comments
@@ -152,7 +152,7 @@ module ActionDispatch
# }
# end
#
- # Using the multiline match modifier will raise an ArgumentError.
+ # Using the multiline match modifier will raise an +ArgumentError+.
# Encoding regular expression modifiers are silently ignored. The
# match will always use the default encoding or ASCII.
#
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index a65f6e1fce..3ba6094fbb 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -335,7 +335,7 @@ module ActionDispatch
#
# [:on]
# Shorthand for wrapping routes in a specific RESTful context. Valid
- # values are :member, :collection, and :new. Only use within
+ # values are +:member+, +:collection+, and +:new+. Only use within
# <tt>resource(s)</tt> block. For example:
#
# resource :bar do
@@ -352,7 +352,7 @@ module ActionDispatch
#
# [:constraints]
# Constrains parameters with a hash of regular expressions or an
- # object that responds to #matches?
+ # object that responds to <tt>matches?</tt>
#
# match 'path/:id', :constraints => { :id => /[A-Z]\d{5}/ }
#
@@ -373,7 +373,7 @@ module ActionDispatch
# See <tt>Scoping#defaults</tt> for its scope equivalent.
#
# [:anchor]
- # Boolean to anchor a #match pattern. Default is true. When set to
+ # Boolean to anchor a <tt>match</tt> pattern. Default is true. When set to
# false, the pattern matches any request prefixed with the given path.
#
# # Matches any request starting with 'path'
@@ -517,15 +517,15 @@ module ActionDispatch
# You may wish to organize groups of controllers under a namespace.
# Most commonly, you might group a number of administrative controllers
# under an +admin+ namespace. You would place these controllers under
- # the app/controllers/admin directory, and you can group them together
- # in your router:
+ # the <tt>app/controllers/admin</tt> directory, and you can group them
+ # together in your router:
#
# namespace "admin" do
# resources :posts, :comments
# end
#
# This will create a number of routes for each of the posts and comments
- # controller. For Admin::PostsController, Rails will create:
+ # controller. For <tt>Admin::PostsController</tt>, Rails will create:
#
# GET /admin/posts
# GET /admin/posts/new
@@ -536,7 +536,7 @@ module ActionDispatch
# DELETE /admin/posts/1
#
# If you want to route /posts (without the prefix /admin) to
- # Admin::PostsController, you could use
+ # <tt>Admin::PostsController</tt>, you could use
#
# scope :module => "admin" do
# resources :posts
@@ -546,7 +546,7 @@ module ActionDispatch
#
# resources :posts, :module => "admin"
#
- # If you want to route /admin/posts to PostsController
+ # If you want to route /admin/posts to +PostsController+
# (without the Admin:: module prefix), you could use
#
# scope "/admin" do
@@ -555,11 +555,11 @@ module ActionDispatch
#
# or, for a single case
#
- # resources :posts, :path => "/admin"
+ # resources :posts, :path => "/admin/posts"
#
# In each of these cases, the named routes remain the same as if you did
# not use scope. In the last case, the following paths map to
- # PostsController:
+ # +PostsController+:
#
# GET /admin/posts
# GET /admin/posts/new
@@ -587,7 +587,7 @@ module ActionDispatch
#
# === Examples
#
- # # route /posts (without the prefix /admin) to Admin::PostsController
+ # # route /posts (without the prefix /admin) to <tt>Admin::PostsController</tt>
# scope :module => "admin" do
# resources :posts
# end
@@ -597,7 +597,7 @@ module ActionDispatch
# resources :posts
# end
#
- # # prefix the routing helper name: sekret_posts_path instead of posts_path
+ # # prefix the routing helper name: +sekret_posts_path+ instead of +posts_path+
# scope :as => "sekret" do
# resources :posts
# end
@@ -679,12 +679,12 @@ module ActionDispatch
# resources :posts
# end
#
- # # maps to Sekret::PostsController rather than Admin::PostsController
+ # # maps to <tt>Sekret::PostsController</tt> rather than <tt>Admin::PostsController</tt>
# namespace :admin, :module => "sekret" do
# resources :posts
# end
#
- # # generates sekret_posts_path rather than admin_posts_path
+ # # generates +sekret_posts_path+ rather than +admin_posts_path+
# namespace :admin, :as => "sekret" do
# resources :posts
# end
@@ -712,6 +712,7 @@ module ActionDispatch
# constraints(:post_id => /\d+\.\d+) do
# resources :comments
# end
+ # end
#
# === Restricting based on IP
#
@@ -846,20 +847,20 @@ module ActionDispatch
# You may wish to organize groups of controllers under a namespace. Most
# commonly, you might group a number of administrative controllers under
# an +admin+ namespace. You would place these controllers under the
- # app/controllers/admin directory, and you can group them together in your
- # router:
+ # <tt>app/controllers/admin</tt> directory, and you can group them together
+ # in your router:
#
# namespace "admin" do
# resources :posts, :comments
# end
#
- # By default the :id parameter doesn't accept dots. If you need to
- # use dots as part of the :id parameter add a constraint which
+ # By default the +:id+ parameter doesn't accept dots. If you need to
+ # use dots as part of the +:id+ parameter add a constraint which
# overrides this restriction, e.g:
#
# resources :articles, :id => /[^\/]+/
#
- # This allows any character other than a slash as part of your :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
@@ -975,7 +976,7 @@ module ActionDispatch
# resource :geocoder
#
# creates six different routes in your application, all mapping to
- # the GeoCoders controller (note that the controller is named after
+ # the +GeoCoders+ controller (note that the controller is named after
# the plural):
#
# GET /geocoder/new
@@ -1024,7 +1025,7 @@ module ActionDispatch
# resources :photos
#
# creates seven different routes in your application, all mapping to
- # the Photos controller:
+ # the +Photos+ controller:
#
# GET /photos/new
# POST /photos
@@ -1107,11 +1108,11 @@ module ActionDispatch
#
# === Examples
#
- # # routes call Admin::PostsController
+ # # routes call <tt>Admin::PostsController</tt>
# resources :posts, :module => "admin"
#
# # resource actions are at /admin/posts.
- # resources :posts, :path => "admin"
+ # resources :posts, :path => "admin/posts"
def resources(*resources, &block)
options = resources.extract_options!
@@ -1151,7 +1152,7 @@ module ActionDispatch
# end
#
# This will enable Rails to recognize paths such as <tt>/photos/search</tt>
- # with GET, and route to the search action of PhotosController. It will also
+ # with GET, and route to the search action of +PhotosController+. It will also
# create the <tt>search_photos_url</tt> and <tt>search_photos_path</tt>
# route helpers.
def collection
@@ -1175,7 +1176,7 @@ module ActionDispatch
# end
#
# This will recognize <tt>/photos/1/preview</tt> with GET, and route to the
- # preview action of PhotosController. It will also create the
+ # preview action of +PhotosController+. It will also create the
# <tt>preview_photo_url</tt> and <tt>preview_photo_path</tt> helpers.
def member
unless resource_scope?
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index 97e8ccc9a5..5097f6732d 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -224,6 +224,7 @@ module ActionDispatch
self.valid_conditions.push(:controller, :action)
@append = []
+ @prepend = []
@disable_clear_and_finalize = false
clear!
end
@@ -232,7 +233,6 @@ module ActionDispatch
clear! unless @disable_clear_and_finalize
eval_block(block)
finalize! unless @disable_clear_and_finalize
-
nil
end
@@ -240,6 +240,10 @@ module ActionDispatch
@append << block
end
+ def prepend(&block)
+ @prepend << block
+ end
+
def eval_block(block)
if block.arity == 1
raise "You are using the old router DSL which has been removed in Rails 3.1. " <<
@@ -262,8 +266,6 @@ module ActionDispatch
end
def clear!
- # Clear the controller cache so we may discover new ones
- @controller_constraints = nil
@finalized = false
routes.clear
named_routes.clear
@@ -271,6 +273,7 @@ module ActionDispatch
:parameters_key => PARAMETERS_KEY,
:request_class => request_class
)
+ @prepend.each { |blk| eval_block(blk) }
end
def install_helpers(destinations = [ActionController::Base, ActionView::Base], regenerate_code = false)
diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb
index d4db78a25a..5893f86798 100644
--- a/actionpack/lib/action_dispatch/routing/url_for.rb
+++ b/actionpack/lib/action_dispatch/routing/url_for.rb
@@ -131,10 +131,10 @@ module ActionDispatch
#
# Examples:
#
- # url_for :controller => 'tasks', :action => 'testing', :host=>'somehost.org', :port=>'8080' # => 'http://somehost.org:8080/tasks/testing'
- # url_for :controller => 'tasks', :action => 'testing', :host=>'somehost.org', :anchor => 'ok', :only_path => true # => '/tasks/testing#ok'
- # url_for :controller => 'tasks', :action => 'testing', :trailing_slash=>true # => 'http://somehost.org/tasks/testing/'
- # url_for :controller => 'tasks', :action => 'testing', :host=>'somehost.org', :number => '33' # => 'http://somehost.org/tasks/testing?number=33'
+ # url_for :controller => 'tasks', :action => 'testing', :host => 'somehost.org', :port => '8080' # => 'http://somehost.org:8080/tasks/testing'
+ # url_for :controller => 'tasks', :action => 'testing', :host => 'somehost.org', :anchor => 'ok', :only_path => true # => '/tasks/testing#ok'
+ # url_for :controller => 'tasks', :action => 'testing', :trailing_slash => true # => 'http://somehost.org/tasks/testing/'
+ # url_for :controller => 'tasks', :action => 'testing', :host => 'somehost.org', :number => '33' # => 'http://somehost.org/tasks/testing?number=33'
def url_for(options = nil)
case options
when String
diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb
index c67a0664dc..5fa91d1a76 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb
@@ -169,7 +169,7 @@ module ActionDispatch
# assert_select "title", "Welcome"
#
# # Page title is "Welcome" and there is only one title element
- # assert_select "title", {:count=>1, :text=>"Welcome"},
+ # assert_select "title", {:count => 1, :text => "Welcome"},
# "Wrong title or more than one title element"
#
# # Page contains no forms
diff --git a/actionpack/lib/action_dispatch/testing/test_process.rb b/actionpack/lib/action_dispatch/testing/test_process.rb
index d430691429..397bda41d5 100644
--- a/actionpack/lib/action_dispatch/testing/test_process.rb
+++ b/actionpack/lib/action_dispatch/testing/test_process.rb
@@ -29,7 +29,7 @@ module ActionDispatch
@response.redirect_url
end
- # Shortcut for <tt>ARack::Test::UploadedFile.new(ActionController::TestCase.fixture_path + path, type)</tt>:
+ # Shortcut for <tt>Rack::Test::UploadedFile.new(ActionController::TestCase.fixture_path + path, type)</tt>:
#
# post :change_avatar, :avatar => fixture_file_upload('/files/spongebob.png', 'image/png')
#
diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb
index 92b6f7c770..a67b61c1ef 100644
--- a/actionpack/lib/action_view.rb
+++ b/actionpack/lib/action_view.rb
@@ -50,6 +50,7 @@ module ActionView
autoload :Resolver
autoload :PathResolver
autoload :FileSystemResolver
+ autoload :OptimizedFileSystemResolver
autoload :FallbackFileSystemResolver
end
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb
index c98110353f..fd2970b8e2 100644
--- a/actionpack/lib/action_view/base.rb
+++ b/actionpack/lib/action_view/base.rb
@@ -85,11 +85,11 @@ module ActionView #:nodoc:
#
# Here are some basic examples:
#
- # xml.em("emphasized") # => <em>emphasized</em>
- # xml.em { xml.b("emph & bold") } # => <em><b>emph &amp; bold</b></em>
- # xml.a("A Link", "href"=>"http://onestepback.org") # => <a href="http://onestepback.org">A Link</a>
- # xml.target("name"=>"compile", "option"=>"fast") # => <target option="fast" name="compile"\>
- # # NOTE: order of attributes is not specified.
+ # xml.em("emphasized") # => <em>emphasized</em>
+ # xml.em { xml.b("emph & bold") } # => <em><b>emph &amp; bold</b></em>
+ # xml.a("A Link", "href" => "http://onestepback.org") # => <a href="http://onestepback.org">A Link</a>
+ # xml.target("name" => "compile", "option" => "fast") # => <target option="fast" name="compile"\>
+ # # NOTE: order of attributes is not specified.
#
# Any method with a block will be treated as an XML markup tag with nested markup in the block. For example, the following:
#
diff --git a/actionpack/lib/action_view/helpers/atom_feed_helper.rb b/actionpack/lib/action_view/helpers/atom_feed_helper.rb
index 96e5722252..889ea8a763 100644
--- a/actionpack/lib/action_view/helpers/atom_feed_helper.rb
+++ b/actionpack/lib/action_view/helpers/atom_feed_helper.rb
@@ -81,8 +81,8 @@ module ActionView
#
# The Atom spec defines five elements (content rights title subtitle
# summary) which may directly contain xhtml content if :type => 'xhtml'
- # is specified as an attribute. If so, this helper will take care of
- # the enclosing div and xhtml namespace declaration. Example usage:
+ # is specified as an attribute. If so, this helper will take care of
+ # the enclosing div and xhtml namespace declaration. Example usage:
#
# entry.summary :type => 'xhtml' do |xhtml|
# xhtml.p pluralize(order.line_items.count, "line item")
@@ -91,8 +91,8 @@ module ActionView
# end
#
#
- # atom_feed yields an AtomFeedBuilder instance. Nested elements yield
- # an AtomBuilder instance.
+ # <tt>atom_feed</tt> yields an +AtomFeedBuilder+ instance. Nested elements yield
+ # an +AtomBuilder+ instance.
def atom_feed(options = {}, &block)
if options[:schema_date]
options[:schema_date] = options[:schema_date].strftime("%Y-%m-%d") if options[:schema_date].respond_to?(:strftime)
diff --git a/actionpack/lib/action_view/helpers/cache_helper.rb b/actionpack/lib/action_view/helpers/cache_helper.rb
index 385378ea29..e81d03b537 100644
--- a/actionpack/lib/action_view/helpers/cache_helper.rb
+++ b/actionpack/lib/action_view/helpers/cache_helper.rb
@@ -3,7 +3,7 @@ module ActionView
module Helpers
module CacheHelper
# This helper exposes a method for caching fragments of a view
- # rather than an entire action or page. This technique is useful
+ # rather than an entire action or page. This technique is useful
# caching pieces like menus, lists of newstopics, static HTML
# fragments, and so on. This method takes a block that contains
# the content you wish to cache.
diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb
index ead7feb091..3b5f4e694f 100644
--- a/actionpack/lib/action_view/helpers/capture_helper.rb
+++ b/actionpack/lib/action_view/helpers/capture_helper.rb
@@ -135,8 +135,12 @@ module ActionView
# for elements that will be fragment cached.
def content_for(name, content = nil, &block)
content = capture(&block) if block_given?
- result = @view_flow.append(name, content) if content
- result unless content
+ if content
+ @view_flow.append(name, content)
+ nil
+ else
+ @view_flow.get(name)
+ end
end
# The same as +content_for+ but when used with streaming flushes
diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb
index d2ddaafcb3..c78c03a5eb 100644
--- a/actionpack/lib/action_view/helpers/date_helper.rb
+++ b/actionpack/lib/action_view/helpers/date_helper.rb
@@ -12,14 +12,14 @@ module ActionView
# select-type methods share a number of common options that are as follows:
#
# * <tt>:prefix</tt> - overwrites the default prefix of "date" used for the select names. So specifying "birthday"
- # would give birthday[month] instead of date[month] if passed to the select_month method.
+ # would give birthday[month] instead of date[month] if passed to the <tt>select_month</tt> method.
# * <tt>:include_blank</tt> - set to true if it should be possible to set an empty date.
# * <tt>:discard_type</tt> - set to true if you want to discard the type part of the select name. If set to true,
- # the select_month method would use simply "date" (which can be overwritten using <tt>:prefix</tt>) instead of
- # "date[month]".
+ # the <tt>select_month</tt> method would use simply "date" (which can be overwritten using <tt>:prefix</tt>) instead
+ # of "date[month]".
module DateHelper
# Reports the approximate distance in time between two Time or Date objects or integers as seconds.
- # Set <tt>include_seconds</tt> to true if you want more detailed approximations when distance < 1 min, 29 secs
+ # Set <tt>include_seconds</tt> to true if you want more detailed approximations when distance < 1 min, 29 secs.
# Distances are reported based on the following table:
#
# 0 <-> 29 secs # => less than a minute
@@ -119,7 +119,7 @@ module ActionView
end
end
- # Like distance_of_time_in_words, but where <tt>to_time</tt> is fixed to <tt>Time.now</tt>.
+ # Like <tt>distance_of_time_in_words</tt>, but where <tt>to_time</tt> is fixed to <tt>Time.now</tt>.
#
# ==== Examples
# time_ago_in_words(3.minutes.from_now) # => 3 minutes
@@ -176,7 +176,7 @@ module ActionView
# NOTE: Discarded selects will default to 1. So if no month select is available, January will be assumed.
#
# ==== Examples
- # # Generates a date select that when POSTed is stored in the post variable, in the written_on attribute
+ # # Generates a date select that when POSTed is stored in the post variable, in the written_on attribute.
# date_select("post", "written_on")
#
# # Generates a date select that when POSTed is stored in the post variable, in the written_on attribute,
@@ -197,7 +197,7 @@ module ActionView
# # lacking a year field.
# date_select("user", "birthday", :order => [:month, :day])
#
- # # Generates a date select that when POSTed is stored in the user variable, in the birthday attribute
+ # # Generates a date select that when POSTed is stored in the post variable, in the written_on attribute
# # which is initially set to the date 3 days from the current date
# date_select("post", "written_on", :default => 3.days.from_now)
#
@@ -205,7 +205,7 @@ module ActionView
# # that will have a default day of 20.
# date_select("credit_card", "bill_due", :default => { :day => 20 })
#
- # # Generates a date select with custom prompts
+ # # Generates a date select with custom prompts.
# date_select("post", "written_on", :prompt => { :day => 'Select day', :month => 'Select month', :year => 'Select year' })
#
# The selects are prepared for multi-parameter assignment to an Active Record object.
@@ -222,22 +222,23 @@ module ActionView
# with <tt>:ampm</tt> option.
#
# This method will also generate 3 input hidden tags, for the actual year, month and day unless the option
- # <tt>:ignore_date</tt> is set to +true+.
+ # <tt>:ignore_date</tt> is set to +true+. If you set the <tt>:ignore_date</tt> to +true+, you must have a
+ # +date_select+ on the same method within the form otherwise an exception will be raised.
#
# If anything is passed in the html_options hash it will be applied to every select tag in the set.
#
# ==== Examples
- # # Creates a time select tag that, when POSTed, will be stored in the post variable in the sunrise attribute
+ # # Creates a time select tag that, when POSTed, will be stored in the post variable in the sunrise attribute.
# time_select("post", "sunrise")
#
# # Creates a time select tag with a seconds field that, when POSTed, will be stored in the post variables in
# # the sunrise attribute.
# time_select("post", "start_time", :include_seconds => true)
#
- # # You can set the :minute_step to 15 which will give you: 00, 15, 30 and 45.
+ # # You can set the <tt>:minute_step</tt> to 15 which will give you: 00, 15, 30 and 45.
# time_select 'game', 'game_time', {:minute_step => 15}
#
- # # Creates a time select tag with a custom prompt. Use :prompt => true for generic prompts.
+ # # Creates a time select tag with a custom prompt. Use <tt>:prompt => true</tt> for generic prompts.
# time_select("post", "written_on", :prompt => {:hour => 'Choose hour', :minute => 'Choose minute', :second => 'Choose seconds'})
# time_select("post", "written_on", :prompt => {:hour => true}) # generic prompt for hours
# time_select("post", "written_on", :prompt => true) # generic prompts for all
@@ -261,7 +262,7 @@ module ActionView
#
# ==== Examples
# # Generates a datetime select that, when POSTed, will be stored in the post variable in the written_on
- # # attribute
+ # # attribute.
# datetime_select("post", "written_on")
#
# # Generates a datetime select with a year select that starts at 1995 that, when POSTed, will be stored in the
@@ -279,7 +280,7 @@ module ActionView
# # as the written_on attribute.
# datetime_select("post", "written_on", :discard_type => true)
#
- # # Generates a datetime select with a custom prompt. Use :prompt=>true for generic prompts.
+ # # Generates a datetime select with a custom prompt. Use <tt>:prompt => true</tt> for generic prompts.
# datetime_select("post", "written_on", :prompt => {:day => 'Choose day', :month => 'Choose month', :year => 'Choose year'})
# datetime_select("post", "written_on", :prompt => {:hour => true}) # generic prompt for hours
# datetime_select("post", "written_on", :prompt => true) # generic prompts for all
@@ -301,7 +302,7 @@ module ActionView
# ==== Examples
# my_date_time = Time.now + 4.days
#
- # # Generates a datetime select that defaults to the datetime in my_date_time (four days after today)
+ # # Generates a datetime select that defaults to the datetime in my_date_time (four days after today).
# select_datetime(my_date_time)
#
# # Generates a datetime select that defaults to today (no specified datetime)
@@ -331,7 +332,7 @@ module ActionView
# # prefixed with 'payday' rather than 'date'
# select_datetime(my_date_time, :prefix => 'payday')
#
- # # Generates a datetime select with a custom prompt. Use :prompt=>true for generic prompts.
+ # # Generates a datetime select with a custom prompt. Use <tt>:prompt => true</tt> for generic prompts.
# select_datetime(my_date_time, :prompt => {:day => 'Choose day', :month => 'Choose month', :year => 'Choose year'})
# select_datetime(my_date_time, :prompt => {:hour => true}) # generic prompt for hours
# select_datetime(my_date_time, :prompt => true) # generic prompts for all
@@ -350,10 +351,10 @@ module ActionView
# ==== Examples
# my_date = Time.today + 6.days
#
- # # Generates a date select that defaults to the date in my_date (six days after today)
+ # # Generates a date select that defaults to the date in my_date (six days afteri today).
# select_date(my_date)
#
- # # Generates a date select that defaults to today (no specified date)
+ # # Generates a date select that defaults to today (no specified date).
# select_date()
#
# # Generates a date select that defaults to the date in my_date (six days after today)
@@ -361,18 +362,18 @@ module ActionView
# select_date(my_date, :order => [:year, :month, :day])
#
# # Generates a date select that discards the type of the field and defaults to the date in
- # # my_date (six days after today)
+ # # my_date (six days after today).
# select_date(my_date, :discard_type => true)
#
# # Generates a date select that defaults to the date in my_date,
- # # which has fields separated by '/'
+ # # which has fields separated by '/'.
# select_date(my_date, :date_separator => '/')
#
# # Generates a date select that defaults to the datetime in my_date (six days after today)
- # # prefixed with 'payday' rather than 'date'
+ # # prefixed with 'payday' rather than 'date'.
# select_date(my_date, :prefix => 'payday')
#
- # # Generates a date select with a custom prompt. Use :prompt=>true for generic prompts.
+ # # Generates a date select with a custom prompt. Use <tt>:prompt => true</tt> for generic prompts.
# select_date(my_date, :prompt => {:day => 'Choose day', :month => 'Choose month', :year => 'Choose year'})
# select_date(my_date, :prompt => {:hour => true}) # generic prompt for hours
# select_date(my_date, :prompt => true) # generic prompts for all
@@ -381,7 +382,7 @@ module ActionView
DateTimeSelector.new(date, options, html_options).select_date
end
- # Returns a set of html select-tags (one for hour and minute)
+ # Returns a set of html select-tags (one for hour and minute).
# You can set <tt>:time_separator</tt> key to format the output, and
# the <tt>:include_seconds</tt> option to include an input for seconds.
#
@@ -390,28 +391,28 @@ module ActionView
# ==== Examples
# my_time = Time.now + 5.days + 7.hours + 3.minutes + 14.seconds
#
- # # Generates a time select that defaults to the time in my_time
+ # # Generates a time select that defaults to the time in my_time.
# select_time(my_time)
#
- # # Generates a time select that defaults to the current time (no specified time)
+ # # Generates a time select that defaults to the current time (no specified time).
# select_time()
#
# # Generates a time select that defaults to the time in my_time,
- # # which has fields separated by ':'
+ # # which has fields separated by ':'.
# select_time(my_time, :time_separator => ':')
#
# # Generates a time select that defaults to the time in my_time,
- # # that also includes an input for seconds
+ # # that also includes an input for seconds.
# select_time(my_time, :include_seconds => true)
#
# # Generates a time select that defaults to the time in my_time, that has fields
- # # separated by ':' and includes an input for seconds
+ # # separated by ':' and includes an input for seconds.
# select_time(my_time, :time_separator => ':', :include_seconds => true)
#
# # Generate a time select field with hours in the AM/PM format
# select_time(my_time, :ampm => true)
#
- # # Generates a time select with a custom prompt. Use :prompt=>true for generic prompts.
+ # # Generates a time select with a custom prompt. Use <tt>:prompt</tt> to true for generic prompts.
# select_time(my_time, :prompt => {:day => 'Choose day', :month => 'Choose month', :year => 'Choose year'})
# select_time(my_time, :prompt => {:hour => true}) # generic prompt for hours
# select_time(my_time, :prompt => true) # generic prompts for all
@@ -427,17 +428,17 @@ module ActionView
# ==== Examples
# my_time = Time.now + 16.minutes
#
- # # Generates a select field for seconds that defaults to the seconds for the time in my_time
+ # # Generates a select field for seconds that defaults to the seconds for the time in my_time.
# select_second(my_time)
#
- # # Generates a select field for seconds that defaults to the number given
+ # # Generates a select field for seconds that defaults to the number given.
# select_second(33)
#
# # Generates a select field for seconds that defaults to the seconds for the time in my_time
- # # that is named 'interval' rather than 'second'
+ # # that is named 'interval' rather than 'second'.
# select_second(my_time, :field_name => 'interval')
#
- # # Generates a select field for seconds with a custom prompt. Use :prompt=>true for a
+ # # Generates a select field for seconds with a custom prompt. Use <tt>:prompt => true</tt> for a
# # generic prompt.
# select_minute(14, :prompt => 'Choose seconds')
#
@@ -453,17 +454,17 @@ module ActionView
# ==== Examples
# my_time = Time.now + 6.hours
#
- # # Generates a select field for minutes that defaults to the minutes for the time in my_time
+ # # Generates a select field for minutes that defaults to the minutes for the time in my_tiime.
# select_minute(my_time)
#
- # # Generates a select field for minutes that defaults to the number given
+ # # Generates a select field for minutes that defaults to the number given.
# select_minute(14)
#
# # Generates a select field for minutes that defaults to the minutes for the time in my_time
- # # that is named 'stride' rather than 'second'
+ # # that is named 'stride' rather than 'second'.
# select_minute(my_time, :field_name => 'stride')
#
- # # Generates a select field for minutes with a custom prompt. Use :prompt=>true for a
+ # # Generates a select field for minutes with a custom prompt. Use <tt>:prompt => true</tt> for a
# # generic prompt.
# select_minute(14, :prompt => 'Choose minutes')
#
@@ -478,17 +479,17 @@ module ActionView
# ==== Examples
# my_time = Time.now + 6.hours
#
- # # Generates a select field for hours that defaults to the hour for the time in my_time
+ # # Generates a select field for hours that defaults to the hour for the time in my_time.
# select_hour(my_time)
#
- # # Generates a select field for hours that defaults to the number given
+ # # Generates a select field for hours that defaults to the number given.
# select_hour(13)
#
# # Generates a select field for hours that defaults to the minutes for the time in my_time
- # # that is named 'stride' rather than 'second'
+ # # that is named 'stride' rather than 'second'.
# select_hour(my_time, :field_name => 'stride')
#
- # # Generates a select field for hours with a custom prompt. Use :prompt => true for a
+ # # Generates a select field for hours with a custom prompt. Use <tt>:prompt => true</tt> for a
# # generic prompt.
# select_hour(13, :prompt => 'Choose hour')
#
@@ -506,17 +507,17 @@ module ActionView
# ==== Examples
# my_date = Time.today + 2.days
#
- # # Generates a select field for days that defaults to the day for the date in my_date
+ # # Generates a select field for days that defaults to the day for the date in my_date.
# select_day(my_time)
#
- # # Generates a select field for days that defaults to the number given
+ # # Generates a select field for days that defaults to the number given.
# select_day(5)
#
# # Generates a select field for days that defaults to the day for the date in my_date
- # # that is named 'due' rather than 'day'
+ # # that is named 'due' rather than 'day'.
# select_day(my_time, :field_name => 'due')
#
- # # Generates a select field for days with a custom prompt. Use :prompt => true for a
+ # # Generates a select field for days with a custom prompt. Use <tt>:prompt => true</tt> for a
# # generic prompt.
# select_day(5, :prompt => 'Choose day')
#
@@ -539,7 +540,7 @@ module ActionView
# select_month(Date.today)
#
# # Generates a select field for months that defaults to the current month that
- # # is named "start" rather than "month"
+ # # is named "start" rather than "month".
# select_month(Date.today, :field_name => 'start')
#
# # Generates a select field for months that defaults to the current month that
@@ -558,7 +559,7 @@ module ActionView
# # will use keys like "Januar", "Marts."
# select_month(Date.today, :use_month_names => %w(Januar Februar Marts ...))
#
- # # Generates a select field for months with a custom prompt. Use :prompt => true for a
+ # # Generates a select field for months with a custom prompt. Use <tt>:prompt => true</tt> for a
# # generic prompt.
# select_month(14, :prompt => 'Choose month')
#
@@ -574,22 +575,22 @@ module ActionView
#
# ==== Examples
# # Generates a select field for years that defaults to the current year that
- # # has ascending year values
+ # # has ascending year values.
# select_year(Date.today, :start_year => 1992, :end_year => 2007)
#
# # Generates a select field for years that defaults to the current year that
- # # is named 'birth' rather than 'year'
+ # # is named 'birth' rather than 'year'.
# select_year(Date.today, :field_name => 'birth')
#
# # Generates a select field for years that defaults to the current year that
- # # has descending year values
+ # # has descending year values.
# select_year(Date.today, :start_year => 2005, :end_year => 1900)
#
# # Generates a select field for years that defaults to the year 2006 that
- # # has ascending year values
+ # # has ascending year values.
# select_year(2006, :start_year => 2000, :end_year => 2010)
#
- # # Generates a select field for years with a custom prompt. Use :prompt => true for a
+ # # Generates a select field for years with a custom prompt. Use <tt>:prompt => true</tt> for a
# # generic prompt.
# select_year(14, :prompt => 'Choose year')
#
@@ -783,7 +784,7 @@ module ActionView
end
# Returns translated month names, but also ensures that a custom month
- # name array has a leading nil element
+ # name array has a leading nil element.
def month_names
month_names = @options[:use_month_names] || translated_month_names
month_names.unshift(nil) if month_names.size < 13
@@ -791,13 +792,13 @@ module ActionView
end
memoize :month_names
- # Returns translated month names
+ # Returns translated month names.
# => [nil, "January", "February", "March",
# "April", "May", "June", "July",
# "August", "September", "October",
# "November", "December"]
#
- # If :use_short_month option is set
+ # If <tt>:use_short_month</tt> option is set
# => [nil, "Jan", "Feb", "Mar", "Apr", "May", "Jun",
# "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
def translated_month_names
@@ -805,13 +806,13 @@ module ActionView
I18n.translate(key, :locale => @options[:locale])
end
- # Lookup month name for number
+ # Lookup month name for number.
# month_name(1) => "January"
#
- # If :use_month_numbers option is passed
+ # If <tt>:use_month_numbers</tt> option is passed
# month_name(1) => 1
#
- # If :add_month_numbers option is passed
+ # If <tt>:add_month_numbers</tt> option is passed
# month_name(1) => "1 - January"
def month_name(number)
if @options[:use_month_numbers]
@@ -832,16 +833,22 @@ module ActionView
I18n.translate(:'date.order', :locale => @options[:locale]) || []
end
- # Build full select tag from date type and options
+ # Build full select tag from date type and options.
def build_options_and_select(type, selected, options = {})
build_select(type, build_options(selected, options))
end
- # Build select option html from date value and options
+ # Build select option html from date value and options.
# build_options(15, :start => 1, :end => 31)
# => "<option value="1">1</option>
- # <option value=\"2\">2</option>
- # <option value=\"3\">3</option>..."
+ # <option value="2">2</option>
+ # <option value="3">3</option>..."
+ #
+ # If <tt>:step</tt> options is passed
+ # build_options(15, :start => 1, :end => 31, :step => 2)
+ # => "<option value="1">1</option>
+ # <option value="3">3</option>
+ # <option value="5">5</option>..."
def build_options(selected, options = {})
start = options.delete(:start) || 0
stop = options.delete(:end) || 59
@@ -860,7 +867,7 @@ module ActionView
(select_options.join("\n") + "\n").html_safe
end
- # Builds select tag from date type and html select options
+ # Builds select tag from date type and html select options.
# build_select(:month, "<option value="1">January</option>...")
# => "<select id="post_written_on_2i" name="post[written_on(2i)]">
# <option value="1">January</option>...
@@ -880,7 +887,7 @@ module ActionView
(content_tag(:select, select_html.html_safe, select_options) + "\n").html_safe
end
- # Builds a prompt option tag with supplied options or from default options
+ # Builds a prompt option tag with supplied options or from default options.
# prompt_option_tag(:month, :prompt => 'Select month')
# => "<option value="">Select month</option>"
def prompt_option_tag(type, options)
@@ -897,7 +904,7 @@ module ActionView
prompt ? content_tag(:option, prompt, :value => '') : ''
end
- # Builds hidden input tag for date part and value
+ # Builds hidden input tag for date part and value.
# build_hidden(:year, 2008)
# => "<input id="post_written_on_1i" name="post[written_on(1i)]" type="hidden" value="2008" />"
def build_hidden(type, value)
@@ -909,7 +916,7 @@ module ActionView
}.merge(@html_options.slice(:disabled))) + "\n").html_safe
end
- # Returns the name attribute for the input tag
+ # Returns the name attribute for the input tag.
# => post[written_on(1i)]
def input_name_from_type(type)
prefix = @options[:prefix] || ActionView::Helpers::DateTimeSelector::DEFAULT_PREFIX
@@ -923,7 +930,7 @@ module ActionView
@options[:discard_type] ? prefix : "#{prefix}[#{field_name}]"
end
- # Returns the id attribute for the input tag
+ # Returns the id attribute for the input tag.
# => "post_written_on_1i"
def input_id_from_type(type)
input_name_from_type(type).gsub(/([\[\(])|(\]\[)/, '_').gsub(/[\]\)]/, '')
@@ -940,7 +947,7 @@ module ActionView
select.html_safe
end
- # Returns the separator for a given datetime component
+ # Returns the separator for a given datetime component.
def separator(type)
case type
when :year
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index b6bb90a3ce..07e2c8d341 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -243,7 +243,7 @@ module ActionView
#
# === Setting the method
#
- # You can force the form to use the full array of HTTP verbs by setting
+ # You can force the form to use the full array of HTTP verbs by setting
#
# :method => (:get|:post|:put|:delete)
#
@@ -584,8 +584,8 @@ module ActionView
# <% end %>
# ...
# <% end %>
- def fields_for(record, record_object = nil, options = {}, &block)
- builder = instantiate_builder(record, record_object, options, &block)
+ def fields_for(record_name, record_object = nil, options = {}, &block)
+ builder = instantiate_builder(record_name, record_object, options, &block)
output = capture(builder, &block)
output.concat builder.hidden_field(:id) if output && options[:hidden_field_id] && !builder.emitted_hidden_id?
output
@@ -898,16 +898,13 @@ module ActionView
private
- def instantiate_builder(record, *args, &block)
- options = args.extract_options!
- record_object = args.shift
-
- case record
+ def instantiate_builder(record_name, record_object, options, &block)
+ case record_name
when String, Symbol
object = record_object
- object_name = record
+ object_name = record_name
else
- object = record
+ object = record_name
object_name = ActiveModel::Naming.param_key(object)
end
@@ -1219,35 +1216,30 @@ module ActionView
RUBY_EVAL
end
- def fields_for(record_or_name_or_array, *args, &block)
- if options.has_key?(:index)
- index = "[#{options[:index]}]"
- elsif defined?(@auto_index)
- self.object_name = @object_name.to_s.sub(/\[\]$/,"")
- index = "[#{@auto_index}]"
- else
- index = ""
- end
-
- args << {} unless args.last.is_a?(Hash)
- args.last[:builder] ||= options[:builder]
- args.last[:parent_builder] = self
+ def fields_for(record_name, record_object = nil, fields_options = {}, &block)
+ fields_options, record_object = record_object, nil if record_object.is_a?(Hash)
+ fields_options[:builder] ||= options[:builder]
+ fields_options[:parent_builder] = self
- case record_or_name_or_array
+ case record_name
when String, Symbol
- if nested_attributes_association?(record_or_name_or_array)
- return fields_for_with_nested_attributes(record_or_name_or_array, args, block)
- else
- name = record_or_name_or_array
+ if nested_attributes_association?(record_name)
+ return fields_for_with_nested_attributes(record_name, record_object, fields_options, block)
end
else
- object = record_or_name_or_array.is_a?(Array) ? record_or_name_or_array.last : record_or_name_or_array
- name = ActiveModel::Naming.param_key(object)
- args.unshift(object)
+ record_object = record_name.is_a?(Array) ? record_name.last : record_name
+ record_name = ActiveModel::Naming.param_key(record_object)
+ end
+
+ index = if options.has_key?(:index)
+ "[#{options[:index]}]"
+ elsif defined?(@auto_index)
+ self.object_name = @object_name.to_s.sub(/\[\]$/,"")
+ "[#{@auto_index}]"
end
- name = "#{object_name}#{index}[#{name}]"
+ record_name = "#{object_name}#{index}[#{record_name}]"
- @template.fields_for(name, *args, &block)
+ @template.fields_for(record_name, record_object, fields_options, &block)
end
def label(method, text = nil, options = {}, &block)
@@ -1336,10 +1328,8 @@ module ActionView
@object.respond_to?("#{association_name}_attributes=")
end
- def fields_for_with_nested_attributes(association_name, args, block)
+ def fields_for_with_nested_attributes(association_name, association, options, block)
name = "#{object_name}[#{association_name}_attributes]"
- options = args.extract_options!
- association = args.shift
association = convert_to_model(association)
if association.respond_to?(:persisted?)
diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb
index 7698602022..0aaa690129 100644
--- a/actionpack/lib/action_view/helpers/form_options_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_options_helper.rb
@@ -274,10 +274,10 @@ module ActionView
# You can optionally provide html attributes as the last element of the array.
#
# Examples:
- # options_for_select([ "Denmark", ["USA", {:class=>'bold'}], "Sweden" ], ["USA", "Sweden"])
+ # options_for_select([ "Denmark", ["USA", {:class => 'bold'}], "Sweden" ], ["USA", "Sweden"])
# <option value="Denmark">Denmark</option>\n<option value="USA" class="bold" selected="selected">USA</option>\n<option value="Sweden" selected="selected">Sweden</option>
#
- # options_for_select([["Dollar", "$", {:class=>"bold"}], ["Kroner", "DKK", {:onclick => "alert('HI');"}]])
+ # options_for_select([["Dollar", "$", {:class => "bold"}], ["Kroner", "DKK", {:onclick => "alert('HI');"}]])
# <option value="$" class="bold">Dollar</option>\n<option value="DKK" onclick="alert('HI');">Kroner</option>
#
# If you wish to specify disabled option tags, set +selected+ to be a hash, with <tt>:disabled</tt> being either a value
diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb
index 9e0f8f32b7..65a98fb27a 100644
--- a/actionpack/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb
@@ -82,22 +82,22 @@ module ActionView
# select_tag "people", options_from_collection_for_select(@people, "id", "name")
# # <select id="people" name="people"><option value="1">David</option></select>
#
- # select_tag "people", "<option>David</option>"
+ # select_tag "people", "<option>David</option>".html_safe
# # => <select id="people" name="people"><option>David</option></select>
#
- # select_tag "count", "<option>1</option><option>2</option><option>3</option><option>4</option>"
+ # select_tag "count", "<option>1</option><option>2</option><option>3</option><option>4</option>".html_safe
# # => <select id="count" name="count"><option>1</option><option>2</option>
# # <option>3</option><option>4</option></select>
#
- # select_tag "colors", "<option>Red</option><option>Green</option><option>Blue</option>", :multiple => true
+ # select_tag "colors", "<option>Red</option><option>Green</option><option>Blue</option>".html_safe, :multiple => true
# # => <select id="colors" multiple="multiple" name="colors[]"><option>Red</option>
# # <option>Green</option><option>Blue</option></select>
#
- # select_tag "locations", "<option>Home</option><option selected="selected">Work</option><option>Out</option>"
+ # select_tag "locations", "<option>Home</option><option selected="selected">Work</option><option>Out</option>".html_safe
# # => <select id="locations" name="locations"><option>Home</option><option selected='selected'>Work</option>
# # <option>Out</option></select>
#
- # select_tag "access", "<option>Read</option><option>Write</option>", :multiple => true, :class => 'form_input'
+ # select_tag "access", "<option>Read</option><option>Write</option>".html_safe, :multiple => true, :class => 'form_input'
# # => <select class="form_input" id="access" multiple="multiple" name="access[]"><option>Read</option>
# # <option>Write</option></select>
#
@@ -107,7 +107,7 @@ module ActionView
# select_tag "people", options_from_collection_for_select(@people, "id", "name"), :prompt => "Select something"
# # => <select id="people" name="people"><option value="">Select something</option><option value="1">David</option></select>
#
- # select_tag "destination", "<option>NYC</option><option>Paris</option><option>Rome</option>", :disabled => true
+ # select_tag "destination", "<option>NYC</option><option>Paris</option><option>Rome</option>".html_safe, :disabled => true
# # => <select disabled="disabled" id="destination" name="destination"><option>NYC</option>
# # <option>Paris</option><option>Rome</option></select>
def select_tag(name, option_tags = nil, options = {})
diff --git a/actionpack/lib/action_view/helpers/translation_helper.rb b/actionpack/lib/action_view/helpers/translation_helper.rb
index ec9bdd5320..fd8fe417d0 100644
--- a/actionpack/lib/action_view/helpers/translation_helper.rb
+++ b/actionpack/lib/action_view/helpers/translation_helper.rb
@@ -15,10 +15,10 @@ module ActionView
# = Action View Translation Helpers
module Helpers
module TranslationHelper
- # Delegates to I18n#translate but also performs three additional functions.
+ # Delegates to <tt>I18n#translate</tt> but also performs three additional functions.
#
- # First, it'll pass the :rescue_format => :html option to I18n so that any
- # thrown MissingTranslation messages will be turned into inline spans that
+ # First, it'll pass the <tt>:rescue_format => :html</tt> option to I18n so that any
+ # thrown +MissingTranslation+ messages will be turned into inline spans that
#
# * have a "translation-missing" class set,
# * contain the missing key as a title attribute and
@@ -54,7 +54,7 @@ module ActionView
end
alias :t :translate
- # Delegates to I18n.localize with no additional functionality.
+ # Delegates to <tt>I18n.localize</tt> with no additional functionality.
def localize(*args)
I18n.localize(*args)
end
diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb
index ffa9a5bb0b..5488c752cc 100644
--- a/actionpack/lib/action_view/helpers/url_helper.rb
+++ b/actionpack/lib/action_view/helpers/url_helper.rb
@@ -420,7 +420,7 @@ module ActionView
end
# Creates a link tag of the given +name+ using a URL created by the set of
- # +options+ if +condition+ is true, in which case only the name is
+ # +options+ if +condition+ is true, otherwise only the name is
# returned. To specialize the default behavior, you can pass a block that
# accepts the name or the full argument list for +link_to_unless+ (see the examples
# in +link_to_unless+).
diff --git a/actionpack/lib/action_view/path_set.rb b/actionpack/lib/action_view/path_set.rb
index 8b840a6463..e0cb5d6a70 100644
--- a/actionpack/lib/action_view/path_set.rb
+++ b/actionpack/lib/action_view/path_set.rb
@@ -35,7 +35,7 @@ module ActionView #:nodoc:
each_with_index do |path, i|
path = path.to_s if path.is_a?(Pathname)
next unless path.is_a?(String)
- self[i] = FileSystemResolver.new(path)
+ self[i] = OptimizedFileSystemResolver.new(path)
end
end
end
diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb
index 98ecd15aa0..b99d24d281 100644
--- a/actionpack/lib/action_view/template.rb
+++ b/actionpack/lib/action_view/template.rb
@@ -79,9 +79,9 @@ module ActionView
# you are handling out-of-band metadata, you are
# also responsible for alerting the user to any
# problems with converting the user's data to
- # the default_internal.
+ # the <tt>default_internal</tt>.
#
- # To do so, simply raise the raise WrongEncodingError
+ # To do so, simply raise the raise +WrongEncodingError+
# as follows:
#
# raise WrongEncodingError.new(
@@ -198,7 +198,7 @@ module ActionView
# Among other things, this method is responsible for properly setting
# the encoding of the source. Until this point, we assume that the
# source is BINARY data. If no additional information is supplied,
- # we assume the encoding is the same as Encoding.default_external.
+ # we assume the encoding is the same as <tt>Encoding.default_external</tt>.
#
# The user can also specify the encoding via a comment on the first
# line of the template (# encoding: NAME-OF-ENCODING). This will work
@@ -212,8 +212,8 @@ module ActionView
# specifying the encoding. For instance, ERB supports <%# encoding: %>
#
# Otherwise, after we figure out the correct encoding, we then
- # encode the source into Encoding.default_internal. In general,
- # this means that templates will be UTF-8 inside of Rails,
+ # encode the source into <tt>Encoding.default_internal</tt>.
+ # In general, this means that templates will be UTF-8 inside of Rails,
# regardless of the original source encoding.
def compile(view, mod) #:nodoc:
method_name = self.method_name
diff --git a/actionpack/lib/action_view/template/error.rb b/actionpack/lib/action_view/template/error.rb
index e246646963..d4448a7b33 100644
--- a/actionpack/lib/action_view/template/error.rb
+++ b/actionpack/lib/action_view/template/error.rb
@@ -1,3 +1,4 @@
+require "active_support/core_ext/array/wrap"
require "active_support/core_ext/enumerable"
module ActionView
@@ -29,6 +30,7 @@ module ActionView
def initialize(paths, path, prefixes, partial, details, *)
@path = path
+ prefixes = Array.wrap(prefixes)
display_paths = paths.compact.map{ |p| p.to_s.inspect }.join(", ")
template_type = if partial
"partial"
diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb
index 870897958a..2b9427ace5 100644
--- a/actionpack/lib/action_view/template/resolver.rb
+++ b/actionpack/lib/action_view/template/resolver.rb
@@ -10,17 +10,16 @@ module ActionView
attr_reader :name, :prefix, :partial, :virtual
alias_method :partial?, :partial
- def initialize(name, prefix, partial)
- @name, @prefix, @partial = name, prefix, partial
- rebuild(@name, @prefix, @partial)
+ def self.build(name, prefix, partial)
+ virtual = ""
+ virtual << "#{prefix}/" unless prefix.empty?
+ virtual << (partial ? "_#{name}" : name)
+ new name, prefix, partial, virtual
end
- def rebuild(name, prefix, partial)
- @virtual = ""
- @virtual << "#{prefix}/" unless prefix.empty?
- @virtual << (partial ? "_#{name}" : name)
-
- self.replace(@virtual)
+ def initialize(name, prefix, partial, virtual)
+ @name, @prefix, @partial = name, prefix, partial
+ super(virtual)
end
end
@@ -60,7 +59,7 @@ module ActionView
# Helpers that builds a path. Useful for building virtual paths.
def build_path(name, prefix, partial)
- Path.new(name, prefix, partial)
+ Path.build(name, prefix, partial)
end
# Handles templates caching. If a key is given and caching is on
@@ -112,7 +111,8 @@ module ActionView
end
end
- class PathResolver < Resolver
+ # An abstract class that implements a Resolver with path semantics.
+ class PathResolver < Resolver #:nodoc:
EXTENSIONS = [:locale, :formats, :handlers]
DEFAULT_PATTERN = ":prefix/:action{.:locale,}{.:formats,}{.:handlers,}"
@@ -124,13 +124,12 @@ module ActionView
private
def find_templates(name, prefix, partial, details)
- path = build_path(name, prefix, partial)
- extensions = Hash[EXTENSIONS.map { |ext| [ext, details[ext]] }.flatten(0)]
- query(path, extensions, details[:formats])
+ path = Path.build(name, prefix, partial)
+ query(path, details, details[:formats])
end
- def query(path, exts, formats)
- query = build_query(path, exts)
+ def query(path, details, formats)
+ query = build_query(path, details)
templates = []
sanitizer = Hash.new { |h,k| h[k] = Dir["#{File.dirname(k)}/*"] }
@@ -138,7 +137,7 @@ module ActionView
next if File.directory?(p) || !sanitizer[p].include?(p)
handler, format = extract_handler_and_format(p, formats)
- contents = File.open(p, "rb") {|io| io.read }
+ contents = File.open(p, "rb") { |io| io.read }
templates << Template.new(contents, File.expand_path(p), handler,
:virtual_path => path.virtual, :format => format, :updated_at => mtime(p))
@@ -147,18 +146,15 @@ module ActionView
templates
end
- # Helper for building query glob string based on resolver's pattern.
- def build_query(path, exts)
+ # Helper for building query glob string based on resolver's pattern.
+ def build_query(path, details)
query = @pattern.dup
query.gsub!(/\:prefix(\/)?/, path.prefix.empty? ? "" : "#{path.prefix}\\1") # prefix can be empty...
query.gsub!(/\:action/, path.partial? ? "_#{path.name}" : path.name)
- exts.each { |ext, variants|
+ details.each do |ext, variants|
query.gsub!(/\:#{ext}/, "{#{variants.compact.uniq.join(',')}}")
- }
-
- query.gsub!('.{html,', '.{html,text.html,')
- query.gsub!('.{text,', '.{text,text.plain,')
+ end
File.expand_path(query, @path)
end
@@ -235,9 +231,25 @@ module ActionView
alias :== :eql?
end
+ # An Optimized resolver for Rails' most common case.
+ class OptimizedFileSystemResolver < FileSystemResolver #:nodoc:
+ def build_query(path, details)
+ exts = EXTENSIONS.map { |ext| details[ext] }
+ query = File.join(@path, path)
+
+ exts.each do |ext|
+ query << "{"
+ ext.compact.each { |e| query << ".#{e}," }
+ query << "}"
+ end
+
+ query
+ end
+ end
+
# The same as FileSystemResolver but does not allow templates to store
# a virtual path since it is invalid for such resolvers.
- class FallbackFileSystemResolver < FileSystemResolver
+ class FallbackFileSystemResolver < FileSystemResolver #:nodoc:
def self.instances
[new(""), new("/")]
end
diff --git a/actionpack/lib/sprockets/railtie.rb b/actionpack/lib/sprockets/railtie.rb
index 9c10decd60..8cee3babe2 100644
--- a/actionpack/lib/sprockets/railtie.rb
+++ b/actionpack/lib/sprockets/railtie.rb
@@ -34,12 +34,12 @@ module Sprockets
app.assets = asset_environment(app)
ActiveSupport.on_load(:action_view) do
- app.assets.context.instance_eval do
+ app.assets.context_class.instance_eval do
include ::ActionView::Helpers::SprocketsHelper
end
end
- app.routes.append do
+ app.routes.prepend do
mount app.assets => assets.prefix
end
@@ -91,7 +91,7 @@ module Sprockets
compressor
when :yui
require 'yui/compressor'
- YUI::JavaScriptCompressor.new(:munge => true)
+ YUI::CssCompressor.new
else
sym
end
diff --git a/actionpack/test/activerecord/controller_runtime_test.rb b/actionpack/test/activerecord/controller_runtime_test.rb
index 7931da3741..b87b9f9c47 100644
--- a/actionpack/test/activerecord/controller_runtime_test.rb
+++ b/actionpack/test/activerecord/controller_runtime_test.rb
@@ -11,6 +11,10 @@ class ControllerRuntimeLogSubscriberTest < ActionController::TestCase
def show
render :inline => "<%= Project.all %>"
end
+
+ def zero
+ render :inline => "Zero DB runtime"
+ end
end
include ActiveSupport::LogSubscriber::TestHelper
@@ -37,6 +41,15 @@ class ControllerRuntimeLogSubscriberTest < ActionController::TestCase
wait
assert_equal 2, @logger.logged(:info).size
- assert_match(/\(Views: [\d.]+ms | ActiveRecord: [\d.]+ms\)/, @logger.logged(:info)[1])
+ assert_match(/\(Views: [\d.]+ms \| ActiveRecord: [\d.]+ms\)/, @logger.logged(:info)[1])
+ end
+
+ def test_runtime_reset_before_requests
+ ActiveRecord::LogSubscriber.runtime += 12345
+ get :zero
+ wait
+
+ assert_equal 2, @logger.logged(:info).size
+ assert_match(/\(Views: [\d.]+ms \| ActiveRecord: 0.0ms\)/, @logger.logged(:info)[1])
end
end
diff --git a/actionpack/test/activerecord/render_partial_with_record_identification_test.rb b/actionpack/test/activerecord/render_partial_with_record_identification_test.rb
index 99f09286ff..97be5a5bb0 100644
--- a/actionpack/test/activerecord/render_partial_with_record_identification_test.rb
+++ b/actionpack/test/activerecord/render_partial_with_record_identification_test.rb
@@ -36,7 +36,7 @@ class RenderPartialWithRecordIdentificationController < ActionController::Base
end
def render_with_record_collection
- @developers = Developer.find(:all)
+ @developers = Developer.all
render :partial => @developers
end
diff --git a/actionpack/test/controller/params_wrapper_test.rb b/actionpack/test/controller/params_wrapper_test.rb
index 548cd02dc0..a50065bcc7 100644
--- a/actionpack/test/controller/params_wrapper_test.rb
+++ b/actionpack/test/controller/params_wrapper_test.rb
@@ -2,7 +2,21 @@ require 'abstract_unit'
module Admin; class User; end; end
+module ParamsWrapperTestHelp
+ def with_default_wrapper_options(&block)
+ @controller.class._wrapper_options = {:format => [:json]}
+ @controller.class.inherited(@controller.class)
+ yield
+ end
+
+ def assert_parameters(expected)
+ assert_equal expected, self.class.controller_class.last_parameters
+ end
+end
+
class ParamsWrapperTest < ActionController::TestCase
+ include ParamsWrapperTestHelp
+
class UsersController < ActionController::Base
class << self
attr_accessor :last_parameters
@@ -133,8 +147,8 @@ class ParamsWrapperTest < ActionController::TestCase
end
def test_derived_wrapped_keys_from_matching_model
- User.expects(:respond_to?).with(:column_names).returns(true)
- User.expects(:column_names).returns(["username"])
+ User.expects(:respond_to?).with(:attribute_names).returns(true)
+ User.expects(:attribute_names).twice.returns(["username"])
with_default_wrapper_options do
@request.env['CONTENT_TYPE'] = 'application/json'
@@ -145,8 +159,8 @@ class ParamsWrapperTest < ActionController::TestCase
def test_derived_wrapped_keys_from_specified_model
with_default_wrapper_options do
- Person.expects(:respond_to?).with(:column_names).returns(true)
- Person.expects(:column_names).returns(["username"])
+ Person.expects(:respond_to?).with(:attribute_names).returns(true)
+ Person.expects(:attribute_names).twice.returns(["username"])
UsersController.wrap_parameters Person
@@ -156,42 +170,52 @@ class ParamsWrapperTest < ActionController::TestCase
end
end
- private
- def with_default_wrapper_options(&block)
- @controller.class._wrapper_options = {:format => [:json]}
- @controller.class.inherited(@controller.class)
- yield
- end
+ def test_not_wrapping_abstract_model
+ User.expects(:respond_to?).with(:attribute_names).returns(true)
+ User.expects(:attribute_names).returns([])
- def assert_parameters(expected)
- assert_equal expected, UsersController.last_parameters
+ with_default_wrapper_options do
+ @request.env['CONTENT_TYPE'] = 'application/json'
+ post :parse, { 'username' => 'sikachu', 'title' => 'Developer' }
+ assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'user' => { 'username' => 'sikachu', 'title' => 'Developer' }})
end
+ end
end
class NamespacedParamsWrapperTest < ActionController::TestCase
- module Admin
- class UsersController < ActionController::Base
- class << self
- attr_accessor :last_parameters
- end
+ include ParamsWrapperTestHelp
- def parse
- self.class.last_parameters = request.params.except(:controller, :action)
- head :ok
+ module Admin
+ module Users
+ class UsersController < ActionController::Base;
+ class << self
+ attr_accessor :last_parameters
+ end
+
+ def parse
+ self.class.last_parameters = request.params.except(:controller, :action)
+ head :ok
+ end
end
end
end
- class Sample
- def self.column_names
+ class SampleOne
+ def self.attribute_names
["username"]
end
end
- tests Admin::UsersController
+ class SampleTwo
+ def self.attribute_names
+ ["title"]
+ end
+ end
+
+ tests Admin::Users::UsersController
def teardown
- Admin::UsersController.last_parameters = nil
+ Admin::Users::UsersController.last_parameters = nil
end
def test_derived_name_from_controller
@@ -203,7 +227,7 @@ class NamespacedParamsWrapperTest < ActionController::TestCase
end
def test_namespace_lookup_from_model
- Admin.const_set(:User, Class.new(Sample))
+ Admin.const_set(:User, Class.new(SampleOne))
begin
with_default_wrapper_options do
@request.env['CONTENT_TYPE'] = 'application/json'
@@ -216,31 +240,48 @@ class NamespacedParamsWrapperTest < ActionController::TestCase
end
def test_hierarchy_namespace_lookup_from_model
- # Make sure that we cleanup ::Admin::User
- admin_user_constant = ::Admin::User
- ::Admin.send :remove_const, :User
-
- Object.const_set(:User, Class.new(Sample))
+ Object.const_set(:User, Class.new(SampleTwo))
begin
with_default_wrapper_options do
@request.env['CONTENT_TYPE'] = 'application/json'
post :parse, { 'username' => 'sikachu', 'title' => 'Developer' }
- assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'user' => { 'username' => 'sikachu' }})
+ assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'user' => { 'title' => 'Developer' }})
end
ensure
Object.send :remove_const, :User
- ::Admin.const_set(:User, admin_user_constant)
end
end
- private
- def with_default_wrapper_options(&block)
- @controller.class._wrapper_options = {:format => [:json]}
- @controller.class.inherited(@controller.class)
- yield
+end
+
+class AnonymousControllerParamsWrapperTest < ActionController::TestCase
+ include ParamsWrapperTestHelp
+
+ tests(Class.new(ActionController::Base) do
+ class << self
+ attr_accessor :last_parameters
+ end
+
+ def parse
+ self.class.last_parameters = request.params.except(:controller, :action)
+ head :ok
end
+ end)
- def assert_parameters(expected)
- assert_equal expected, Admin::UsersController.last_parameters
+ def test_does_not_implicitly_wrap_params
+ with_default_wrapper_options do
+ @request.env['CONTENT_TYPE'] = 'application/json'
+ post :parse, { 'username' => 'sikachu' }
+ assert_parameters({ 'username' => 'sikachu' })
+ end
+ end
+
+ def test_does_wrap_params_if_name_provided
+ with_default_wrapper_options do
+ @controller.class.wrap_parameters(:name => "guest")
+ @request.env['CONTENT_TYPE'] = 'application/json'
+ post :parse, { 'username' => 'sikachu' }
+ assert_parameters({ 'username' => 'sikachu', 'guest' => { 'username' => 'sikachu' }})
end
+ end
end
diff --git a/actionpack/test/controller/request_forgery_protection_test.rb b/actionpack/test/controller/request_forgery_protection_test.rb
index 31f4bf3a76..dea80ed887 100644
--- a/actionpack/test/controller/request_forgery_protection_test.rb
+++ b/actionpack/test/controller/request_forgery_protection_test.rb
@@ -81,22 +81,25 @@ module RequestForgeryProtectionTests
@token = "cf50faa3fe97702ca1ae"
ActiveSupport::SecureRandom.stubs(:base64).returns(@token)
- ActionController::Base.request_forgery_protection_token = :authenticity_token
+ ActionController::Base.request_forgery_protection_token = :custom_authenticity_token
end
+ def teardown
+ ActionController::Base.request_forgery_protection_token = nil
+ end
def test_should_render_form_with_token_tag
assert_not_blocked do
get :index
end
- assert_select 'form>div>input[name=?][value=?]', 'authenticity_token', @token
+ assert_select 'form>div>input[name=?][value=?]', 'custom_authenticity_token', @token
end
def test_should_render_button_to_with_token_tag
assert_not_blocked do
get :show_button
end
- assert_select 'form>div>input[name=?][value=?]', 'authenticity_token', @token
+ assert_select 'form>div>input[name=?][value=?]', 'custom_authenticity_token', @token
end
def test_should_allow_get
@@ -128,15 +131,15 @@ module RequestForgeryProtectionTests
end
def test_should_allow_post_with_token
- assert_not_blocked { post :index, :authenticity_token => @token }
+ assert_not_blocked { post :index, :custom_authenticity_token => @token }
end
def test_should_allow_put_with_token
- assert_not_blocked { put :index, :authenticity_token => @token }
+ assert_not_blocked { put :index, :custom_authenticity_token => @token }
end
def test_should_allow_delete_with_token
- assert_not_blocked { delete :index, :authenticity_token => @token }
+ assert_not_blocked { delete :index, :custom_authenticity_token => @token }
end
def test_should_allow_post_with_token_in_header
@@ -172,10 +175,18 @@ end
class RequestForgeryProtectionControllerTest < ActionController::TestCase
include RequestForgeryProtectionTests
+ setup do
+ ActionController::Base.request_forgery_protection_token = :custom_authenticity_token
+ end
+
+ teardown do
+ ActionController::Base.request_forgery_protection_token = nil
+ end
+
test 'should emit a csrf-param meta tag and a csrf-token meta tag' do
ActiveSupport::SecureRandom.stubs(:base64).returns(@token + '<=?')
get :meta
- assert_select 'meta[name=?][content=?]', 'csrf-param', 'authenticity_token'
+ assert_select 'meta[name=?][content=?]', 'csrf-param', 'custom_authenticity_token'
assert_select 'meta[name=?][content=?]', 'csrf-token', 'cf50faa3fe97702ca1ae&lt;=?'
end
end
diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb
index d128006404..25b1b4f745 100644
--- a/actionpack/test/dispatch/request_test.rb
+++ b/actionpack/test/dispatch/request_test.rb
@@ -358,6 +358,13 @@ class RequestTest < ActiveSupport::TestCase
assert request.head?
end
+ test "post masquerading as put" do
+ request = stub_request 'REQUEST_METHOD' => 'PUT', "rack.methodoverride.original_method" => "POST"
+ assert_equal "POST", request.method
+ assert_equal "PUT", request.request_method
+ assert request.put?
+ end
+
test "xml format" do
request = stub_request
request.expects(:parameters).at_least_once.returns({ :format => 'xml' })
diff --git a/actionpack/test/dispatch/response_body_is_proc_test.rb b/actionpack/test/dispatch/response_body_is_proc_test.rb
new file mode 100644
index 0000000000..fd94832624
--- /dev/null
+++ b/actionpack/test/dispatch/response_body_is_proc_test.rb
@@ -0,0 +1,37 @@
+require 'abstract_unit'
+
+class ResponseBodyIsProcTest < ActionDispatch::IntegrationTest
+ class TestController < ActionController::Base
+ def test
+ self.response_body = proc { |response, output|
+ output.write 'Hello'
+ }
+ end
+ end
+
+ def test_simple_get
+ with_test_route_set do
+ assert_deprecated do
+ get '/test'
+ end
+ assert_response :success
+ assert_equal 'Hello', response.body
+ end
+ end
+
+ private
+
+ def with_test_route_set(options = {})
+ with_routing do |set|
+ set.draw do
+ match ':action', :to => ::ResponseBodyIsProcTest::TestController
+ end
+
+ @app = self.class.build_app(set) do |middleware|
+ middleware.delete "ActionDispatch::ShowExceptions"
+ end
+
+ yield
+ end
+ end
+end
diff --git a/actionpack/test/template/capture_helper_test.rb b/actionpack/test/template/capture_helper_test.rb
index 592c7da060..a9157e711c 100644
--- a/actionpack/test/template/capture_helper_test.rb
+++ b/actionpack/test/template/capture_helper_test.rb
@@ -38,7 +38,15 @@ class CaptureHelperTest < ActionView::TestCase
assert_equal '&lt;em&gt;bar&lt;/em&gt;', string
end
- def test_content_for
+ def test_capture_used_for_read
+ content_for :foo, "foo"
+ assert_equal "foo", content_for(:foo)
+
+ content_for(:bar){ "bar" }
+ assert_equal "bar", content_for(:bar)
+ end
+
+ def test_content_for_question_mark
assert ! content_for?(:title)
content_for :title, 'title'
assert content_for?(:title)
@@ -49,14 +57,14 @@ class CaptureHelperTest < ActionView::TestCase
assert !content_for?(:title)
provide :title, "hi"
assert content_for?(:title)
- assert_equal "hi", @view_flow.get(:title)
+ assert_equal "hi", content_for(:title)
provide :title, "<p>title</p>"
- assert_equal "hi&lt;p&gt;title&lt;/p&gt;", @view_flow.get(:title)
+ assert_equal "hi&lt;p&gt;title&lt;/p&gt;", content_for(:title)
@view_flow = ActionView::OutputFlow.new
provide :title, "hi"
provide :title, "<p>title</p>".html_safe
- assert_equal "hi<p>title</p>", @view_flow.get(:title)
+ assert_equal "hi<p>title</p>", content_for(:title)
end
def test_with_output_buffer_swaps_the_output_buffer_given_no_argument
diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb
index c25c850eb3..286bfb4d04 100644
--- a/actionpack/test/template/form_helper_test.rb
+++ b/actionpack/test/template/form_helper_test.rb
@@ -1725,6 +1725,20 @@ class FormHelperTest < ActionView::TestCase
assert_dom_equal expected, output_buffer
end
+ def test_form_for_and_fields_for_with_non_nested_association_and_without_object
+ form_for(@post) do |f|
+ concat f.fields_for(:category) { |c|
+ concat c.text_field(:name)
+ }
+ end
+
+ expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', 'put') do
+ "<input name='post[category][name]' type='text' size='30' id='post_category_name' />"
+ end
+
+ assert_dom_equal expected, output_buffer
+ end
+
class LabelledFormBuilder < ActionView::Helpers::FormBuilder
(field_helpers - %w(hidden_field)).each do |selector|
class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
diff --git a/actionpack/test/template/lookup_context_test.rb b/actionpack/test/template/lookup_context_test.rb
index f34a40795a..47b70f05ab 100644
--- a/actionpack/test/template/lookup_context_test.rb
+++ b/actionpack/test/template/lookup_context_test.rb
@@ -256,4 +256,13 @@ class TestMissingTemplate < ActiveSupport::TestCase
end
assert_match %r{Missing partial parent/foo, child/foo with .* Searched in:\n \* "/Path/to/views"\n}, e.message
end
+
+ test "if a single prefix is passed as a string and the lookup fails, MissingTemplate accepts it" do
+ e = assert_raise ActionView::MissingTemplate do
+ details = {:handlers=>[], :formats=>[], :locale=>[]}
+ @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
diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb
index d4e912c410..86d08a43a5 100644
--- a/actionpack/test/template/render_test.rb
+++ b/actionpack/test/template/render_test.rb
@@ -325,7 +325,7 @@ class CachedViewRenderTest < ActiveSupport::TestCase
# Ensure view path cache is primed
def setup
view_paths = ActionController::Base.view_paths
- assert_equal ActionView::FileSystemResolver, view_paths.first.class
+ assert_equal ActionView::OptimizedFileSystemResolver, view_paths.first.class
setup_view(view_paths)
end
diff --git a/activemodel/CHANGELOG b/activemodel/CHANGELOG
index c26924cf09..be4de2e53c 100644
--- a/activemodel/CHANGELOG
+++ b/activemodel/CHANGELOG
@@ -18,7 +18,36 @@
* Add support for selectively enabling/disabling observers [Myron Marston]
-*Rails 3.0.2 (unreleased)*
+*Rails 3.0.7 (April 18, 2011)*
+
+*No changes.
+
+
+*Rails 3.0.6 (April 5, 2011)
+
+* Fix when database column name has some symbolic characters (e.g. Oracle CASE# VARCHAR2(20)) #5818 #6850 [Robert Pankowecki, Santiago Pastorino]
+
+* Fix length validation for fixnums #6556 [Andriy Tyurnikov]
+
+* Fix i18n key collision with namespaced models #6448 [yves.senn]
+
+
+*Rails 3.0.5 (February 26, 2011)*
+
+* No changes.
+
+
+*Rails 3.0.4 (February 8, 2011)*
+
+* No changes.
+
+
+*Rails 3.0.3 (November 16, 2010)*
+
+* No changes.
+
+
+*Rails 3.0.2 (November 15, 2010)*
* No changes
diff --git a/activemodel/lib/active_model/conversion.rb b/activemodel/lib/active_model/conversion.rb
index e3992e842a..1405b1bfe3 100644
--- a/activemodel/lib/active_model/conversion.rb
+++ b/activemodel/lib/active_model/conversion.rb
@@ -21,8 +21,8 @@ module ActiveModel
#
module Conversion
# If your object is already designed to implement all of the Active Model
- # you can use the default to_model implementation, which simply returns
- # self.
+ # you can use the default <tt>:to_model</tt> implementation, which simply
+ # returns self.
#
# If your model does not act like an Active Model object, then you should
# define <tt>:to_model</tt> yourself returning a proxy object that wraps
@@ -35,13 +35,13 @@ module ActiveModel
# if the object is persisted or not.
#
# Note the default implementation uses persisted? just because all objects
- # in Ruby 1.8.x responds to :id.
+ # in Ruby 1.8.x responds to <tt>:id</tt>.
def to_key
persisted? ? [id] : nil
end
# Returns a string representing the object's key suitable for use in URLs,
- # or nil if persisted? is false
+ # or nil if <tt>persisted?</tt> is false.
def to_param
persisted? ? to_key.join('-') : nil
end
diff --git a/activemodel/lib/active_model/mass_assignment_security.rb b/activemodel/lib/active_model/mass_assignment_security.rb
index 01eef762fd..483b577681 100644
--- a/activemodel/lib/active_model/mass_assignment_security.rb
+++ b/activemodel/lib/active_model/mass_assignment_security.rb
@@ -35,17 +35,17 @@ module ActiveModel
# protected
#
# def account_params
- # scope = admin ? :admin : :default
- # sanitize_for_mass_assignment(params[:account], scope)
+ # role = admin ? :admin : :default
+ # sanitize_for_mass_assignment(params[:account], role)
# end
#
# end
#
module ClassMethods
# Attributes named in this macro are protected from mass-assignment
- # whenever attributes are sanitized before assignment. A scope for the
- # attributes is optional, if no scope is provided then :default is used.
- # A scope can be defined by using the :as option.
+ # 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.
#
# Mass-assignment to these attributes will simply be ignored, to assign
# to them you can use direct writer methods. This is meant to protect
@@ -67,7 +67,7 @@ module ActiveModel
# end
# end
#
- # When using a :default scope :
+ # When using the :default role :
#
# customer = Customer.new
# customer.assign_attributes({ "name" => "David", "credit_rating" => "Excellent", :last_login => 1.day.ago }, :as => :default)
@@ -78,7 +78,7 @@ module ActiveModel
# customer.credit_rating = "Average"
# customer.credit_rating # => "Average"
#
- # And using the :admin scope :
+ # And using the :admin role :
#
# customer = Customer.new
# customer.assign_attributes({ "name" => "David", "credit_rating" => "Excellent", :last_login => 1.day.ago }, :as => :admin)
@@ -93,10 +93,10 @@ module ActiveModel
# to sanitize attributes won't provide sufficient protection.
def attr_protected(*args)
options = args.extract_options!
- scope = options[:as] || :default
+ role = options[:as] || :default
self._protected_attributes = protected_attributes_configs.dup
- self._protected_attributes[scope] = self.protected_attributes(scope) + args
+ self._protected_attributes[role] = self.protected_attributes(role) + args
self._active_authorizer = self._protected_attributes
end
@@ -104,8 +104,8 @@ module ActiveModel
# Specifies a white list of model attributes that can be set via
# mass-assignment.
#
- # Like +attr_protected+, a scope for the attributes is optional,
- # if no scope is provided then :default is used. A scope can be defined by
+ # 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.
#
# This is the opposite of the +attr_protected+ macro: Mass-assignment
@@ -131,7 +131,7 @@ module ActiveModel
# end
# end
#
- # When using a :default scope :
+ # When using the :default role :
#
# customer = Customer.new
# customer.assign_attributes({ "name" => "David", "credit_rating" => "Excellent", :last_login => 1.day.ago }, :as => :default)
@@ -141,7 +141,7 @@ module ActiveModel
# customer.credit_rating = "Average"
# customer.credit_rating # => "Average"
#
- # And using the :admin scope :
+ # And using the :admin role :
#
# customer = Customer.new
# customer.assign_attributes({ "name" => "David", "credit_rating" => "Excellent", :last_login => 1.day.ago }, :as => :admin)
@@ -152,20 +152,20 @@ module ActiveModel
# to sanitize attributes won't provide sufficient protection.
def attr_accessible(*args)
options = args.extract_options!
- scope = options[:as] || :default
+ role = options[:as] || :default
self._accessible_attributes = accessible_attributes_configs.dup
- self._accessible_attributes[scope] = self.accessible_attributes(scope) + args
+ self._accessible_attributes[role] = self.accessible_attributes(role) + args
self._active_authorizer = self._accessible_attributes
end
- def protected_attributes(scope = :default)
- protected_attributes_configs[scope]
+ def protected_attributes(role = :default)
+ protected_attributes_configs[role]
end
- def accessible_attributes(scope = :default)
- accessible_attributes_configs[scope]
+ def accessible_attributes(role = :default)
+ accessible_attributes_configs[role]
end
def active_authorizers
@@ -198,12 +198,12 @@ module ActiveModel
protected
- def sanitize_for_mass_assignment(attributes, scope = :default)
- mass_assignment_authorizer(scope).sanitize(attributes)
+ def sanitize_for_mass_assignment(attributes, role = :default)
+ mass_assignment_authorizer(role).sanitize(attributes)
end
- def mass_assignment_authorizer(scope = :default)
- self.class.active_authorizer[scope]
+ def mass_assignment_authorizer(role = :default)
+ self.class.active_authorizer[role]
end
end
end
diff --git a/activemodel/lib/active_model/serializers/xml.rb b/activemodel/lib/active_model/serializers/xml.rb
index d4295e6afe..19639b1363 100644
--- a/activemodel/lib/active_model/serializers/xml.rb
+++ b/activemodel/lib/active_model/serializers/xml.rb
@@ -33,6 +33,7 @@ module ActiveModel
protected
def compute_type
+ return if value.nil?
type = ActiveSupport::XmlMini::TYPE_NAMES[value.class.name]
type ||= :string if value.respond_to?(:to_str)
type ||= :yaml
diff --git a/activemodel/lib/active_model/validations/length.rb b/activemodel/lib/active_model/validations/length.rb
index 72735cfb89..d595a5fb43 100644
--- a/activemodel/lib/active_model/validations/length.rb
+++ b/activemodel/lib/active_model/validations/length.rb
@@ -16,7 +16,7 @@ module ActiveModel
options[:maximum] -= 1 if range.exclude_end?
end
- super(options.reverse_merge(:tokenizer => DEFAULT_TOKENIZER))
+ super
end
def check_validity!
@@ -36,7 +36,7 @@ module ActiveModel
end
def validate_each(record, attribute, value)
- value = options[:tokenizer].call(value) if value.kind_of?(String)
+ value = (options[:tokenizer] || DEFAULT_TOKENIZER).call(value) if value.kind_of?(String)
CHECKS.each do |key, validity_check|
next unless check_value = options[key]
diff --git a/activemodel/lib/active_model/validations/numericality.rb b/activemodel/lib/active_model/validations/numericality.rb
index ae576462e6..42556c80a9 100644
--- a/activemodel/lib/active_model/validations/numericality.rb
+++ b/activemodel/lib/active_model/validations/numericality.rb
@@ -9,10 +9,6 @@ module ActiveModel
RESERVED_OPTIONS = CHECKS.keys + [:only_integer]
- def initialize(options)
- super(options.reverse_merge(:only_integer => false, :allow_nil => false))
- end
-
def check_validity!
keys = CHECKS.keys - [:odd, :even]
options.slice(*keys).each do |option, value|
diff --git a/activemodel/test/cases/mass_assignment_security_test.rb b/activemodel/test/cases/mass_assignment_security_test.rb
index b22ce874ea..43a12eed61 100644
--- a/activemodel/test/cases/mass_assignment_security_test.rb
+++ b/activemodel/test/cases/mass_assignment_security_test.rb
@@ -10,7 +10,7 @@ class MassAssignmentSecurityTest < ActiveModel::TestCase
assert_equal expected, sanitized
end
- def test_only_moderator_scope_attribute_accessible
+ def test_only_moderator_role_attribute_accessible
user = SpecialUser.new
expected = { "name" => "John Smith", "email" => "john@smith.com" }
sanitized = user.sanitize_for_mass_assignment(expected.merge("admin" => true), :moderator)
@@ -27,7 +27,7 @@ class MassAssignmentSecurityTest < ActiveModel::TestCase
assert_equal expected, sanitized
end
- def test_admin_scoped_attributes_accessible
+ def test_attributes_accessible_with_admin_role
user = Person.new
expected = { "name" => "John Smith", "email" => "john@smith.com", "admin" => true }
sanitized = user.sanitize_for_mass_assignment(expected.merge("super_powers" => true), :admin)
diff --git a/activemodel/test/cases/serializers/xml_serialization_test.rb b/activemodel/test/cases/serializers/xml_serialization_test.rb
index b6a2f88667..8f5c196850 100644
--- a/activemodel/test/cases/serializers/xml_serialization_test.rb
+++ b/activemodel/test/cases/serializers/xml_serialization_test.rb
@@ -92,6 +92,10 @@ class XmlSerializationTest < ActiveModel::TestCase
test "should serialize string" do
assert_match %r{<name>aaron stack</name>}, @contact.to_xml
end
+
+ test "should serialize nil" do
+ assert_match %r{<pseudonyms nil=\"true\"></pseudonyms>}, @contact.to_xml(:methods => :pseudonyms)
+ end
test "should serialize integer" do
assert_match %r{<age type="integer">25</age>}, @contact.to_xml
diff --git a/activemodel/test/cases/validations/conditional_validation_test.rb b/activemodel/test/cases/validations/conditional_validation_test.rb
index 3cb95b4a00..e06b04af19 100644
--- a/activemodel/test/cases/validations/conditional_validation_test.rb
+++ b/activemodel/test/cases/validations/conditional_validation_test.rb
@@ -11,7 +11,7 @@ class ConditionalValidationTest < ActiveModel::TestCase
def test_if_validation_using_method_true
# When the method returns true
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :if => :condition_is_true )
+ Topic.validates_length_of( :title, :maximum => 5, :too_long => "hoo %{count}", :if => :condition_is_true )
t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
assert t.invalid?
assert t.errors[:title].any?
@@ -20,7 +20,7 @@ class ConditionalValidationTest < ActiveModel::TestCase
def test_unless_validation_using_method_true
# When the method returns true
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :unless => :condition_is_true )
+ Topic.validates_length_of( :title, :maximum => 5, :too_long => "hoo %{count}", :unless => :condition_is_true )
t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
assert t.valid?
assert t.errors[:title].empty?
@@ -28,7 +28,7 @@ class ConditionalValidationTest < ActiveModel::TestCase
def test_if_validation_using_method_false
# When the method returns false
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :if => :condition_is_true_but_its_not )
+ Topic.validates_length_of( :title, :maximum => 5, :too_long => "hoo %{count}", :if => :condition_is_true_but_its_not )
t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
assert t.valid?
assert t.errors[:title].empty?
@@ -36,7 +36,7 @@ class ConditionalValidationTest < ActiveModel::TestCase
def test_unless_validation_using_method_false
# When the method returns false
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :unless => :condition_is_true_but_its_not )
+ Topic.validates_length_of( :title, :maximum => 5, :too_long => "hoo %{count}", :unless => :condition_is_true_but_its_not )
t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
assert t.invalid?
assert t.errors[:title].any?
@@ -45,7 +45,7 @@ class ConditionalValidationTest < ActiveModel::TestCase
def test_if_validation_using_string_true
# When the evaluated string returns true
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :if => "a = 1; a == 1" )
+ Topic.validates_length_of( :title, :maximum => 5, :too_long => "hoo %{count}", :if => "a = 1; a == 1" )
t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
assert t.invalid?
assert t.errors[:title].any?
@@ -54,7 +54,7 @@ class ConditionalValidationTest < ActiveModel::TestCase
def test_unless_validation_using_string_true
# When the evaluated string returns true
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :unless => "a = 1; a == 1" )
+ Topic.validates_length_of( :title, :maximum => 5, :too_long => "hoo %{count}", :unless => "a = 1; a == 1" )
t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
assert t.valid?
assert t.errors[:title].empty?
@@ -62,7 +62,7 @@ class ConditionalValidationTest < ActiveModel::TestCase
def test_if_validation_using_string_false
# When the evaluated string returns false
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :if => "false")
+ Topic.validates_length_of( :title, :maximum => 5, :too_long => "hoo %{count}", :if => "false")
t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
assert t.valid?
assert t.errors[:title].empty?
@@ -70,7 +70,7 @@ class ConditionalValidationTest < ActiveModel::TestCase
def test_unless_validation_using_string_false
# When the evaluated string returns false
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :unless => "false")
+ Topic.validates_length_of( :title, :maximum => 5, :too_long => "hoo %{count}", :unless => "false")
t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
assert t.invalid?
assert t.errors[:title].any?
@@ -79,7 +79,7 @@ class ConditionalValidationTest < ActiveModel::TestCase
def test_if_validation_using_block_true
# When the block returns true
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}",
+ Topic.validates_length_of( :title, :maximum => 5, :too_long => "hoo %{count}",
:if => Proc.new { |r| r.content.size > 4 } )
t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
assert t.invalid?
@@ -89,7 +89,7 @@ class ConditionalValidationTest < ActiveModel::TestCase
def test_unless_validation_using_block_true
# When the block returns true
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}",
+ Topic.validates_length_of( :title, :maximum => 5, :too_long => "hoo %{count}",
:unless => Proc.new { |r| r.content.size > 4 } )
t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
assert t.valid?
@@ -98,7 +98,7 @@ class ConditionalValidationTest < ActiveModel::TestCase
def test_if_validation_using_block_false
# When the block returns false
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}",
+ Topic.validates_length_of( :title, :maximum => 5, :too_long => "hoo %{count}",
:if => Proc.new { |r| r.title != "uhohuhoh"} )
t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
assert t.valid?
@@ -107,7 +107,7 @@ class ConditionalValidationTest < ActiveModel::TestCase
def test_unless_validation_using_block_false
# When the block returns false
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}",
+ Topic.validates_length_of( :title, :maximum => 5, :too_long => "hoo %{count}",
:unless => Proc.new { |r| r.title != "uhohuhoh"} )
t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
assert t.invalid?
diff --git a/activemodel/test/cases/validations/format_validation_test.rb b/activemodel/test/cases/validations/format_validation_test.rb
index 73647efea5..2ce714fef0 100644
--- a/activemodel/test/cases/validations/format_validation_test.rb
+++ b/activemodel/test/cases/validations/format_validation_test.rb
@@ -27,7 +27,7 @@ class PresenceValidationTest < ActiveModel::TestCase
end
def test_validate_format_with_allow_blank
- Topic.validates_format_of(:title, :with => /^Validation\smacros \w+!$/, :allow_blank=>true)
+ Topic.validates_format_of(:title, :with => /^Validation\smacros \w+!$/, :allow_blank => true)
assert Topic.new("title" => "Shouldn't be valid").invalid?
assert Topic.new("title" => "").valid?
assert Topic.new("title" => nil).valid?
diff --git a/activemodel/test/cases/validations/inclusion_validation_test.rb b/activemodel/test/cases/validations/inclusion_validation_test.rb
index 92c473de0e..413da92de4 100644
--- a/activemodel/test/cases/validations/inclusion_validation_test.rb
+++ b/activemodel/test/cases/validations/inclusion_validation_test.rb
@@ -42,7 +42,7 @@ class InclusionValidationTest < ActiveModel::TestCase
end
def test_validates_inclusion_of_with_allow_nil
- Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ), :allow_nil=>true )
+ Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ), :allow_nil => true )
assert Topic.new("title" => "a!", "content" => "abc").invalid?
assert Topic.new("title" => "", "content" => "abc").invalid?
diff --git a/activemodel/test/cases/validations/length_validation_test.rb b/activemodel/test/cases/validations/length_validation_test.rb
index f02514639b..44048a9c1d 100644
--- a/activemodel/test/cases/validations/length_validation_test.rb
+++ b/activemodel/test/cases/validations/length_validation_test.rb
@@ -11,7 +11,7 @@ class LengthValidationTest < ActiveModel::TestCase
end
def test_validates_length_of_with_allow_nil
- Topic.validates_length_of( :title, :is => 5, :allow_nil=>true )
+ Topic.validates_length_of( :title, :is => 5, :allow_nil => true )
assert Topic.new("title" => "ab").invalid?
assert Topic.new("title" => "").invalid?
@@ -20,7 +20,7 @@ class LengthValidationTest < ActiveModel::TestCase
end
def test_validates_length_of_with_allow_blank
- Topic.validates_length_of( :title, :is => 5, :allow_blank=>true )
+ Topic.validates_length_of( :title, :is => 5, :allow_blank => true )
assert Topic.new("title" => "ab").invalid?
assert Topic.new("title" => "").valid?
@@ -176,16 +176,16 @@ class LengthValidationTest < ActiveModel::TestCase
end
def test_validates_length_of_nasty_params
- assert_raise(ArgumentError) { Topic.validates_length_of(:title, :is=>-6) }
- assert_raise(ArgumentError) { Topic.validates_length_of(:title, :within=>6) }
- assert_raise(ArgumentError) { Topic.validates_length_of(:title, :minimum=>"a") }
- assert_raise(ArgumentError) { Topic.validates_length_of(:title, :maximum=>"a") }
- assert_raise(ArgumentError) { Topic.validates_length_of(:title, :within=>"a") }
- assert_raise(ArgumentError) { Topic.validates_length_of(:title, :is=>"a") }
+ assert_raise(ArgumentError) { Topic.validates_length_of(:title, :is => -6) }
+ assert_raise(ArgumentError) { Topic.validates_length_of(:title, :within => 6) }
+ assert_raise(ArgumentError) { Topic.validates_length_of(:title, :minimum => "a") }
+ assert_raise(ArgumentError) { Topic.validates_length_of(:title, :maximum => "a") }
+ assert_raise(ArgumentError) { Topic.validates_length_of(:title, :within => "a") }
+ assert_raise(ArgumentError) { Topic.validates_length_of(:title, :is => "a") }
end
def test_validates_length_of_custom_errors_for_minimum_with_message
- Topic.validates_length_of( :title, :minimum=>5, :message=>"boo %{count}" )
+ Topic.validates_length_of( :title, :minimum => 5, :message => "boo %{count}" )
t = Topic.new("title" => "uhoh", "content" => "whatever")
assert t.invalid?
assert t.errors[:title].any?
@@ -193,7 +193,7 @@ class LengthValidationTest < ActiveModel::TestCase
end
def test_validates_length_of_custom_errors_for_minimum_with_too_short
- Topic.validates_length_of( :title, :minimum=>5, :too_short=>"hoo %{count}" )
+ Topic.validates_length_of( :title, :minimum => 5, :too_short => "hoo %{count}" )
t = Topic.new("title" => "uhoh", "content" => "whatever")
assert t.invalid?
assert t.errors[:title].any?
@@ -201,7 +201,7 @@ class LengthValidationTest < ActiveModel::TestCase
end
def test_validates_length_of_custom_errors_for_maximum_with_message
- Topic.validates_length_of( :title, :maximum=>5, :message=>"boo %{count}" )
+ Topic.validates_length_of( :title, :maximum => 5, :message => "boo %{count}" )
t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
assert t.invalid?
assert t.errors[:title].any?
@@ -222,7 +222,7 @@ class LengthValidationTest < ActiveModel::TestCase
end
def test_validates_length_of_custom_errors_for_maximum_with_too_long
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}" )
+ Topic.validates_length_of( :title, :maximum => 5, :too_long => "hoo %{count}" )
t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
assert t.invalid?
assert t.errors[:title].any?
@@ -244,7 +244,7 @@ class LengthValidationTest < ActiveModel::TestCase
end
def test_validates_length_of_custom_errors_for_is_with_message
- Topic.validates_length_of( :title, :is=>5, :message=>"boo %{count}" )
+ Topic.validates_length_of( :title, :is => 5, :message => "boo %{count}" )
t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
assert t.invalid?
assert t.errors[:title].any?
@@ -252,7 +252,7 @@ class LengthValidationTest < ActiveModel::TestCase
end
def test_validates_length_of_custom_errors_for_is_with_wrong_length
- Topic.validates_length_of( :title, :is=>5, :wrong_length=>"hoo %{count}" )
+ Topic.validates_length_of( :title, :is => 5, :wrong_length => "hoo %{count}" )
t = Topic.new("title" => "uhohuhoh", "content" => "whatever")
assert t.invalid?
assert t.errors[:title].any?
@@ -331,7 +331,7 @@ class LengthValidationTest < ActiveModel::TestCase
end
def test_validates_length_of_with_block
- Topic.validates_length_of :content, :minimum => 5, :too_short=>"Your essay must be at least %{count} words.",
+ Topic.validates_length_of :content, :minimum => 5, :too_short => "Your essay must be at least %{count} words.",
:tokenizer => lambda {|str| str.scan(/\w+/) }
t = Topic.new(:content => "this content should be long enough")
assert t.valid?
diff --git a/activemodel/test/models/contact.rb b/activemodel/test/models/contact.rb
index f4f3078473..7bfc542afb 100644
--- a/activemodel/test/models/contact.rb
+++ b/activemodel/test/models/contact.rb
@@ -16,6 +16,10 @@ class Contact
options.each { |name, value| send("#{name}=", value) }
end
+ def pseudonyms
+ nil
+ end
+
def persisted?
id
end
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG
index a03751a6c1..502a7e43de 100644
--- a/activerecord/CHANGELOG
+++ b/activerecord/CHANGELOG
@@ -1,6 +1,20 @@
*Rails 3.1.0 (unreleased)*
-* AR#new, AR#create and AR#update_attributes all accept a second hash as option that allows you
+* Add block setting of attributes to singular associations:
+
+ class User < ActiveRecord::Base
+ has_one :account
+ end
+
+ user.build_account{ |a| a.credit_limit => 100.0 }
+
+ The block is called after the instance has been initialized. [Andrew White]
+
+* Add ActiveRecord::Base.attribute_names to return a list of attribute names. This will return an empty array if the model is abstract or table does not exists. [Prem Sichanugrist]
+
+* CSV Fixtures are deprecated and support will be removed in Rails 3.2.0
+
+* AR#new, AR#create, AR#create!, AR#update_attributes and AR#update_attributes! all accept a second hash as option that allows you
to specify which role to consider when assigning attributes. This is built on top of ActiveModel's
new mass assignment capabilities:
@@ -12,7 +26,9 @@
Post.new(params[:post], :as => :admin)
assign_attributes() with similar API was also added and attributes=(params, guard) was deprecated.
-
+
+ Please note that this changes the method signatures for AR#new, AR#create, AR#create!, AR#update_attributes and AR#update_attributes!. If you have overwritten these methods you should update them accordingly.
+
[Josh Kalderimis]
* default_scope can take a block, lambda, or any other object which responds to `call` for lazy
@@ -290,6 +306,84 @@ IrreversibleMigration exception will be raised when going down.
[Aaron Patterson]
+*Rails 3.0.7 (April 18, 2011)*
+
+* Destroying records via nested attributes works independent of reject_if LH #6006 [Durran Jordan]
+
+* Delegate any? and many? to Model.scoped for consistency [Andrew White]
+
+* Quote the ORDER BY clause in batched finds - fixes #6620 [Andrew White]
+
+* Change exists? so records are not instantiated - fixes #6127. This prevents after_find
+ and after_initialize callbacks being triggered when checking for record existence.
+ [Andrew White]
+
+* Fix performance bug with attribute accessors which only occurred on Ruby 1.8.7, and ensure we
+ cache type-casted values when the column returned from the db contains non-standard chars.
+ [Jon Leighton]
+
+* Fix a performance regression introduced here 86acbf1cc050c8fa8c74a10c735e467fb6fd7df8
+ related to read_attribute method [Stian Grytøyr]
+
+
+*Rails 3.0.6 (April 5, 2011)*
+
+* Un-deprecate reorder method [Sebastian Martinez]
+
+* Extensions are applied when calling +except+ or +only+ on relations.
+ Thanks to Iain Hecker.
+
+* Schemas set in set_table_name are respected by the mysql adapter. LH #5322
+
+* Fixed a bug when empty? was called on a grouped Relation that wasn't loaded.
+ LH #5829
+
+* Reapply extensions when using except and only. Thanks Iain Hecker.
+
+* Binary data is escaped when being inserted to SQLite3 Databases. Thanks
+ Naruse!
+
+
+*Rails 3.0.5 (February 26, 2011)*
+
+* Model.where(:column => 1).where(:column => 2) will always produce an AND
+query.
+
+ [Aaron Patterson]
+
+* Deprecated support for interpolated association conditions in the form of :conditions => 'foo = #{bar}'.
+
+ Instead, you should use a proc, like so:
+
+ Before:
+
+ has_many :things, :conditions => 'foo = #{bar}'
+
+ After:
+
+ has_many :things, :conditions => proc { "foo = #{bar}" }
+
+ Inside the proc, 'self' is the object which is the owner of the association, unless you are
+ eager loading the association, in which case 'self' is the class which the association is within.
+
+ You can have any "normal" conditions inside the proc, so the following will work too:
+
+ has_many :things, :conditions => proc { ["foo = ?", bar] }
+
+ Previously :insert_sql and :delete_sql on has_and_belongs_to_many association allowed you to call
+ 'record' to get the record being inserted or deleted. This is now passed as an argument to
+ the proc.
+
+ [Jon Leighton]
+
+
+*Rails 3.0.4 (February 8, 2011)*
+
+* Added deprecation warning for has_and_belongs_to_many associations where the join table has
+ additional attributes other than the keys. Access to these attributes is removed in 3.1.
+ Please use has_many :through instead. [Jon Leighton]
+
+
*Rails 3.0.3 (November 16, 2010)*
* Support find by class like this: Post.where(:name => Post)
@@ -326,10 +420,12 @@ IrreversibleMigration exception will be raised when going down.
[Aaron Patterson]
+
*Rails 3.0.1 (October 15, 2010)*
* Introduce a fix for CVE-2010-3993
+
*Rails 3.0.0 (August 29, 2010)*
* Changed update_attribute to not run callbacks and update the record directly in the database [Neeraj Singh]
@@ -529,12 +625,12 @@ IrreversibleMigration exception will be raised when going down.
* Add Support for updating deeply nested models from a single form. #1202 [Eloy Duran]
- class Book < ActiveRecord::Base
- has_one :author
- has_many :pages
+ class Book < ActiveRecord::Base
+ has_one :author
+ has_many :pages
- accepts_nested_attributes_for :author, :pages
- end
+ accepts_nested_attributes_for :author, :pages
+ end
* Make after_save callbacks fire only if the record was successfully saved. #1735 [Michael Lovitt]
@@ -954,7 +1050,7 @@ so newlines etc are escaped #10385 [Norbert Crombach]
"foo.bar" => "`foo`.`bar`"
* Complete the assimilation of Sexy Migrations from ErrFree [Chris Wanstrath, PJ Hyett]
- http://errtheblog.com/post/2381
+ http://errtheblog.com/post/2381
* Qualified column names work in hash conditions, like :conditions => { 'comments.created_at' => ... }. #9733 [Jack Danger Canty]
@@ -1070,7 +1166,7 @@ single-table inheritance. #3833, #9886 [Gabriel Gironda, rramdas, François Bea
* Improve performance and functionality of the postgresql adapter. Closes #8049 [roderickvd]
- For more information see: http://dev.rubyonrails.org/ticket/8049
+ For more information see: http://dev.rubyonrails.org/ticket/8049
* Don't clobber includes passed to has_many.count [Jack Danger Canty]
@@ -1580,8 +1676,8 @@ during calendar reform. #7649, #7724 [fedot, Geoff Buesing]
* Added support for conditions on Base.exists? #5689 [Josh Peek]. Examples:
assert (Topic.exists?(:author_name => "David"))
- assert (Topic.exists?(:author_name => "Mary", :approved => true))
- assert (Topic.exists?(["parent_id = ?", 1]))
+ assert (Topic.exists?(:author_name => "Mary", :approved => true))
+ assert (Topic.exists?(["parent_id = ?", 1]))
* Schema dumper quotes date :default values. [Dave Thomas]
@@ -2037,8 +2133,8 @@ during calendar reform. #7649, #7724 [fedot, Geoff Buesing]
* Added support for conditions on Base.exists? #5689 [Josh Peek]. Examples:
assert (Topic.exists?(:author_name => "David"))
- assert (Topic.exists?(:author_name => "Mary", :approved => true))
- assert (Topic.exists?(["parent_id = ?", 1]))
+ assert (Topic.exists?(:author_name => "Mary", :approved => true))
+ assert (Topic.exists?(["parent_id = ?", 1]))
* Schema dumper quotes date :default values. [Dave Thomas]
diff --git a/activerecord/README.rdoc b/activerecord/README.rdoc
index a27640eac9..3a89446a83 100644
--- a/activerecord/README.rdoc
+++ b/activerecord/README.rdoc
@@ -219,4 +219,4 @@ API documentation is at
Bug reports and feature requests can be filed with the rest for the Ruby on Rails project here:
-* https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets
+* https://github.com/rails/rails/issues
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index 08fb6bf3c4..9bc44e5163 100644
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -1379,7 +1379,7 @@ module ActiveRecord
# [:touch]
# If true, the associated object will be touched (the updated_at/on attributes set to now)
# when this record is either saved or destroyed. If you specify a symbol, that attribute
- # will be updated with the current time instead of the updated_at/on attribute.
+ # will be updated with the current time in addition to the updated_at/on attribute.
# [:inverse_of]
# Specifies the name of the <tt>has_one</tt> or <tt>has_many</tt> association on the associated
# object that is the inverse of this <tt>belongs_to</tt> association. Does not work in
diff --git a/activerecord/lib/active_record/associations/alias_tracker.rb b/activerecord/lib/active_record/associations/alias_tracker.rb
index 634dee2289..44e2ee141e 100644
--- a/activerecord/lib/active_record/associations/alias_tracker.rb
+++ b/activerecord/lib/active_record/associations/alias_tracker.rb
@@ -50,7 +50,7 @@ module ActiveRecord
end
def pluralize(table_name)
- ActiveRecord::Base.pluralize_table_names ? table_name.to_s.pluralize : table_name
+ ActiveRecord::Base.pluralize_table_names ? table_name.to_s.pluralize : table_name.to_s
end
private
diff --git a/activerecord/lib/active_record/associations/builder/singular_association.rb b/activerecord/lib/active_record/associations/builder/singular_association.rb
index 06a414b874..638a2ec72a 100644
--- a/activerecord/lib/active_record/associations/builder/singular_association.rb
+++ b/activerecord/lib/active_record/associations/builder/singular_association.rb
@@ -13,19 +13,32 @@ module ActiveRecord::Associations::Builder
private
+ def define_readers
+ super
+ name = self.name
+
+ model.redefine_method("#{name}_loaded?") do
+ ActiveSupport::Deprecation.warn(
+ "Calling obj.#{name}_loaded? is deprecated. Please use " \
+ "obj.association(:#{name}).loaded? instead."
+ )
+ association(name).loaded?
+ end
+ end
+
def define_constructors
name = self.name
- model.redefine_method("build_#{name}") do |*params|
- association(name).build(*params)
+ model.redefine_method("build_#{name}") do |*params, &block|
+ association(name).build(*params, &block)
end
- model.redefine_method("create_#{name}") do |*params|
- association(name).create(*params)
+ model.redefine_method("create_#{name}") do |*params, &block|
+ association(name).create(*params, &block)
end
- model.redefine_method("create_#{name}!") do |*params|
- association(name).create!(*params)
+ model.redefine_method("create_#{name}!") do |*params, &block|
+ association(name).create!(*params, &block)
end
end
end
diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb
index 6cdec8c487..902ad8cb64 100644
--- a/activerecord/lib/active_record/associations/collection_association.rb
+++ b/activerecord/lib/active_record/associations/collection_association.rb
@@ -4,7 +4,7 @@ module ActiveRecord
module Associations
# = Active Record Association Collection
#
- # AssociationCollection is an abstract class that provides common stuff to
+ # CollectionAssociation is an abstract class that provides common stuff to
# ease the implementation of association proxies that represent
# collections. See the class hierarchy in AssociationProxy.
#
@@ -94,7 +94,13 @@ module ActiveRecord
end
def build(attributes = {}, options = {}, &block)
- build_or_create(:build, attributes, options, &block)
+ if attributes.is_a?(Array)
+ attributes.collect { |attr| build(attr, options, &block) }
+ else
+ add_to_target(build_record(attributes, options)) do |record|
+ yield(record) if block_given?
+ end
+ end
end
def create(attributes = {}, options = {}, &block)
@@ -102,7 +108,16 @@ module ActiveRecord
raise ActiveRecord::RecordNotSaved, "You cannot call create unless the parent is saved"
end
- build_or_create(:create, attributes, options, &block)
+ if attributes.is_a?(Array)
+ attributes.collect { |attr| create(attr, options, &block) }
+ else
+ transaction do
+ add_to_target(build_record(attributes, options)) do |record|
+ yield(record) if block_given?
+ insert_record(record)
+ end
+ end
+ end
end
def create!(attrs = {}, options = {}, &block)
@@ -321,15 +336,7 @@ module ActiveRecord
def load_target
if find_target?
- targets = []
-
- begin
- targets = find_target
- rescue ActiveRecord::RecordNotFound
- reset
- end
-
- @target = merge_target_lists(targets, target)
+ @target = merge_target_lists(find_target, target)
end
loaded!
@@ -337,20 +344,18 @@ module ActiveRecord
end
def add_to_target(record)
- transaction do
- callback(:before_add, record)
- yield(record) if block_given?
-
- if options[:uniq] && index = @target.index(record)
- @target[index] = record
- else
- @target << record
- end
+ callback(:before_add, record)
+ yield(record) if block_given?
- callback(:after_add, record)
- set_inverse_instance(record)
+ if options[:uniq] && index = @target.index(record)
+ @target[index] = record
+ else
+ @target << record
end
+ callback(:after_add, record)
+ set_inverse_instance(record)
+
record
end
@@ -374,7 +379,7 @@ module ActiveRecord
if options[:finder_sql]
reflection.klass.find_by_sql(custom_finder_sql)
else
- find(:all)
+ scoped.all
end
records = options[:uniq] ? uniq(records) : records
@@ -382,38 +387,35 @@ module ActiveRecord
records
end
- def merge_target_lists(loaded, existing)
- return loaded if existing.empty?
- return existing if loaded.empty?
-
- loaded.map do |f|
- i = existing.index(f)
- if i
- existing.delete_at(i).tap do |t|
- keys = ["id"] + t.changes.keys + (f.attribute_names - t.attribute_names)
- # FIXME: this call to attributes causes many NoMethodErrors
- attributes = f.attributes
- (attributes.keys - keys).each do |k|
- t.send("#{k}=", attributes[k])
- end
+ # We have some records loaded from the database (persisted) and some that are
+ # in-memory (memory). The same record may be represented in the persisted array
+ # and in the memory array.
+ #
+ # So the task of this method is to merge them according to the following rules:
+ #
+ # * The final array must not have duplicates
+ # * The order of the persisted array is to be preserved
+ # * Any changes made to attributes on objects in the memory array are to be preserved
+ # * Otherwise, attributes should have the value found in the database
+ def merge_target_lists(persisted, memory)
+ return persisted if memory.empty?
+ return memory if persisted.empty?
+
+ persisted.map! do |record|
+ mem_record = memory.delete(record)
+
+ if mem_record
+ (record.attribute_names - mem_record.changes.keys).each do |name|
+ mem_record[name] = record[name]
end
- else
- f
- end
- end + existing
- end
- def build_or_create(method, attributes, options)
- records = Array.wrap(attributes).map do |attrs|
- record = build_record(attrs, options)
-
- add_to_target(record) do
- yield(record) if block_given?
- insert_record(record) if method == :create
+ mem_record
+ else
+ record
end
end
- attributes.is_a?(Array) ? records : records.first
+ persisted + memory
end
# Do the relevant stuff to insert the given record into the association collection.
@@ -421,8 +423,15 @@ module ActiveRecord
raise NotImplementedError
end
+ def create_scope
+ scoped.scope_for_create.stringify_keys
+ end
+
def build_record(attributes, options)
- reflection.build_association(scoped.scope_for_create.merge(attributes), options)
+ record = reflection.build_association(attributes, options)
+ record.assign_attributes(create_scope.except(*record.changed), :without_protection => true)
+ record.assign_attributes(attributes, options)
+ record
end
def delete_or_destroy(records, method)
diff --git a/activerecord/lib/active_record/associations/has_one_association.rb b/activerecord/lib/active_record/associations/has_one_association.rb
index 7134dc85c8..2f3a6e71f1 100644
--- a/activerecord/lib/active_record/associations/has_one_association.rb
+++ b/activerecord/lib/active_record/associations/has_one_association.rb
@@ -10,7 +10,7 @@ module ActiveRecord
reflection.klass.transaction do
if target && target != record
- remove_target!(options[:dependent])
+ remove_target!(options[:dependent]) unless target.destroyed?
end
if record
diff --git a/activerecord/lib/active_record/associations/singular_association.rb b/activerecord/lib/active_record/associations/singular_association.rb
index ea4d73d414..68fe0bde76 100644
--- a/activerecord/lib/active_record/associations/singular_association.rb
+++ b/activerecord/lib/active_record/associations/singular_association.rb
@@ -17,20 +17,28 @@ module ActiveRecord
replace(record)
end
- def create(attributes = {}, options = {})
- new_record(:create, attributes, options)
+ def create(attributes = {}, options = {}, &block)
+ build(attributes, options, &block).tap { |record| record.save }
end
- def create!(attributes = {}, options = {})
- build(attributes, options).tap { |record| record.save! }
+ def create!(attributes = {}, options = {}, &block)
+ build(attributes, options, &block).tap { |record| record.save! }
end
- def build(attributes = {}, options = {})
- new_record(:build, attributes, options)
+ def build(attributes = {}, options = {}, &block)
+ record = reflection.build_association(attributes, options)
+ record.assign_attributes(create_scope.except(*record.changed), :without_protection => true)
+ yield(record) if block_given?
+ set_new_record(record)
+ record
end
private
+ def create_scope
+ scoped.scope_for_create.stringify_keys.except(klass.primary_key)
+ end
+
def find_target
scoped.first.tap { |record| set_inverse_instance(record) }
end
@@ -43,13 +51,6 @@ module ActiveRecord
def set_new_record(record)
replace(record)
end
-
- def new_record(method, attributes, options)
- attributes = scoped.scope_for_create.merge(attributes || {})
- record = reflection.send("#{method}_association", attributes, options)
- set_new_record(record)
- record
- end
end
end
end
diff --git a/activerecord/lib/active_record/associations/through_association.rb b/activerecord/lib/active_record/associations/through_association.rb
index e6ab628719..53c5c3cedf 100644
--- a/activerecord/lib/active_record/associations/through_association.rb
+++ b/activerecord/lib/active_record/associations/through_association.rb
@@ -14,7 +14,10 @@ module ActiveRecord
def target_scope
scope = super
chain[1..-1].each do |reflection|
- scope = scope.merge(reflection.klass.scoped)
+ scope = scope.merge(
+ reflection.klass.scoped.with_default_scope.
+ except(:select, :create_with)
+ )
end
scope
end
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 78318b1be0..cd16b8d3ca 100644
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -482,7 +482,7 @@ module ActiveRecord #:nodoc:
# # Create a single new object
# User.create(:first_name => 'Jamie')
#
- # # Create a single new object using the :admin mass-assignment security scope
+ # # Create a single new object using the :admin mass-assignment security role
# User.create({ :first_name => 'Jamie', :is_admin => true }, :as => :admin)
#
# # Create a single new object bypassing mass-assignment security
@@ -767,6 +767,17 @@ module ActiveRecord #:nodoc:
super || (table_exists? && column_names.include?(attribute.to_s.sub(/=$/, '')))
end
+ # Returns an array of column names as strings if it's not
+ # an abstract class and table exists.
+ # Otherwise it returns an empty array.
+ def attribute_names
+ @attribute_names ||= if !abstract_class? && table_exists?
+ column_names
+ else
+ []
+ end
+ end
+
# Set the lookup ancestors for ActiveModel.
def lookup_ancestors #:nodoc:
klass = self
@@ -895,7 +906,7 @@ module ActiveRecord #:nodoc:
# not use the default_scope:
#
# Post.unscoped {
- # limit(10) # Fires "SELECT * FROM posts LIMIT 10"
+ # Post.limit(10) # Fires "SELECT * FROM posts LIMIT 10"
# }
#
# It is recommended to use block form of unscoped because chaining unscoped with <tt>scope</tt>
@@ -1486,7 +1497,7 @@ MSG
# # Instantiates a single new object
# User.new(:first_name => 'Jamie')
#
- # # Instantiates a single new object using the :admin mass-assignment security scope
+ # # Instantiates a single new object using the :admin mass-assignment security role
# User.new({ :first_name => 'Jamie', :is_admin => true }, :as => :admin)
#
# # Instantiates a single new object bypassing mass-assignment security
@@ -1652,17 +1663,16 @@ MSG
return unless new_attributes.is_a?(Hash)
- guard_protected_attributes ||= true
- if guard_protected_attributes
- assign_attributes(new_attributes)
- else
+ if guard_protected_attributes == false
assign_attributes(new_attributes, :without_protection => true)
+ else
+ assign_attributes(new_attributes)
end
end
# Allows you to set all the attributes for a particular mass-assignment
- # security scope by passing in a hash of attributes with keys matching
- # the attribute names (which again matches the column names) and the scope
+ # security role by passing in a hash of attributes with keys matching
+ # the attribute names (which again matches the column names) and the role
# name using the :as option.
#
# To bypass mass-assignment security you can use the :without_protection => true
@@ -1688,13 +1698,15 @@ MSG
# user.name # => "Josh"
# user.is_admin? # => true
def assign_attributes(new_attributes, options = {})
+ return unless new_attributes
+
attributes = new_attributes.stringify_keys
- scope = options[:as] || :default
+ role = options[:as] || :default
multi_parameter_attributes = []
unless options[:without_protection]
- attributes = sanitize_for_mass_assignment(attributes, scope)
+ attributes = sanitize_for_mass_assignment(attributes, role)
end
attributes.each do |k, v|
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
index 3045e30407..b3eb23bbb3 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
@@ -6,15 +6,7 @@ module ActiveRecord
# Returns an array of record hashes with the column names as keys and
# column values as values.
def select_all(sql, name = nil, binds = [])
- if supports_statement_cache?
- select(sql, name, binds)
- else
- return select(sql, name) if binds.empty?
- binds = binds.dup
- select sql.gsub('?') {
- quote(*binds.shift.reverse)
- }, name
- end
+ select(sql, name, binds)
end
# Returns a record hash with the column names as keys and column values
diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
index 8af22fe9f5..ac2da73a84 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
@@ -184,6 +184,10 @@ module ActiveRecord
QUOTED_FALSE
end
+ def substitute_at(column, index)
+ Arel.sql "\0"
+ end
+
# REFERENTIAL INTEGRITY ====================================
def disable_referential_integrity(&block) #:nodoc:
@@ -292,14 +296,14 @@ module ActiveRecord
binds = binds.dup
# Pretend to support bind parameters
- execute sql.gsub('?') { quote(*binds.shift.reverse) }, name
+ execute sql.gsub("\0") { quote(*binds.shift.reverse) }, name
end
def exec_delete(sql, name, binds)
binds = binds.dup
# Pretend to support bind parameters
- execute sql.gsub('?') { quote(*binds.shift.reverse) }, name
+ execute sql.gsub("\0") { quote(*binds.shift.reverse) }, name
@connection.affected_rows
end
alias :exec_update :exec_delete
@@ -646,7 +650,8 @@ module ActiveRecord
# Returns an array of record hashes with the column names as keys and
# column values as values.
def select(sql, name = nil, binds = [])
- exec_query(sql, name, binds).to_a
+ binds = binds.dup
+ exec_query(sql.gsub("\0") { quote(*binds.shift.reverse) }, name).to_a
end
def exec_query(sql, name = 'SQL', binds = [])
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 37db2be7a9..f4beeceb61 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -39,6 +39,16 @@ module ActiveRecord
# :stopdoc:
class << self
attr_accessor :money_precision
+ def string_to_time(string)
+ return string unless String === string
+
+ case string
+ when 'infinity' then 1.0 / 0.0
+ when '-infinity' then -1.0 / 0.0
+ else
+ super
+ end
+ end
end
# :startdoc:
@@ -349,6 +359,9 @@ module ActiveRecord
return super unless column
case value
+ when Float
+ return super unless value.infinite? && column.type == :datetime
+ "'#{value.to_s.downcase}'"
when Numeric
return super unless column.sql_type == 'money'
# Not truly string input, so doesn't require (or allow) escape string syntax.
diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb
index 0e3ed7aac7..4aa6389a04 100644
--- a/activerecord/lib/active_record/fixtures.rb
+++ b/activerecord/lib/active_record/fixtures.rb
@@ -13,6 +13,7 @@ require 'active_support/core_ext/array/wrap'
require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/logger'
require 'active_support/ordered_hash'
+require 'active_support/core_ext/module/deprecation'
if defined? ActiveRecord
class FixtureClassNotFound < ActiveRecord::ActiveRecordError #:nodoc:
@@ -28,11 +29,9 @@ class FixturesFileNotFound < StandardError; end
#
# = Fixture formats
#
-# Fixtures come in 3 flavors:
+# Fixtures come in 1 flavor:
#
# 1. YAML fixtures
-# 2. CSV fixtures
-# 3. Single-file fixtures
#
# == YAML fixtures
#
@@ -74,56 +73,6 @@ class FixturesFileNotFound < StandardError; end
# parent_id: 1
# title: Child
#
-# == CSV fixtures
-#
-# Fixtures can also be kept in the Comma Separated Value (CSV) format. Akin to YAML fixtures, CSV fixtures are stored
-# in a single file, but instead end with the <tt>.csv</tt> file extension
-# (Rails example: <tt><your-rails-app>/test/fixtures/web_sites.csv</tt>).
-#
-# The format of this type of fixture file is much more compact than the others, but also a little harder to read by us
-# humans. The first line of the CSV file is a comma-separated list of field names. The rest of the
-# file is then comprised
-# of the actual data (1 per line). Here's an example:
-#
-# id, name, url
-# 1, Ruby On Rails, http://www.rubyonrails.org
-# 2, Google, http://www.google.com
-#
-# Should you have a piece of data with a comma character in it, you can place double quotes around that value. If you
-# need to use a double quote character, you must escape it with another double quote.
-#
-# Another unique attribute of the CSV fixture is that it has *no* fixture name like the other two formats. Instead, the
-# fixture names are automatically generated by deriving the class name of the fixture file and adding an incrementing
-# number to the end. In our example, the 1st fixture would be called "web_site_1" and the 2nd one would be called
-# "web_site_2".
-#
-# Most databases and spreadsheets support exporting to CSV format, so this is a great format for you to choose if you
-# have existing data somewhere already.
-#
-# == Single-file fixtures
-#
-# This type of fixture was the original format for Active Record that has since been deprecated in
-# favor of the YAML and CSV formats.
-# Fixtures for this format are created by placing text files in a sub-directory (with the name of the model)
-# to the directory appointed by <tt>ActiveSupport::TestCase.fixture_path=(path)</tt> (this is automatically
-# configured for Rails, so you can just put your files in <tt><your-rails-app>/test/fixtures/<your-model-name>/</tt> --
-# like <tt><your-rails-app>/test/fixtures/web_sites/</tt> for the WebSite model).
-#
-# Each text file placed in this directory represents a "record". Usually these types of fixtures are named without
-# extensions, but if you are on a Windows machine, you might consider adding <tt>.txt</tt> as the extension.
-# Here's what the above example might look like:
-#
-# web_sites/google
-# web_sites/yahoo.txt
-# web_sites/ruby-on-rails
-#
-# The file format of a standard fixture is simple. Each line is a property (or column in db speak) and has the syntax
-# of "name => value". Here's an example of the ruby-on-rails fixture above:
-#
-# id => 1
-# name => Ruby on Rails
-# url => http://www.rubyonrails.org
-#
# = Using fixtures in testcases
#
# Since fixtures are a testing construct, we use them in our unit and functional tests. There are two ways to use the
@@ -176,7 +125,7 @@ class FixturesFileNotFound < StandardError; end
# = Dynamic fixtures with ERB
#
# Some times you don't care about the content of the fixtures as much as you care about the volume. In these cases, you can
-# mix ERB in with your YAML or CSV fixtures to create a bunch of fixtures for load testing, like:
+# mix ERB in with your YAML fixtures to create a bunch of fixtures for load testing, like:
#
# <% for i in 1..1000 %>
# fix_<%= i %>:
@@ -752,6 +701,7 @@ module ActiveRecord
fixtures["#{@class_name.to_s.underscore}_#{i+=1}"] = ActiveRecord::Fixture.new(data, model_class)
end
end
+ deprecate :read_csv_fixture_files
def yaml_file_path
"#{@fixture_path}.yml"
diff --git a/activerecord/lib/active_record/identity_map.rb b/activerecord/lib/active_record/identity_map.rb
index f88ead9ca0..b15b5a8133 100644
--- a/activerecord/lib/active_record/identity_map.rb
+++ b/activerecord/lib/active_record/identity_map.rb
@@ -12,10 +12,36 @@ module ActiveRecord
# In order to enable IdentityMap, set <tt>config.active_record.identity_map = true</tt>
# in your <tt>config/application.rb</tt> file.
#
- # IdentityMap is disabled by default.
+ # IdentityMap is disabled by default and still in development (i.e. use it with care).
+ #
+ # == Associations
+ #
+ # Active Record Identity Map does not track associations yet. For example:
+ #
+ # comment = @post.comments.first
+ # comment.post = nil
+ # @post.comments.include?(comment) #=> true
+ #
+ # Ideally, the example above would return false, removing the comment object from the
+ # post association when the association is nullified. This may cause side effects, as
+ # in the situation below, if Identity Map is enabled:
+ #
+ # Post.has_many :comments, :dependent => :destroy
+ #
+ # comment = @post.comments.first
+ # comment.post = nil
+ # comment.save
+ # Post.destroy(@post.id)
+ #
+ # Without using Identity Map, the code above will destroy the @post object leaving
+ # the comment object intact. However, once we enable Identity Map, the post loaded
+ # by Post.destroy is exactly the same object as the object @post. As the object @post
+ # still has the comment object in @post.comments, once Identity Map is enabled, the
+ # comment object will be accidently removed.
+ #
+ # This inconsistency is meant to be fixed in future Rails releases.
#
module IdentityMap
- extend ActiveSupport::Concern
class << self
def enabled=(flag)
@@ -53,7 +79,7 @@ module ActiveRecord
if record.is_a?(klass)
ActiveSupport::Notifications.instrument("identity.active_record",
- :line => "From Identity Map (id: #{primary_key})",
+ :line => "From Identity Map (id: #{primary_key})",
:name => "#{klass} Loaded",
:connection_id => object_id)
diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb
index 9a31675782..cdedcde0eb 100644
--- a/activerecord/lib/active_record/locking/optimistic.rb
+++ b/activerecord/lib/active_record/locking/optimistic.rb
@@ -94,7 +94,7 @@ module ActiveRecord
relation = self.class.unscoped
stmt = relation.where(
- relation.table[self.class.primary_key].eq(quoted_id).and(
+ relation.table[self.class.primary_key].eq(id).and(
relation.table[lock_col].eq(quote_value(previous_lock_value))
)
).arel.compile_update(arel_attributes_values(false, false, attribute_names))
diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb
index b4531ed35f..b9041f44d8 100644
--- a/activerecord/lib/active_record/persistence.rb
+++ b/activerecord/lib/active_record/persistence.rb
@@ -146,7 +146,7 @@ module ActiveRecord
# will fail and false will be returned.
#
# When updating model attributes, mass-assignment security protection is respected.
- # If no +:as+ option is supplied then the +:default+ scope will be used.
+ # If no +:as+ option is supplied then the +:default+ role will be used.
# If you want to bypass the protection given by +attr_protected+ and
# +attr_accessible+ then you can do so using the +:without_protection+ option.
def update_attributes(attributes, options = {})
diff --git a/activerecord/lib/active_record/railties/controller_runtime.rb b/activerecord/lib/active_record/railties/controller_runtime.rb
index bc6ca936c0..9e3b3429e4 100644
--- a/activerecord/lib/active_record/railties/controller_runtime.rb
+++ b/activerecord/lib/active_record/railties/controller_runtime.rb
@@ -2,13 +2,21 @@ require 'active_support/core_ext/module/attr_internal'
module ActiveRecord
module Railties
- module ControllerRuntime
+ module ControllerRuntime #:nodoc:
extend ActiveSupport::Concern
protected
attr_internal :db_runtime
+ def process_action(action, *args)
+ # We also need to reset the runtime before each action
+ # because of queries in middleware or in cases we are streaming
+ # and it won't be cleaned up by the method below.
+ ActiveRecord::LogSubscriber.reset_runtime
+ super
+ end
+
def cleanup_view_runtime
if ActiveRecord::Base.connected?
db_rt_before_render = ActiveRecord::LogSubscriber.reset_runtime
diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake
index c6bc040f9f..85ad43b35f 100644
--- a/activerecord/lib/active_record/railties/databases.rake
+++ b/activerecord/lib/active_record/railties/databases.rake
@@ -203,18 +203,18 @@ db_namespace = namespace :db do
# only files matching "20091231235959_some_name.rb" pattern
if match_data = /^(\d{14})_(.+)\.rb$/.match(file)
status = db_list.delete(match_data[1]) ? 'up' : 'down'
- file_list << [status, match_data[1], match_data[2]]
+ file_list << [status, match_data[1], match_data[2].humanize]
end
end
+ db_list.map! do |version|
+ ['up', version, '********** NO FILE **********']
+ end
# output
puts "\ndatabase: #{config['database']}\n\n"
puts "#{'Status'.center(8)} #{'Migration ID'.ljust(14)} Migration Name"
puts "-" * 50
- file_list.each do |file|
- puts "#{file[0].center(8)} #{file[1].ljust(14)} #{file[2].humanize}"
- end
- db_list.each do |version|
- puts "#{'up'.center(8)} #{version.ljust(14)} *** NO FILE ***"
+ (db_list + file_list).sort_by {|migration| migration[1]}.each do |migration|
+ puts "#{migration[0].center(8)} #{migration[1].ljust(14)} #{migration[2]}"
end
puts
end
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index 869eebfa34..0fcae92d51 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -146,7 +146,7 @@ module ActiveRecord
if options.except(:distinct).present?
apply_finder_options(options.except(:distinct)).calculate(operation, column_name, :distinct => options[:distinct])
else
- if eager_loading? || includes_values.present?
+ if eager_loading? || (includes_values.present? && references_eager_loaded_tables?)
construct_relation_for_association_calculations.calculate(operation, column_name, options)
else
perform_calculation(operation, column_name, options)
@@ -161,21 +161,20 @@ module ActiveRecord
def perform_calculation(operation, column_name, options = {})
operation = operation.to_s.downcase
- distinct = nil
+ distinct = options[:distinct]
if operation == "count"
column_name ||= (select_for_count || :all)
unless arel.ast.grep(Arel::Nodes::OuterJoin).empty?
distinct = true
- column_name = primary_key if column_name == :all
end
+ column_name = primary_key if column_name == :all && distinct
+
distinct = nil if column_name =~ /\s*DISTINCT\s+/i
end
- distinct = options[:distinct] || distinct
-
if @group_values.any?
execute_grouped_calculation(operation, column_name, distinct)
else
@@ -197,7 +196,7 @@ module ActiveRecord
def execute_simple_calculation(operation, column_name, distinct) #:nodoc:
# Postgresql doesn't like ORDER BY when there are no GROUP BY
- relation = except(:order)
+ relation = reorder(nil)
if operation == "count" && (relation.limit_value || relation.offset_value)
# Shortcut when limit is zero.
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index 57c9921ea8..32d1cff6c3 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -375,7 +375,12 @@ module ActiveRecord
if loaded?
@records.last
else
- @last ||= reverse_order.limit(1).to_a[0]
+ @last ||=
+ if offset_value || limit_value
+ to_a.last
+ else
+ reverse_order.limit(1).to_a[0]
+ end
end
end
diff --git a/activerecord/lib/active_record/session_store.rb b/activerecord/lib/active_record/session_store.rb
index 7e77aefb21..c3e976002e 100644
--- a/activerecord/lib/active_record/session_store.rb
+++ b/activerecord/lib/active_record/session_store.rb
@@ -40,7 +40,7 @@ module ActiveRecord
# You must implement these methods:
#
# self.find_by_session_id(session_id)
- # initialize(hash_of_session_id_and_data)
+ # initialize(hash_of_session_id_and_data, options_hash = {})
# attr_reader :session_id
# attr_accessor :data
# save
@@ -83,6 +83,8 @@ module ActiveRecord
cattr_accessor :data_column_name
self.data_column_name = 'data'
+ attr_accessible :session_id, :data, :marshaled_data
+
before_save :marshal_data!
before_save :raise_on_session_data_overflow!
@@ -123,7 +125,7 @@ module ActiveRecord
end
end
- def initialize(attributes = nil)
+ def initialize(attributes = nil, options = {})
@data = nil
super
end
diff --git a/activerecord/lib/active_record/test_case.rb b/activerecord/lib/active_record/test_case.rb
index 29efbbcb8c..0d47eb3338 100644
--- a/activerecord/lib/active_record/test_case.rb
+++ b/activerecord/lib/active_record/test_case.rb
@@ -13,6 +13,13 @@ module ActiveRecord
ActiveRecord::IdentityMap.clear
end
+ # Backport skip to Ruby 1.8. test/unit doesn't support it, so just
+ # make it a noop.
+ unless instance_methods.map(&:to_s).include?("skip")
+ def skip(message)
+ end
+ end
+
def assert_date_from_db(expected, actual, message = nil)
# SybaseAdapter doesn't have a separate column type just for dates,
# so the time is in the string and incorrectly formatted
diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb
index de36dd20b3..59b6876135 100644
--- a/activerecord/lib/active_record/validations.rb
+++ b/activerecord/lib/active_record/validations.rb
@@ -32,11 +32,11 @@ module ActiveRecord
module ClassMethods
# Creates an object just like Base.create but calls <tt>save!</tt> instead of +save+
# so an exception is raised if the record is invalid.
- def create!(attributes = nil, &block)
+ def create!(attributes = nil, options = {}, &block)
if attributes.is_a?(Array)
- attributes.collect { |attr| create!(attr, &block) }
+ attributes.collect { |attr| create!(attr, options, &block) }
else
- object = new(attributes)
+ object = new(attributes, options)
yield(object) if block_given?
object.save!
object
diff --git a/activerecord/test/cases/adapters/mysql2/bind_parameter_test.rb b/activerecord/test/cases/adapters/mysql2/bind_parameter_test.rb
new file mode 100644
index 0000000000..cd9c1041dc
--- /dev/null
+++ b/activerecord/test/cases/adapters/mysql2/bind_parameter_test.rb
@@ -0,0 +1,50 @@
+require "cases/helper"
+require 'models/topic'
+
+module ActiveRecord
+ module ConnectionAdapters
+ class Mysql2Adapter
+ class BindParameterTest < ActiveRecord::TestCase
+ fixtures :topics
+
+ def test_update_question_marks
+ str = "foo?bar"
+ x = Topic.find :first
+ x.title = str
+ x.content = str
+ x.save!
+ x.reload
+ assert_equal str, x.title
+ assert_equal str, x.content
+ end
+
+ def test_create_question_marks
+ str = "foo?bar"
+ x = Topic.create!(:title => str, :content => str)
+ x.reload
+ assert_equal str, x.title
+ assert_equal str, x.content
+ end
+
+ def test_update_null_bytes
+ str = "foo\0bar"
+ x = Topic.find :first
+ x.title = str
+ x.content = str
+ x.save!
+ x.reload
+ assert_equal str, x.title
+ assert_equal str, x.content
+ end
+
+ def test_create_null_bytes
+ str = "foo\0bar"
+ x = Topic.create!(:title => str, :content => str)
+ x.reload
+ assert_equal str, x.title
+ assert_equal str, x.content
+ end
+ end
+ end
+ end
+end
diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb
index ddcc36c841..b993bf6e90 100644
--- a/activerecord/test/cases/associations/belongs_to_associations_test.rb
+++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb
@@ -626,4 +626,25 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
assert_equal "Bob", firm.name
end
+
+ def test_build_with_block
+ client = Client.create(:name => 'Client Company')
+
+ firm = client.build_firm{ |f| f.name = 'Agency Company' }
+ assert_equal 'Agency Company', firm.name
+ end
+
+ def test_create_with_block
+ client = Client.create(:name => 'Client Company')
+
+ firm = client.create_firm{ |f| f.name = 'Agency Company' }
+ assert_equal 'Agency Company', firm.name
+ end
+
+ def test_create_bang_with_block
+ client = Client.create(:name => 'Client Company')
+
+ firm = client.create_firm!{ |f| f.name = 'Agency Company' }
+ assert_equal 'Agency Company', firm.name
+ end
end
diff --git a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb
index 39e8a7960a..49d8722aff 100644
--- a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb
+++ b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb
@@ -51,7 +51,9 @@ class CascadedEagerLoadingTest < ActiveRecord::TestCase
categories = Category.joins(:categorizations).includes([{:posts=>:comments}, :authors])
assert_nothing_raised do
- assert_equal 3, categories.count
+ assert_equal 4, categories.count
+ assert_equal 4, categories.all.count
+ assert_equal 3, categories.count(:distinct => true)
assert_equal 3, categories.all.uniq.size # Must uniq since instantiating with inner joins will get dupes
end
end
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb
index 247decc67b..522ac56d82 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -66,6 +66,63 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal 'exotic', bulb.name
end
+ def test_create_from_association_with_nil_values_should_work
+ car = Car.create(:name => 'honda')
+
+ bulb = car.bulbs.new(nil)
+ assert_equal 'defaulty', bulb.name
+
+ bulb = car.bulbs.build(nil)
+ assert_equal 'defaulty', bulb.name
+
+ bulb = car.bulbs.create(nil)
+ assert_equal 'defaulty', bulb.name
+ end
+
+ def test_association_keys_bypass_attribute_protection
+ car = Car.create(:name => 'honda')
+
+ bulb = car.bulbs.new
+ assert_equal car.id, bulb.car_id
+
+ bulb = car.bulbs.new :car_id => car.id + 1
+ assert_equal car.id, bulb.car_id
+
+ bulb = car.bulbs.build
+ assert_equal car.id, bulb.car_id
+
+ bulb = car.bulbs.build :car_id => car.id + 1
+ assert_equal car.id, bulb.car_id
+
+ bulb = car.bulbs.create
+ assert_equal car.id, bulb.car_id
+
+ bulb = car.bulbs.create :car_id => car.id + 1
+ assert_equal car.id, bulb.car_id
+ end
+
+ def test_association_conditions_bypass_attribute_protection
+ car = Car.create(:name => 'honda')
+
+ bulb = car.frickinawesome_bulbs.new
+ assert_equal true, bulb.frickinawesome?
+
+ bulb = car.frickinawesome_bulbs.new(:frickinawesome => false)
+ assert_equal true, bulb.frickinawesome?
+
+ bulb = car.frickinawesome_bulbs.build
+ assert_equal true, bulb.frickinawesome?
+
+ bulb = car.frickinawesome_bulbs.build(:frickinawesome => false)
+ assert_equal true, bulb.frickinawesome?
+
+ bulb = car.frickinawesome_bulbs.create
+ assert_equal true, bulb.frickinawesome?
+
+ bulb = car.frickinawesome_bulbs.create(:frickinawesome => false)
+ assert_equal true, bulb.frickinawesome?
+ end
+
# When creating objects on the association, we must not do it within a scope (even though it
# would be convenient), because this would cause that scope to be applied to any callbacks etc.
def test_build_and_create_should_not_happen_within_scope
@@ -1388,4 +1445,27 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_not_equal target.object_id, ary.object_id
end
+
+ def test_merging_with_custom_attribute_writer
+ bulb = Bulb.new(:color => "red")
+ assert_equal "RED!", bulb.color
+
+ car = Car.create!
+ car.bulbs << bulb
+
+ assert_equal "RED!", car.bulbs.to_a.first.color
+ end
+
+ def test_new_is_called_with_attributes_and_options
+ car = Car.create(:name => 'honda')
+
+ bulb = car.bulbs.build
+ assert_equal Bulb, bulb.class
+
+ bulb = car.bulbs.build(:bulb_type => :custom)
+ assert_equal Bulb, bulb.class
+
+ bulb = car.bulbs.build({ :bulb_type => :custom }, :as => :admin)
+ assert_equal CustomBulb, bulb.class
+ end
end
diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb
index f3c96ccbe6..f3bf5baa95 100644
--- a/activerecord/test/cases/associations/has_one_associations_test.rb
+++ b/activerecord/test/cases/associations/has_one_associations_test.rb
@@ -4,6 +4,7 @@ require 'models/project'
require 'models/company'
require 'models/ship'
require 'models/pirate'
+require 'models/car'
require 'models/bulb'
class HasOneAssociationsTest < ActiveRecord::TestCase
@@ -95,6 +96,15 @@ class HasOneAssociationsTest < ActiveRecord::TestCase
assert_nil Account.find(old_account_id).firm_id
end
+ def test_natural_assignment_to_nil_after_destroy
+ firm = companies(:rails_core)
+ old_account_id = firm.account.id
+ firm.account.destroy
+ firm.account = nil
+ assert_nil companies(:rails_core).account
+ assert_raise(ActiveRecord::RecordNotFound) { Account.find(old_account_id) }
+ end
+
def test_association_change_calls_delete
companies(:first_firm).deletable_account = Account.new(:credit_limit => 5)
assert_equal [], Account.destroyed_account_ids[companies(:first_firm).id]
@@ -359,4 +369,82 @@ class HasOneAssociationsTest < ActiveRecord::TestCase
assert_equal pirate.id, ships(:black_pearl).reload.pirate_id
assert_nil new_ship.pirate_id
end
+
+ def test_deprecated_association_loaded
+ firm = companies(:first_firm)
+ firm.association(:account).stubs(:loaded?).returns(stub)
+
+ assert_deprecated do
+ assert_equal firm.association(:account).loaded?, firm.account_loaded?
+ end
+ end
+
+ def test_association_keys_bypass_attribute_protection
+ car = Car.create(:name => 'honda')
+
+ bulb = car.build_bulb
+ assert_equal car.id, bulb.car_id
+
+ bulb = car.build_bulb :car_id => car.id + 1
+ assert_equal car.id, bulb.car_id
+
+ bulb = car.create_bulb
+ assert_equal car.id, bulb.car_id
+
+ bulb = car.create_bulb :car_id => car.id + 1
+ assert_equal car.id, bulb.car_id
+ end
+
+ def test_association_conditions_bypass_attribute_protection
+ car = Car.create(:name => 'honda')
+
+ bulb = car.build_frickinawesome_bulb
+ assert_equal true, bulb.frickinawesome?
+
+ bulb = car.build_frickinawesome_bulb(:frickinawesome => false)
+ assert_equal true, bulb.frickinawesome?
+
+ bulb = car.create_frickinawesome_bulb
+ assert_equal true, bulb.frickinawesome?
+
+ bulb = car.create_frickinawesome_bulb(:frickinawesome => false)
+ assert_equal true, bulb.frickinawesome?
+ end
+
+ def test_new_is_called_with_attributes_and_options
+ car = Car.create(:name => 'honda')
+
+ bulb = car.build_bulb
+ assert_equal Bulb, bulb.class
+
+ bulb = car.build_bulb
+ assert_equal Bulb, bulb.class
+
+ bulb = car.build_bulb(:bulb_type => :custom)
+ assert_equal Bulb, bulb.class
+
+ bulb = car.build_bulb({ :bulb_type => :custom }, :as => :admin)
+ assert_equal CustomBulb, bulb.class
+ end
+
+ def test_build_with_block
+ car = Car.create(:name => 'honda')
+
+ bulb = car.build_bulb{ |b| b.color = 'Red' }
+ assert_equal 'RED!', bulb.color
+ end
+
+ def test_create_with_block
+ car = Car.create(:name => 'honda')
+
+ bulb = car.create_bulb{ |b| b.color = 'Red' }
+ assert_equal 'RED!', bulb.color
+ end
+
+ def test_create_bang_with_block
+ car = Car.create(:name => 'honda')
+
+ bulb = car.create_bulb!{ |b| b.color = 'Red' }
+ assert_equal 'RED!', bulb.color
+ end
end
diff --git a/activerecord/test/cases/associations/has_one_through_associations_test.rb b/activerecord/test/cases/associations/has_one_through_associations_test.rb
index 968025ade8..2503349c08 100644
--- a/activerecord/test/cases/associations/has_one_through_associations_test.rb
+++ b/activerecord/test/cases/associations/has_one_through_associations_test.rb
@@ -310,4 +310,8 @@ class HasOneThroughAssociationsTest < ActiveRecord::TestCase
assert_equal dashboard, minivan.dashboard
assert_equal dashboard, minivan.speedometer.dashboard
end
+
+ def test_has_one_through_with_custom_select_on_join_model_default_scope
+ assert_equal clubs(:boring_club), members(:groucho).selected_club
+ end
end
diff --git a/activerecord/test/cases/associations/inner_join_association_test.rb b/activerecord/test/cases/associations/inner_join_association_test.rb
index 124693f7c9..e5e9ca6131 100644
--- a/activerecord/test/cases/associations/inner_join_association_test.rb
+++ b/activerecord/test/cases/associations/inner_join_association_test.rb
@@ -2,6 +2,7 @@ require "cases/helper"
require 'models/post'
require 'models/comment'
require 'models/author'
+require 'models/essay'
require 'models/category'
require 'models/categorization'
require 'models/person'
@@ -9,7 +10,7 @@ require 'models/tagging'
require 'models/tag'
class InnerJoinAssociationTest < ActiveRecord::TestCase
- fixtures :authors, :posts, :comments, :categories, :categories_posts, :categorizations,
+ fixtures :authors, :essays, :posts, :comments, :categories, :categories_posts, :categorizations,
:taggings, :tags
def test_construct_finder_sql_applies_aliases_tables_on_association_conditions
diff --git a/activerecord/test/cases/associations/join_model_test.rb b/activerecord/test/cases/associations/join_model_test.rb
index 49a1c117bc..8e23ab78be 100644
--- a/activerecord/test/cases/associations/join_model_test.rb
+++ b/activerecord/test/cases/associations/join_model_test.rb
@@ -13,6 +13,9 @@ require 'models/vertex'
require 'models/edge'
require 'models/book'
require 'models/citation'
+require 'models/aircraft'
+require 'models/engine'
+require 'models/car'
class AssociationsJoinModelTest < ActiveRecord::TestCase
self.use_transactional_fixtures = false unless supports_savepoints?
@@ -704,6 +707,15 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
assert_equal [9, 10, new_comment.id], authors(:david).sti_post_comments.map(&:id).sort
end
+ def test_has_many_with_pluralize_table_names_false
+ engine = Engine.create(:car_id => 1)
+ Aircraft.pluralize_table_names = false
+ aircraft = Aircraft.create!(:name => "Airbus 380", :id => 1)
+ assert_equal aircraft.engines, [engine]
+ ensure
+ ActiveRecord::Base.pluralize_table_names = true
+ end
+
private
# create dynamic Post models to allow different dependency options
def find_post_with_dependency(post_id, association, association_name, dependency)
diff --git a/activerecord/test/cases/associations_test.rb b/activerecord/test/cases/associations_test.rb
index 04f628a398..49d82ba2df 100644
--- a/activerecord/test/cases/associations_test.rb
+++ b/activerecord/test/cases/associations_test.rb
@@ -85,7 +85,7 @@ class AssociationsTest < ActiveRecord::TestCase
def test_should_construct_new_finder_sql_after_create
person = Person.new :first_name => 'clark'
- assert_equal [], person.readers.find(:all)
+ assert_equal [], person.readers.all
person.save!
reader = Reader.create! :person => person, :post => Post.new(:title => "foo", :body => "bar")
assert person.readers.find(reader.id)
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index 1775ba9999..bfb66f07da 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -45,6 +45,10 @@ class ReadonlyTitlePost < Post
attr_readonly :title
end
+class ProtectedTitlePost < Post
+ attr_protected :title
+end
+
class Weird < ActiveRecord::Base; end
class Boolean < ActiveRecord::Base; end
@@ -105,7 +109,7 @@ class BasicsTest < ActiveRecord::TestCase
def test_select_symbol
topic_ids = Topic.select(:id).map(&:id).sort
- assert_equal Topic.find(:all).map(&:id).sort, topic_ids
+ assert_equal Topic.all.map(&:id).sort, topic_ids
end
def test_table_exists
@@ -491,8 +495,9 @@ class BasicsTest < ActiveRecord::TestCase
def test_attributes_guard_protected_attributes_is_deprecated
attributes = { "title" => "An amazing title" }
- topic = Topic.new
- assert_deprecated { topic.send(:attributes=, attributes, false) }
+ post = ProtectedTitlePost.new
+ assert_deprecated { post.send(:attributes=, attributes, false) }
+ assert_equal "An amazing title", post.title
end
def test_multiparameter_attributes_on_date
@@ -1785,4 +1790,17 @@ class BasicsTest < ActiveRecord::TestCase
assert_equal expected.attributes, actual.attributes
end
+
+ def test_attribute_names
+ assert_equal ["id", "type", "ruby_type", "firm_id", "firm_name", "name", "client_of", "rating", "account_id"],
+ Company.attribute_names
+ end
+
+ def test_attribute_names_on_table_not_exists
+ assert_equal [], NonExistentTable.attribute_names
+ end
+
+ def test_attribtue_names_on_abstract_class
+ assert_equal [], AbstractCompany.attribute_names
+ end
end
diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb
index 654c4c9010..56f6d795b6 100644
--- a/activerecord/test/cases/calculations_test.rb
+++ b/activerecord/test/cases/calculations_test.rb
@@ -319,6 +319,17 @@ class CalculationsTest < ActiveRecord::TestCase
assert_equal 4, Account.count(:distinct => true, :include => :firm, :select => :credit_limit)
end
+ def test_should_not_perform_joined_include_by_default
+ assert_equal Account.count, Account.includes(:firm).count
+ queries = assert_sql { Account.includes(:firm).count }
+ assert_no_match(/join/i, queries.last)
+ end
+
+ def test_should_perform_joined_include_when_referencing_included_tables
+ joined_count = Account.includes(:firm).where(:companies => {:name => '37signals'}).count
+ assert_equal 1, joined_count
+ end
+
def test_should_count_scoped_select
Account.update_all("credit_limit = NULL")
assert_equal 0, Account.scoped(:select => "credit_limit").count
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index be4ba18555..4e75eafe3d 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -683,6 +683,27 @@ class FinderTest < ActiveRecord::TestCase
assert_nil Topic.find_last_by_title_and_author_name(topic.title, "Anonymous")
end
+ def test_find_last_with_limit_gives_same_result_when_loaded_and_unloaded
+ scope = Topic.limit(2)
+ unloaded_last = scope.last
+ loaded_last = scope.all.last
+ assert_equal loaded_last, unloaded_last
+ end
+
+ def test_find_last_with_limit_and_offset_gives_same_result_when_loaded_and_unloaded
+ scope = Topic.offset(2).limit(2)
+ unloaded_last = scope.last
+ loaded_last = scope.all.last
+ assert_equal loaded_last, unloaded_last
+ end
+
+ def test_find_last_with_offset_gives_same_result_when_loaded_and_unloaded
+ scope = Topic.offset(3)
+ unloaded_last = scope.last
+ loaded_last = scope.all.last
+ assert_equal loaded_last, unloaded_last
+ end
+
def test_find_all_by_one_attribute
topics = Topic.find_all_by_content("Have a nice day")
assert_equal 2, topics.size
diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb
index 2bf192e2c6..b0bd9c5763 100644
--- a/activerecord/test/cases/fixtures_test.rb
+++ b/activerecord/test/cases/fixtures_test.rb
@@ -175,7 +175,9 @@ class FixturesTest < ActiveRecord::TestCase
end
def test_empty_csv_fixtures
- assert_not_nil ActiveRecord::Fixtures.new( Account.connection, "accounts", 'Account', FIXTURES_ROOT + "/naked/csv/accounts")
+ assert_deprecated do
+ assert_not_nil ActiveRecord::Fixtures.new( Account.connection, "accounts", 'Account', FIXTURES_ROOT + "/naked/csv/accounts")
+ end
end
def test_omap_fixtures
diff --git a/activerecord/test/cases/locking_test.rb b/activerecord/test/cases/locking_test.rb
index 636a709924..61baa55027 100644
--- a/activerecord/test/cases/locking_test.rb
+++ b/activerecord/test/cases/locking_test.rb
@@ -5,6 +5,7 @@ require 'models/job'
require 'models/reader'
require 'models/legacy_thing'
require 'models/reference'
+require 'models/string_key_object'
class LockWithoutDefault < ActiveRecord::Base; end
@@ -18,7 +19,40 @@ class ReadonlyFirstNamePerson < Person
end
class OptimisticLockingTest < ActiveRecord::TestCase
- fixtures :people, :legacy_things, :references
+ fixtures :people, :legacy_things, :references, :string_key_objects
+
+ def test_non_integer_lock_existing
+ s1 = StringKeyObject.find("record1")
+ s2 = StringKeyObject.find("record1")
+ assert_equal 0, s1.lock_version
+ assert_equal 0, s2.lock_version
+
+ s1.name = 'updated record'
+ s1.save!
+ assert_equal 1, s1.lock_version
+ assert_equal 0, s2.lock_version
+
+ s2.name = 'doubly updated record'
+ assert_raise(ActiveRecord::StaleObjectError) { s2.save! }
+ end
+
+ def test_non_integer_lock_destroy
+ s1 = StringKeyObject.find("record1")
+ s2 = StringKeyObject.find("record1")
+ assert_equal 0, s1.lock_version
+ assert_equal 0, s2.lock_version
+
+ s1.name = 'updated record'
+ s1.save!
+ assert_equal 1, s1.lock_version
+ assert_equal 0, s2.lock_version
+ assert_raise(ActiveRecord::StaleObjectError) { s2.destroy }
+
+ assert s1.destroy
+ assert s1.frozen?
+ assert s1.destroyed?
+ assert_raises(ActiveRecord::RecordNotFound) { StringKeyObject.find("record1") }
+ end
def test_lock_existing
p1 = Person.find(1)
diff --git a/activerecord/test/cases/mass_assignment_security_test.rb b/activerecord/test/cases/mass_assignment_security_test.rb
index fbbae99e8b..765033852d 100644
--- a/activerecord/test/cases/mass_assignment_security_test.rb
+++ b/activerecord/test/cases/mass_assignment_security_test.rb
@@ -87,7 +87,11 @@ class MassAssignmentSecurityTest < ActiveRecord::TestCase
end
end
- def test_assign_attributes_uses_default_scope_when_no_scope_is_provided
+ def test_mass_assigning_does_not_choke_on_nil
+ Firm.new.assign_attributes(nil)
+ end
+
+ def test_assign_attributes_uses_default_role_when_no_role_is_provided
p = LoosePerson.new
p.assign_attributes(attributes_hash)
@@ -101,28 +105,28 @@ class MassAssignmentSecurityTest < ActiveRecord::TestCase
assert_all_attributes(p)
end
- def test_assign_attributes_with_default_scope_and_attr_protected_attributes
+ def test_assign_attributes_with_default_role_and_attr_protected_attributes
p = LoosePerson.new
p.assign_attributes(attributes_hash, :as => :default)
assert_default_attributes(p)
end
- def test_assign_attributes_with_admin_scope_and_attr_protected_attributes
+ def test_assign_attributes_with_admin_role_and_attr_protected_attributes
p = LoosePerson.new
p.assign_attributes(attributes_hash, :as => :admin)
assert_admin_attributes(p)
end
- def test_assign_attributes_with_default_scope_and_attr_accessible_attributes
+ def test_assign_attributes_with_default_role_and_attr_accessible_attributes
p = TightPerson.new
p.assign_attributes(attributes_hash, :as => :default)
assert_default_attributes(p)
end
- def test_assign_attributes_with_admin_scope_and_attr_accessible_attributes
+ def test_assign_attributes_with_admin_role_and_attr_accessible_attributes
p = TightPerson.new
p.assign_attributes(attributes_hash, :as => :admin)
@@ -153,30 +157,42 @@ class MassAssignmentSecurityTest < ActiveRecord::TestCase
assert_default_attributes(p, true)
end
- def test_new_with_admin_scope_with_attr_accessible_attributes
+ def test_new_with_admin_role_with_attr_accessible_attributes
p = TightPerson.new(attributes_hash, :as => :admin)
assert_admin_attributes(p)
end
- def test_new_with_admin_scope_with_attr_protected_attributes
+ def test_new_with_admin_role_with_attr_protected_attributes
p = LoosePerson.new(attributes_hash, :as => :admin)
assert_admin_attributes(p)
end
- def test_create_with_admin_scope_with_attr_accessible_attributes
+ def test_create_with_admin_role_with_attr_accessible_attributes
p = TightPerson.create(attributes_hash, :as => :admin)
assert_admin_attributes(p, true)
end
- def test_create_with_admin_scope_with_attr_protected_attributes
+ def test_create_with_admin_role_with_attr_protected_attributes
p = LoosePerson.create(attributes_hash, :as => :admin)
assert_admin_attributes(p, true)
end
+ def test_create_with_bang_with_admin_role_with_attr_accessible_attributes
+ p = TightPerson.create!(attributes_hash, :as => :admin)
+
+ assert_admin_attributes(p, true)
+ end
+
+ def test_create_with_bang_with_admin_role_with_attr_protected_attributes
+ p = LoosePerson.create!(attributes_hash, :as => :admin)
+
+ assert_admin_attributes(p, true)
+ end
+
def test_new_with_without_protection_with_attr_accessible_attributes
p = TightPerson.new(attributes_hash, :without_protection => true)
@@ -201,6 +217,18 @@ class MassAssignmentSecurityTest < ActiveRecord::TestCase
assert_all_attributes(p)
end
+ def test_create_with_bang_with_without_protection_with_attr_accessible_attributes
+ p = TightPerson.create!(attributes_hash, :without_protection => true)
+
+ assert_all_attributes(p)
+ end
+
+ def test_create_with_bang_with_without_protection_with_attr_protected_attributes
+ p = LoosePerson.create!(attributes_hash, :without_protection => true)
+
+ assert_all_attributes(p)
+ end
+
def test_protection_against_class_attribute_writers
[:logger, :configurations, :primary_key_prefix_type, :table_name_prefix, :table_name_suffix, :pluralize_table_names,
:default_timezone, :schema_format, :lock_optimistically, :record_timestamps].each do |method|
@@ -230,12 +258,12 @@ class MassAssignmentSecurityHasOneRelationsTest < ActiveRecord::TestCase
assert_default_attributes(best_friend)
end
- def test_has_one_build_with_admin_scope_with_attr_protected_attributes
+ def test_has_one_build_with_admin_role_with_attr_protected_attributes
best_friend = @person.build_best_friend(attributes_hash, :as => :admin)
assert_admin_attributes(best_friend)
end
- def test_has_one_build_with_admin_scope_with_attr_accessible_attributes
+ def test_has_one_build_with_admin_role_with_attr_accessible_attributes
best_friend = @person.build_best_friend(attributes_hash, :as => :admin)
assert_admin_attributes(best_friend)
end
@@ -257,12 +285,12 @@ class MassAssignmentSecurityHasOneRelationsTest < ActiveRecord::TestCase
assert_default_attributes(best_friend, true)
end
- def test_has_one_create_with_admin_scope_with_attr_protected_attributes
+ def test_has_one_create_with_admin_role_with_attr_protected_attributes
best_friend = @person.create_best_friend(attributes_hash, :as => :admin)
assert_admin_attributes(best_friend, true)
end
- def test_has_one_create_with_admin_scope_with_attr_accessible_attributes
+ def test_has_one_create_with_admin_role_with_attr_accessible_attributes
best_friend = @person.create_best_friend(attributes_hash, :as => :admin)
assert_admin_attributes(best_friend, true)
end
@@ -284,12 +312,12 @@ class MassAssignmentSecurityHasOneRelationsTest < ActiveRecord::TestCase
assert_default_attributes(best_friend, true)
end
- def test_has_one_create_with_bang_with_admin_scope_with_attr_protected_attributes
+ def test_has_one_create_with_bang_with_admin_role_with_attr_protected_attributes
best_friend = @person.create_best_friend!(attributes_hash, :as => :admin)
assert_admin_attributes(best_friend, true)
end
- def test_has_one_create_with_bang_with_admin_scope_with_attr_accessible_attributes
+ def test_has_one_create_with_bang_with_admin_role_with_attr_accessible_attributes
best_friend = @person.create_best_friend!(attributes_hash, :as => :admin)
assert_admin_attributes(best_friend, true)
end
@@ -318,12 +346,12 @@ class MassAssignmentSecurityBelongsToRelationsTest < ActiveRecord::TestCase
assert_default_attributes(best_friend)
end
- def test_has_one_build_with_admin_scope_with_attr_protected_attributes
+ def test_has_one_build_with_admin_role_with_attr_protected_attributes
best_friend = @person.build_best_friend_of(attributes_hash, :as => :admin)
assert_admin_attributes(best_friend)
end
- def test_has_one_build_with_admin_scope_with_attr_accessible_attributes
+ def test_has_one_build_with_admin_role_with_attr_accessible_attributes
best_friend = @person.build_best_friend_of(attributes_hash, :as => :admin)
assert_admin_attributes(best_friend)
end
@@ -345,12 +373,12 @@ class MassAssignmentSecurityBelongsToRelationsTest < ActiveRecord::TestCase
assert_default_attributes(best_friend, true)
end
- def test_has_one_create_with_admin_scope_with_attr_protected_attributes
+ def test_has_one_create_with_admin_role_with_attr_protected_attributes
best_friend = @person.create_best_friend_of(attributes_hash, :as => :admin)
assert_admin_attributes(best_friend, true)
end
- def test_has_one_create_with_admin_scope_with_attr_accessible_attributes
+ def test_has_one_create_with_admin_role_with_attr_accessible_attributes
best_friend = @person.create_best_friend_of(attributes_hash, :as => :admin)
assert_admin_attributes(best_friend, true)
end
@@ -372,12 +400,12 @@ class MassAssignmentSecurityBelongsToRelationsTest < ActiveRecord::TestCase
assert_default_attributes(best_friend, true)
end
- def test_has_one_create_with_bang_with_admin_scope_with_attr_protected_attributes
+ def test_has_one_create_with_bang_with_admin_role_with_attr_protected_attributes
best_friend = @person.create_best_friend!(attributes_hash, :as => :admin)
assert_admin_attributes(best_friend, true)
end
- def test_has_one_create_with_bang_with_admin_scope_with_attr_accessible_attributes
+ def test_has_one_create_with_bang_with_admin_role_with_attr_accessible_attributes
best_friend = @person.create_best_friend!(attributes_hash, :as => :admin)
assert_admin_attributes(best_friend, true)
end
@@ -406,12 +434,12 @@ class MassAssignmentSecurityHasManyRelationsTest < ActiveRecord::TestCase
assert_default_attributes(best_friend)
end
- def test_has_one_build_with_admin_scope_with_attr_protected_attributes
+ def test_has_one_build_with_admin_role_with_attr_protected_attributes
best_friend = @person.best_friends.build(attributes_hash, :as => :admin)
assert_admin_attributes(best_friend)
end
- def test_has_one_build_with_admin_scope_with_attr_accessible_attributes
+ def test_has_one_build_with_admin_role_with_attr_accessible_attributes
best_friend = @person.best_friends.build(attributes_hash, :as => :admin)
assert_admin_attributes(best_friend)
end
@@ -433,12 +461,12 @@ class MassAssignmentSecurityHasManyRelationsTest < ActiveRecord::TestCase
assert_default_attributes(best_friend, true)
end
- def test_has_one_create_with_admin_scope_with_attr_protected_attributes
+ def test_has_one_create_with_admin_role_with_attr_protected_attributes
best_friend = @person.best_friends.create(attributes_hash, :as => :admin)
assert_admin_attributes(best_friend, true)
end
- def test_has_one_create_with_admin_scope_with_attr_accessible_attributes
+ def test_has_one_create_with_admin_role_with_attr_accessible_attributes
best_friend = @person.best_friends.create(attributes_hash, :as => :admin)
assert_admin_attributes(best_friend, true)
end
@@ -460,12 +488,12 @@ class MassAssignmentSecurityHasManyRelationsTest < ActiveRecord::TestCase
assert_default_attributes(best_friend, true)
end
- def test_has_one_create_with_bang_with_admin_scope_with_attr_protected_attributes
+ def test_has_one_create_with_bang_with_admin_role_with_attr_protected_attributes
best_friend = @person.best_friends.create!(attributes_hash, :as => :admin)
assert_admin_attributes(best_friend, true)
end
- def test_has_one_create_with_bang_with_admin_scope_with_attr_accessible_attributes
+ def test_has_one_create_with_bang_with_admin_role_with_attr_accessible_attributes
best_friend = @person.best_friends.create!(attributes_hash, :as => :admin)
assert_admin_attributes(best_friend, true)
end
diff --git a/activerecord/test/cases/method_scoping_test.rb b/activerecord/test/cases/method_scoping_test.rb
index 7f0f007a70..a0cb5dbdc5 100644
--- a/activerecord/test/cases/method_scoping_test.rb
+++ b/activerecord/test/cases/method_scoping_test.rb
@@ -68,7 +68,7 @@ class MethodScopingTest < ActiveRecord::TestCase
def test_scoped_find_all
Developer.send(:with_scope, :find => { :conditions => "name = 'David'" }) do
- assert_equal [developers(:david)], Developer.find(:all)
+ assert_equal [developers(:david)], Developer.all
end
end
@@ -235,23 +235,23 @@ class MethodScopingTest < ActiveRecord::TestCase
def test_immutable_scope
options = { :conditions => "name = 'David'" }
Developer.send(:with_scope, :find => options) do
- assert_equal %w(David), Developer.find(:all).map { |d| d.name }
+ assert_equal %w(David), Developer.all.map(&:name)
options[:conditions] = "name != 'David'"
- assert_equal %w(David), Developer.find(:all).map { |d| d.name }
+ assert_equal %w(David), Developer.all.map(&:name)
end
scope = { :find => { :conditions => "name = 'David'" }}
Developer.send(:with_scope, scope) do
- assert_equal %w(David), Developer.find(:all).map { |d| d.name }
+ assert_equal %w(David), Developer.all.map(&:name)
scope[:find][:conditions] = "name != 'David'"
- assert_equal %w(David), Developer.find(:all).map { |d| d.name }
+ assert_equal %w(David), Developer.all.map(&:name)
end
end
def test_scoped_with_duck_typing
scoping = Struct.new(:current_scope).new(:find => { :conditions => ["name = ?", 'David'] })
Developer.send(:with_scope, scoping) do
- assert_equal %w(David), Developer.find(:all).map { |d| d.name }
+ assert_equal %w(David), Developer.all.map(&:name)
end
end
@@ -432,7 +432,7 @@ class NestedScopingTest < ActiveRecord::TestCase
def test_merged_scoped_find_combines_and_sanitizes_conditions
Developer.send(:with_scope, :find => { :conditions => ["name = ?", 'David'] }) do
Developer.send(:with_scope, :find => { :conditions => ['salary > ?', 9000] }) do
- assert_equal %w(David), Developer.find(:all).map { |d| d.name }
+ assert_equal %w(David), Developer.all.map(&:name)
end
end
end
@@ -487,9 +487,9 @@ class NestedScopingTest < ActiveRecord::TestCase
options2 = { :conditions => "name = 'David'" }
Developer.send(:with_scope, :find => options1) do
Developer.send(:with_exclusive_scope, :find => options2) do
- assert_equal %w(David), Developer.find(:all).map { |d| d.name }
+ assert_equal %w(David), Developer.all.map(&:name)
options1[:conditions] = options2[:conditions] = nil
- assert_equal %w(David), Developer.find(:all).map { |d| d.name }
+ assert_equal %w(David), Developer.all.map(&:name)
end
end
end
@@ -499,9 +499,9 @@ class NestedScopingTest < ActiveRecord::TestCase
options2 = { :conditions => "salary > 10000" }
Developer.send(:with_scope, :find => options1) do
Developer.send(:with_scope, :find => options2) do
- assert_equal %w(Jamis), Developer.find(:all).map { |d| d.name }
+ assert_equal %w(Jamis), Developer.all.map(&:name)
options1[:conditions] = options2[:conditions] = nil
- assert_equal %w(Jamis), Developer.find(:all).map { |d| d.name }
+ assert_equal %w(Jamis), Developer.all.map(&:name)
end
end
end
diff --git a/activerecord/test/cases/named_scope_test.rb b/activerecord/test/cases/named_scope_test.rb
index 8fd1fc2577..34188e4915 100644
--- a/activerecord/test/cases/named_scope_test.rb
+++ b/activerecord/test/cases/named_scope_test.rb
@@ -462,7 +462,7 @@ class NamedScopeTest < ActiveRecord::TestCase
[:destroy_all, :reset, :delete_all].each do |method|
before = post.comments.containing_the_letter_e
post.association(:comments).send(method)
- assert before.object_id != post.comments.containing_the_letter_e.object_id, "AssociationCollection##{method} should reset the named scopes cache"
+ assert before.object_id != post.comments.containing_the_letter_e.object_id, "CollectionAssociation##{method} should reset the named scopes cache"
end
end
diff --git a/activerecord/test/cases/persistence_test.rb b/activerecord/test/cases/persistence_test.rb
index b066575af8..57d1441128 100644
--- a/activerecord/test/cases/persistence_test.rb
+++ b/activerecord/test/cases/persistence_test.rb
@@ -336,6 +336,10 @@ class PersistencesTest < ActiveRecord::TestCase
assert !Topic.find(1).approved?
end
+ def test_update_attribute_does_not_choke_on_nil
+ assert Topic.find(1).update_attributes(nil)
+ end
+
def test_update_attribute_for_readonly_attribute
minivan = Minivan.find('m1')
assert_raises(ActiveRecord::ActiveRecordError) { minivan.update_attribute(:color, 'black') }
diff --git a/activerecord/test/cases/relation_scoping_test.rb b/activerecord/test/cases/relation_scoping_test.rb
index 864b3d4846..c215602567 100644
--- a/activerecord/test/cases/relation_scoping_test.rb
+++ b/activerecord/test/cases/relation_scoping_test.rb
@@ -462,4 +462,8 @@ class DefaultScopingTest < ActiveRecord::TestCase
assert DeveloperCalledJamis.unscoped.poor.include?(developers(:david).becomes(DeveloperCalledJamis))
assert_equal 10, DeveloperCalledJamis.unscoped.poor.length
end
+
+ def test_default_scope_order_ignored_by_aggregations
+ assert_equal DeveloperOrderedBySalary.all.count, DeveloperOrderedBySalary.count
+ end
end
diff --git a/activerecord/test/cases/session_store/session_test.rb b/activerecord/test/cases/session_store/session_test.rb
index cee5ddd003..669c0b7b4d 100644
--- a/activerecord/test/cases/session_store/session_test.rb
+++ b/activerecord/test/cases/session_store/session_test.rb
@@ -21,6 +21,12 @@ module ActiveRecord
assert_equal 'sessions', Session.table_name
end
+ def test_accessible_attributes
+ assert Session.accessible_attributes.include?(:session_id)
+ assert Session.accessible_attributes.include?(:data)
+ assert Session.accessible_attributes.include?(:marshaled_data)
+ end
+
def test_create_table!
assert !Session.table_exists?
Session.create_table!
diff --git a/activerecord/test/cases/timestamp_test.rb b/activerecord/test/cases/timestamp_test.rb
index ceb1452afd..22d4cac422 100644
--- a/activerecord/test/cases/timestamp_test.rb
+++ b/activerecord/test/cases/timestamp_test.rb
@@ -14,6 +14,32 @@ class TimestampTest < ActiveRecord::TestCase
@previously_updated_at = @developer.updated_at
end
+ def test_load_infinity_and_beyond
+ unless current_adapter?(:PostgreSQLAdapter)
+ return skip("only tested on postgresql")
+ end
+
+ d = Developer.find_by_sql("select 'infinity'::timestamp as updated_at")
+ assert d.first.updated_at.infinite?, 'timestamp should be infinite'
+
+ d = Developer.find_by_sql("select '-infinity'::timestamp as updated_at")
+ time = d.first.updated_at
+ assert time.infinite?, 'timestamp should be infinite'
+ assert_operator time, :<, 0
+ end
+
+ def test_save_infinity_and_beyond
+ unless current_adapter?(:PostgreSQLAdapter)
+ return skip("only tested on postgresql")
+ end
+
+ d = Developer.create!(:name => 'aaron', :updated_at => 1.0 / 0.0)
+ assert_equal(1.0 / 0.0, d.updated_at)
+
+ d = Developer.create!(:name => 'aaron', :updated_at => -1.0 / 0.0)
+ assert_equal(-1.0 / 0.0, d.updated_at)
+ end
+
def test_saving_a_changed_record_updates_its_timestamp
@developer.name = "Jack Bauer"
@developer.save!
diff --git a/activerecord/test/cases/xml_serialization_test.rb b/activerecord/test/cases/xml_serialization_test.rb
index a6074b23e7..756c8a32eb 100644
--- a/activerecord/test/cases/xml_serialization_test.rb
+++ b/activerecord/test/cases/xml_serialization_test.rb
@@ -143,10 +143,7 @@ class NilXmlSerializationTest < ActiveRecord::TestCase
end
def test_should_serialize_yaml
- assert %r{<preferences(.*)></preferences>}.match(@xml)
- attributes = $1
- assert_match %r{type="yaml"}, attributes
- assert_match %r{nil="true"}, attributes
+ assert_match %r{<preferences nil=\"true\"></preferences>}, @xml
end
end
diff --git a/activerecord/test/fixtures/all/people.csv b/activerecord/test/fixtures/all/people.yml
index e69de29bb2..e69de29bb2 100644
--- a/activerecord/test/fixtures/all/people.csv
+++ b/activerecord/test/fixtures/all/people.yml
diff --git a/activerecord/test/fixtures/memberships.yml b/activerecord/test/fixtures/memberships.yml
index 60eb641054..a5d52bd438 100644
--- a/activerecord/test/fixtures/memberships.yml
+++ b/activerecord/test/fixtures/memberships.yml
@@ -25,3 +25,10 @@ blarpy_winkup_crazy_club:
member_id: 3
favourite: false
type: CurrentMembership
+
+selected_membership_of_boring_club:
+ joined_on: <%= 3.weeks.ago.to_s(:db) %>
+ club: boring_club
+ member_id: 1
+ favourite: false
+ type: SelectedMembership
diff --git a/activerecord/test/fixtures/string_key_objects.yml b/activerecord/test/fixtures/string_key_objects.yml
new file mode 100644
index 0000000000..fa1299915b
--- /dev/null
+++ b/activerecord/test/fixtures/string_key_objects.yml
@@ -0,0 +1,7 @@
+first:
+ id: record1
+ name: first record
+
+second:
+ id: record2
+ name: second record
diff --git a/activerecord/test/models/aircraft.rb b/activerecord/test/models/aircraft.rb
new file mode 100644
index 0000000000..0c47aab539
--- /dev/null
+++ b/activerecord/test/models/aircraft.rb
@@ -0,0 +1,3 @@
+class Aircraft < ActiveRecord::Base
+ has_many :engines, :foreign_key => "car_id"
+end
diff --git a/activerecord/test/models/bulb.rb b/activerecord/test/models/bulb.rb
index c68d008c26..0dcc8d5970 100644
--- a/activerecord/test/models/bulb.rb
+++ b/activerecord/test/models/bulb.rb
@@ -2,6 +2,8 @@ class Bulb < ActiveRecord::Base
default_scope where(:name => 'defaulty')
belongs_to :car
+ attr_protected :car_id, :frickinawesome
+
attr_reader :scope_after_initialize
after_initialize :record_scope_after_initialize
@@ -9,4 +11,21 @@ class Bulb < ActiveRecord::Base
@scope_after_initialize = self.class.scoped
end
+ def color=(color)
+ self[:color] = color.upcase + "!"
+ end
+
+ def self.new(attributes = {}, options = {}, &block)
+ bulb_type = (attributes || {}).delete(:bulb_type)
+
+ if options && options[:as] == :admin && bulb_type.present?
+ bulb_class = "#{bulb_type.to_s.camelize}Bulb".constantize
+ bulb_class.new(attributes, options, &block)
+ else
+ super
+ end
+ end
end
+
+class CustomBulb < Bulb
+end \ No newline at end of file
diff --git a/activerecord/test/models/car.rb b/activerecord/test/models/car.rb
index b036f0f5c9..76f20b1061 100644
--- a/activerecord/test/models/car.rb
+++ b/activerecord/test/models/car.rb
@@ -2,6 +2,11 @@ class Car < ActiveRecord::Base
has_many :bulbs
has_many :foo_bulbs, :class_name => "Bulb", :conditions => { :name => 'foo' }
+ has_many :frickinawesome_bulbs, :class_name => "Bulb", :conditions => { :frickinawesome => true }
+
+ has_one :bulb
+ has_one :frickinawesome_bulb, :class_name => "Bulb", :conditions => { :frickinawesome => true }
+
has_many :tyres
has_many :engines
has_many :wheels, :as => :wheelable
diff --git a/activerecord/test/models/member.rb b/activerecord/test/models/member.rb
index 991e0e051f..11a0f4ff63 100644
--- a/activerecord/test/models/member.rb
+++ b/activerecord/test/models/member.rb
@@ -1,8 +1,10 @@
class Member < ActiveRecord::Base
has_one :current_membership
+ has_one :selected_membership
has_one :membership
has_many :fellow_members, :through => :club, :source => :members
has_one :club, :through => :current_membership
+ has_one :selected_club, :through => :selected_membership, :source => :club
has_one :favourite_club, :through => :membership, :conditions => ["memberships.favourite = ?", true], :source => :club
has_one :hairy_club, :through => :membership, :conditions => {:clubs => {:name => "Moustache and Eyebrow Fancier Club"}}, :source => :club
has_one :sponsor, :as => :sponsorable
diff --git a/activerecord/test/models/membership.rb b/activerecord/test/models/membership.rb
index 905f948c37..bcbb7e42c5 100644
--- a/activerecord/test/models/membership.rb
+++ b/activerecord/test/models/membership.rb
@@ -7,3 +7,9 @@ class CurrentMembership < Membership
belongs_to :member
belongs_to :club
end
+
+class SelectedMembership < Membership
+ def self.default_scope
+ select("'1' as foo")
+ end
+end
diff --git a/activerecord/test/models/string_key_object.rb b/activerecord/test/models/string_key_object.rb
new file mode 100644
index 0000000000..f8d4c6e0e4
--- /dev/null
+++ b/activerecord/test/models/string_key_object.rb
@@ -0,0 +1,3 @@
+class StringKeyObject < ActiveRecord::Base
+ set_primary_key :id
+end
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index 9479242e4f..4fe311b441 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -40,6 +40,10 @@ ActiveRecord::Schema.define do
t.references :account
end
+ create_table :aircraft, :force => true do |t|
+ t.string :name
+ end
+
create_table :audit_logs, :force => true do |t|
t.column :message, :string, :null=>false
t.column :developer_id, :integer, :null=>false
@@ -89,6 +93,8 @@ ActiveRecord::Schema.define do
create_table :bulbs, :force => true do |t|
t.integer :car_id
t.string :name
+ t.boolean :frickinawesome
+ t.string :color
end
create_table "CamelCase", :force => true do |t|
@@ -543,6 +549,12 @@ ActiveRecord::Schema.define do
t.string :sponsorable_type
end
+ create_table :string_key_objects, :id => false, :primary_key => :id, :force => true do |t|
+ t.string :id
+ t.string :name
+ t.integer :lock_version, :null => false, :default => 0
+ end
+
create_table :students, :force => true do |t|
t.string :name
end
diff --git a/activeresource/CHANGELOG b/activeresource/CHANGELOG
index 386bafd7de..a4e79f3d77 100644
--- a/activeresource/CHANGELOG
+++ b/activeresource/CHANGELOG
@@ -2,14 +2,42 @@
* No changes
-*Rails 3.0.2 (unreleased)*
+
+*Rails 3.0.7 (April 18, 2011)*
+
+*No changes.
+
+
+*Rails 3.0.6 (April 5, 2011)
+
+* No changes.
+
+
+*Rails 3.0.5 (February 26, 2011)*
+
+* No changes.
+
+
+*Rails 3.0.4 (February 8, 2011)*
+
+* No changes.
+
+
+*Rails 3.0.3 (November 16, 2010)*
+
+* No changes.
+
+
+*Rails 3.0.2 (November 15, 2010)*
* No changes
+
*Rails 3.0.1 (October 15, 2010)*
* No Changes, just a version bump.
+
*Rails 3.0.0 (August 29, 2010)*
* JSON: set Base.include_root_in_json = true to include a root value in the JSON: {"post": {"title": ...}}. Mirrors the Active Record option. [Santiago Pastorino]
diff --git a/activeresource/lib/active_resource.rb b/activeresource/lib/active_resource.rb
index 186865f811..0794a1a800 100644
--- a/activeresource/lib/active_resource.rb
+++ b/activeresource/lib/active_resource.rb
@@ -1,5 +1,5 @@
#--
-# Copyright (c) 2006 David Heinemeier Hansson
+# Copyright (c) 2006-2011 David Heinemeier Hansson
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
diff --git a/activeresource/test/cases/format_test.rb b/activeresource/test/cases/format_test.rb
index fc1a7b8c6f..f8d33f99fa 100644
--- a/activeresource/test/cases/format_test.rb
+++ b/activeresource/test/cases/format_test.rb
@@ -86,7 +86,7 @@ class FormatTest < Test::Unit::TestCase
def test_serialization_of_nested_resource
address = { :street => '12345 Street' }
- person = { :name=> 'Rus', :address => address}
+ person = { :name => 'Rus', :address => address}
[:json, :xml].each do |format|
encoded_person = ActiveResource::Formats[format].encode(person)
diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG
index 69e9cbfd42..23b0df1d5c 100644
--- a/activesupport/CHANGELOG
+++ b/activesupport/CHANGELOG
@@ -1,5 +1,7 @@
*Rails 3.1.0 (unreleased)*
+* New reporting method Kernel#quietly. [fxn]
+
* Add String#inquiry as a convenience method for turning a string into a StringInquirer object [DHH]
* Add Object#in? to test if an object is included in another object [Prem Sichanugrist, Brian Morearty, John Reitano]
@@ -19,14 +21,44 @@ advantage of the new ClassCache.
* Added before_remove_const callback to ActiveSupport::Dependencies.remove_unloadable_constants! [Andrew White]
-*Rails 3.0.2 (unreleased)*
+* JSON decoding now uses the multi_json gem which also vendors a json engine called OkJson. The yaml backend has been removed in favor of OkJson as a default engine for 1.8.x, while the built in 1.9.x json implementation will be used by default. [Josh Kalderimis]
+
+
+*Rails 3.0.7 (April 18, 2011)*
+
+* Hash.from_xml no longer loses attributes on tags containing only whitespace [André Arko]
+
+
+*Rails 3.0.6 (April 5, 2011)
+
+* No changes.
+
+
+*Rails 3.0.5 (February 26, 2011)*
+
+* No changes.
+
+
+*Rails 3.0.4 (February 8, 2011)*
+
+* No changes.
+
+
+*Rails 3.0.3 (November 16, 2010)*
+
+* No changes.
+
+
+*Rails 3.0.2 (November 15, 2010)*
* Added before_remove_const callback to ActiveSupport::Dependencies.remove_unloadable_constants! [Andrew White]
+
*Rails 3.0.1 (October 15, 2010)*
* No Changes, just a version bump.
+
*Rails 3.0.0 (August 29, 2010)*
* Implemented String#strip_heredoc. [fxn]
diff --git a/activesupport/README.rdoc b/activesupport/README.rdoc
index 13ca4b3bf1..8bb15e849a 100644
--- a/activesupport/README.rdoc
+++ b/activesupport/README.rdoc
@@ -30,4 +30,4 @@ API documentation is at
Bug reports and feature requests can be filed with the rest for the Ruby on Rails project here:
-* https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets
+* https://github.com/rails/rails/issues
diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb
index 6b87774978..a846f81c12 100644
--- a/activesupport/lib/active_support.rb
+++ b/activesupport/lib/active_support.rb
@@ -1,5 +1,5 @@
#--
-# Copyright (c) 2005 David Heinemeier Hansson
+# Copyright (c) 2005-2011 David Heinemeier Hansson
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
diff --git a/activesupport/lib/active_support/buffered_logger.rb b/activesupport/lib/active_support/buffered_logger.rb
index 88b50fc506..a14f008be5 100644
--- a/activesupport/lib/active_support/buffered_logger.rb
+++ b/activesupport/lib/active_support/buffered_logger.rb
@@ -49,10 +49,12 @@ module ActiveSupport
@log = log
elsif File.exist?(log)
@log = open(log, (File::WRONLY | File::APPEND))
+ @log.binmode
@log.sync = true
else
FileUtils.mkdir_p(File.dirname(log))
@log = open(log, (File::WRONLY | File::APPEND | File::CREAT))
+ @log.binmode
@log.sync = true
end
end
diff --git a/activesupport/lib/active_support/core_ext/array/conversions.rb b/activesupport/lib/active_support/core_ext/array/conversions.rb
index baefa9cae4..3b22e8b4f9 100644
--- a/activesupport/lib/active_support/core_ext/array/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/array/conversions.rb
@@ -37,12 +37,12 @@ class Array
# Converts a collection of elements into a formatted string by calling
# <tt>to_s</tt> on all elements and joining them:
#
- # Blog.find(:all).to_formatted_s # => "First PostSecond PostThird Post"
+ # Blog.all.to_formatted_s # => "First PostSecond PostThird Post"
#
# Adding in the <tt>:db</tt> argument as the format yields a prettier
# output:
#
- # Blog.find(:all).to_formatted_s(:db) # => "First Post,Second Post,Third Post"
+ # Blog.all.to_formatted_s(:db) # => "First Post,Second Post,Third Post"
def to_formatted_s(format = :default)
case format
when :db
diff --git a/activesupport/lib/active_support/core_ext/array/random_access.rb b/activesupport/lib/active_support/core_ext/array/random_access.rb
index 9eba4642b8..bb1807a68a 100644
--- a/activesupport/lib/active_support/core_ext/array/random_access.rb
+++ b/activesupport/lib/active_support/core_ext/array/random_access.rb
@@ -7,7 +7,7 @@ class Array
#
# [1,2,3,4,5,6].sample # => 4
# [1,2,3,4,5,6].sample(3) # => [2, 4, 5]
- # [1,2,3,4,5,6].sample(-3) # => ArgumentError: negative sample number
+ # [1,2,3,4,5,6].sample(-3) # => ArgumentError: negative array size
# [].sample # => nil
# [].sample(3) # => []
def sample(n=nil)
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 bd5c7a187f..9c5f97b0e9 100644
--- a/activesupport/lib/active_support/core_ext/array/uniq_by.rb
+++ b/activesupport/lib/active_support/core_ext/array/uniq_by.rb
@@ -1,8 +1,7 @@
class Array
- # Return an unique array based on the criteria given as a proc.
+ # Returns an unique array based on the criteria given as a +Proc+.
#
- # [1, 2, 3, 4].uniq_by { |i| i.odd? }
- # # => [1, 2]
+ # [1, 2, 3, 4].uniq_by { |i| i.odd? } # => [1, 2]
#
def uniq_by
hash, array = {}, []
diff --git a/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb b/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb
index ca3db2349e..ec475134ef 100644
--- a/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb
+++ b/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb
@@ -130,7 +130,6 @@ class Class # :nodoc:
end
def write_inheritable_attribute(key, value)
- ActiveSupport::Deprecation.warn ClassInheritableAttributes::DEPRECATION_WARNING_MESSAGE
if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES)
@inheritable_attributes = {}
end
@@ -148,7 +147,6 @@ class Class # :nodoc:
end
def read_inheritable_attribute(key)
- ActiveSupport::Deprecation.warn ClassInheritableAttributes::DEPRECATION_WARNING_MESSAGE
inheritable_attributes[key]
end
diff --git a/activesupport/lib/active_support/core_ext/date/calculations.rb b/activesupport/lib/active_support/core_ext/date/calculations.rb
index 724e076407..236055d77a 100644
--- a/activesupport/lib/active_support/core_ext/date/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/date/calculations.rb
@@ -206,7 +206,7 @@ class Date
# 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)
def beginning_of_month
- self.acts_like?(:time) ? change(:day => 1,:hour => 0, :min => 0, :sec => 0) : change(:day => 1)
+ self.acts_like?(:time) ? change(:day => 1, :hour => 0) : change(:day => 1)
end
alias :at_beginning_of_month :beginning_of_month
@@ -231,13 +231,13 @@ class Date
# Returns a new Date/DateTime representing the start of the year (1st of january; DateTime objects will have time set to 0:00)
def beginning_of_year
- self.acts_like?(:time) ? change(:month => 1, :day => 1, :hour => 0, :min => 0, :sec => 0) : change(:month => 1, :day => 1)
+ self.acts_like?(:time) ? change(:month => 1, :day => 1, :hour => 0) : change(:month => 1, :day => 1)
end
alias :at_beginning_of_year :beginning_of_year
# Returns a new Time representing the end of the year (31st of december; DateTime objects will have time set to 23:59:59)
def end_of_year
- self.acts_like?(:time) ? change(:month => 12,:day => 31,:hour => 23, :min => 59, :sec => 59) : change(:month => 12, :day => 31)
+ self.acts_like?(:time) ? change(:month => 12, :day => 31, :hour => 23, :min => 59, :sec => 59) : change(:month => 12, :day => 31)
end
alias :at_end_of_year :end_of_year
diff --git a/activesupport/lib/active_support/core_ext/date/conversions.rb b/activesupport/lib/active_support/core_ext/date/conversions.rb
index 769ead9544..338104fd05 100644
--- a/activesupport/lib/active_support/core_ext/date/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/date/conversions.rb
@@ -1,6 +1,7 @@
require 'date'
require 'active_support/inflector/methods'
require 'active_support/core_ext/date/zones'
+require 'active_support/core_ext/module/remove_method'
class Date
DATE_FORMATS = {
@@ -13,10 +14,10 @@ class Date
}
# Ruby 1.9 has Date#to_time which converts to localtime only.
- remove_method :to_time if method_defined?(:to_time)
+ remove_possible_method :to_time
# Ruby 1.9 has Date#xmlschema which converts to a string without the time component.
- remove_method :xmlschema if method_defined?(:xmlschema)
+ remove_possible_method :xmlschema
# Convert to a formatted string. See DATE_FORMATS for predefined formats.
#
diff --git a/activesupport/lib/active_support/core_ext/date_time/conversions.rb b/activesupport/lib/active_support/core_ext/date_time/conversions.rb
index 21b84b994b..ca899c714c 100644
--- a/activesupport/lib/active_support/core_ext/date_time/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/date_time/conversions.rb
@@ -51,25 +51,25 @@ class DateTime
utc? && alternate_utc_string || ActiveSupport::TimeZone.seconds_to_utc_offset(utc_offset, colon)
end
- # Overrides the default inspect method with a human readable one, e.g., "Mon, 21 Feb 2005 14:30:00 +0000"
+ # Overrides the default inspect method with a human readable one, e.g., "Mon, 21 Feb 2005 14:30:00 +0000".
def readable_inspect
to_s(:rfc822)
end
alias_method :default_inspect, :inspect
alias_method :inspect, :readable_inspect
- # Converts self to a Ruby Date object; time portion is discarded
+ # Converts self to a Ruby Date object; time portion is discarded.
def to_date
::Date.new(year, month, day)
end unless instance_methods(false).include?(:to_date)
- # Attempts to convert self to a Ruby Time object; returns self if out of range of Ruby Time class
- # If self has an offset other than 0, self will just be returned unaltered, since there's no clean way to map it to a Time
+ # Attempts to convert self to a Ruby Time object; returns self if out of range of Ruby Time class.
+ # If self has an offset other than 0, self will just be returned unaltered, since there's no clean way to map it to a Time.
def to_time
self.offset == 0 ? ::Time.utc_time(year, month, day, hour, min, sec, sec_fraction * (RUBY_VERSION < '1.9' ? 86400000000 : 1000000)) : self
end
- # To be able to keep Times, Dates and DateTimes interchangeable on conversions
+ # To be able to keep Times, Dates and DateTimes interchangeable on conversions.
def to_datetime
self
end unless instance_methods(false).include?(:to_datetime)
@@ -79,17 +79,17 @@ class DateTime
civil(year, month, day, hour, min, sec, offset)
end
- # Converts datetime to an appropriate format for use in XML
+ # Converts datetime to an appropriate format for use in XML.
def xmlschema
strftime("%Y-%m-%dT%H:%M:%S%Z")
end unless instance_methods(false).include?(:xmlschema)
- # Converts self to a floating-point number of seconds since the Unix epoch
+ # Converts self to a floating-point number of seconds since the Unix epoch.
def to_f
seconds_since_unix_epoch.to_f
end
- # Converts self to an integer number of seconds since the Unix epoch
+ # Converts self to an integer number of seconds since the Unix epoch.
def to_i
seconds_since_unix_epoch.to_i
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 aad4b61e16..c2a6476604 100644
--- a/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb
+++ b/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb
@@ -9,4 +9,16 @@ class Hash
def with_indifferent_access
ActiveSupport::HashWithIndifferentAccess.new_from_hash_copying_default(self)
end
+
+ # Called when object is nested under an object that receives
+ # #with_indifferent_access. This method with be called on the current object
+ # by the enclosing object and is aliased to #with_indifferent_access by
+ # default. Subclasses of Hash may overwrite this method to return +self+ if
+ # converting to an +ActiveSupport::HashWithIndifferentAccess+ would not be
+ # desirable.
+ #
+ # 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/hash/slice.rb b/activesupport/lib/active_support/core_ext/hash/slice.rb
index e4a864c20f..d7fb2da0fb 100644
--- a/activesupport/lib/active_support/core_ext/hash/slice.rb
+++ b/activesupport/lib/active_support/core_ext/hash/slice.rb
@@ -21,7 +21,7 @@ class Hash
# Replaces the hash with only the given keys.
# Returns a hash contained the removed key/value pairs
- # {:a => 1, :b => 2, :c => 3, :d => 4}.slice!(:a, :b) # => {:c => 3, :d =>4}
+ # {:a => 1, :b => 2, :c => 3, :d => 4}.slice!(:a, :b) # => {:c => 3, :d => 4}
def slice!(*keys)
keys = keys.map! { |key| convert_key(key) } if respond_to?(:convert_key)
omit = slice(*self.keys - keys)
diff --git a/activesupport/lib/active_support/core_ext/integer/inflections.rb b/activesupport/lib/active_support/core_ext/integer/inflections.rb
index e81e7af436..0e606056c0 100644
--- a/activesupport/lib/active_support/core_ext/integer/inflections.rb
+++ b/activesupport/lib/active_support/core_ext/integer/inflections.rb
@@ -4,10 +4,13 @@ class Integer
# Ordinalize turns a number into an ordinal string used to denote the
# position in an ordered sequence such as 1st, 2nd, 3rd, 4th.
#
- # 1.ordinalize # => "1st"
- # 2.ordinalize # => "2nd"
- # 1002.ordinalize # => "1002nd"
- # 1003.ordinalize # => "1003rd"
+ # 1.ordinalize # => "1st"
+ # 2.ordinalize # => "2nd"
+ # 1002.ordinalize # => "1002nd"
+ # 1003.ordinalize # => "1003rd"
+ # -11.ordinalize # => "-11th"
+ # -1001.ordinalize # => "-1001st"
+ #
def ordinalize
ActiveSupport::Inflector.ordinalize(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 37a827123a..c6920098a8 100644
--- a/activesupport/lib/active_support/core_ext/kernel/reporting.rb
+++ b/activesupport/lib/active_support/core_ext/kernel/reporting.rb
@@ -62,7 +62,7 @@ module Kernel
# Captures the given stream and returns it:
#
- # stream = capture(:stdout){ puts "Cool" }
+ # stream = capture(:stdout) { puts "Cool" }
# stream # => "Cool\n"
#
def capture(stream)
@@ -78,4 +78,16 @@ module Kernel
result
end
alias :silence :capture
+
+ # Silences both STDOUT and STDERR, even for subprocesses.
+ #
+ # quietly { system 'bundle install' }
+ #
+ def quietly
+ silence_stream(STDOUT) do
+ silence_stream(STDERR) do
+ yield
+ end
+ end
+ end
end
diff --git a/activesupport/lib/active_support/core_ext/module/attr_accessor_with_default.rb b/activesupport/lib/active_support/core_ext/module/attr_accessor_with_default.rb
index e3259a0a84..984f6fb957 100644
--- a/activesupport/lib/active_support/core_ext/module/attr_accessor_with_default.rb
+++ b/activesupport/lib/active_support/core_ext/module/attr_accessor_with_default.rb
@@ -19,6 +19,7 @@ class Module
# attr_accessor_with_default(:element_name) { name.underscore }
#
def attr_accessor_with_default(sym, default = Proc.new)
+ ActiveSupport::Deprecation.warn "attr_accessor_with_default is deprecated. Use Ruby instead!"
define_method(sym, block_given? ? default : Proc.new { default })
module_eval(<<-EVAL, __FILE__, __LINE__ + 1)
def #{sym}=(value) # def age=(value)
diff --git a/activesupport/lib/active_support/core_ext/module/deprecation.rb b/activesupport/lib/active_support/core_ext/module/deprecation.rb
index 9c169a2598..5a5b4e3f80 100644
--- a/activesupport/lib/active_support/core_ext/module/deprecation.rb
+++ b/activesupport/lib/active_support/core_ext/module/deprecation.rb
@@ -1,5 +1,3 @@
-require 'active_support/deprecation'
-
class Module
# Declare that a method has been deprecated.
# deprecate :foo
diff --git a/activesupport/lib/active_support/core_ext/object/blank.rb b/activesupport/lib/active_support/core_ext/object/blank.rb
index 20085c4fb3..fb5abf2aa5 100644
--- a/activesupport/lib/active_support/core_ext/object/blank.rb
+++ b/activesupport/lib/active_support/core_ext/object/blank.rb
@@ -1,14 +1,14 @@
class Object
# An object is blank if it's false, empty, or a whitespace string.
- # For example, "", " ", +nil+, [], and {} are blank.
+ # For example, "", " ", +nil+, [], and {} are all blank.
#
# This simplifies:
#
- # if !address.nil? && !address.empty?
+ # if address.nil? || address.empty?
#
# ...to:
#
- # if !address.blank?
+ # if address.blank?
def blank?
respond_to?(:empty?) ? empty? : !self
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 c23afabfdb..1397142c04 100644
--- a/activesupport/lib/active_support/core_ext/object/with_options.rb
+++ b/activesupport/lib/active_support/core_ext/object/with_options.rb
@@ -7,7 +7,7 @@ class Object
# provided. Each method called on the block variable must take an options
# hash as its final argument.
#
- # Without with_options, this code contains duplication:
+ # Without <tt>with_options></tt>, this code contains duplication:
#
# class Account < ActiveRecord::Base
# has_many :customers, :dependent => :destroy
@@ -16,7 +16,7 @@ class Object
# has_many :expenses, :dependent => :destroy
# end
#
- # Using with_options, we can remove the duplication:
+ # Using <tt>with_options</tt>, we can remove the duplication:
#
# class Account < ActiveRecord::Base
# with_options :dependent => :destroy do |assoc|
@@ -29,11 +29,14 @@ class Object
#
# It can also be used with an explicit receiver:
#
- # map.with_options :controller => "people" do |people|
- # people.connect "/people", :action => "index"
- # people.connect "/people/:id", :action => "show"
+ # I18n.with_options :locale => user.locale, :scope => "newsletter" do |i18n|
+ # subject i18n.t :subject
+ # body i18n.t :body, :user_name => user.name
# end
#
+ # <tt>with_options</tt> 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/behavior.rb b/activesupport/lib/active_support/core_ext/string/behavior.rb
index 9d45fbca45..4aa960039b 100644
--- a/activesupport/lib/active_support/core_ext/string/behavior.rb
+++ b/activesupport/lib/active_support/core_ext/string/behavior.rb
@@ -1,6 +1,5 @@
class String
- # Enable more predictable duck-typing on String-like classes. See
- # Object#acts_like?.
+ # Enable more predictable duck-typing on String-like classes. See <tt>Object#acts_like?</tt>.
def acts_like_string?
true
end
diff --git a/activesupport/lib/active_support/core_ext/string/exclude.rb b/activesupport/lib/active_support/core_ext/string/exclude.rb
index 5ca268b953..5e184ec1b3 100644
--- a/activesupport/lib/active_support/core_ext/string/exclude.rb
+++ b/activesupport/lib/active_support/core_ext/string/exclude.rb
@@ -1,5 +1,5 @@
class String
- # The inverse of String#include?. Returns true if the string does not include the other string.
+ # The inverse of <tt>String#include?</tt>. Returns true if the string does not include the other string.
def exclude?(string)
!include?(string)
end
diff --git a/activesupport/lib/active_support/core_ext/string/inquiry.rb b/activesupport/lib/active_support/core_ext/string/inquiry.rb
index 604f3bf4dc..5f0a017de6 100644
--- a/activesupport/lib/active_support/core_ext/string/inquiry.rb
+++ b/activesupport/lib/active_support/core_ext/string/inquiry.rb
@@ -1,7 +1,7 @@
require 'active_support/string_inquirer'
class String
- # Wraps the current string in the ActiveSupport::StringInquirer class,
+ # Wraps the current string in the <tt>ActiveSupport::StringInquirer</tt> class,
# which gives you a prettier way to test for equality. Example:
#
# env = "production".inquiry
diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb
index 7e134db118..dcac17536a 100644
--- a/activesupport/lib/active_support/core_ext/time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/time/calculations.rb
@@ -187,7 +187,7 @@ class Time
# Returns a new Time representing the start of the day (0:00)
def beginning_of_day
#(self - seconds_since_midnight).change(:usec => 0)
- change(:hour => 0, :min => 0, :sec => 0, :usec => 0)
+ change(:hour => 0)
end
alias :midnight :beginning_of_day
alias :at_midnight :beginning_of_day
@@ -201,7 +201,7 @@ class Time
# Returns a new Time representing the start of the month (1st of the month, 0:00)
def beginning_of_month
#self - ((self.mday-1).days + self.seconds_since_midnight)
- change(:day => 1,:hour => 0, :min => 0, :sec => 0, :usec => 0)
+ change(:day => 1, :hour => 0)
end
alias :at_beginning_of_month :beginning_of_month
@@ -227,7 +227,7 @@ class Time
# Returns a new Time representing the start of the year (1st of january, 0:00)
def beginning_of_year
- change(:month => 1, :day => 1, :hour => 0, :min => 0, :sec => 0, :usec => 0)
+ change(:month => 1, :day => 1, :hour => 0)
end
alias :at_beginning_of_year :beginning_of_year
diff --git a/activesupport/lib/active_support/hash_with_indifferent_access.rb b/activesupport/lib/active_support/hash_with_indifferent_access.rb
index 79a0de7940..39ebc1ec82 100644
--- a/activesupport/lib/active_support/hash_with_indifferent_access.rb
+++ b/activesupport/lib/active_support/hash_with_indifferent_access.rb
@@ -10,6 +10,10 @@ module ActiveSupport
true
end
+ def with_indifferent_access
+ self
+ end
+
def initialize(constructor = {})
if constructor.is_a?(Hash)
super()
@@ -58,8 +62,12 @@ module ActiveSupport
# hash_1.update(hash_2) # => {"key"=>"New Value!"}
#
def update(other_hash)
- other_hash.each_pair { |key, value| regular_writer(convert_key(key), convert_value(value)) }
- self
+ if other_hash.is_a? HashWithIndifferentAccess
+ super(other_hash)
+ else
+ other_hash.each_pair { |key, value| regular_writer(convert_key(key), convert_value(value)) }
+ self
+ end
end
alias_method :merge!, :update
@@ -140,8 +148,8 @@ module ActiveSupport
end
def convert_value(value)
- if value.class == Hash
- self.class.new_from_hash_copying_default(value)
+ if value.is_a? Hash
+ value.nested_under_indifferent_access
elsif value.is_a?(Array)
value.dup.replace(value.map { |e| convert_value(e) })
else
diff --git a/activesupport/lib/active_support/inflector/methods.rb b/activesupport/lib/active_support/inflector/methods.rb
index dd2beef89d..a2c4f7bfda 100644
--- a/activesupport/lib/active_support/inflector/methods.rb
+++ b/activesupport/lib/active_support/inflector/methods.rb
@@ -135,6 +135,8 @@ module ActiveSupport
# ordinalize(2) # => "2nd"
# ordinalize(1002) # => "1002nd"
# ordinalize(1003) # => "1003rd"
+ # ordinalize(-11) # => "-11th"
+ # ordinalize(-1021) # => "-1021st"
def ordinalize(number)
if (11..13).include?(number.to_i.abs % 100)
"#{number}th"
@@ -148,4 +150,4 @@ module ActiveSupport
end
end
end
-end \ No newline at end of file
+end
diff --git a/activesupport/lib/active_support/json/encoding.rb b/activesupport/lib/active_support/json/encoding.rb
index 1fafc36ee8..d22fe14b33 100644
--- a/activesupport/lib/active_support/json/encoding.rb
+++ b/activesupport/lib/active_support/json/encoding.rb
@@ -2,6 +2,7 @@ require 'active_support/core_ext/object/to_json'
require 'active_support/core_ext/module/delegation'
require 'active_support/deprecation'
require 'active_support/json/variable'
+require 'active_support/ordered_hash'
require 'bigdecimal'
require 'active_support/core_ext/big_decimal/conversions' # for #to_s
diff --git a/activesupport/lib/active_support/log_subscriber/test_helper.rb b/activesupport/lib/active_support/log_subscriber/test_helper.rb
index 392e33edbc..3e54134c5c 100644
--- a/activesupport/lib/active_support/log_subscriber/test_helper.rb
+++ b/activesupport/lib/active_support/log_subscriber/test_helper.rb
@@ -1,5 +1,6 @@
require 'active_support/log_subscriber'
require 'active_support/buffered_logger'
+require 'active_support/notifications'
module ActiveSupport
class LogSubscriber
diff --git a/activesupport/lib/active_support/ordered_hash.rb b/activesupport/lib/active_support/ordered_hash.rb
index fbc40d1b69..762a64a881 100644
--- a/activesupport/lib/active_support/ordered_hash.rb
+++ b/activesupport/lib/active_support/ordered_hash.rb
@@ -43,6 +43,10 @@ module ActiveSupport
end
end
+ def nested_under_indifferent_access
+ self
+ end
+
# Hash is ordered in Ruby 1.9!
if RUBY_VERSION < '1.9'
diff --git a/activesupport/lib/active_support/secure_random.rb b/activesupport/lib/active_support/secure_random.rb
index 368954907f..52f8c72b77 100644
--- a/activesupport/lib/active_support/secure_random.rb
+++ b/activesupport/lib/active_support/secure_random.rb
@@ -1,205 +1,6 @@
-begin
- require 'securerandom'
-rescue LoadError
-end
+require 'securerandom'
module ActiveSupport
- if defined?(::SecureRandom)
- # Use Ruby's SecureRandom library if available.
- SecureRandom = ::SecureRandom # :nodoc:
- else
- # = Secure random number generator interface.
- #
- # This library is an interface for secure random number generator which is
- # suitable for generating session key in HTTP cookies, etc.
- #
- # It supports following secure random number generators.
- #
- # * openssl
- # * /dev/urandom
- # * Win32
- #
- # *Note*: This module is based on the SecureRandom library from Ruby 1.9,
- # revision 18786, August 23 2008. It's 100% interface-compatible with Ruby 1.9's
- # SecureRandom library.
- #
- # == Example
- #
- # # random hexadecimal string.
- # p SecureRandom.hex(10) # => "52750b30ffbc7de3b362"
- # p SecureRandom.hex(10) # => "92b15d6c8dc4beb5f559"
- # p SecureRandom.hex(11) # => "6aca1b5c58e4863e6b81b8"
- # p SecureRandom.hex(12) # => "94b2fff3e7fd9b9c391a2306"
- # p SecureRandom.hex(13) # => "39b290146bea6ce975c37cfc23"
- # ...
- #
- # # random base64 string.
- # p SecureRandom.base64(10) # => "EcmTPZwWRAozdA=="
- # p SecureRandom.base64(10) # => "9b0nsevdwNuM/w=="
- # p SecureRandom.base64(10) # => "KO1nIU+p9DKxGg=="
- # p SecureRandom.base64(11) # => "l7XEiFja+8EKEtY="
- # p SecureRandom.base64(12) # => "7kJSM/MzBJI+75j8"
- # p SecureRandom.base64(13) # => "vKLJ0tXBHqQOuIcSIg=="
- # ...
- #
- # # random binary string.
- # p SecureRandom.random_bytes(10) # => "\016\t{\370g\310pbr\301"
- # p SecureRandom.random_bytes(10) # => "\323U\030TO\234\357\020\a\337"
- # ...
- #
- module SecureRandom
-
- # Generates a random binary string.
- #
- # The argument n specifies the length of the result string.
- #
- # If n is not specified, 16 is assumed.
- # It may be larger in future.
- #
- # If secure random number generator is not available,
- # NotImplementedError is raised.
- #
- def self.random_bytes(n=nil)
- n ||= 16
-
- unless defined? OpenSSL
- begin
- require 'openssl'
- rescue LoadError
- end
- end
-
- if defined? OpenSSL::Random
- return OpenSSL::Random.random_bytes(n)
- end
-
- if !defined?(@has_urandom) || @has_urandom
- flags = File::RDONLY
- flags |= File::NONBLOCK if defined? File::NONBLOCK
- flags |= File::NOCTTY if defined? File::NOCTTY
- flags |= File::NOFOLLOW if defined? File::NOFOLLOW
- begin
- File.open("/dev/urandom", flags) {|f|
- unless f.stat.chardev?
- raise Errno::ENOENT
- end
- @has_urandom = true
- ret = f.readpartial(n)
- if ret.length != n
- raise NotImplementedError, "Unexpected partial read from random device"
- end
- return ret
- }
- rescue Errno::ENOENT
- @has_urandom = false
- end
- end
-
- unless defined?(@has_win32)
- begin
- require 'Win32API'
-
- crypt_acquire_context = Win32API.new("advapi32", "CryptAcquireContext", 'PPPII', 'L')
- @crypt_gen_random = Win32API.new("advapi32", "CryptGenRandom", 'LIP', 'L')
-
- hProvStr = " " * 4
- prov_rsa_full = 1
- crypt_verifycontext = 0xF0000000
-
- if crypt_acquire_context.call(hProvStr, nil, nil, prov_rsa_full, crypt_verifycontext) == 0
- raise SystemCallError, "CryptAcquireContext failed: #{lastWin32ErrorMessage}"
- end
- @hProv, = hProvStr.unpack('L')
-
- @has_win32 = true
- rescue LoadError
- @has_win32 = false
- end
- end
- if @has_win32
- bytes = " " * n
- if @crypt_gen_random.call(@hProv, bytes.size, bytes) == 0
- raise SystemCallError, "CryptGenRandom failed: #{lastWin32ErrorMessage}"
- end
- return bytes
- end
-
- raise NotImplementedError, "No random device"
- end
-
- # Generates a random hex string.
- #
- # The argument n specifies the length of the random length.
- # The length of the result string is twice of n.
- #
- # If n is not specified, 16 is assumed.
- # It may be larger in future.
- #
- # If secure random number generator is not available,
- # NotImplementedError is raised.
- #
- def self.hex(n=nil)
- random_bytes(n).unpack("H*")[0]
- end
-
- # Generates a random base64 string.
- #
- # The argument n specifies the length of the random length.
- # The length of the result string is about 4/3 of n.
- #
- # If n is not specified, 16 is assumed.
- # It may be larger in future.
- #
- # If secure random number generator is not available,
- # NotImplementedError is raised.
- #
- def self.base64(n=nil)
- [random_bytes(n)].pack("m*").delete("\n")
- end
-
- # Generates a random number.
- #
- # If an positive integer is given as n,
- # SecureRandom.random_number returns an integer:
- # 0 <= SecureRandom.random_number(n) < n.
- #
- # If 0 is given or an argument is not given,
- # SecureRandom.random_number returns an float:
- # 0.0 <= SecureRandom.random_number() < 1.0.
- #
- def self.random_number(n=0)
- if 0 < n
- hex = n.to_s(16)
- hex = '0' + hex if (hex.length & 1) == 1
- bin = [hex].pack("H*")
- mask = bin[0]
- mask |= mask >> 1
- mask |= mask >> 2
- mask |= mask >> 4
- begin
- rnd = SecureRandom.random_bytes(bin.length)
- rnd[0] = rnd[0] & mask
- end until rnd < bin
- rnd.unpack("H*")[0].hex
- else
- # assumption: Float::MANT_DIG <= 64
- i64 = SecureRandom.random_bytes(8).unpack("Q")[0]
- Math.ldexp(i64 >> (64-Float::MANT_DIG), -Float::MANT_DIG)
- end
- end
-
- # Following code is based on David Garamond's GUID library for Ruby.
- def self.lastWin32ErrorMessage # :nodoc:
- get_last_error = Win32API.new("kernel32", "GetLastError", '', 'L')
- format_message = Win32API.new("kernel32", "FormatMessageA", 'LPLLPLPPPPPPPP', 'L')
- format_message_ignore_inserts = 0x00000200
- format_message_from_system = 0x00001000
-
- code = get_last_error.call
- msg = "\0" * 1024
- len = format_message.call(format_message_ignore_inserts + format_message_from_system, 0, code, 0, msg, 1024, nil, nil, nil, nil, nil, nil, nil, nil)
- msg[0, len].tr("\r", '').chomp
- end
- end
- end
+ # Use Ruby's SecureRandom library.
+ SecureRandom = ::SecureRandom # :nodoc:
end
diff --git a/activesupport/lib/active_support/xml_mini.rb b/activesupport/lib/active_support/xml_mini.rb
index dff8a8f4c4..6e12404ad4 100644
--- a/activesupport/lib/active_support/xml_mini.rb
+++ b/activesupport/lib/active_support/xml_mini.rb
@@ -139,7 +139,9 @@ module ActiveSupport
protected
def _dasherize(key)
- key.gsub(/(?!^[_]*)_(?![_]*$)/, '-')
+ # $2 must be a non-greedy regex for this to work
+ left, middle, right = /\A(_*)(.*?)(_*)\Z/.match(key.strip)[1,3]
+ "#{left}#{middle.tr('_ ', '--')}#{right}"
end
# TODO: Add support for other encodings
diff --git a/activesupport/test/buffered_logger_test.rb b/activesupport/test/buffered_logger_test.rb
index 8d1b1c02c6..21049d685b 100644
--- a/activesupport/test/buffered_logger_test.rb
+++ b/activesupport/test/buffered_logger_test.rb
@@ -2,6 +2,7 @@ require 'abstract_unit'
require 'multibyte_test_helpers'
require 'stringio'
require 'fileutils'
+require 'tempfile'
require 'active_support/buffered_logger'
class BufferedLoggerTest < Test::Unit::TestCase
@@ -16,6 +17,44 @@ class BufferedLoggerTest < Test::Unit::TestCase
@logger = Logger.new(@output)
end
+ def test_write_binary_data_to_existing_file
+ t = Tempfile.new ['development', 'log']
+ t.binmode
+ t.write 'hi mom!'
+ t.close
+
+ logger = Logger.new t.path
+ logger.level = Logger::DEBUG
+
+ str = "\x80"
+ if str.respond_to?(:force_encoding)
+ str.force_encoding("ASCII-8BIT")
+ end
+
+ logger.add Logger::DEBUG, str
+ logger.flush
+ ensure
+ logger.close
+ t.close true
+ end
+
+ def test_write_binary_data_create_file
+ fname = File.join Dir.tmpdir, 'lol', 'rofl.log'
+ logger = Logger.new fname
+ logger.level = Logger::DEBUG
+
+ str = "\x80"
+ if str.respond_to?(:force_encoding)
+ str.force_encoding("ASCII-8BIT")
+ end
+
+ logger.add Logger::DEBUG, str
+ logger.flush
+ ensure
+ logger.close
+ File.unlink fname
+ end
+
def test_should_log_debugging_message_when_debugging
@logger.level = Logger::DEBUG
@logger.add(Logger::DEBUG, @message)
diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb
index 3ef080e1cb..b2c85f15cb 100644
--- a/activesupport/test/core_ext/hash_ext_test.rb
+++ b/activesupport/test/core_ext/hash_ext_test.rb
@@ -16,6 +16,12 @@ class HashExtTest < Test::Unit::TestCase
class SubclassingHash < Hash
end
+ class NonIndifferentHash < Hash
+ def nested_under_indifferent_access
+ self
+ end
+ end
+
def setup
@strings = { 'a' => 1, 'b' => 2 }
@symbols = { :a => 1, :b => 2 }
@@ -109,9 +115,12 @@ class HashExtTest < Test::Unit::TestCase
assert_equal @strings, @mixed.with_indifferent_access.dup.stringify_keys!
end
- def test_hash_subclass
- flash = { "foo" => SubclassingHash.new.tap { |h| h["bar"] = "baz" } }.with_indifferent_access
- assert_kind_of SubclassingHash, flash["foo"]
+ 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"]
+
+ foo = { "foo" => NonIndifferentHash.new.tap { |h| h["bar"] = "baz" } }.with_indifferent_access
+ assert_kind_of NonIndifferentHash, foo["foo"]
end
def test_indifferent_assorted
@@ -962,6 +971,11 @@ class HashToXmlTest < Test::Unit::TestCase
assert_nil hash_wia.default
end
+ def test_should_return_self_for_with_indifferent_access
+ hash_wia = HashWithIndifferentAccess.new
+ assert_equal hash_wia, hash_wia.with_indifferent_access
+ end
+
def test_should_copy_the_default_value_when_converting_to_hash_with_indifferent_access
hash = Hash.new(3)
hash_wia = hash.with_indifferent_access
diff --git a/activesupport/test/core_ext/module/attr_accessor_with_default_test.rb b/activesupport/test/core_ext/module/attr_accessor_with_default_test.rb
index b9b60c4d6d..0ecd16b051 100644
--- a/activesupport/test/core_ext/module/attr_accessor_with_default_test.rb
+++ b/activesupport/test/core_ext/module/attr_accessor_with_default_test.rb
@@ -1,7 +1,7 @@
require 'abstract_unit'
require 'active_support/core_ext/module/attr_accessor_with_default'
-class AttrAccessorWithDefaultTest < Test::Unit::TestCase
+class AttrAccessorWithDefaultTest < ActiveSupport::TestCase
def setup
@target = Class.new do
def helper
@@ -12,20 +12,28 @@ class AttrAccessorWithDefaultTest < Test::Unit::TestCase
end
def test_default_arg
- @target.attr_accessor_with_default :foo, :bar
+ assert_deprecated do
+ @target.attr_accessor_with_default :foo, :bar
+ end
assert_equal(:bar, @instance.foo)
@instance.foo = nil
assert_nil(@instance.foo)
end
def test_default_proc
- @target.attr_accessor_with_default(:foo) {helper.upcase}
+ assert_deprecated do
+ @target.attr_accessor_with_default(:foo) {helper.upcase}
+ end
assert_equal('HELPER', @instance.foo)
@instance.foo = nil
assert_nil(@instance.foo)
end
def test_invalid_args
- assert_raise(ArgumentError) {@target.attr_accessor_with_default :foo}
+ assert_raise(ArgumentError) do
+ assert_deprecated do
+ @target.attr_accessor_with_default :foo
+ end
+ end
end
end
diff --git a/activesupport/test/ordered_hash_test.rb b/activesupport/test/ordered_hash_test.rb
index 50168fa78f..f3dcd7b068 100644
--- a/activesupport/test/ordered_hash_test.rb
+++ b/activesupport/test/ordered_hash_test.rb
@@ -1,6 +1,7 @@
require 'abstract_unit'
require 'active_support/json'
require 'active_support/core_ext/object/to_json'
+require 'active_support/core_ext/hash/indifferent_access'
class OrderedHashTest < Test::Unit::TestCase
def setup
@@ -243,6 +244,11 @@ class OrderedHashTest < Test::Unit::TestCase
assert_equal @other_ordered_hash.keys, @ordered_hash.keys
end
+ def test_nested_under_indifferent_access
+ flash = {:a => ActiveSupport::OrderedHash[:b, 1, :c, 2]}.with_indifferent_access
+ assert_kind_of ActiveSupport::OrderedHash, flash[:a]
+ end
+
def test_each_after_yaml_serialization
values = []
@deserialized_ordered_hash = YAML.load(YAML.dump(@ordered_hash))
diff --git a/activesupport/test/xml_mini_test.rb b/activesupport/test/xml_mini_test.rb
index 310d86a019..e2b90ae16e 100644
--- a/activesupport/test/xml_mini_test.rb
+++ b/activesupport/test/xml_mini_test.rb
@@ -87,6 +87,16 @@ module XmlMiniTest
@xml.to_tag(:b, "Howdy", @options)
assert_xml "<b>Howdy</b>"
end
+
+ test "#to_tag should dasherize the space when passed a string with spaces as a key" do
+ @xml.to_tag("New York", 33, @options)
+ assert_xml "<New---York type=\"integer\">33</New---York>"
+ end
+
+ test "#to_tag should dasherize the space when passed a symbol with spaces as a key" do
+ @xml.to_tag(:"New York", 33, @options)
+ assert_xml "<New---York type=\"integer\">33</New---York>"
+ end
# TODO: test the remaining functions hidden in #to_tag.
end
end
diff --git a/railties/CHANGELOG b/railties/CHANGELOG
index 21666103de..c465b08594 100644
--- a/railties/CHANGELOG
+++ b/railties/CHANGELOG
@@ -1,5 +1,7 @@
*Rails 3.1.0 (unreleased)*
+* Application and plugin generation run bundle install unless --skip-gemfile or --skip-bundle. [fxn]
+
* Fixed database tasks for jdbc* adapters #jruby
[Rashmi Yadav]
@@ -28,7 +30,7 @@ by the prototype-rails gem. [fxn]
* jQuery is the new default JavaScript library. [fxn]
-* Changed scaffold and app generator to create Ruby 1.9 style hash when running on Ruby 1.9 [Prem Sichanugrist]
+* Changed scaffold, application, and mailer generator to create Ruby 1.9 style hash when running on Ruby 1.9 [Prem Sichanugrist]
So instead of creating something like:
@@ -74,10 +76,42 @@ by the prototype-rails gem. [fxn]
* Include all helpers from plugins and shared engines in application [Piotr Sarnacki]
+
+*Rails 3.0.7 (April 18, 2011)*
+
+*No changes.
+
+
+*Rails 3.0.6 (April 5, 2011)
+
+* No changes.
+
+
+*Rails 3.0.5 (February 26, 2011)*
+
+* No changes.
+
+
+*Rails 3.0.4 (February 8, 2011)*
+
+* No changes.
+
+
+*Rails 3.0.3 (November 16, 2010)*
+
+* No changes.
+
+
+*Rails 3.0.2 (November 15, 2010)*
+
+* No changes.
+
+
*Rails 3.0.1 (October 15, 2010)*
* No Changes, just a version bump.
+
*Rails 3.0.0 (August 29, 2010)*
* Application generation: --skip-testunit and --skip-activerecord become --skip-test-unit and --skip-active-record respectively. [fxn]
diff --git a/railties/guides/rails_guides/generator.rb b/railties/guides/rails_guides/generator.rb
index 154355cac1..14d671c8f3 100644
--- a/railties/guides/rails_guides/generator.rb
+++ b/railties/guides/rails_guides/generator.rb
@@ -38,9 +38,10 @@
# Note that if you are working on a guide generation will by default process
# only that one, so ONLY is rarely used nowadays.
#
-# LANGUAGE
-# Use LANGUAGE when you want to generate translated guides in <tt>source/<LANGUAGE></tt>
-# folder (such as <tt>source/es</tt>). Ignore it when generating English guides.
+# GUIDES_LANGUAGE
+# Use GUIDES_LANGUAGE when you want to generate translated guides in
+# <tt>source/<GUIDES_LANGUAGE></tt> folder (such as <tt>source/es</tt>).
+# Ignore it when generating English guides.
#
# EDGE
# Set to "1" to indicate generated guides should be marked as edge. This
@@ -67,7 +68,7 @@ module RailsGuides
GUIDES_RE = /\.(?:textile|html\.erb)$/
def initialize(output=nil)
- @lang = ENV['LANGUAGE']
+ @lang = ENV['GUIDES_LANGUAGE']
initialize_dirs(output)
create_output_dir_if_needed
set_flags_from_environment
diff --git a/railties/guides/source/action_controller_overview.textile b/railties/guides/source/action_controller_overview.textile
index 3a1a4ee66e..891bae3d5e 100644
--- a/railties/guides/source/action_controller_overview.textile
+++ b/railties/guides/source/action_controller_overview.textile
@@ -110,6 +110,32 @@ When this form is submitted, the value of +params[:client]+ will be <tt>{"name"
Note that the +params+ hash is actually an instance of +HashWithIndifferentAccess+ from Active Support, which acts like a hash that lets you use symbols and strings interchangeably as keys.
+h4. JSON/XML parameters
+
+If you're writing a web service application, you might find yourself more comfortable on accepting parameters in JSON or XML format. Rails will automatically convert your parameters into +params+ hash, which you'll be able to access like you would normally do with form data.
+
+So for example, if you are sending this JSON parameter:
+
+<pre>
+{ "company": { "name": "acme", "address": "123 Carrot Street" } }
+</pre>
+
+You'll get <tt>params[:company]</tt> as <tt>{ :name => "acme", "address" => "123 Carrot Street" }</tt>.
+
+Also, if you've turned on +config.wrap_parameters+ in your initializer or calling +wrap_parameters+ in your controller, you can safely omit the root element in the JSON/XML parameter. The parameters will be cloned and wrapped in the key according to your controller's name by default. So the above parameter can be written as:
+
+<pre>
+{ "name": "acme", "address": "123 Carrot Street" }
+</pre>
+
+And assume that you're sending the data to +CompaniesController+, it would then be wrapped in +:company+ key like this:
+
+<ruby>
+{ :name => "acme", :address => "123 Carrot Street", :company => { :name => "acme", :address => "123 Carrot Street" }}
+</ruby>
+
+You can customize the name of the key or specific parameters you want to wrap by consulting the "API documentation":http://api.rubyonrails.org/classes/ActionController/ParamsWrapper.html
+
h4. Routing Parameters
The +params+ hash will always contain the +:controller+ and +:action+ keys, but you should use the methods +controller_name+ and +action_name+ instead to access these values. Any other parameters defined by the routing, such as +:id+ will also be available. As an example, consider a listing of clients where the list can show either active or inactive clients. We can add a route which captures the +:status+ parameter in a "pretty" URL:
diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile
index f2170e120b..66869b4eeb 100644
--- a/railties/guides/source/active_support_core_extensions.textile
+++ b/railties/guides/source/active_support_core_extensions.textile
@@ -417,6 +417,14 @@ silence_stream(STDOUT) do
end
</ruby>
+The +quietly+ method addresses the common use case where you want to silence STDOUT and STDERR, even in subprocesses:
+
+<ruby>
+quietly { system 'bundle install' }
+</ruby>
+
+For example, the railties test suite uses that one in a few places to prevent command messages from being echoed intermixed with the progress status.
+
Silencing exceptions is also possible with +suppress+. This method receives an arbitrary number of exception classes. If an exception is raised during the execution of the block and is +kind_of?+ any of the arguments, +suppress+ captures it and returns silently. Otherwise the exception is reraised:
<ruby>
@@ -1833,6 +1841,8 @@ The method +ordinalize+ returns the ordinal string corresponding to the receiver
2.ordinalize # => "2nd"
53.ordinalize # => "53rd"
2009.ordinalize # => "2009th"
+-21.ordinalize # => "-21st"
+-134.ordinalize # => "-134th"
</ruby>
NOTE: Defined in +active_support/core_ext/integer/inflections.rb+.
diff --git a/railties/guides/source/association_basics.textile b/railties/guides/source/association_basics.textile
index 94dce1b97b..458bfefad8 100644
--- a/railties/guides/source/association_basics.textile
+++ b/railties/guides/source/association_basics.textile
@@ -342,9 +342,9 @@ In designing a data model, you will sometimes find a model that should have a re
<ruby>
class Employee < ActiveRecord::Base
- has_many :subordinates, :class_name => "Employee",
+ has_many :subordinates, :class_name => "Employee"
+ belongs_to :manager, :class_name => "Employee",
:foreign_key => "manager_id"
- belongs_to :manager, :class_name => "Employee"
end
</ruby>
diff --git a/railties/guides/source/caching_with_rails.textile b/railties/guides/source/caching_with_rails.textile
index 799339e674..91827fd493 100644
--- a/railties/guides/source/caching_with_rails.textile
+++ b/railties/guides/source/caching_with_rails.textile
@@ -98,7 +98,7 @@ You can also use +:if+ (or +:unless+) to pass a Proc that specifies when the act
You can modify the default action cache path by passing a +:cache_path+ option. This will be passed directly to +ActionCachePath.path_for+. This is handy for actions with multiple possible routes that should be cached differently. If a block is given, it is called with the current controller instance.
-Finally, if you are using memcached, you can also pass +:expires_in+. In fact, all parameters not used by +caches_action+ are sent to the underlying cache store.
+Finally, if you are using memcached or Ehcache, you can also pass +:expires_in+. In fact, all parameters not used by +caches_action+ are sent to the underlying cache store.
INFO: Action caching runs in an after filter. Thus, invalid requests won't generate spurious cache entries as long as you halt them. Typically, a redirection in some before filter that checks request preconditions does the job.
@@ -304,6 +304,35 @@ The +write+ and +fetch+ methods on this cache accept two additional options that
ActionController::Base.cache_store = :mem_cache_store, "cache-1.example.com", "cache-2.example.com"
</ruby>
+h4. ActiveSupport::Cache::EhcacheStore
+
+If you are using JRuby you can use Terracotta's Ehcache as the cache store for your application. Ehcache is an open source Java cache that also offers an enterprise version with increased scalability, management, and commercial support. You must first install the jruby-ehcache-rails3 gem (version 1.1.0 or later) to use this cache store.
+
+<ruby>
+ActionController::Base.cache_store = :ehcache_store
+</ruby>
+
+When initializing the cache, you may use the +:ehcache_config+ option to specify the Ehcache config file to use (where the default is "ehcache.xml" in your Rails config directory), and the :cache_name option to provide a custom name for your cache (the default is rails_cache).
+
+In addition to the standard +:expires_in+ option, the +write+ method on this cache can also accept the additional +:unless_exist+ option, which will cause the cache store to use Ehcache's +putIfAbsent+ method instead of +put+, and therefore will not overwrite an existing entry. Additionally, the +write+ method supports all of the properties exposed by the "Ehcache Element class":http://ehcache.org/apidocs/net/sf/ehcache/Element.html , including:
+
+|_. Property |_. Argument Type |_. Description |
+| elementEvictionData | ElementEvictionData | Sets this element's eviction data instance. |
+| eternal | boolean | Sets whether the element is eternal. |
+| timeToIdle, tti | int | Sets time to idle |
+| timeToLive, ttl, expires_in | int | Sets time to Live |
+| version | long | Sets the version attribute of the ElementAttributes object. |
+
+These options are passed to the +write+ method as Hash options using either camelCase or underscore notation, as in the following examples:
+
+<ruby>
+Rails.cache.write('key', 'value', :time_to_idle => 60.seconds, :timeToLive => 600.seconds)
+caches_action :index, :expires_in => 60.seconds, :unless_exist => true
+</ruby>
+
+For more information about Ehcache, see "http://ehcache.org/":http://ehcache.org/ .
+For more information about Ehcache for JRuby and Rails, see "http://ehcache.org/documentation/jruby.html":http://ehcache.org/documentation/jruby.html
+
h4. Custom Cache Stores
You can create your own custom cache store by simply extending +ActiveSupport::Cache::Store+ and implementing the appropriate methods. In this way, you can swap in any number of caching technologies into your Rails application.
diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile
index d7069b31fc..fbe3d46367 100644
--- a/railties/guides/source/configuring.textile
+++ b/railties/guides/source/configuring.textile
@@ -9,37 +9,38 @@ endprologue.
h3. Locations for Initialization Code
-Rails offers (at least) four good spots to place initialization code:
+Rails offers four standard spots to place initialization code:
-* application.rb
-* Environment-specific Configuration Files
+* +config/application.rb+
+* Environment-specific configuration files
* Initializers
-* After-Initializers
+* After-initializers
h3. Running Code Before Rails
-To run some code before Rails itself is loaded, simply put it above the call to
-+require 'rails/all'+ in your +application.rb+.
+In the rare event that your application needs to run some code before Rails itself is loaded, put it above the call to +require 'rails/all'+ in your +config/application.rb+.
h3. Configuring Rails Components
-In general, the work of configuring Rails means configuring the components of Rails, as well as configuring Rails itself. The +application.rb+ and environment-specific configuration files (such as +config/environments/production.rb+) allow you to specify the various settings that you want to pass down to all of the components. For example, the default Rails 3.0 +application.rb+ file includes this setting:
+In general, the work of configuring Rails means configuring the components of Rails, as well as configuring Rails itself. The configuration file +config/application.rb+ and environment-specific configuration files (such as +config/environments/production.rb+) allow you to specify the various settings that you want to pass down to all of the components.
+
+For example, the default +config/application.rb+ file includes this setting:
<ruby>
- config.filter_parameters += [:password]
+config.filter_parameters += [:password]
</ruby>
-This is a setting for Rails itself. If you want to pass settings to individual Rails components, you can do so via the same +config+ object:
+This is a setting for Rails itself. If you want to pass settings to individual Rails components, you can do so via the same +config+ object in +config/application.rb+:
<ruby>
- config.active_record.timestamped_migrations = false
+config.active_record.observers = [:hotel_observer, :review_observer]
</ruby>
Rails will use that particular setting to configure Active Record.
h4. Rails General Configuration
-* +config.after_initialize+ takes a block which will be ran _after_ Rails has finished initializing. Useful for configuring values set up by other initializers:
+* +config.after_initialize+ takes a block which will be ran _after_ Rails has finished initializing the application. That includes the initialization of the framework itself, plugins, engines, and all the application's initializers in +config/initializers+. Useful for configuring values set up by other initializers:
<ruby>
config.after_initialize do
@@ -47,71 +48,63 @@ config.after_initialize do
end
</ruby>
-* +config.allow_concurrency+ should be set to +true+ to allow concurrent (threadsafe) action processing. Set to +false+ by default. You probably don't want to call this one directly, though, because a series of other adjustments need to be made for threadsafe mode to work properly. Can also be enabled with +threadsafe!+.
+* +config.allow_concurrency+ should be true to allow concurrent (threadsafe) action processing. False by default. You probably don't want to call this one directly, though, because a series of other adjustments need to be made for threadsafe mode to work properly. Can also be enabled with +threadsafe!+.
-* +config.asset_host+ sets the host for the assets. Useful when CDNs are used for hosting assets rather than the application server itself. Shorter version of +config.action_controller.asset_host+.
+* +config.asset_host+ sets the host for the assets. Useful when CDNs are used for hosting assets, or when you want to work around the concurrency constraints builtin in browsers using different domain aliases. Shorter version of +config.action_controller.asset_host+.
-* +config.asset_path+ takes a block which configures where assets can be found. Shorter version of +config.action_controller.asset_path+.
+* +config.asset_path+ can take a callable, a string, or be +nil+. Default is +nil+. If set, this configuration parameter let's you decorate asset paths. For example, the normal path for +blog.js+ would be +/javascripts/blog.js+, let that absolute path be +path+. If +config.asset_path+ is a callable, Rails calls it when generating asset paths passing +path+ as argument. If +config.asset_path+ is a string, it is expected to be a +sprintf+ format string with a +%s+ where +path+ will get inserted. In either case, Rails outputs the decorated path. *This option is ignored if the asset pipeline is enabled, which is by default*. Shorter version of +config.action_controller.asset_path+.
<ruby>
- config.asset_path = proc { |asset_path| "assets/#{asset_path}" }
+config.asset_path = proc { |path| "/blog/public#{path}" }
</ruby>
-* +config.autoload_once_paths+ accepts an array of paths from which Rails will automatically load from only once. All elements of this array must also be in +autoload_paths+.
-
-* +config.autoload_paths+ accepts an array of additional paths to prepend to the load path. By default, all app, lib, vendor and mock paths are included in this list.
+* +config.autoload_once_paths+ accepts an array of paths from which Rails will autoload constants that won't be wiped per request. Relevant if +config.cache_classes+ is false, which is the case in development mode by default. Otherwise, all autoloading happens only once. All elements of this array must also be in +autoload_paths+. Default is an empty array.
-* +config.cache_classes+ controls whether or not application classes should be reloaded on each request. Defaults to _true_ in development, _false_ in test and production. Can also be enabled with +threadsafe!+.
+* +config.autoload_paths+ accepts an array of paths from which Rails will autoload constants. Default is all directories under +app+.
-* +config.action_view.cache_template_loading+ controls whether or not templates should be reloaded on each request. Defaults to whatever is set for config.cache_classes.
+* +config.cache_classes+ controls whether or not application classes and modules should be reloaded on each request. Defaults to true in development mode, and false in test and production modes. Can also be enabled with +threadsafe!+.
-* +config.cache_store+ configures which cache store to use for Rails caching. Options include +:memory_store+, +:file_store+, +:mem_cache_store+ or the name of your own custom class. Defaults to +:file_store+.
+* +config.action_view.cache_template_loading+ controls whether or not templates should be reloaded on each request. Defaults to whatever is set for +config.cache_classes+.
-* +config.colorize_logging+ specifies whether or not to use ANSI color codes when logging information. Defaults to _true_.
+* +config.cache_store+ configures which cache store to use for Rails caching. Options include one of the symbols +:memory_store+, +:file_store+, +:mem_cache_store+, or an object that implements the cache API. Defaults to +:file_store+ if the directory +tmp/cache+ exists, and to +:memory_store+ otherwise.
-* +config.consider_all_requests_local+ is generally set to +true+ during development and +false+ during production; if it is set to +true+, then any error will cause detailed debugging information to be dumped in the HTTP response. For finer-grained control, set this to +false+ and implement +local_request?+ in controllers to specify which requests should provide debugging information on errors.
+* +config.colorize_logging+ specifies whether or not to use ANSI color codes when logging information. Defaults to true.
-* +config.controller_paths+ configures where Rails can find controllers for this application.
+* +config.consider_all_requests_local+ is a flag. If true then any error will cause detailed debugging information to be dumped in the HTTP response, and the +Rails::Info+ controller will show the application runtime context in +/rails/info/properties+. True by default in development and test environments, and false in production mode. For finer-grained control, set this to false and implement +local_request?+ in controllers to specify which requests should provide debugging information on errors.
-* +config.dependency_loading+ enables or disables dependency loading during the request cycle. Setting dependency_loading to _true_ will allow new classes to be loaded during a request and setting it to _false_ will disable this behavior. Can also be enabled with +threadsafe!+.
+* +config.dependency_loading+ is a flag that allows you to disable constant autoloading setting it to false. It only has effect if +config.cache_classes+ is true, which it is by default in production mode. This flag is set to false by +config.threadsafe!+.
-* +config.eager_load_paths+ accepts an array of paths from which Rails will eager load on boot if cache classes is enabled. Defaults to every folder in the +app+ directory of the application. All elements of this array must also be in +load_paths+.
+* +config.eager_load_paths+ accepts an array of paths from which Rails will eager load on boot if cache classes is enabled. Defaults to every folder in the +app+ directory of the application.
* +config.encoding+ sets up the application-wide encoding. Defaults to UTF-8.
* +config.filter_parameters+ used for filtering out the parameters that you don't want shown in the logs, such as passwords or credit card numbers.
-* +config.force_ssl+ forcing all requests to be under HTTPS protocol by using +Rack::SSL+ middleware. This will secure your application from a session hijack attempt.
-
-* +config.helper_paths+ configures where Rails can find helpers for this application.
+* +config.force_ssl+ forces all requests to be under HTTPS protocol by using +Rack::SSL+ middleware.
-* +config.log_level+ defines the verbosity of the Rails logger. In production mode, this defaults to +:info+. In development mode, it defaults to +:debug+.
+* +config.log_level+ defines the verbosity of the Rails logger. This option defaults to +:debug+ for all modes except production, where it defaults to +:info+.
-* +config.log_path+ overrides the path to the log file to use. Defaults to +log/#{environment}.log+ (e.g. log/development.log or log/production.log).
+* +config.logger+ accepts a logger conforming to the interface of Log4r or the default Ruby 1.8+ +Logger+ class. Defaults to an instance of +ActiveSupport::BufferedLogger+, with auto flushing off in production mode.
-* +config.logger+ accepts a logger conforming to the interface of Log4r or the default Ruby 1.8+ Logger class, which is then used to log information from Action Controller. Set to nil to disable logging.
+* +config.middleware+ allows you to configure the application's middleware. This is covered in depth in the "Configuring Middleware":configuring-middleware section below.
-* +config.middleware+ allows you to configure the application's middleware. This is covered in depth in the "Configuring Middleware" section below.
+* +config.plugins+ accepts the list of plugins to load. If this is set to +nil+, default, all plugins will be loaded. If this is set to +[]+, no plugins will be loaded. Otherwise, plugins will be loaded in the order specified. This option let's you enforce some particular loading order, useful when dependencies between plugins require it. For that use case, put first the plugins you want to be loaded in a certain order, and then the special symbol +:all+ to have the rest loaded without the need to specify them.
-* +config.plugins+ accepts the list of plugins to load. If this is set to nil, all plugins will be loaded. If this is set to [], no plugins will be loaded. Otherwise, plugins will be loaded in the order specified.
+* +config.preload_frameworks+ enables or disables preloading all frameworks at startup. Enabled by +config.threadsafe!+. Defaults to +nil+, so is disabled.
-* +config.preload_frameworks+ enables or disables preloading all frameworks at startup. Can also be enabled with +threadsafe!+. Defaults to +nil+, so is disabled.
+* +config.reload_plugins+ enables or disables plugin reloading. Defaults to false.
-* +config.reload_plugins+ enables or disables plugin reloading.
+* +config.secret_token+ used for specifying a key which allows sessions for the application to be verified against a known secure key to prevent tampering. Applications get +config.secret_token+ initialized to a random key in +config/initializers/secret_token.rb+.
-* +config.root+ configures the root path of the application.
+* +config.serve_static_assets+ configures Rails to serve static assets. Defaults to true, but in the production environment is turned off. The server software used to run the application should be used to serve the assets instead.
-* +config.secret_token+ used for specifying a key which allows sessions for the application to be verified against a known secure key to prevent tampering.
-
-* +config.serve_static_assets+ configures Rails to serve static assets. Defaults to _true_, but in the production environment is turned off. The server software used to run the application should be used to serve the assets instead.
-
-* +config.session_store+ is usually set up in +config/initializers/session_store.rb+ and specifies what class to use to store the session. Custom session stores can be specified like so:
+* +config.session_store+ is usually set up in +config/initializers/session_store.rb+ and specifies what class to use to store the session. Possible values are +:cookie_store+, default, +:mem_cache_store+, and +:disabled+. The last one tells Rails not to deal with sessions. Custom session stores can also be specified like so:
<ruby>
- config.session_store = :my_custom_store
+config.session_store :my_custom_store
</ruby>
-This custom store must be defined as +ActionDispatch::Session::MyCustomStore+.
+This custom store must be defined as +ActionDispatch::Session::MyCustomStore+. In addition to symbols, they can also be objects implementing a certain API, like +ActiveRecord::SessionStore+, in which case no special namespace is required.
* +config.threadsafe!+ enables +allow_concurrency+, +cache_classes+, +dependency_loading+ and +preload_frameworks+ to make the application threadsafe.
@@ -119,7 +112,9 @@ WARNING: Threadsafe operation is incompatible with the normal workings of develo
* +config.time_zone+ sets the default time zone for the application and enables time zone awareness for Active Record.
-* +config.whiny_nils+ enables or disables warnings when any methods of nil are invoked. Defaults to _true_ in development and test environments.
+* +config.whiny_nils+ enables or disables warnings when a certain set of methods are invoked on +nil+ and it does not respond to them. Defaults to true in development and test environments.
+
+* +config.assets.enabled+ a flag that controls whether the asset pipeline is enabled. It is explicitly initialized in +config/application.rb+.
h4. Configuring Generators
diff --git a/railties/guides/source/contributing_to_ruby_on_rails.textile b/railties/guides/source/contributing_to_ruby_on_rails.textile
index cb09b180a2..5eb925d7d2 100644
--- a/railties/guides/source/contributing_to_ruby_on_rails.textile
+++ b/railties/guides/source/contributing_to_ruby_on_rails.textile
@@ -232,11 +232,11 @@ You can also help out by examining pull requests that have been submitted to Rub
$ git checkout -b testing_branch
</shell>
-Then you can use their remote branch to update your codebase. For example, let's say the GitHub user JohnSmith has forked and pushed to the master branch located at https://github.com/JohnSmith/rails.
+Then you can use their remote branch to update your codebase. For example, let's say the GitHub user JohnSmith has forked and pushed to the topic branch located at https://github.com/JohnSmith/rails.
<shell>
$ git remote add JohnSmith git://github.com/JohnSmith/rails.git
-$ git pull JohnSmith master
+$ git pull JohnSmith topic
</shell>
After applying their branch, test it out! Here are some things to think about:
@@ -300,10 +300,16 @@ h4. Follow the Coding Conventions
Rails follows a simple set of coding style conventions.
-* Two spaces, no tabs
-* Prefer +&amp;&amp;+/+||+ over +and+/+or+
-* +MyClass.my_method(my_arg)+ not +my_method( my_arg )+ or +my_method my_arg+
-* Follow the conventions you see used in the source already
+* Two spaces, no tabs.
+* No trailing whitespace. Blank lines should not have any space.
+* Indent after private/protected.
+* Prefer +&amp;&amp;+/+||+ over +and+/+or+.
+* Prefer class << self block over self.method for class methods.
+* +MyClass.my_method(my_arg)+ not +my_method( my_arg )+ or +my_method my_arg+.
+* a = b and not a=b.
+* Follow the conventions you see used in the source already.
+
+These are some guidelines and please use your best judgement in using them.
h4. Sanity Check
@@ -344,20 +350,22 @@ Navigate to the Rails "GitHub repository":https://github.com/rails/rails and pre
Add the new remote to your local repository on your local machine:
<shell>
-$ git remote add mine https://&lt;your user name&gt;@github.com/&lt;your user name&gt;/rails.git
+$ git remote add mine https://<your user name>@github.com/<your user name>/rails.git
</shell>
Push to your remote:
<shell>
-$ git push mine master
+$ git push mine my_new_branch
</shell>
h4. Issue a Pull Request
-Navigate to the Rails repository you just pushed to (e.g. https://github.com/&lt;your user name&gt;/rails) and press "Pull Request" in the upper right hand corner.
-
-Ensure the changesets you introduced are included in the "Commits" tab and that the "Files Changed" incorporate all of your changes.
+Navigate to the Rails repository you just pushed to (e.g. https://github.com/<your user name>/rails) and press "Pull Request" in the upper right hand corner.
+
+Write your branch name in branch field (is filled with master by default) and press "Update Commit Range"
+
+Ensure the changesets you introduced are included in the "Commits" tab and that the "Files Changed" incorporate all of your changes.
Fill in some details about your potential patch including a meaningful title. When finished, press "Send pull request." Rails Core will be notified about your submission.
@@ -377,6 +385,7 @@ All contributions, either via master or docrails, get credit in "Rails Contribut
h3. Changelog
+* May 12, 2011: Modified to prefer topic branches instead of master branch for users contributions by "Guillermo Iguaran":http://quillarb.org
* April 29, 2011: Reflect GitHub Issues and Pull Request workflow by "Dan Pickett":http://www.enlightsolutions.com
* April 14, 2011: Modified Contributing to the Rails Code section to add '[#ticket_number state:commited]' on patches commit messages by "Sebastian Martinez":http://wyeworks.com
* December 28, 2010: Complete revision by "Xavier Noria":credits.html#fxn
diff --git a/railties/guides/source/generators.textile b/railties/guides/source/generators.textile
index ac709968d9..a3181b9ac5 100644
--- a/railties/guides/source/generators.textile
+++ b/railties/guides/source/generators.textile
@@ -111,7 +111,6 @@ In order to understand what a generator template means, let's create the file +l
<ruby>
# Add initialization content here
-
</ruby>
And now let's change the generator to copy this template when invoked:
@@ -286,8 +285,8 @@ end
Now, when the helper generator is invoked and TestUnit is configured as the test framework, it will try to invoke both +Rails::TestUnitGenerator+ and +TestUnit::MyHelperGenerator+. Since none of those are defined, we can tell our generator to invoke +TestUnit::Generators::HelperGenerator+ instead, which is defined since it's a Rails generator. To do that, we just need to add:
<ruby>
- # Search for :helper instead of :my_helper
- hook_for :test_framework, :as => :helper
+# Search for :helper instead of :my_helper
+hook_for :test_framework, :as => :helper
</ruby>
And now you can re-run scaffold for another resource and see it generating tests as well!
@@ -412,7 +411,7 @@ h4. +plugin+
+plugin+ will install a plugin into the current application.
<ruby>
- plugin("dynamic-form", :git => "git://github.com/rails/dynamic-form.git")
+plugin("dynamic-form", :git => "git://github.com/rails/dynamic-form.git")
</ruby>
Available options are:
@@ -441,13 +440,13 @@ Available options are:
Any additional options passed to this method are put on the end of the line:
<ruby>
- gem("devise", :git => "git://github.com/plataformatec/devise", :branch => "master")
+gem("devise", :git => "git://github.com/plataformatec/devise", :branch => "master")
</ruby>
The above code will put the following line into +Gemfile+:
<ruby>
- gem "devise", :git => "git://github.com/plataformatec/devise", :branch => "master"
+gem "devise", :git => "git://github.com/plataformatec/devise", :branch => "master"
</ruby>
@@ -456,7 +455,7 @@ h4. +add_source+
Adds a specified source to +Gemfile+:
<ruby>
- add_source "http://gems.github.com"
+add_source "http://gems.github.com"
</ruby>
h4. +application+
@@ -464,7 +463,7 @@ h4. +application+
Adds a line to +config/application.rb+ directly after the application class definition.
<ruby>
- application "config.asset_host = 'http://example.com'"
+application "config.asset_host = 'http://example.com'"
</ruby>
This method can also take a block:
@@ -490,10 +489,10 @@ h4. +git+
Runs the specified git command:
<ruby>
- git :init
- git :add => "."
- git :commit => "-m First commit!"
- git :add => "onefile.rb", :rm => "badfile.cxx"
+git :init
+git :add => "."
+git :commit => "-m First commit!"
+git :add => "onefile.rb", :rm => "badfile.cxx"
</ruby>
The values of the hash here being the arguments or options passed to the specific git command. As per the final example shown here, multiple git commands can be specified at a time, but the order of their running is not guaranteed to be the same as the order that they were specified in.
@@ -503,15 +502,15 @@ h4. +vendor+
Places a file into +vendor+ which contains the specified code.
<ruby>
- vendor("sekrit.rb", '#top secret stuff')
+vendor("sekrit.rb", '#top secret stuff')
</ruby>
This method also takes a block:
<ruby>
- vendor("seeds.rb") do
- "puts 'in ur app, seeding ur database'"
- end
+vendor("seeds.rb") do
+ "puts 'in ur app, seeding ur database'"
+end
</ruby>
h4. +lib+
@@ -519,7 +518,7 @@ h4. +lib+
Places a file into +lib+ which contains the specified code.
<ruby>
- lib("special.rb", 'p Rails.root')
+lib("special.rb", 'p Rails.root')
</ruby>
This method also takes a block:
@@ -535,7 +534,7 @@ h4. +rakefile+
Creates a Rake file in the +lib/tasks+ directory of the application.
<ruby>
- rakefile("test.rake", 'hello there')
+rakefile("test.rake", 'hello there')
</ruby>
This method also takes a block:
@@ -555,7 +554,7 @@ h4. +initializer+
Creates an initializer in the +config/initializers+ directory of the application:
<ruby>
- initializer("begin.rb", "puts 'this is the beginning'")
+initializer("begin.rb", "puts 'this is the beginning'")
</ruby>
This method also takes a block:
@@ -571,7 +570,7 @@ h4. +generate+
Runs the specified generator where the first argument is the generator name and the remaining arguments are passed directly to the generator.
<ruby>
- generate("scaffold", "forums title:string description:text")
+generate("scaffold", "forums title:string description:text")
</ruby>
@@ -580,7 +579,7 @@ h4. +rake+
Runs the specified Rake task.
<ruby>
- rake("db:migrate")
+rake("db:migrate")
</ruby>
Available options are:
@@ -593,7 +592,7 @@ h4. +capify!+
Runs the +capify+ command from Capistrano at the root of the application which generates Capistrano configuration.
<ruby>
- capify!
+capify!
</ruby>
h4. +route+
@@ -601,7 +600,7 @@ h4. +route+
Adds text to the +config/routes.rb+ file:
<ruby>
- route("resources :people")
+route("resources :people")
</ruby>
h4. +readme+
@@ -609,7 +608,7 @@ h4. +readme+
Output the contents of a file in the template's +source_path+, usually a README.
<ruby>
- readme("README")
+readme("README")
</ruby>
h3. Changelog
diff --git a/railties/guides/source/getting_started.textile b/railties/guides/source/getting_started.textile
index a826a33120..1c66115d44 100644
--- a/railties/guides/source/getting_started.textile
+++ b/railties/guides/source/getting_started.textile
@@ -1450,14 +1450,14 @@ Two very common sources of data that are not UTF-8:
h3. Changelog
-* April 26, 2011: Changed migration code from +up+, +down+ pair to +change+ method "Prem Sichanugrist":"http://sikachu.com"
-* April 11, 2011: Changed scaffold_controller generator to create format block for JSON instead of XML "Sebastian Martinez":http://www.wyeworks.com
+* April 26, 2011: Change migration code from +up+, +down+ pair to +change+ method by "Prem Sichanugrist":http://sikachu.com
+* April 11, 2011: Change scaffold_controller generator to create format block for JSON instead of XML by "Sebastian Martinez":http://www.wyeworks.com
* August 30, 2010: Minor editing after Rails 3 release by "Joost Baaij":http://www.spacebabies.nl
* July 12, 2010: Fixes, editing and updating of code samples by "Jaime Iniesta":http://jaimeiniesta.com
* May 16, 2010: Added a section on configuration gotchas to address common encoding problems that people might have by "Yehuda Katz":http://www.yehudakatz.com
* April 30, 2010: Fixes, editing and updating of code samples by "Rohit Arondekar":http://rohitarondekar.com
-* April 25, 2010: Couple of more minor fixups "Mikel Lindsaar":credits.html#raasdnil
-* April 1, 2010: Fixed document to validate XHTML 1.0 Strict. "Jaime Iniesta":http://jaimeiniesta.com
+* April 25, 2010: Couple of more minor fixups by "Mikel Lindsaar":credits.html#raasdnil
+* April 1, 2010: Fixed document to validate XHTML 1.0 Strict by "Jaime Iniesta":http://jaimeiniesta.com
* February 8, 2010: Full re-write for Rails 3.0-beta, added helpers and before_filters, refactored code by "Mikel Lindsaar":credits.html#raasdnil
* January 24, 2010: Re-write for Rails 3.0 by "Mikel Lindsaar":credits.html#raasdnil
* July 18, 2009: Minor cleanup in anticipation of Rails 2.3.3 by "Mike Gunderloy":credits.html#mgunderloy
diff --git a/railties/guides/source/rails_on_rack.textile b/railties/guides/source/rails_on_rack.textile
index b1db2942dd..aa53aa6db6 100644
--- a/railties/guides/source/rails_on_rack.textile
+++ b/railties/guides/source/rails_on_rack.textile
@@ -117,8 +117,6 @@ You can add a new middleware to the middleware stack using any of the following
* +config.middleware.insert_after(existing_middleware, new_middleware, args)+ - Adds the new middleware after the specified existing middleware in the middleware stack.
-<strong>Example:</strong>
-
<ruby>
# config/environment.rb
@@ -134,8 +132,6 @@ h5. Swapping a Middleware
You can swap an existing middleware in the middleware stack using +config.middleware.swap+.
-<strong>Example:</strong>
-
<ruby>
# config/environment.rb
@@ -173,8 +169,6 @@ h4. Customizing Internal Middleware Stack
It's possible to replace the entire middleware stack with a custom stack using +ActionController::Dispatcher.middleware=+.
-<strong>Example:</strong>
-
Put the following in an initializer:
<ruby>
diff --git a/railties/guides/source/security.textile b/railties/guides/source/security.textile
index 8c408ec06b..e0ccc7a6e6 100644
--- a/railties/guides/source/security.textile
+++ b/railties/guides/source/security.textile
@@ -372,7 +372,7 @@ def signup
end
</ruby>
-Mass-assignment saves you much work, because you don't have to set each value individually. Simply pass a hash to the new() method, or assign attributes=(attributes) a hash value, to set the model's attributes to the values in the hash. The problem is that it is often used in conjunction with the parameters (params) hash available in the controller, which may be manipulated by an attacker. He may do so by changing the URL like this:
+Mass-assignment saves you much work, because you don't have to set each value individually. Simply pass a hash to the +new+ method, or +assign_attributes=+ a hash value, to set the model's attributes to the values in the hash. The problem is that it is often used in conjunction with the parameters (params) hash available in the controller, which may be manipulated by an attacker. He may do so by changing the URL like this:
<pre>
"name":http://www.example.com/user/signup?user[name]=ow3ned&user[admin]=1
@@ -386,7 +386,7 @@ params[:user] # => {:name => “ow3ned”, :admin => true}
So if you create a new user using mass-assignment, it may be too easy to become an administrator.
-Note that this vulnerability is not restricted to database columns. Any setter method, unless explicitly protected, is accessible via the <tt>attributes=</tt> method. In fact, this vulnerability is extended even further with the introduction of nested mass assignment (and nested object forms) in Rails 2.3. The +accepts_nested_attributes_for+ declaration provides us the ability to extend mass assignment to model associations (+has_many+, +has_one+, +has_and_belongs_to_many+). For example:
+Note that this vulnerability is not restricted to database columns. Any setter method, unless explicitly protected, is accessible via the <tt>attributes=</tt> method. In fact, this vulnerability is extended even further with the introduction of nested mass assignment (and nested object forms) in Rails 2.3+. The +accepts_nested_attributes_for+ declaration provides us the ability to extend mass assignment to model associations (+has_many+, +has_one+, +has_and_belongs_to_many+). For example:
<ruby>
class Person < ActiveRecord::Base
@@ -410,7 +410,7 @@ To avoid this, Rails provides two class methods in your Active Record class to c
attr_protected :admin
</ruby>
-+attr_protected+ also optionally takes a scope option using :as which allows you to define multiple mass-assignment groupings. If no scope is defined then attributes will be added to the default group.
++attr_protected+ also optionally takes a role option using :as which allows you to define multiple mass-assignment groupings. If no role is defined then attributes will be added to the :default role.
<ruby>
attr_protected :last_login, :as => :admin
@@ -433,7 +433,7 @@ params[:user] # => {:name => "ow3ned", :admin => true}
@user.admin # => true
</ruby>
-When assigning attributes in Active Record using +attributes=+, or +update_attributes+ the :default scope will be used. To assign attributes using different scopes you should use +assign_attributes+ which accepts an optional :as options parameter. If no :as option is provided then the :default scope will be used. You can also bypass mass-assignment security by using the +:without_protection+ option. Here is an example:
+When assigning attributes in Active Record using +attributes=+ the :default role will be used. To assign attributes using different roles you should use +assign_attributes+ which accepts an optional :as options parameter. If no :as option is provided then the :default role will be used. You can also bypass mass-assignment security by using the +:without_protection+ option. Here is an example:
<ruby>
@user = User.new
@@ -451,7 +451,7 @@ When assigning attributes in Active Record using +attributes=+, or +update_attri
@user.is_admin # => true
</ruby>
-In a similar way, +new+, +create+ and <tt>create!</tt> methods respect mass-assignment security and accepts either +:as+ or +:without_protection+ options. For example:
+In a similar way, +new+, +create+, <tt>create!</tt>, +update_attributes+, and +update_attributes!+ methods all respect mass-assignment security and accept either +:as+ or +:without_protection+ options. For example:
<ruby>
@user = User.new({ :name => 'Sebastian', :is_admin => true }, :as => :admin)
diff --git a/railties/guides/source/testing.textile b/railties/guides/source/testing.textile
index efa2bbdca6..7a93c3a1e6 100644
--- a/railties/guides/source/testing.textile
+++ b/railties/guides/source/testing.textile
@@ -38,7 +38,7 @@ When you do end up destroying your testing database (and it will happen, trust m
h4. Rails Sets up for Testing from the Word Go
-Rails creates a +test+ folder for you as soon as you create a Rails project using +rails _application_name_+. If you list the contents of this folder then you shall see:
+Rails creates a +test+ folder for you as soon as you create a Rails project using +rails new+ _application_name_. If you list the contents of this folder then you shall see:
<shell>
$ ls -F test/
@@ -54,7 +54,7 @@ For good tests, you'll need to give some thought to setting up test data. In Rai
h5. What are Fixtures?
-_Fixtures_ is a fancy word for sample data. Fixtures allow you to populate your testing database with predefined data before your tests run. Fixtures are database independent and assume one of two formats: *YAML* or *CSV*. In this guide, we will use *YAML*, which is the preferred format.
+_Fixtures_ is a fancy word for sample data. Fixtures allow you to populate your testing database with predefined data before your tests run. Fixtures are database independent and assume a single format: *YAML*.
You'll find fixtures under your +test/fixtures+ directory. When you run +rails generate model+ to create a new model, fixture stubs will be automatically created and placed in this directory.
@@ -81,7 +81,7 @@ Each fixture is given a name followed by an indented list of colon-separated key
h5. ERB'in It Up
-ERB allows you to embed ruby code within templates. Both the YAML and CSV fixture formats are pre-processed with ERB when you load fixtures. This allows you to use Ruby to help you generate some sample data.
+ERB allows you to embed ruby code within templates. YAML fixture format is pre-processed with ERB when you load fixtures. This allows you to use Ruby to help you generate some sample data.
<erb>
<% earth_size = 20 %>
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index dd01bbab1d..1e4d25f18c 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -157,7 +157,8 @@ module Rails
middleware.use ::Rack::Lock unless config.allow_concurrency
middleware.use ::Rack::Runtime
- middleware.use ::Rails::Rack::Logger
+ middleware.use ::Rack::MethodOverride
+ middleware.use ::Rails::Rack::Logger # must come after Rack::MethodOverride to properly log overridden methods
middleware.use ::ActionDispatch::ShowExceptions, config.consider_all_requests_local
middleware.use ::ActionDispatch::RemoteIp, config.action_dispatch.ip_spoofing_check, config.action_dispatch.trusted_proxies
middleware.use ::Rack::Sendfile, config.action_dispatch.x_sendfile_header
@@ -171,7 +172,6 @@ module Rails
end
middleware.use ::ActionDispatch::ParamsParser
- middleware.use ::Rack::MethodOverride
middleware.use ::ActionDispatch::Head
middleware.use ::Rack::ConditionalGet
middleware.use ::Rack::ETag, "no-cache"
@@ -199,4 +199,4 @@ module Rails
require "rails/console/helpers"
end
end
-end \ No newline at end of file
+end
diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb
index 29b9c27a13..3b74de690a 100644
--- a/railties/lib/rails/application/configuration.rb
+++ b/railties/lib/rails/application/configuration.rb
@@ -34,7 +34,7 @@ module Rails
@assets = ActiveSupport::OrderedOptions.new
@assets.enabled = false
@assets.paths = []
- @assets.precompile = [ /\w+\.(?!js|css)$/, "application.js", "application.css" ]
+ @assets.precompile = [ /\w+\.(?!js|css).+/, "application.js", "application.css" ]
@assets.prefix = "/assets"
@assets.js_compressor = nil
diff --git a/railties/lib/rails/commands.rb b/railties/lib/rails/commands.rb
index 4182757346..4a082aedb8 100644
--- a/railties/lib/rails/commands.rb
+++ b/railties/lib/rails/commands.rb
@@ -6,7 +6,8 @@ aliases = {
"g" => "generate",
"c" => "console",
"s" => "server",
- "db" => "dbconsole"
+ "db" => "dbconsole",
+ "r" => "runner"
}
command = ARGV.shift
diff --git a/railties/lib/rails/commands/runner.rb b/railties/lib/rails/commands/runner.rb
index ddd08a32ee..f8b00e7249 100644
--- a/railties/lib/rails/commands/runner.rb
+++ b/railties/lib/rails/commands/runner.rb
@@ -25,7 +25,7 @@ ARGV.clone.options do |opts|
opts.separator "-------------------------------------------------------------"
opts.separator "#!/usr/bin/env #{File.expand_path($0)} runner"
opts.separator ""
- opts.separator "Product.find(:all).each { |p| p.price *= 2 ; p.save! }"
+ opts.separator "Product.all.each { |p| p.price *= 2 ; p.save! }"
opts.separator "-------------------------------------------------------------"
end
diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb
index 2015a944f0..6a125685d0 100644
--- a/railties/lib/rails/engine.rb
+++ b/railties/lib/rails/engine.rb
@@ -523,6 +523,7 @@ module Rails
initializer :append_assets_path do |app|
app.config.assets.paths.unshift *paths["vendor/assets"].existent
+ app.config.assets.paths.unshift *paths["lib/assets"].existent
app.config.assets.paths.unshift *paths["app/assets"].existent
end
diff --git a/railties/lib/rails/engine/configuration.rb b/railties/lib/rails/engine/configuration.rb
index 241db4b0a9..f424492bb4 100644
--- a/railties/lib/rails/engine/configuration.rb
+++ b/railties/lib/rails/engine/configuration.rb
@@ -47,6 +47,7 @@ module Rails
paths.add "app/mailers", :eager_load => true
paths.add "app/views"
paths.add "lib", :load_path => true
+ paths.add "lib/assets", :glob => "*"
paths.add "lib/tasks", :glob => "**/*.rake"
paths.add "config"
paths.add "config/environments", :glob => "#{Rails.env}.rb"
diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb
index e8709b2ddd..a5743762e5 100644
--- a/railties/lib/rails/generators/app_base.rb
+++ b/railties/lib/rails/generators/app_base.rb
@@ -28,6 +28,9 @@ module Rails
class_option :skip_gemfile, :type => :boolean, :default => false,
:desc => "Don't create a Gemfile"
+ class_option :skip_bundle, :type => :boolean, :default => false,
+ :desc => "Don't run bundle install"
+
class_option :skip_git, :type => :boolean, :aliases => "-G", :default => false,
:desc => "Skip Git ignores and keeps"
@@ -184,13 +187,18 @@ module Rails
"gem '#{options[:javascript]}-rails'" unless options[:skip_javascript]
end
- def bundle_if_dev_or_edge
- bundle_command = File.basename(Thor::Util.ruby_command).sub(/ruby/, 'bundle')
- run "#{bundle_command} install" if dev_or_edge?
+ def bundle_command(command)
+ require 'bundler'
+ require 'bundler/cli'
+
+ say_status :run, "bundle #{command}"
+ Bundler::CLI.new.send(command)
+ rescue
+ say_status :failure, "bundler raised an exception, are you offline?", :red
end
- def dev_or_edge?
- options.dev? || options.edge?
+ def run_bundle
+ bundle_command('install') unless options[:skip_gemfile] || options[:skip_bundle]
end
def empty_directory_with_gitkeep(destination, config = {})
diff --git a/railties/lib/rails/generators/base.rb b/railties/lib/rails/generators/base.rb
index 8d03cb911b..1f6a7a2f59 100644
--- a/railties/lib/rails/generators/base.rb
+++ b/railties/lib/rails/generators/base.rb
@@ -117,8 +117,8 @@ module Rails
#
# ==== Switches
#
- # All hooks come with switches for user interface. If the user don't want
- # to use any test framework, he can do:
+ # All hooks come with switches for user interface. If you do not want
+ # to use any test framework, you can do:
#
# rails generate controller Account --skip-test-framework
#
diff --git a/railties/lib/rails/generators/generated_attribute.rb b/railties/lib/rails/generators/generated_attribute.rb
index b26161f1d0..9450894b05 100644
--- a/railties/lib/rails/generators/generated_attribute.rb
+++ b/railties/lib/rails/generators/generated_attribute.rb
@@ -13,12 +13,13 @@ module Rails
def field_type
@field_type ||= case type
- when :integer, :float, :decimal then :text_field
- when :time then :time_select
- when :datetime, :timestamp then :datetime_select
- when :date then :date_select
- when :text then :text_area
- when :boolean then :check_box
+ when :integer then :number_field
+ when :float, :decimal then :text_field
+ when :time then :time_select
+ when :datetime, :timestamp then :datetime_select
+ when :date then :date_select
+ when :text then :text_area
+ when :boolean then :check_box
else
:text_field
end
diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb
index d79f76c799..5f9fb9685c 100644
--- a/railties/lib/rails/generators/rails/app/app_generator.rb
+++ b/railties/lib/rails/generators/rails/app/app_generator.rb
@@ -9,11 +9,20 @@ module Rails
@options = generator.options
end
- private
+ private
+ %w(template copy_file directory empty_directory inside
+ empty_directory_with_gitkeep create_file chmod shebang).each do |method|
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
+ def #{method}(*args, &block)
+ @generator.send(:#{method}, *args, &block)
+ end
+ RUBY
+ end
- def method_missing(meth, *args, &block)
- @generator.send(meth, *args, &block)
- end
+ # TODO: Remove once this is fully in place
+ def method_missing(meth, *args, &block)
+ @generator.send(meth, *args, &block)
+ end
end
# The application builder allows you to override elements of the application
@@ -21,7 +30,7 @@ module Rails
# generator.
#
# This allows you to override entire operations, like the creation of the
- # Gemfile, README, or javascript files, without needing to know exactly
+ # Gemfile, README, or JavaScript files, without needing to know exactly
# what those operations do so you can create another template action.
class AppBuilder
def rakefile
@@ -215,7 +224,7 @@ module Rails
build(:leftovers)
end
- public_task :apply_rails_template, :bundle_if_dev_or_edge
+ public_task :apply_rails_template, :run_bundle
protected
diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile
index a69efdf29d..20bd9db624 100644
--- a/railties/lib/rails/generators/rails/app/templates/Gemfile
+++ b/railties/lib/rails/generators/rails/app/templates/Gemfile
@@ -9,7 +9,7 @@ source 'http://rubygems.org'
<%= "gem 'json'\n" if RUBY_VERSION < "1.9.2" -%>
gem 'sass'
gem 'coffee-script'
-gem 'uglifier'
+# gem 'uglifier'
<%= gem_for_javascript %>
@@ -22,4 +22,4 @@ gem 'uglifier'
# To use debugger
# <%= gem_for_ruby_debugger %>
-<%= gem_for_turn -%> \ No newline at end of file
+<%= gem_for_turn -%>
diff --git a/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt b/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt
index 612c614f2e..19294b3478 100644
--- a/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt
+++ b/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt
@@ -1,5 +1,8 @@
-// FIXME: Tell people that this is a manifest file, real code should go into discrete files
-// FIXME: Tell people how Sprockets and CoffeeScript works
+// This is a manifest file that'll be compiled into including all the files listed below.
+// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
+// be included in the compiled file accessible from http://example.com/assets/application.js
+// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
+// the compiled file.
//
<% unless options[:skip_javascript] -%>
//= require <%= options[:javascript] %>
diff --git a/railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css b/railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css
index f4b082ccc0..fc25b5723f 100644
--- a/railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css
+++ b/railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css
@@ -1,5 +1,7 @@
/*
- * FIXME: Introduce SCSS & Sprockets
+ * This is a manifest file that'll automatically include all the stylesheets available in this directory
+ * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
+ * the top of the compiled file, but it's generally better to create a new file per style scope.
*= require_self
*= require_tree .
*/ \ No newline at end of file
diff --git a/railties/lib/rails/generators/rails/app/templates/config/application.rb b/railties/lib/rails/generators/rails/app/templates/config/application.rb
index e1946807b0..8ff80c6fd3 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/application.rb
+++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb
@@ -56,11 +56,6 @@ module <%= app_const_base %>
# Configure sensitive parameters which will be filtered from the log file.
config.filter_parameters += [:password]
-<% unless options[:skip_active_record] -%>
- # Enable IdentityMap for Active Record, to disable set to false or remove the line below.
- config.active_record.identity_map = true
-<% end -%>
-
# Enable the asset pipeline
config.assets.enabled = true
end
diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/frontbase.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/frontbase.yml
index c0c3588be1..4807986333 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/databases/frontbase.yml
+++ b/railties/lib/rails/generators/rails/app/templates/config/databases/frontbase.yml
@@ -2,7 +2,10 @@
#
# Get the bindings:
# gem install ruby-frontbase
-
+#
+# Configure Using Gemfile
+# gem 'ruby-frontbase'
+#
development:
adapter: frontbase
host: localhost
diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/ibm_db.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/ibm_db.yml
index df5ef33064..3d689a110a 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/databases/ibm_db.yml
+++ b/railties/lib/rails/generators/rails/app/templates/config/databases/ibm_db.yml
@@ -28,6 +28,9 @@
# On Windows:
# Issue the command: gem install ibm_db
#
+# Configure Using Gemfile
+# gem 'ibm_db'
+#
# For more details on the installation and the connection parameters below,
# please refer to the latest documents at http://rubyforge.org/docman/?group_id=2361
diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml
index ca807c9f3f..6bf83e86a5 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml
+++ b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml
@@ -3,6 +3,9 @@
# Install the MySQL driver:
# gem install activerecord-jdbcmysql-adapter
#
+# Configure Using Gemfile
+# gem 'activerecord-jdbcmysql-adapter'
+#
# And be sure to use new-style password hashing:
# http://dev.mysql.com/doc/refman/5.0/en/old-client.html
development:
diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml
index a228aca5d2..0c7f45322b 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml
+++ b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml
@@ -8,6 +8,10 @@
# gem install pg
# Choose the win32 build.
# Install PostgreSQL and put its /bin directory on your path.
+#
+# Configure Using Gemfile
+# gem 'activerecord-jdbcpostgresql-adapter'
+
development:
adapter: jdbcpostgresql
encoding: unicode
diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml
index 30776b3b4e..6d241d57ae 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml
+++ b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml
@@ -1,6 +1,9 @@
# SQLite version 3.x
# gem 'activerecord-jdbcsqlite3-adapter'
-
+#
+# Configure Using Gemfile
+# gem 'activerecord-jdbcsqlite3-adapter'
+#
development:
adapter: jdbcsqlite3
database: db/development.sqlite3
diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml
index 5d28c7c312..62dc7b2c48 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml
+++ b/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml
@@ -1,7 +1,7 @@
# MySQL. Versions 4.1 and 5.0 are recommended.
#
-# Install the MySQL driver:
-# gem install mysql2
+# Ensure the MySQL gem is defined in your Gemfile
+# gem 'mysql2'
#
# And be sure to use new-style password hashing:
# http://dev.mysql.com/doc/refman/5.0/en/old-client.html
diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml
index 4e6391e3d6..467dfc3956 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml
+++ b/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml
@@ -8,6 +8,10 @@
# gem install pg
# Choose the win32 build.
# Install PostgreSQL and put its /bin directory on your path.
+#
+# Configure Using Gemfile
+# gem 'pg'
+#
development:
adapter: postgresql
encoding: unicode
diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml
index 90d87cc295..5989eaf9dd 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml
+++ b/railties/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml
@@ -1,5 +1,6 @@
# SQLite version 3.x
-# gem install sqlite3
+# Ensure the SQLite 3 gem is defined in your Gemfile
+# gem 'sqlite3'
development:
adapter: sqlite3
database: db/development.sqlite3
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt
index 41b2374eda..066aa54862 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt
@@ -22,4 +22,3 @@
# Only use best-standards-support built into browsers
config.action_dispatch.best_standards_support = :builtin
end
-
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
index 9553f3bdde..1c3dc1117f 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
@@ -31,7 +31,7 @@
# Use a different cache store in production
# config.cache_store = :mem_cache_store
- # Enable serving of images, stylesheets, and javascripts from an asset server
+ # Enable serving of images, stylesheets, and JavaScripts from an asset server
# config.action_controller.asset_host = "http://assets.example.com"
# Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt
index 32ffbee7a1..e56195da80 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt
@@ -4,7 +4,7 @@
# which will be enabled by default in the upcoming version of Ruby on Rails.
# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
-ActionController::Base.wrap_parameters :format => [:json]
+ActionController::Base.wrap_parameters <%= key_value :format, "[:json]" %>
# Disable root element in JSON by default.
if defined?(ActiveRecord)
diff --git a/railties/lib/rails/generators/rails/app/templates/db/seeds.rb.tt b/railties/lib/rails/generators/rails/app/templates/db/seeds.rb.tt
index 9a2efa68a7..f75c5dd941 100644
--- a/railties/lib/rails/generators/rails/app/templates/db/seeds.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/db/seeds.rb.tt
@@ -4,4 +4,4 @@
# Examples:
#
# cities = City.create([{ <%= key_value :name, "'Chicago'" %> }, { <%= key_value :name, "'Copenhagen'" %> }])
-# Mayor.create(<%= key_value :name, "'Daley'" %>, <%= key_value :city, "cities.first" %>)
+# Mayor.create(<%= key_value :name, "'Emanuel'" %>, <%= key_value :city, "cities.first" %>)
diff --git a/railties/lib/rails/generators/rails/app/templates/gitignore b/railties/lib/rails/generators/rails/app/templates/gitignore
index f0fa30c536..923b697662 100644
--- a/railties/lib/rails/generators/rails/app/templates/gitignore
+++ b/railties/lib/rails/generators/rails/app/templates/gitignore
@@ -2,3 +2,4 @@
db/*.sqlite3
log/*.log
tmp/
+.sass-cache/
diff --git a/railties/lib/rails/generators/rails/assets/USAGE b/railties/lib/rails/generators/rails/assets/USAGE
index adebfd7e6f..c5375cdc06 100644
--- a/railties/lib/rails/generators/rails/assets/USAGE
+++ b/railties/lib/rails/generators/rails/assets/USAGE
@@ -1,8 +1,8 @@
Description:
- Stubs out a new asset placeholders. Pass the asset name, either CamelCased
+ Stubs out new asset placeholders. Pass the asset name, either CamelCased
or under_scored.
- To create assets within a folder, specify the assets name as a
+ To create an asset within a folder, specify the asset's name as a
path like 'parent/name'.
This generates a JavaScript stub in app/assets/javascripts and a stylesheet
@@ -15,6 +15,6 @@ Example:
`rails generate assets posts`
Posts assets.
- Javascript: app/assets/javascripts/posts.js
+ JavaScript: app/assets/javascripts/posts.js
Stylesheet: app/assets/stylesheets/posts.css
diff --git a/railties/lib/rails/generators/rails/assets/assets_generator.rb b/railties/lib/rails/generators/rails/assets/assets_generator.rb
index 80beb7abfe..2d52da77eb 100644
--- a/railties/lib/rails/generators/rails/assets/assets_generator.rb
+++ b/railties/lib/rails/generators/rails/assets/assets_generator.rb
@@ -1,11 +1,11 @@
module Rails
module Generators
class AssetsGenerator < NamedBase
- class_option :javascripts, :type => :boolean, :desc => "Generate javascripts"
- class_option :stylesheets, :type => :boolean, :desc => "Generate stylesheets"
+ class_option :javascripts, :type => :boolean, :desc => "Generate JavaScripts"
+ class_option :stylesheets, :type => :boolean, :desc => "Generate Stylesheets"
- class_option :javascript_engine, :desc => "Engine for javascripts"
- class_option :stylesheet_engine, :desc => "Engine for stylesheets"
+ class_option :javascript_engine, :desc => "Engine for JavaScripts"
+ class_option :stylesheet_engine, :desc => "Engine for Stylesheets"
def create_javascript_files
return unless options.javascripts?
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 6201595308..939c0cd727 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
@@ -209,7 +209,7 @@ task :default => :test
build(:leftovers)
end
- public_task :apply_rails_template, :bundle_if_dev_or_edge
+ public_task :apply_rails_template, :run_bundle
protected
diff --git a/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb
index 6eef0dbe5b..aa9b45c5a5 100644
--- a/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb
+++ b/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb
@@ -6,8 +6,8 @@ module Rails
remove_hook_for :resource_controller
remove_class_option :actions
- class_option :stylesheets, :type => :boolean, :desc => "Generate stylesheets"
- class_option :stylesheet_engine, :desc => "Engine for stylesheets"
+ class_option :stylesheets, :type => :boolean, :desc => "Generate Stylesheets"
+ class_option :stylesheet_engine, :desc => "Engine for Stylesheets"
hook_for :scaffold_controller, :required => true
diff --git a/railties/lib/rails/tasks/framework.rake b/railties/lib/rails/tasks/framework.rake
index 5222b7bf50..77a5c4dc6c 100644
--- a/railties/lib/rails/tasks/framework.rake
+++ b/railties/lib/rails/tasks/framework.rake
@@ -1,6 +1,6 @@
namespace :rails do
- desc "Update both configs and public/javascripts from Rails (or use just update:javascripts or update:configs)"
- task :update => [ "update:configs", "update:javascripts", "update:scripts", "update:application_controller" ]
+ desc "Update configs and some other initially generated files (or use just update:configs, update:scripts, or update:application_controller)"
+ task :update => [ "update:configs", "update:scripts", "update:application_controller" ]
desc "Applies the template supplied by LOCATION=/path/to/template"
task :template do
@@ -58,11 +58,6 @@ namespace :rails do
invoke_from_app_generator :create_config_files
end
- # desc "Update Prototype javascripts from your current rails install"
- task :javascripts do
- invoke_from_app_generator :create_javascript_files
- end
-
# desc "Adds new scripts to the application script/ directory"
task :scripts do
invoke_from_app_generator :create_script_files
diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb
new file mode 100644
index 0000000000..624dd2a23f
--- /dev/null
+++ b/railties/test/application/assets_test.rb
@@ -0,0 +1,58 @@
+require 'isolation/abstract_unit'
+require 'rack/test'
+
+module ApplicationTests
+ class RoutingTest < Test::Unit::TestCase
+ include ActiveSupport::Testing::Isolation
+ include Rack::Test::Methods
+
+ def setup
+ build_app
+ boot_rails
+ end
+
+ def app
+ @app ||= Rails.application
+ end
+
+ test "assets routes have higher priority" do
+ app_file "app/assets/javascripts/demo.js.erb", "<%= :alert %>();"
+
+ app_file 'config/routes.rb', <<-RUBY
+ AppTemplate::Application.routes.draw do
+ match '*path', :to => lambda { |env| [200, { "Content-Type" => "text/html" }, "Not an asset"] }
+ end
+ RUBY
+
+ get "/assets/demo.js"
+ assert_match "alert()", last_response.body
+ end
+
+ test "does not stream session cookies back" do
+ puts "PENDING SPROCKETS AND RACK RELEASE"
+ # app_file "app/assets/javascripts/demo.js.erb", "<%= :alert %>();"
+ #
+ # app_file "config/routes.rb", <<-RUBY
+ # AppTemplate::Application.routes.draw do
+ # match '/omg', :to => "omg#index"
+ # end
+ # RUBY
+ #
+ # require "#{app_path}/config/environment"
+ #
+ # class ::OmgController < ActionController::Base
+ # def index
+ # flash[:cool_story] = true
+ # render :text => "ok"
+ # end
+ # end
+ #
+ # get "/omg"
+ # assert_equal 'ok', last_response.body
+ #
+ # get "/assets/demo.js"
+ # assert_match "alert()", last_response.body
+ # assert_equal nil, last_response.headers["Set-Cookie"]
+ end
+ end
+end
diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb
index 6193e72625..0e27c9606d 100644
--- a/railties/test/application/configuration_test.rb
+++ b/railties/test/application/configuration_test.rb
@@ -225,8 +225,6 @@ module ApplicationTests
make_basic_app
class ::OmgController < ActionController::Base
- protect_from_forgery
-
def index
render :inline => "<%= csrf_meta_tags %>"
end
@@ -236,6 +234,21 @@ module ApplicationTests
assert last_response.body =~ /csrf\-param/
end
+ test "request forgery token param can be changed" do
+ make_basic_app do
+ app.config.action_controller.request_forgery_protection_token = '_xsrf_token_here'
+ end
+
+ class ::OmgController < ActionController::Base
+ def index
+ render :inline => "<%= csrf_meta_tags %>"
+ end
+ end
+
+ get "/"
+ assert last_response.body =~ /_xsrf_token_here/
+ end
+
test "config.action_controller.perform_caching = true" do
make_basic_app do |app|
app.config.action_controller.perform_caching = true
@@ -439,7 +452,7 @@ module ApplicationTests
app_file 'app/models/post.rb', <<-RUBY
class Post
- def self.column_names
+ def self.attribute_names
%w(title)
end
end
diff --git a/railties/test/application/initializers/frameworks_test.rb b/railties/test/application/initializers/frameworks_test.rb
index 19311a7fa0..196d121c14 100644
--- a/railties/test/application/initializers/frameworks_test.rb
+++ b/railties/test/application/initializers/frameworks_test.rb
@@ -166,7 +166,7 @@ module ApplicationTests
require "#{app_path}/config/environment"
- expects = [ActiveRecord::IdentityMap::Middleware, ActiveRecord::ConnectionAdapters::ConnectionManagement, ActiveRecord::QueryCache, ActiveRecord::SessionStore]
+ expects = [ActiveRecord::ConnectionAdapters::ConnectionManagement, ActiveRecord::QueryCache, ActiveRecord::SessionStore]
middleware = Rails.application.config.middleware.map { |m| m.klass }
assert_equal expects, middleware & expects
end
diff --git a/railties/test/application/middleware_test.rb b/railties/test/application/middleware_test.rb
index 01e6c49d9c..8bfde00af5 100644
--- a/railties/test/application/middleware_test.rb
+++ b/railties/test/application/middleware_test.rb
@@ -23,20 +23,19 @@ module ApplicationTests
"Rack::Lock",
"ActiveSupport::Cache::Strategy::LocalCache",
"Rack::Runtime",
- "Rails::Rack::Logger",
+ "Rack::MethodOverride",
+ "Rails::Rack::Logger", # must come after Rack::MethodOverride to properly log overridden methods
"ActionDispatch::ShowExceptions",
"ActionDispatch::RemoteIp",
"Rack::Sendfile",
"ActionDispatch::Reloader",
"ActionDispatch::Callbacks",
- "ActiveRecord::IdentityMap::Middleware",
"ActiveRecord::ConnectionAdapters::ConnectionManagement",
"ActiveRecord::QueryCache",
"ActionDispatch::Cookies",
"ActionDispatch::Session::CookieStore",
"ActionDispatch::Flash",
"ActionDispatch::ParamsParser",
- "Rack::MethodOverride",
"ActionDispatch::Head",
"Rack::ConditionalGet",
"Rack::ETag",
@@ -121,6 +120,7 @@ module ApplicationTests
end
test "identity map is inserted" do
+ add_to_config "config.active_record.identity_map = true"
boot!
assert middleware.include?("ActiveRecord::IdentityMap::Middleware")
end
diff --git a/railties/test/application/rack/logger_test.rb b/railties/test/application/rack/logger_test.rb
new file mode 100644
index 0000000000..a29244357c
--- /dev/null
+++ b/railties/test/application/rack/logger_test.rb
@@ -0,0 +1,40 @@
+require "isolation/abstract_unit"
+require "active_support/log_subscriber/test_helper"
+require "rack/test"
+
+module ApplicationTests
+ module RackTests
+ class LoggerTest < Test::Unit::TestCase
+ include ActiveSupport::LogSubscriber::TestHelper
+ include Rack::Test::Methods
+
+ def setup
+ build_app
+ require "#{app_path}/config/environment"
+ super
+ end
+
+ def logs
+ @logs ||= @logger.logged(:info)
+ end
+
+ test "logger logs proper HTTP verb and path" do
+ get "/blah"
+ wait
+ assert_match /^Started GET "\/blah"/, logs[0]
+ end
+
+ test "logger logs HTTP verb override" do
+ post "/", {:_method => 'put'}
+ wait
+ assert_match /^Started PUT "\/"/, logs[0]
+ end
+
+ test "logger logs HEAD requests" do
+ post "/", {:_method => 'head'}
+ wait
+ assert_match /^Started HEAD "\/"/, logs[0]
+ end
+ end
+ end
+end
diff --git a/railties/test/application/routing_test.rb b/railties/test/application/routing_test.rb
index 62589c998d..e3a7f8a63c 100644
--- a/railties/test/application/routing_test.rb
+++ b/railties/test/application/routing_test.rb
@@ -1,14 +1,14 @@
require 'isolation/abstract_unit'
+require 'rack/test'
module ApplicationTests
class RoutingTest < Test::Unit::TestCase
include ActiveSupport::Testing::Isolation
+ include Rack::Test::Methods
def setup
build_app
boot_rails
- require 'rack/test'
- extend Rack::Test::Methods
end
test "rails/info/properties in development" do
diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb
index cc0bd53639..9e1d47cd2f 100644
--- a/railties/test/generators/app_generator_test.rb
+++ b/railties/test/generators/app_generator_test.rb
@@ -66,8 +66,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
end
def test_application_new_exits_with_non_zero_code_on_invalid_application_name
- # TODO: Suppress the output of this (it's because of a Thor::Error)
- `rails new test`
+ quietly { system 'rails new test' }
assert_equal false, $?.success?
end
@@ -97,7 +96,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
generator = Rails::Generators::AppGenerator.new ["rails"], { :with_dispatchers => true },
:destination_root => app_moved_root, :shell => @shell
generator.send(:app_const)
- silence(:stdout){ generator.send(:create_config_files) }
+ quietly { generator.send(:create_config_files) }
assert_file "myapp_moved/config/environment.rb", /Myapp::Application\.initialize!/
assert_file "myapp_moved/config/initializers/session_store.rb", /_myapp_session/
end
@@ -112,7 +111,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
generator = Rails::Generators::AppGenerator.new ["rails"], { :with_dispatchers => true }, :destination_root => app_root, :shell => @shell
generator.send(:app_const)
- silence(:stdout){ generator.send(:create_config_files) }
+ quietly { generator.send(:create_config_files) }
assert_file "myapp/config/initializers/session_store.rb", /_myapp_session/
end
@@ -259,7 +258,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
protected
def action(*args, &block)
- silence(:stdout){ generator.send(*args, &block) }
+ silence(:stdout) { generator.send(*args, &block) }
end
end
@@ -285,6 +284,6 @@ protected
end
def action(*args, &block)
- silence(:stdout){ generator.send(*args, &block) }
+ silence(:stdout) { generator.send(*args, &block) }
end
end
diff --git a/railties/test/generators/generated_attribute_test.rb b/railties/test/generators/generated_attribute_test.rb
index 064546a3f3..0d2e624f44 100644
--- a/railties/test/generators/generated_attribute_test.rb
+++ b/railties/test/generators/generated_attribute_test.rb
@@ -4,8 +4,12 @@ require 'rails/generators/generated_attribute'
class GeneratedAttributeTest < Rails::Generators::TestCase
include GeneratorsTestHelper
+ def test_field_type_returns_number_field
+ assert_field_type :integer, :number_field
+ end
+
def test_field_type_returns_text_field
- %w(integer float decimal string).each do |attribute_type|
+ %w(float decimal string).each do |attribute_type|
assert_field_type attribute_type, :text_field
end
end
diff --git a/railties/test/generators/mailer_generator_test.rb b/railties/test/generators/mailer_generator_test.rb
index f4fdc46328..bf1cfe5305 100644
--- a/railties/test/generators/mailer_generator_test.rb
+++ b/railties/test/generators/mailer_generator_test.rb
@@ -10,7 +10,11 @@ class MailerGeneratorTest < Rails::Generators::TestCase
run_generator
assert_file "app/mailers/notifier.rb" do |mailer|
assert_match /class Notifier < ActionMailer::Base/, mailer
- assert_match /default :from => "from@example.com"/, mailer
+ if RUBY_VERSION < "1.9"
+ assert_match /default :from => "from@example.com"/, mailer
+ else
+ assert_match /default from: "from@example.com"/, mailer
+ end
end
end
@@ -73,15 +77,33 @@ class MailerGeneratorTest < Rails::Generators::TestCase
assert_file "app/mailers/notifier.rb" do |mailer|
assert_instance_method :foo, mailer do |foo|
- assert_match /mail :to => "to@example.org"/, foo
+ if RUBY_VERSION < "1.9"
+ assert_match /mail :to => "to@example.org"/, foo
+ else
+ assert_match /mail to: "to@example.org"/, foo
+ end
assert_match /@greeting = "Hi"/, foo
end
assert_instance_method :bar, mailer do |bar|
- assert_match /mail :to => "to@example.org"/, bar
+ if RUBY_VERSION < "1.9"
+ assert_match /mail :to => "to@example.org"/, bar
+ else
+ assert_match /mail to: "to@example.org"/, bar
+ end
assert_match /@greeting = "Hi"/, bar
end
end
+ end
+ def test_force_old_style_hash
+ run_generator ["notifier", "foo", "--old-style-hash"]
+ assert_file "app/mailers/notifier.rb" do |mailer|
+ assert_match /default :from => "from@example.com"/, mailer
+
+ assert_instance_method :foo, mailer do |foo|
+ assert_match /mail :to => "to@example.org"/, foo
+ end
+ end
end
end
diff --git a/railties/test/generators/namespaced_generators_test.rb b/railties/test/generators/namespaced_generators_test.rb
index eb56e8d1a4..38f024f061 100644
--- a/railties/test/generators/namespaced_generators_test.rb
+++ b/railties/test/generators/namespaced_generators_test.rb
@@ -163,7 +163,11 @@ class NamespacedMailerGeneratorTest < NamespacedGeneratorTestCase
assert_file "app/mailers/test_app/notifier.rb" do |mailer|
assert_match /module TestApp/, mailer
assert_match /class Notifier < ActionMailer::Base/, mailer
- assert_match /default :from => "from@example.com"/, mailer
+ if RUBY_VERSION < "1.9"
+ assert_match /default :from => "from@example.com"/, mailer
+ else
+ assert_match /default from: "from@example.com"/, mailer
+ end
end
end
diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb
index f637a6a17e..2af728e766 100644
--- a/railties/test/generators/plugin_new_generator_test.rb
+++ b/railties/test/generators/plugin_new_generator_test.rb
@@ -119,17 +119,17 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase
assert_match(/It works from file!/, run_generator([destination_root, "-m", "lib/template.rb"]))
end
- def test_ensure_that_tests_works
+ def test_ensure_that_tests_work
run_generator
FileUtils.cd destination_root
- `bundle install`
+ quietly { system 'bundle install' }
assert_match(/1 tests, 1 assertions, 0 failures, 0 errors/, `bundle exec rake test`)
end
def test_ensure_that_tests_works_in_full_mode
run_generator [destination_root, "--full", "--skip_active_record"]
FileUtils.cd destination_root
- `bundle install`
+ quietly { system 'bundle install' }
assert_match(/1 tests, 1 assertions, 0 failures, 0 errors/, `bundle exec rake test`)
end
diff --git a/railties/test/generators/shared_generator_tests.rb b/railties/test/generators/shared_generator_tests.rb
index 03fd64ca38..be9aef8a41 100644
--- a/railties/test/generators/shared_generator_tests.rb
+++ b/railties/test/generators/shared_generator_tests.rb
@@ -6,7 +6,6 @@ module SharedGeneratorTests
Rails.application = TestApp::Application
super
Rails::Generators::AppGenerator.instance_variable_set('@desc', nil)
- @bundle_command = File.basename(Thor::Util.ruby_command).sub(/ruby/, 'bundle')
Kernel::silence_warnings do
Thor::Base.shell.send(:attr_accessor, :always_force)
@@ -24,7 +23,12 @@ module SharedGeneratorTests
def test_skeleton_is_created
run_generator
- default_files.each{ |path| assert_file path }
+ default_files.each { |path| assert_file path }
+ end
+
+ def test_generation_runs_bundle_install
+ generator([destination_root]).expects(:bundle_command).with('install').once
+ quietly { generator.invoke_all }
end
def test_plugin_new_generate_pretend
@@ -84,20 +88,7 @@ module SharedGeneratorTests
template.instance_eval "def read; self; end" # Make the string respond to read
generator([destination_root], :template => path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template)
- assert_match(/It works!/, silence(:stdout){ generator.invoke_all })
- end
-
- def test_dev_option
- generator([destination_root], :dev => true).expects(:run).with("#{@bundle_command} install")
- silence(:stdout){ generator.invoke_all }
- rails_path = File.expand_path('../../..', Rails.root)
- assert_file 'Gemfile', /^gem\s+["']rails["'],\s+:path\s+=>\s+["']#{Regexp.escape(rails_path)}["']$/
- end
-
- def test_edge_option
- generator([destination_root], :edge => true).expects(:run).with("#{@bundle_command} install")
- silence(:stdout){ generator.invoke_all }
- assert_file 'Gemfile', %r{^gem\s+["']rails["'],\s+:git\s+=>\s+["']#{Regexp.escape("git://github.com/rails/rails.git")}["']$}
+ assert_match(/It works!/, capture(:stdout) { generator.invoke_all })
end
def test_template_raises_an_error_with_invalid_path
@@ -112,7 +103,7 @@ module SharedGeneratorTests
template.instance_eval "def read; self; end" # Make the string respond to read
generator([destination_root], :template => path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template)
- assert_match(/It works!/, silence(:stdout){ generator.invoke_all })
+ assert_match(/It works!/, capture(:stdout) { generator.invoke_all })
end
def test_template_is_executed_when_supplied_an_https_path
@@ -121,21 +112,36 @@ module SharedGeneratorTests
template.instance_eval "def read; self; end" # Make the string respond to read
generator([destination_root], :template => path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template)
- assert_match(/It works!/, silence(:stdout){ generator.invoke_all })
+ assert_match(/It works!/, capture(:stdout) { generator.invoke_all })
end
def test_dev_option
- generator([destination_root], :dev => true).expects(:run).with("#{@bundle_command} install")
- silence(:stdout){ generator.invoke_all }
+ generator([destination_root], :dev => true).expects(:bundle_command).with('install').once
+ quietly { generator.invoke_all }
rails_path = File.expand_path('../../..', Rails.root)
assert_file 'Gemfile', /^gem\s+["']rails["'],\s+:path\s+=>\s+["']#{Regexp.escape(rails_path)}["']$/
end
def test_edge_option
- generator([destination_root], :edge => true).expects(:run).with("#{@bundle_command} install")
- silence(:stdout){ generator.invoke_all }
+ generator([destination_root], :edge => true).expects(:bundle_command).with('install').once
+ quietly { generator.invoke_all }
assert_file 'Gemfile', %r{^gem\s+["']rails["'],\s+:git\s+=>\s+["']#{Regexp.escape("git://github.com/rails/rails.git")}["']$}
end
+
+ def test_skip_gemfile
+ generator([destination_root], :skip_gemfile => true).expects(:bundle_command).never
+ quietly { generator.invoke_all }
+ assert_no_file 'Gemfile'
+ end
+
+ def test_skip_bundle
+ generator([destination_root], :skip_bundle => true).expects(:bundle_command).never
+ quietly { generator.invoke_all }
+
+ # skip_bundle is only about running bundle install, ensure the Gemfile is still
+ # generated.
+ assert_file 'Gemfile'
+ end
end
module SharedCustomGeneratorTests
@@ -143,7 +149,6 @@ module SharedCustomGeneratorTests
Rails.application = TestApp::Application
super
Rails::Generators::AppGenerator.instance_variable_set('@desc', nil)
- @bundle_command = File.basename(Thor::Util.ruby_command).sub(/ruby/, 'bundle')
end
def teardown
@@ -191,7 +196,7 @@ module SharedCustomGeneratorTests
template.instance_eval "def read; self; end" # Make the string respond to read
generator([destination_root], :builder => path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template)
- capture(:stdout) { generator.invoke_all }
+ quietly { generator.invoke_all }
default_files.each{ |path| assert_no_file(path) }
end
diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb
index 0c588ba773..b5b21f9ebe 100644
--- a/railties/test/railties/engine_test.rb
+++ b/railties/test/railties/engine_test.rb
@@ -93,6 +93,34 @@ module RailtiesTest
assert_equal "HELLO WORLD", last_response.body
end
+ test "pass the value of the segment" do
+ controller "foo", <<-RUBY
+ class FooController < ActionController::Base
+ def index
+ render :text => params[:username]
+ end
+ end
+ RUBY
+
+ @plugin.write "config/routes.rb", <<-RUBY
+ Bukkits::Engine.routes.draw do
+ root :to => "foo#index"
+ end
+ RUBY
+
+ app_file "config/routes.rb", <<-RUBY
+ Rails.application.routes.draw do
+ mount(Bukkits::Engine => "/:username")
+ end
+ RUBY
+
+ boot_rails
+
+ get("/arunagw")
+ assert_equal "arunagw", last_response.body
+
+ end
+
test "it provides routes as default endpoint" do
@plugin.write "lib/bukkits.rb", <<-RUBY
class Bukkits
diff --git a/railties/test/railties/shared_tests.rb b/railties/test/railties/shared_tests.rb
index e975950b85..e5debf29ae 100644
--- a/railties/test/railties/shared_tests.rb
+++ b/railties/test/railties/shared_tests.rb
@@ -15,11 +15,10 @@ module RailtiesTest
boot_rails
require 'rack/test'
- require 'coffee_script'
extend Rack::Test::Methods
get "/assets/engine.js"
- assert_match "alert();", last_response.body
+ assert_match "alert()", last_response.body
end
def test_copying_migrations