aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile4
-rw-r--r--actionmailer/lib/action_mailer.rb3
-rw-r--r--actionmailer/lib/action_mailer/base.rb3
-rw-r--r--actionmailer/test/abstract_unit.rb3
-rw-r--r--actionmailer/test/base_test.rb13
-rw-r--r--actionmailer/test/fixtures/anonymous/welcome.erb1
-rw-r--r--actionpack/CHANGELOG.md19
-rw-r--r--actionpack/Rakefile1
-rw-r--r--actionpack/lib/abstract_controller.rb4
-rw-r--r--actionpack/lib/abstract_controller/callbacks.rb2
-rw-r--r--actionpack/lib/action_controller/caching/pages.rb14
-rw-r--r--actionpack/lib/action_controller/log_subscriber.rb2
-rw-r--r--actionpack/lib/action_controller/metal/conditional_get.rb1
-rw-r--r--actionpack/lib/action_controller/metal/helpers.rb1
-rw-r--r--actionpack/lib/action_controller/metal/http_authentication.rb86
-rw-r--r--actionpack/lib/action_controller/metal/mime_responds.rb7
-rw-r--r--actionpack/lib/action_controller/metal/redirecting.rb5
-rw-r--r--actionpack/lib/action_controller/metal/renderers.rb1
-rw-r--r--actionpack/lib/action_controller/metal/request_forgery_protection.rb2
-rw-r--r--actionpack/lib/action_controller/metal/url_for.rb3
-rw-r--r--actionpack/lib/action_controller/record_identifier.rb6
-rw-r--r--actionpack/lib/action_controller/test_case.rb9
-rw-r--r--actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb1
-rw-r--r--actionpack/lib/action_dispatch.rb6
-rw-r--r--actionpack/lib/action_dispatch/http/filter_parameters.rb3
-rw-r--r--actionpack/lib/action_dispatch/http/request.rb3
-rw-r--r--actionpack/lib/action_dispatch/middleware/exception_wrapper.rb3
-rw-r--r--actionpack/lib/action_dispatch/middleware/flash.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/cookie_store.rb2
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb37
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb2
-rw-r--r--actionpack/lib/action_dispatch/routing/url_for.rb2
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/dom.rb6
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/response.rb6
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/routing.rb3
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/selector.rb6
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/tag.rb3
-rw-r--r--actionpack/lib/action_dispatch/testing/integration.rb31
-rw-r--r--actionpack/lib/action_view.rb9
-rw-r--r--actionpack/lib/action_view/asset_paths.rb2
-rw-r--r--actionpack/lib/action_view/base.rb1
-rw-r--r--actionpack/lib/action_view/context.rb4
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helper.rb69
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb4
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb3
-rw-r--r--actionpack/lib/action_view/helpers/cache_helper.rb1
-rw-r--r--actionpack/lib/action_view/helpers/capture_helper.rb1
-rw-r--r--actionpack/lib/action_view/helpers/date_helper.rb26
-rw-r--r--actionpack/lib/action_view/helpers/debug_helper.rb3
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb6
-rw-r--r--actionpack/lib/action_view/helpers/form_options_helper.rb52
-rw-r--r--actionpack/lib/action_view/helpers/form_tag_helper.rb24
-rw-r--r--actionpack/lib/action_view/helpers/number_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/sanitize_helper.rb3
-rw-r--r--actionpack/lib/action_view/helpers/tag_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/tags/base.rb8
-rw-r--r--actionpack/lib/action_view/helpers/tags/date_field.rb1
-rw-r--r--actionpack/lib/action_view/helpers/tags/file_field.rb4
-rw-r--r--actionpack/lib/action_view/helpers/tags/hidden_field.rb4
-rw-r--r--actionpack/lib/action_view/helpers/tags/number_field.rb1
-rw-r--r--actionpack/lib/action_view/helpers/text_helper.rb47
-rw-r--r--actionpack/lib/action_view/helpers/url_helper.rb14
-rw-r--r--actionpack/lib/action_view/renderer/abstract_renderer.rb4
-rw-r--r--actionpack/lib/action_view/renderer/partial_renderer.rb71
-rw-r--r--actionpack/lib/action_view/template/handlers.rb2
-rw-r--r--actionpack/lib/action_view/template/handlers/raw.rb11
-rw-r--r--actionpack/lib/action_view/template/resolver.rb5
-rw-r--r--actionpack/test/abstract_unit.rb6
-rw-r--r--actionpack/test/controller/integration_test.rb80
-rw-r--r--actionpack/test/controller/new_base/render_text_test.rb4
-rw-r--r--actionpack/test/dispatch/routing_assertions_test.rb6
-rw-r--r--actionpack/test/dispatch/routing_test.rb126
-rw-r--r--actionpack/test/fixtures/plain_text.raw1
-rw-r--r--actionpack/test/fixtures/plain_text_with_characters.raw1
-rw-r--r--actionpack/test/fixtures/routes/bogus.rb1
-rw-r--r--actionpack/test/fixtures/routes/external.rb1
-rw-r--r--actionpack/test/template/asset_tag_helper_test.rb11
-rw-r--r--actionpack/test/template/form_options_helper_test.rb78
-rw-r--r--actionpack/test/template/form_tag_helper_test.rb16
-rw-r--r--actionpack/test/template/render_test.rb8
-rw-r--r--actionpack/test/template/template_test.rb7
-rw-r--r--actionpack/test/template/testing/fixture_resolver_test.rb4
-rw-r--r--actionpack/test/template/testing/null_resolver_test.rb4
-rw-r--r--actionpack/test/template/text_helper_test.rb8
-rw-r--r--actionpack/test/template/url_helper_test.rb16
-rw-r--r--actionpack/test/ts_isolated.rb3
-rw-r--r--activemodel/README.rdoc2
-rw-r--r--activemodel/lib/active_model.rb7
-rw-r--r--activemodel/lib/active_model/attribute_methods.rb20
-rw-r--r--activemodel/lib/active_model/dirty.rb2
-rw-r--r--activemodel/lib/active_model/mass_assignment_security.rb2
-rw-r--r--activemodel/lib/active_model/mass_assignment_security/sanitizer.rb31
-rw-r--r--activemodel/lib/active_model/secure_password.rb15
-rw-r--r--activemodel/lib/active_model/serialization.rb6
-rw-r--r--activemodel/lib/active_model/serializers/xml.rb4
-rw-r--r--activemodel/lib/active_model/validations.rb6
-rw-r--r--activemodel/lib/active_model/validations/acceptance.rb4
-rw-r--r--activemodel/lib/active_model/validations/confirmation.rb4
-rw-r--r--activemodel/lib/active_model/validations/exclusion.rb38
-rw-r--r--activemodel/lib/active_model/validations/format.rb52
-rw-r--r--activemodel/lib/active_model/validations/inclusion.rb26
-rw-r--r--activemodel/lib/active_model/validations/length.rb43
-rw-r--r--activemodel/lib/active_model/validations/numericality.rb50
-rw-r--r--activemodel/lib/active_model/validations/presence.rb28
-rw-r--r--activemodel/lib/active_model/validations/with.rb10
-rw-r--r--activemodel/test/cases/attribute_methods_test.rb19
-rw-r--r--activemodel/test/cases/dirty_test.rb2
-rw-r--r--activemodel/test/cases/helper.rb3
-rw-r--r--activemodel/test/cases/mass_assignment_security/sanitizer_test.rb8
-rw-r--r--activemodel/test/cases/mass_assignment_security_test.rb2
-rw-r--r--activemodel/test/cases/secure_password_test.rb30
-rw-r--r--activemodel/test/cases/serialization_test.rb18
-rw-r--r--activemodel/test/cases/serializers/xml_serialization_test.rb17
-rw-r--r--activemodel/test/cases/validations_test.rb15
-rw-r--r--activemodel/test/models/administrator.rb3
-rw-r--r--activemodel/test/models/user.rb3
-rw-r--r--activemodel/test/models/visitor.rb7
-rw-r--r--activerecord/CHANGELOG.md27
-rw-r--r--activerecord/lib/active_record.rb5
-rw-r--r--activerecord/lib/active_record/aggregations.rb2
-rw-r--r--activerecord/lib/active_record/associations.rb2
-rw-r--r--activerecord/lib/active_record/associations/collection_association.rb18
-rw-r--r--activerecord/lib/active_record/associations/collection_proxy.rb79
-rw-r--r--activerecord/lib/active_record/autosave_association.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb26
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb22
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/column.rb1
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid.rb15
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb56
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb14
-rw-r--r--activerecord/lib/active_record/core.rb31
-rw-r--r--activerecord/lib/active_record/fixtures.rb161
-rw-r--r--activerecord/lib/active_record/nested_attributes.rb8
-rw-r--r--activerecord/lib/active_record/persistence.rb1
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb55
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb3
-rw-r--r--activerecord/lib/active_record/relation/merger.rb3
-rw-r--r--activerecord/lib/active_record/relation/predicate_builder.rb6
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb74
-rw-r--r--activerecord/lib/active_record/relation/spawn_methods.rb13
-rw-r--r--activerecord/lib/active_record/schema.rb17
-rw-r--r--activerecord/lib/active_record/session_store.rb15
-rw-r--r--activerecord/lib/active_record/store.rb18
-rw-r--r--activerecord/lib/active_record/transactions.rb10
-rw-r--r--activerecord/test/cases/adapters/postgresql/datatype_test.rb19
-rw-r--r--activerecord/test/cases/adapters/sqlite3/copy_table_test.rb8
-rw-r--r--activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb17
-rw-r--r--activerecord/test/cases/ar_schema_test.rb7
-rw-r--r--activerecord/test/cases/associations/eager_test.rb2
-rw-r--r--activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb13
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb39
-rw-r--r--activerecord/test/cases/associations/join_model_test.rb2
-rw-r--r--activerecord/test/cases/autosave_association_test.rb4
-rw-r--r--activerecord/test/cases/base_test.rb18
-rw-r--r--activerecord/test/cases/bind_parameter_test.rb17
-rw-r--r--activerecord/test/cases/calculations_test.rb15
-rw-r--r--activerecord/test/cases/finder_test.rb1
-rw-r--r--activerecord/test/cases/helper.rb4
-rw-r--r--activerecord/test/cases/migration/change_schema_test.rb4
-rw-r--r--activerecord/test/cases/migration/column_attributes_test.rb10
-rw-r--r--activerecord/test/cases/migration_test.rb25
-rw-r--r--activerecord/test/cases/readonly_test.rb1
-rw-r--r--activerecord/test/cases/relation_scoping_test.rb2
-rw-r--r--activerecord/test/cases/relation_test.rb7
-rw-r--r--activerecord/test/cases/relations_test.rb8
-rw-r--r--activerecord/test/cases/schema_dumper_test.rb21
-rw-r--r--activerecord/test/cases/session_store/sql_bypass_test.rb (renamed from activerecord/test/cases/session_store/sql_bypass.rb)5
-rw-r--r--activerecord/test/cases/store_test.rb36
-rw-r--r--activerecord/test/cases/transaction_callbacks_test.rb37
-rw-r--r--activerecord/test/models/admin/user.rb2
-rw-r--r--activerecord/test/schema/schema.rb3
-rw-r--r--activerecord/test/schema/sqlite_specific_schema.rb2
-rw-r--r--activesupport/CHANGELOG.md4
-rw-r--r--activesupport/lib/active_support/backtrace_cleaner.rb6
-rw-r--r--activesupport/lib/active_support/cache/file_store.rb6
-rw-r--r--activesupport/lib/active_support/cache/memory_store.rb1
-rw-r--r--activesupport/lib/active_support/callbacks.rb36
-rw-r--r--activesupport/lib/active_support/core_ext/array/wrap.rb3
-rw-r--r--activesupport/lib/active_support/core_ext/date/calculations.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/date/conversions.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/date_time/calculations.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/date_time/conversions.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/enumerable.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/hash/deep_merge.rb9
-rw-r--r--activesupport/lib/active_support/core_ext/hash/diff.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/hash/keys.rb12
-rw-r--r--activesupport/lib/active_support/core_ext/integer/multiple.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/module/aliasing.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/object/deep_dup.rb24
-rw-r--r--activesupport/lib/active_support/core_ext/object/duplicable.rb26
-rw-r--r--activesupport/lib/active_support/core_ext/object/instance_variables.rb9
-rw-r--r--activesupport/lib/active_support/core_ext/object/try.rb8
-rw-r--r--activesupport/lib/active_support/core_ext/range.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/range/blockless_step.rb13
-rw-r--r--activesupport/lib/active_support/core_ext/range/conversions.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/string.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/string/access.rb71
-rw-r--r--activesupport/lib/active_support/core_ext/string/conversions.rb12
-rw-r--r--activesupport/lib/active_support/core_ext/string/exclude.rb7
-rw-r--r--activesupport/lib/active_support/core_ext/string/filters.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/string/inflections.rb6
-rw-r--r--activesupport/lib/active_support/core_ext/string/inquiry.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/string/interpolation.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/string/output_safety.rb16
-rw-r--r--activesupport/lib/active_support/dependencies.rb10
-rw-r--r--activesupport/lib/active_support/deprecation/behaviors.rb4
-rw-r--r--activesupport/lib/active_support/duration.rb1
-rw-r--r--activesupport/lib/active_support/i18n.rb1
-rw-r--r--activesupport/lib/active_support/inflections.rb2
-rw-r--r--activesupport/lib/active_support/inflector/inflections.rb9
-rw-r--r--activesupport/lib/active_support/inflector/methods.rb13
-rw-r--r--activesupport/lib/active_support/inflector/transliterate.rb2
-rw-r--r--activesupport/lib/active_support/json/encoding.rb2
-rw-r--r--activesupport/lib/active_support/log_subscriber/test_helper.rb8
-rw-r--r--activesupport/lib/active_support/multibyte.rb3
-rw-r--r--activesupport/lib/active_support/multibyte/chars.rb11
-rw-r--r--activesupport/lib/active_support/multibyte/unicode.rb3
-rw-r--r--activesupport/lib/active_support/ordered_hash.rb12
-rw-r--r--activesupport/lib/active_support/railtie.rb7
-rw-r--r--activesupport/lib/active_support/ruby/shim.rb15
-rw-r--r--activesupport/lib/active_support/tagged_logging.rb2
-rw-r--r--activesupport/lib/active_support/testing/performance.rb6
-rw-r--r--activesupport/lib/active_support/testing/performance/ruby.rb2
-rw-r--r--activesupport/lib/active_support/time_with_zone.rb4
-rw-r--r--activesupport/lib/active_support/values/time_zone.rb15
-rw-r--r--activesupport/test/abstract_unit.rb3
-rw-r--r--activesupport/test/caching_test.rb7
-rw-r--r--activesupport/test/callback_inheritance_test.rb2
-rw-r--r--activesupport/test/callbacks_test.rb6
-rw-r--r--activesupport/test/core_ext/duplicable_test.rb4
-rw-r--r--activesupport/test/core_ext/hash_ext_test.rb10
-rw-r--r--activesupport/test/core_ext/object_and_class_ext_test.rb14
-rw-r--r--activesupport/test/core_ext/range_ext_test.rb10
-rw-r--r--activesupport/test/core_ext/string_ext_test.rb24
-rw-r--r--activesupport/test/inflector_test_cases.rb1
-rw-r--r--activesupport/test/log_subscriber_test.rb2
-rw-r--r--activesupport/test/time_zone_test.rb18
-rw-r--r--activesupport/test/ts_isolated.rb2
-rw-r--r--guides/code/getting_started/config/boot.rb2
-rw-r--r--guides/code/getting_started/public/robots.txt2
-rw-r--r--guides/code/getting_started/test/performance/browsing_test.rb2
-rw-r--r--guides/rails_guides.rb3
-rw-r--r--guides/source/action_view_overview.textile2
-rw-r--r--guides/source/active_model_basics.textile5
-rw-r--r--guides/source/active_record_querying.textile18
-rw-r--r--guides/source/active_support_core_extensions.textile30
-rw-r--r--guides/source/ajax_on_rails.textile4
-rw-r--r--guides/source/asset_pipeline.textile37
-rw-r--r--guides/source/caching_with_rails.textile36
-rw-r--r--guides/source/configuring.textile6
-rw-r--r--guides/source/engines.textile15
-rw-r--r--guides/source/form_helpers.textile2
-rw-r--r--guides/source/getting_started.textile293
-rw-r--r--guides/source/i18n.textile6
-rw-r--r--guides/source/initialization.textile2
-rw-r--r--guides/source/layouts_and_rendering.textile6
-rw-r--r--guides/source/migrations.textile16
-rw-r--r--guides/source/security.textile2
-rw-r--r--guides/w3c_validator.rb1
-rw-r--r--load_paths.rb1
-rw-r--r--railties/CHANGELOG.md2
-rw-r--r--railties/Rakefile3
-rw-r--r--railties/lib/rails.rb3
-rw-r--r--railties/lib/rails/commands/application.rb1
-rw-r--r--railties/lib/rails/commands/plugin_new.rb2
-rw-r--r--railties/lib/rails/engine.rb10
-rw-r--r--railties/lib/rails/generators.rb4
-rw-r--r--railties/lib/rails/generators/actions.rb42
-rw-r--r--railties/lib/rails/generators/app_base.rb11
-rw-r--r--railties/lib/rails/generators/base.rb3
-rw-r--r--railties/lib/rails/generators/migration.rb4
-rw-r--r--railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/application.rb2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/boot.rb2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/public/humans.txt.tt2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/public/robots.txt2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/test/performance/browsing_test.rb2
-rw-r--r--railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb2
-rw-r--r--railties/lib/rails/generators/rails/plugin_new/templates/rails/boot.rb1
-rw-r--r--railties/lib/rails/generators/test_unit/plugin/templates/test_helper.rb1
-rw-r--r--railties/test/generators/app_generator_test.rb47
-rw-r--r--railties/test/generators/plugin_new_generator_test.rb16
-rw-r--r--railties/test/isolation/abstract_unit.rb5
-rw-r--r--railties/test/railties/engine_test.rb10
-rwxr-xr-xtools/profile1
286 files changed, 2289 insertions, 1477 deletions
diff --git a/Gemfile b/Gemfile
index 10202ca877..7ae8344b1f 100644
--- a/Gemfile
+++ b/Gemfile
@@ -50,7 +50,7 @@ instance_eval File.read local_gemfile if File.exists? local_gemfile
platforms :mri do
group :test do
- gem 'ruby-prof', '0.10.8'
+ gem 'ruby-prof', '~> 0.11.2'
end
end
@@ -60,7 +60,7 @@ platforms :ruby do
gem 'nokogiri', '>= 1.4.5'
# AR
- gem 'sqlite3', '~> 1.3.5'
+ gem 'sqlite3', '~> 1.3.6'
group :db do
gem 'pg', '>= 0.11.0'
diff --git a/actionmailer/lib/action_mailer.rb b/actionmailer/lib/action_mailer.rb
index 1045dd58ef..e45a1cd5ff 100644
--- a/actionmailer/lib/action_mailer.rb
+++ b/actionmailer/lib/action_mailer.rb
@@ -21,9 +21,6 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
-actionpack_path = File.expand_path('../../../actionpack/lib', __FILE__)
-$:.unshift(actionpack_path) if File.directory?(actionpack_path) && !$:.include?(actionpack_path)
-
require 'abstract_controller'
require 'action_view'
require 'action_mailer/version'
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb
index e24a7f52d5..4f0cff0612 100644
--- a/actionmailer/lib/action_mailer/base.rb
+++ b/actionmailer/lib/action_mailer/base.rb
@@ -3,6 +3,7 @@ require 'action_mailer/collector'
require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/string/inflections'
require 'active_support/core_ext/hash/except'
+require 'active_support/core_ext/module/anonymous'
require 'action_mailer/log_subscriber'
module ActionMailer #:nodoc:
@@ -401,7 +402,7 @@ module ActionMailer #:nodoc:
end
def mailer_name
- @mailer_name ||= name.underscore
+ @mailer_name ||= anonymous? ? "anonymous" : name.underscore
end
attr_writer :mailer_name
alias :controller_path :mailer_name
diff --git a/actionmailer/test/abstract_unit.rb b/actionmailer/test/abstract_unit.rb
index 487102b564..99c44179fd 100644
--- a/actionmailer/test/abstract_unit.rb
+++ b/actionmailer/test/abstract_unit.rb
@@ -8,9 +8,6 @@ silence_warnings do
Encoding.default_external = "UTF-8"
end
-lib = File.expand_path("#{File.dirname(__FILE__)}/../lib")
-$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib)
-
require 'minitest/autorun'
require 'action_mailer'
require 'action_mailer/test_case'
diff --git a/actionmailer/test/base_test.rb b/actionmailer/test/base_test.rb
index aed3ee1874..1d747ed18a 100644
--- a/actionmailer/test/base_test.rb
+++ b/actionmailer/test/base_test.rb
@@ -610,6 +610,19 @@ class BaseTest < ActiveSupport::TestCase
assert_equal Set.new(["notify"]), FooMailer.action_methods
end
+ test "mailer can be anonymous" do
+ mailer = Class.new(ActionMailer::Base) do
+ def welcome
+ mail
+ end
+ end
+
+ assert_equal "anonymous", mailer.mailer_name
+
+ assert_equal "Welcome", mailer.welcome.subject
+ assert_equal "Anonymous mailer body", mailer.welcome.body.encoded.strip
+ end
+
protected
# Execute the block setting the given values and restoring old values after
diff --git a/actionmailer/test/fixtures/anonymous/welcome.erb b/actionmailer/test/fixtures/anonymous/welcome.erb
new file mode 100644
index 0000000000..8361da62c4
--- /dev/null
+++ b/actionmailer/test/fixtures/anonymous/welcome.erb
@@ -0,0 +1 @@
+Anonymous mailer body
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index b819f2e613..8df943139e 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,5 +1,22 @@
## Rails 4.0.0 (unreleased) ##
+* Templates without a handler extension now raises a deprecation warning but still
+ defaults to ERb. In future releases, it will simply return the template contents. *Steve Klabnik*
+
+* Remove `:disable_with` in favor of `'data-disable-with'` option from `submit_tag`, `button_tag` and `button_to` helpers.
+
+ *Carlos Galdino + Rafael Mendonça França*
+
+* Remove `:mouseover` option from `image_tag` helper. *Rafael Mendonça França*
+
+* The `select` method (select tag) forces :include_blank if `required` is true and
+ `display size` is one and `multiple` is not true. *Angelo Capilleri*
+
+* Copy literal route constraints to defaults so that url generation know about them.
+ The copied constraints are `:protocol`, `:subdomain`, `:domain`, `:host` and `:port`.
+
+ *Andrew White*
+
* `respond_to` and `respond_with` now raise ActionController::UnknownFormat instead
of directly returning head 406. The exception is rescued and converted to 406
in the exception handling middleware. *Steven Soroka*
@@ -5775,7 +5792,7 @@
== Rendering a collection of partials
The example of partial use describes a familar pattern where a template needs
- to iterate over a array and render a sub template for each of the elements.
+ to iterate over an array and render a sub template for each of the elements.
This pattern has been implemented as a single method that accepts an array and
renders a partial by the same name of as the elements contained within. So the
three-lined example in "Using partials" can be rewritten with a single line:
diff --git a/actionpack/Rakefile b/actionpack/Rakefile
index 17d95bfd1d..50e3bb0d48 100644
--- a/actionpack/Rakefile
+++ b/actionpack/Rakefile
@@ -23,6 +23,7 @@ end
namespace :test do
Rake::TestTask.new(:isolated) do |t|
+ t.libs << 'test'
t.pattern = 'test/ts_isolated.rb'
end
diff --git a/actionpack/lib/abstract_controller.rb b/actionpack/lib/abstract_controller.rb
index cc5878c88e..b95ea5f0b2 100644
--- a/actionpack/lib/abstract_controller.rb
+++ b/actionpack/lib/abstract_controller.rb
@@ -1,9 +1,5 @@
-activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
-$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
-
require 'action_pack'
require 'active_support/concern'
-require 'active_support/ruby/shim'
require 'active_support/dependencies/autoload'
require 'active_support/core_ext/class/attribute'
require 'active_support/core_ext/module/attr_internal'
diff --git a/actionpack/lib/abstract_controller/callbacks.rb b/actionpack/lib/abstract_controller/callbacks.rb
index 520c210721..5705ab590c 100644
--- a/actionpack/lib/abstract_controller/callbacks.rb
+++ b/actionpack/lib/abstract_controller/callbacks.rb
@@ -14,7 +14,7 @@ module AbstractController
# Override AbstractController::Base's process_action to run the
# process_action callbacks around the normal behavior.
def process_action(*args)
- run_callbacks(:process_action, action_name) do
+ run_callbacks(:process_action) do
super
end
end
diff --git a/actionpack/lib/action_controller/caching/pages.rb b/actionpack/lib/action_controller/caching/pages.rb
index 307594d54a..dd4eddbe9a 100644
--- a/actionpack/lib/action_controller/caching/pages.rb
+++ b/actionpack/lib/action_controller/caching/pages.rb
@@ -60,7 +60,8 @@ module ActionController #:nodoc:
end
module ClassMethods
- # Expires the page that was cached with the +path+ as a key. Example:
+ # Expires the page that was cached with the +path+ as a key.
+ #
# expire_page "/lists/show"
def expire_page(path)
return unless perform_caching
@@ -72,7 +73,8 @@ module ActionController #:nodoc:
end
end
- # Manually cache the +content+ in the key determined by +path+. Example:
+ # Manually cache the +content+ in the key determined by +path+.
+ #
# cache_page "I'm the cached content", "/lists/show"
def cache_page(content, path, extension = nil, gzip = Zlib::BEST_COMPRESSION)
return unless perform_caching
@@ -93,8 +95,6 @@ module ActionController #:nodoc:
#
# You can also pass a :gzip option to override the class configuration one.
#
- # Usage:
- #
# # cache the index action
# caches_page :index
#
@@ -142,7 +142,8 @@ module ActionController #:nodoc:
end
end
- # Expires the page that was cached with the +options+ as a key. Example:
+ # Expires the page that was cached with the +options+ as a key.
+ #
# expire_page :controller => "lists", :action => "show"
def expire_page(options = {})
return unless self.class.perform_caching
@@ -161,7 +162,8 @@ module ActionController #:nodoc:
end
# Manually cache the +content+ in the key determined by +options+. If no content is provided, the contents of response.body is used.
- # If no options are provided, the url of the current request being handled is used. Example:
+ # If no options are provided, the url of the current request being handled is used.
+ #
# cache_page "I'm the cached content", :controller => "lists", :action => "show"
def cache_page(content = nil, options = nil, gzip = Zlib::BEST_COMPRESSION)
return unless self.class.perform_caching && caching_allowed?
diff --git a/actionpack/lib/action_controller/log_subscriber.rb b/actionpack/lib/action_controller/log_subscriber.rb
index 4c76f4c43b..11aa393bf9 100644
--- a/actionpack/lib/action_controller/log_subscriber.rb
+++ b/actionpack/lib/action_controller/log_subscriber.rb
@@ -20,7 +20,7 @@ module ActionController
status = payload[:status]
if status.nil? && payload[:exception].present?
- status = Rack::Utils.status_code(ActionDispatch::ExceptionWrapper.new({}, payload[:exception]).status_code)
+ status = ActionDispatch::ExceptionWrapper.new({}, payload[:exception]).status_code
end
message = "Completed #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]} in %.0fms" % event.duration
message << " (#{additions.join(" | ")})" unless additions.blank?
diff --git a/actionpack/lib/action_controller/metal/conditional_get.rb b/actionpack/lib/action_controller/metal/conditional_get.rb
index 5b25a0d303..2193dde667 100644
--- a/actionpack/lib/action_controller/metal/conditional_get.rb
+++ b/actionpack/lib/action_controller/metal/conditional_get.rb
@@ -108,7 +108,6 @@ module ActionController
# Sets a HTTP 1.1 Cache-Control header. Defaults to issuing a <tt>private</tt> instruction, so that
# intermediate caches must not cache the response.
#
- # Examples:
# expires_in 20.minutes
# expires_in 3.hours, :public => true
# expires_in 3.hours, :public => true, :must_revalidate => true
diff --git a/actionpack/lib/action_controller/metal/helpers.rb b/actionpack/lib/action_controller/metal/helpers.rb
index 1a4bca12d2..86d061e3b7 100644
--- a/actionpack/lib/action_controller/metal/helpers.rb
+++ b/actionpack/lib/action_controller/metal/helpers.rb
@@ -16,7 +16,6 @@ module ActionController
# Additional helpers can be specified using the +helper+ class method in ActionController::Base or any
# controller which inherits from it.
#
- # ==== Examples
# The +to_s+ method from the \Time class can be wrapped in a helper method to display a custom message if
# a \Time object is blank:
#
diff --git a/actionpack/lib/action_controller/metal/http_authentication.rb b/actionpack/lib/action_controller/metal/http_authentication.rb
index 87225d74c1..57bb0e2a32 100644
--- a/actionpack/lib/action_controller/metal/http_authentication.rb
+++ b/actionpack/lib/action_controller/metal/http_authentication.rb
@@ -2,8 +2,9 @@ require 'base64'
require 'active_support/core_ext/object/blank'
module ActionController
+ # Makes it dead easy to do HTTP Basic, Digest and Token authentication.
module HttpAuthentication
- # Makes it dead easy to do HTTP \Basic and \Digest authentication.
+ # Makes it dead easy to do HTTP \Basic authentication.
#
# === Simple \Basic example
#
@@ -60,47 +61,6 @@ module ActionController
#
# assert_equal 200, status
# end
- #
- # === Simple \Digest example
- #
- # require 'digest/md5'
- # class PostsController < ApplicationController
- # REALM = "SuperSecret"
- # USERS = {"dhh" => "secret", #plain text password
- # "dap" => Digest::MD5.hexdigest(["dap",REALM,"secret"].join(":"))} #ha1 digest password
- #
- # before_filter :authenticate, :except => [:index]
- #
- # def index
- # render :text => "Everyone can see me!"
- # end
- #
- # def edit
- # render :text => "I'm only accessible if you know the password"
- # end
- #
- # private
- # def authenticate
- # authenticate_or_request_with_http_digest(REALM) do |username|
- # USERS[username]
- # end
- # end
- # end
- #
- # === Notes
- #
- # The +authenticate_or_request_with_http_digest+ block must return the user's password
- # or the ha1 digest hash so the framework can appropriately hash to check the user's
- # credentials. Returning +nil+ will cause authentication to fail.
- #
- # Storing the ha1 hash: MD5(username:realm:password), is better than storing a plain password. If
- # the password file or database is compromised, the attacker would be able to use the ha1 hash to
- # authenticate as the user at this +realm+, but would not have the user's password to try using at
- # other sites.
- #
- # In rare instances, web servers or front proxies strip authorization headers before
- # they reach your application. You can debug this situation by logging all environment
- # variables, and check for HTTP_AUTHORIZATION, amongst others.
module Basic
extend self
@@ -155,6 +115,48 @@ module ActionController
end
end
+ # Makes it dead easy to do HTTP \Digest authentication.
+ #
+ # === Simple \Digest example
+ #
+ # require 'digest/md5'
+ # class PostsController < ApplicationController
+ # REALM = "SuperSecret"
+ # USERS = {"dhh" => "secret", #plain text password
+ # "dap" => Digest::MD5.hexdigest(["dap",REALM,"secret"].join(":"))} #ha1 digest password
+ #
+ # before_filter :authenticate, :except => [:index]
+ #
+ # def index
+ # render :text => "Everyone can see me!"
+ # end
+ #
+ # def edit
+ # render :text => "I'm only accessible if you know the password"
+ # end
+ #
+ # private
+ # def authenticate
+ # authenticate_or_request_with_http_digest(REALM) do |username|
+ # USERS[username]
+ # end
+ # end
+ # end
+ #
+ # === Notes
+ #
+ # The +authenticate_or_request_with_http_digest+ block must return the user's password
+ # or the ha1 digest hash so the framework can appropriately hash to check the user's
+ # credentials. Returning +nil+ will cause authentication to fail.
+ #
+ # Storing the ha1 hash: MD5(username:realm:password), is better than storing a plain password. If
+ # the password file or database is compromised, the attacker would be able to use the ha1 hash to
+ # authenticate as the user at this +realm+, but would not have the user's password to try using at
+ # other sites.
+ #
+ # In rare instances, web servers or front proxies strip authorization headers before
+ # they reach your application. You can debug this situation by logging all environment
+ # variables, and check for HTTP_AUTHORIZATION, amongst others.
module Digest
extend self
diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb
index 7917926978..0b800c3c62 100644
--- a/actionpack/lib/action_controller/metal/mime_responds.rb
+++ b/actionpack/lib/action_controller/metal/mime_responds.rb
@@ -16,8 +16,6 @@ module ActionController #:nodoc:
# Defines mime types that are rendered by default when invoking
# <tt>respond_with</tt>.
#
- # Examples:
- #
# respond_to :html, :xml, :json
#
# Specifies that all actions in the controller respond to requests
@@ -185,7 +183,6 @@ module ActionController #:nodoc:
# end
#
# Be sure to check respond_with and respond_to documentation for more examples.
- #
def respond_to(*mimes, &block)
raise ArgumentError, "respond_to takes either types or a block, never both" if mimes.any? && block_given?
@@ -323,7 +320,6 @@ module ActionController #:nodoc:
# a successful html +post+ request.
# 2. <tt>:action</tt> - overwrites the default render action used after an
# unsuccessful html +post+ request.
- #
def respond_with(*resources, &block)
raise "In order to use respond_with, first you need to declare the formats your " <<
"controller responds to in the class level" if self.class.mimes_for_respond_to.empty?
@@ -339,7 +335,6 @@ module ActionController #:nodoc:
# Collect mimes declared in the class method respond_to valid for the
# current action.
- #
def collect_mimes_from_class_level #:nodoc:
action = action_name.to_s
@@ -362,7 +357,6 @@ module ActionController #:nodoc:
#
# Sends :not_acceptable to the client and returns nil if no suitable format
# is available.
- #
def retrieve_collector_from_mimes(mimes=nil, &block) #:nodoc:
mimes ||= collect_mimes_from_class_level
collector = Collector.new(mimes)
@@ -401,7 +395,6 @@ module ActionController #:nodoc:
# A subsequent call to #negotiate_format(request) will enable the Collector
# to determine which specific mime-type it should respond with for the current
# request, with this response then being accessible by calling #response.
- #
class Collector
include AbstractController::Collector
attr_accessor :order, :format
diff --git a/actionpack/lib/action_controller/metal/redirecting.rb b/actionpack/lib/action_controller/metal/redirecting.rb
index 5e7bd44562..ee0e69d87c 100644
--- a/actionpack/lib/action_controller/metal/redirecting.rb
+++ b/actionpack/lib/action_controller/metal/redirecting.rb
@@ -24,7 +24,6 @@ module ActionController
# * <tt>:back</tt> - Back to the page that issued the request. Useful for forms that are triggered from multiple places.
# Short-hand for <tt>redirect_to(request.env["HTTP_REFERER"])</tt>
#
- # Examples:
# redirect_to :action => "show", :id => 5
# redirect_to post
# redirect_to "http://www.rubyonrails.org"
@@ -35,7 +34,6 @@ module ActionController
#
# The redirection happens as a "302 Moved" header unless otherwise specified.
#
- # Examples:
# redirect_to post_url(@post), :status => :found
# redirect_to :action=>'atom', :status => :moved_permanently
# redirect_to post_url(@post), :status => 301
@@ -51,14 +49,12 @@ module ActionController
# around this you can return a <tt>303 See Other</tt> status code which will be
# followed using a GET request.
#
- # Examples:
# redirect_to posts_url, :status => :see_other
# redirect_to :action => 'index', :status => 303
#
# It is also possible to assign a flash message as part of the redirection. There are two special accessors for the commonly used flash names
# +alert+ and +notice+ as well as a general purpose +flash+ bucket.
#
- # Examples:
# redirect_to post_url(@post), :alert => "Watch it, mister!"
# redirect_to post_url(@post), :status=> :found, :notice => "Pay attention to the road"
# redirect_to post_url(@post), :status => 301, :flash => { :updated_post_id => @post.id }
@@ -69,6 +65,7 @@ module ActionController
def redirect_to(options = {}, response_status = {}) #:doc:
raise ActionControllerError.new("Cannot redirect to nil!") unless options
raise AbstractController::DoubleRenderError if response_body
+ logger.debug { "Redirected by #{caller(1).first rescue "unknown"}" } if logger
self.status = _extract_redirect_to_status(options, response_status)
self.location = _compute_redirect_to_location(options)
diff --git a/actionpack/lib/action_controller/metal/renderers.rb b/actionpack/lib/action_controller/metal/renderers.rb
index 4a0c1c7dd7..1927c8bdc7 100644
--- a/actionpack/lib/action_controller/metal/renderers.rb
+++ b/actionpack/lib/action_controller/metal/renderers.rb
@@ -49,7 +49,6 @@ module ActionController
# is the value paired with its key and the second is the remaining
# hash of options passed to +render+.
#
- # === Example
# Create a csv renderer:
#
# ActionController::Renderers.add :csv do |obj, options|
diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
index 0bff1825d9..95b0e99ed5 100644
--- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
@@ -51,8 +51,6 @@ module ActionController #:nodoc:
module ClassMethods
# Turn on request forgery protection. Bear in mind that only non-GET, HTML/JavaScript requests are checked.
#
- # Example:
- #
# class FooController < ApplicationController
# protect_from_forgery :except => :index
#
diff --git a/actionpack/lib/action_controller/metal/url_for.rb b/actionpack/lib/action_controller/metal/url_for.rb
index 8e7b56dbcc..e28c05cc2d 100644
--- a/actionpack/lib/action_controller/metal/url_for.rb
+++ b/actionpack/lib/action_controller/metal/url_for.rb
@@ -6,8 +6,6 @@ module ActionController
# 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
@@ -19,7 +17,6 @@ module ActionController
# @url = root_path # named route from the application.
# end
# end
- #
module UrlFor
extend ActiveSupport::Concern
diff --git a/actionpack/lib/action_controller/record_identifier.rb b/actionpack/lib/action_controller/record_identifier.rb
index e7af3f5b8d..16a5decc62 100644
--- a/actionpack/lib/action_controller/record_identifier.rb
+++ b/actionpack/lib/action_controller/record_identifier.rb
@@ -3,7 +3,7 @@ require 'active_support/core_ext/module'
module ActionController
# The record identifier encapsulates a number of naming conventions for dealing with records, like Active Records or
# pretty much any other model type that has an id. These patterns are then used to try elevate the view actions to
- # a higher logical level. Example:
+ # a higher logical level.
#
# # routes
# resources :posts
@@ -30,7 +30,7 @@ module ActionController
JOIN = '_'.freeze
NEW = 'new'.freeze
- # The DOM class convention is to use the singular form of an object or class. Examples:
+ # The DOM class convention is to use the singular form of an object or class.
#
# dom_class(post) # => "post"
# dom_class(Person) # => "person"
@@ -45,7 +45,7 @@ module ActionController
end
# The DOM id convention is to use the singular form of an object or class with the id following an underscore.
- # If no id is found, prefix with "new_" instead. Examples:
+ # If no id is found, prefix with "new_" instead.
#
# dom_id(Post.find(45)) # => "post_45"
# dom_id(Post.new) # => "new_post"
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index ad02375f12..98f70f2336 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -56,8 +56,6 @@ module ActionController
# Asserts that the request was rendered with the appropriate template file or partials.
#
- # ==== Examples
- #
# # assert that the "new" view template was rendered
# assert_template "new"
#
@@ -84,7 +82,6 @@ module ActionController
#
# # assert that the "_customer" partial was rendered with a specific object
# assert_template :partial => '_customer', :locals => { :customer => @customer }
- #
def assert_template(options = {}, message = nil)
# Force body to be read in case the
# template is being streamed
@@ -96,7 +93,7 @@ module ActionController
rendered = @templates
msg = message || sprintf("expecting <%s> but rendering with <%s>",
options.inspect, rendered.keys)
- assert_block(msg) do
+ assert(msg) do
if options
rendered.any? { |t,num| t.match(options) }
else
@@ -350,7 +347,6 @@ module ActionController
# == \Testing named routes
#
# If you're using named routes, they can be easily tested using the original named routes' methods straight in the test case.
- # Example:
#
# assert_redirected_to page_url(:title => 'foo')
class TestCase < ActiveSupport::TestCase
@@ -369,12 +365,11 @@ module ActionController
module ClassMethods
# Sets the controller class name. Useful if the name can't be inferred from test class.
- # Normalizes +controller_class+ before using. Examples:
+ # Normalizes +controller_class+ before using.
#
# tests WidgetController
# tests :widget
# tests 'widget'
- #
def tests(controller_class)
case controller_class
when String, Symbol
diff --git a/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb b/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
index 114b0e73c9..6b269e7a31 100644
--- a/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
+++ b/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
@@ -1,6 +1,7 @@
require 'set'
require 'cgi'
require 'active_support/core_ext/class/attribute'
+require 'active_support/core_ext/class/attribute_accessors'
module HTML
class Sanitizer
diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb
index e3b04ac097..1e4ac70f3d 100644
--- a/actionpack/lib/action_dispatch.rb
+++ b/actionpack/lib/action_dispatch.rb
@@ -21,12 +21,6 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
-activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
-$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
-
-activemodel_path = File.expand_path('../../../activemodel/lib', __FILE__)
-$:.unshift(activemodel_path) if File.directory?(activemodel_path) && !$:.include?(activemodel_path)
-
require 'active_support'
require 'active_support/dependencies/autoload'
require 'active_support/core_ext/module/attribute_accessors'
diff --git a/actionpack/lib/action_dispatch/http/filter_parameters.rb b/actionpack/lib/action_dispatch/http/filter_parameters.rb
index 132b0c82bc..6413929be3 100644
--- a/actionpack/lib/action_dispatch/http/filter_parameters.rb
+++ b/actionpack/lib/action_dispatch/http/filter_parameters.rb
@@ -10,8 +10,6 @@ module ActionDispatch
# value of the params hash and all subhashes is passed to it, the value
# or key can be replaced using String#replace or similar method.
#
- # Examples:
- #
# env["action_dispatch.parameter_filter"] = [:password]
# => replaces the value to all keys matching /password/i with "[FILTERED]"
#
@@ -22,7 +20,6 @@ module ActionDispatch
# v.reverse! if k =~ /secret/i
# end
# => reverses the value to all keys matching /secret/i
- #
module FilterParameters
extend ActiveSupport::Concern
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index 9748956052..56908b5794 100644
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -6,7 +6,6 @@ require 'active_support/core_ext/hash/indifferent_access'
require 'active_support/core_ext/string/access'
require 'active_support/inflector'
require 'action_dispatch/http/headers'
-require 'action_dispatch/request/session'
require 'action_controller/metal/exceptions'
module ActionDispatch
@@ -18,6 +17,8 @@ module ActionDispatch
include ActionDispatch::Http::Upload
include ActionDispatch::Http::URL
+ autoload :Session, 'action_dispatch/request/session'
+
LOCALHOST = Regexp.union [/^127\.0\.0\.\d{1,3}$/, /^::1$/, /^0:0:0:0:0:0:0:1(%.*)?$/]
ENV_METHODS = %w[ AUTH_TYPE GATEWAY_INTERFACE
diff --git a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
index 982f6641bf..a8f49bd3bd 100644
--- a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
+++ b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
@@ -1,5 +1,6 @@
require 'action_controller/metal/exceptions'
require 'active_support/core_ext/exception'
+require 'active_support/core_ext/class/attribute_accessors'
module ActionDispatch
class ExceptionWrapper
@@ -76,4 +77,4 @@ module ActionDispatch
@backtrace_cleaner ||= @env['action_dispatch.backtrace_cleaner']
end
end
-end \ No newline at end of file
+end
diff --git a/actionpack/lib/action_dispatch/middleware/flash.rb b/actionpack/lib/action_dispatch/middleware/flash.rb
index 17776c2356..9928b7cc3a 100644
--- a/actionpack/lib/action_dispatch/middleware/flash.rb
+++ b/actionpack/lib/action_dispatch/middleware/flash.rb
@@ -11,7 +11,7 @@ module ActionDispatch
# The flash provides a way to pass temporary objects between actions. Anything you place in the flash will be exposed
# to the very next action and then cleared out. This is a great way of doing notices and alerts, such as a create
# action that sets <tt>flash[:notice] = "Post successfully created"</tt> before redirecting to a display action that can
- # then expose the flash to its template. Actually, that exposure is automatically done. Example:
+ # then expose the flash to its template. Actually, that exposure is automatically done.
#
# class PostsController < ActionController::Base
# def create
diff --git a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
index dbcf703ec3..7efc094f98 100644
--- a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
@@ -27,7 +27,7 @@ module ActionDispatch
# CGI::Session instance as an argument. It's important that the secret
# is not vulnerable to a dictionary attack. Therefore, you should choose
# a secret consisting of random numbers and letters and more than 30
- # characters. Examples:
+ # characters.
#
# :secret => '449fe2e7daee471bffae2fd8dc02313d'
# :secret => Proc.new { User.current_user.secret_key }
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index 2a7d540517..67a208263b 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -1,5 +1,6 @@
require 'active_support/core_ext/hash/except'
require 'active_support/core_ext/hash/reverse_merge'
+require 'active_support/core_ext/hash/slice'
require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/enumerable'
require 'active_support/inflector'
@@ -100,6 +101,10 @@ module ActionDispatch
raise ArgumentError, "Regexp multiline option not allowed in routing requirements: #{requirement.inspect}"
end
end
+
+ if @options[:constraints].is_a?(Hash)
+ (@options[:defaults] ||= {}).reverse_merge!(defaults_from_constraints(@options[:constraints]))
+ end
end
# match "account/overview"
@@ -245,6 +250,11 @@ module ActionDispatch
def default_action
@options[:action] || @scope[:action]
end
+
+ def defaults_from_constraints(constraints)
+ url_keys = [:protocol, :subdomain, :domain, :host, :port]
+ constraints.slice(*url_keys).select{ |k, v| v.is_a?(String) || v.is_a?(Fixnum) }
+ end
end
# Invokes Rack::Mount::Utils.normalize path and ensure that
@@ -485,8 +495,6 @@ module ActionDispatch
# Define a route that only recognizes HTTP GET.
# For supported arguments, see <tt>Base#match</tt>.
#
- # Example:
- #
# get 'bacon', :to => 'food#bacon'
def get(*args, &block)
map_method(:get, args, &block)
@@ -495,8 +503,6 @@ module ActionDispatch
# Define a route that only recognizes HTTP POST.
# For supported arguments, see <tt>Base#match</tt>.
#
- # Example:
- #
# post 'bacon', :to => 'food#bacon'
def post(*args, &block)
map_method(:post, args, &block)
@@ -505,8 +511,6 @@ module ActionDispatch
# Define a route that only recognizes HTTP PATCH.
# For supported arguments, see <tt>Base#match</tt>.
#
- # Example:
- #
# patch 'bacon', :to => 'food#bacon'
def patch(*args, &block)
map_method(:patch, args, &block)
@@ -515,8 +519,6 @@ module ActionDispatch
# Define a route that only recognizes HTTP PUT.
# For supported arguments, see <tt>Base#match</tt>.
#
- # Example:
- #
# put 'bacon', :to => 'food#bacon'
def put(*args, &block)
map_method(:put, args, &block)
@@ -525,8 +527,6 @@ module ActionDispatch
# Define a route that only recognizes HTTP DELETE.
# For supported arguments, see <tt>Base#match</tt>.
#
- # Example:
- #
# delete 'broccoli', :to => 'food#broccoli'
def delete(*args, &block)
map_method(:delete, args, &block)
@@ -641,6 +641,10 @@ module ActionDispatch
block, options[:constraints] = options[:constraints], {}
end
+ if options[:constraints].is_a?(Hash)
+ (options[:defaults] ||= {}).reverse_merge!(defaults_from_constraints(options[:constraints]))
+ end
+
scope_options.each do |option|
if value = options.delete(option)
recover[option] = @scope[option]
@@ -667,7 +671,6 @@ module ActionDispatch
# Scopes routes to a specific controller
#
- # Example:
# controller "food" do
# match "bacon", :action => "bacon"
# end
@@ -849,6 +852,11 @@ module ActionDispatch
def override_keys(child) #:nodoc:
child.key?(:only) || child.key?(:except) ? [:only, :except] : []
end
+
+ def defaults_from_constraints(constraints)
+ url_keys = [:protocol, :subdomain, :domain, :host, :port]
+ constraints.slice(*url_keys).select{ |k, v| v.is_a?(String) || v.is_a?(Fixnum) }
+ end
end
# Resource routing allows you to quickly declare all of the common routes
@@ -1317,10 +1325,11 @@ module ActionDispatch
msg = "Your router tried to #draw the external file #{name}.rb,\n" \
"but the file was not found in:\n\n"
msg += @draw_paths.map { |_path| " * #{_path}" }.join("\n")
- raise msg
+ raise ArgumentError, msg
end
-
- instance_eval(path.join("#{name}.rb").read)
+
+ route_path = path.join("#{name}.rb")
+ instance_eval(route_path.read, route_path.to_s)
end
# match 'path' => 'controller#action'
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index 58c67e2cbe..0ae668d42a 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -103,7 +103,7 @@ module ActionDispatch
inner_options = args.extract_options!
result = options.dup
- if args.any?
+ if args.size > 0
keys = segment_keys
if args.size < keys.size - 1 # take format into account
keys -= self.url_options.keys if self.respond_to?(:url_options)
diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb
index ee02f4b531..fd3bed7e8f 100644
--- a/actionpack/lib/action_dispatch/routing/url_for.rb
+++ b/actionpack/lib/action_dispatch/routing/url_for.rb
@@ -132,8 +132,6 @@ module ActionDispatch
# Any other key (<tt>:controller</tt>, <tt>:action</tt>, etc.) given to
# +url_for+ is forwarded to the Routes module.
#
- # 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
diff --git a/actionpack/lib/action_dispatch/testing/assertions/dom.rb b/actionpack/lib/action_dispatch/testing/assertions/dom.rb
index edea6dab39..7dc3d0f97c 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/dom.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/dom.rb
@@ -5,11 +5,8 @@ module ActionDispatch
module DomAssertions
# \Test two HTML strings for equivalency (e.g., identical up to reordering of attributes)
#
- # ==== Examples
- #
# # assert that the referenced method generates the appropriate HTML string
# assert_dom_equal '<a href="http://www.example.com">Apples</a>', link_to("Apples", "http://www.example.com")
- #
def assert_dom_equal(expected, actual, message = "")
expected_dom = HTML::Document.new(expected).root
actual_dom = HTML::Document.new(actual).root
@@ -18,11 +15,8 @@ module ActionDispatch
# The negated form of +assert_dom_equivalent+.
#
- # ==== Examples
- #
# # assert that the referenced method does not generate the specified HTML string
# assert_dom_not_equal '<a href="http://www.example.com">Apples</a>', link_to("Oranges", "http://www.example.com")
- #
def assert_dom_not_equal(expected, actual, message = "")
expected_dom = HTML::Document.new(expected).root
actual_dom = HTML::Document.new(actual).root
diff --git a/actionpack/lib/action_dispatch/testing/assertions/response.rb b/actionpack/lib/action_dispatch/testing/assertions/response.rb
index 8f6fff5d32..3d121b6b9c 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/response.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/response.rb
@@ -15,14 +15,11 @@ module ActionDispatch
# or its symbolic equivalent <tt>assert_response(:not_implemented)</tt>.
# See Rack::Utils::SYMBOL_TO_STATUS_CODE for a full list.
#
- # ==== Examples
- #
# # assert that the response was a redirection
# assert_response :redirect
#
# # assert that the response code was status code 401 (unauthorized)
# assert_response 401
- #
def assert_response(type, message = nil)
message ||= "Expected response to be a <#{type}>, but was <#{@response.response_code}>"
@@ -42,8 +39,6 @@ module ActionDispatch
# This match can be partial, such that <tt>assert_redirected_to(:controller => "weblog")</tt> will also
# match the redirection of <tt>redirect_to(:controller => "weblog", :action => "show")</tt> and so on.
#
- # ==== Examples
- #
# # assert that the redirection was to the "index" action on the WeblogController
# assert_redirected_to :controller => "weblog", :action => "index"
#
@@ -55,7 +50,6 @@ module ActionDispatch
#
# # asserts that the redirection matches the regular expression
# assert_redirected_to %r(\Ahttp://example.org)
- #
def assert_redirected_to(options = {}, message=nil)
assert_response(:redirect, message)
return true if options === @response.location
diff --git a/actionpack/lib/action_dispatch/testing/assertions/routing.rb b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
index 1f4b905d18..567ca0c392 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/routing.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
@@ -26,7 +26,6 @@ module ActionDispatch
#
# The +message+ parameter allows you to pass in an error message that is displayed upon failure.
#
- # ==== Examples
# # Check the default route (i.e., the index action)
# assert_recognizes({:controller => 'items', :action => 'index'}, 'items')
#
@@ -57,7 +56,6 @@ module ActionDispatch
#
# The +defaults+ parameter is unused.
#
- # ==== Examples
# # Asserts that the default action is generated for a route with no action
# assert_generates "/items", :controller => "items", :action => "index"
#
@@ -100,7 +98,6 @@ module ActionDispatch
# The +extras+ hash allows you to specify options that would normally be provided as a query string to the action. The
# +message+ parameter allows you to specify a custom error message to display upon failure.
#
- # ==== Examples
# # Assert a basic route: a controller with the default action (index)
# assert_routing '/home', :controller => 'home', :action => 'index'
#
diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb
index ea1ed20f3c..5f9c3bbf48 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb
@@ -39,7 +39,6 @@ module ActionDispatch
# The selector may be a CSS selector expression (String), an expression
# with substitution values (Array) or an HTML::Selector object.
#
- # ==== Examples
# # Selects all div tags
# divs = css_select("div")
#
@@ -58,7 +57,6 @@ module ActionDispatch
# inputs = css_select(form, "input")
# ...
# end
- #
def css_select(*args)
# See assert_select to understand what's going on here.
arg = args.shift
@@ -340,7 +338,6 @@ module ActionDispatch
# The content of each element is un-encoded, and wrapped in the root
# element +encoded+. It then calls the block with all un-encoded elements.
#
- # ==== Examples
# # Selects all bold tags from within the title of an Atom feed's entries (perhaps to nab a section name prefix)
# assert_select "feed[xmlns='http://www.w3.org/2005/Atom']" do
# # Select each entry item and then the title item
@@ -401,8 +398,6 @@ module ActionDispatch
# You must enable deliveries for this assertion to work, use:
# ActionMailer::Base.perform_deliveries = true
#
- # ==== Examples
- #
# assert_select_email do
# assert_select "h1", "Email alert"
# end
@@ -413,7 +408,6 @@ module ActionDispatch
# # Work with items here...
# end
# end
- #
def assert_select_email(&block)
deliveries = ActionMailer::Base.deliveries
assert !deliveries.empty?, "No e-mail in delivery list"
diff --git a/actionpack/lib/action_dispatch/testing/assertions/tag.rb b/actionpack/lib/action_dispatch/testing/assertions/tag.rb
index 5c735e61b2..68f1347e7c 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/tag.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/tag.rb
@@ -48,8 +48,6 @@ module ActionDispatch
# * if the condition is +true+, the value must not be +nil+.
# * if the condition is +false+ or +nil+, the value must be +nil+.
#
- # === Examples
- #
# # Assert that there is a "span" tag
# assert_tag :tag => "span"
#
@@ -104,7 +102,6 @@ module ActionDispatch
# Identical to +assert_tag+, but asserts that a matching tag does _not_
# exist. (See +assert_tag+ for a full discussion of the syntax.)
#
- # === Examples
# # Assert that there is not a "div" containing a "p"
# assert_no_tag :tag => "div", :descendant => { :tag => "p" }
#
diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb
index 69d54f6981..08fd28d72d 100644
--- a/actionpack/lib/action_dispatch/testing/integration.rb
+++ b/actionpack/lib/action_dispatch/testing/integration.rb
@@ -201,9 +201,16 @@ module ActionDispatch
reset!
end
- remove_method :default_url_options
- def default_url_options
- { :host => host, :protocol => https? ? "https" : "http" }
+ def url_options
+ @url_options ||= default_url_options.dup.tap do |url_options|
+ url_options.reverse_merge!(controller.url_options) if controller
+
+ if @app.respond_to?(:routes) && @app.routes.respond_to?(:default_url_options)
+ url_options.reverse_merge!(@app.routes.default_url_options)
+ end
+
+ url_options.reverse_merge!(:host => host, :protocol => https? ? "https" : "http")
+ end
end
# Resets the instance. This can be used to reset the state information
@@ -216,6 +223,7 @@ module ActionDispatch
@controller = @request = @response = nil
@_mock_session = nil
@request_count = 0
+ @url_options = nil
self.host = DEFAULT_HOST
self.remote_addr = "127.0.0.1"
@@ -310,6 +318,7 @@ module ActionDispatch
response = _mock_session.last_response
@response = ActionDispatch::TestResponse.new(response.status, response.headers, response.body)
@html_document = nil
+ @url_options = nil
@controller = session.last_request.env['action_controller.instance']
@@ -367,12 +376,14 @@ module ActionDispatch
end
end
- extend ActiveSupport::Concern
- include ActionDispatch::Routing::UrlFor
+ def default_url_options
+ reset! unless integration_session
+ integration_session.default_url_options
+ end
- def url_options
+ def default_url_options=(options)
reset! unless integration_session
- integration_session.url_options
+ integration_session.default_url_options = options
end
def respond_to?(method, include_private = false)
@@ -476,6 +487,7 @@ module ActionDispatch
class IntegrationTest < ActiveSupport::TestCase
include Integration::Runner
include ActionController::TemplateAssertions
+ include ActionDispatch::Routing::UrlFor
@@app = nil
@@ -495,5 +507,10 @@ module ActionDispatch
def app
super || self.class.app
end
+
+ def url_options
+ reset! unless integration_session
+ integration_session.url_options
+ end
end
end
diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb
index 349a3fcc6e..3823f87027 100644
--- a/actionpack/lib/action_view.rb
+++ b/actionpack/lib/action_view.rb
@@ -21,9 +21,7 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
-require 'active_support/ruby/shim'
-require 'active_support/core_ext/class/attribute_accessors'
-
+require 'active_support'
require 'action_pack'
module ActionView
@@ -78,7 +76,8 @@ module ActionView
ENCODING_FLAG = '#.*coding[:=]\s*(\S+)[ \t]*'
end
-require 'active_support/i18n'
require 'active_support/core_ext/string/output_safety'
-I18n.load_path << "#{File.dirname(__FILE__)}/action_view/locale/en.yml"
+ActiveSupport.on_load(:i18n) do
+ I18n.load_path << "#{File.dirname(__FILE__)}/action_view/locale/en.yml"
+end
diff --git a/actionpack/lib/action_view/asset_paths.rb b/actionpack/lib/action_view/asset_paths.rb
index add8d94b70..4ce41d51f1 100644
--- a/actionpack/lib/action_view/asset_paths.rb
+++ b/actionpack/lib/action_view/asset_paths.rb
@@ -4,7 +4,7 @@ require 'action_controller/metal/exceptions'
module ActionView
class AssetPaths #:nodoc:
- URI_REGEXP = %r{^[-a-z]+://|^cid:|^//}
+ URI_REGEXP = %r{^[-a-z]+://|^(?:cid|data):|^//}
attr_reader :config, :controller
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb
index 5f81f24a2e..f98648d930 100644
--- a/actionpack/lib/action_view/base.rb
+++ b/actionpack/lib/action_view/base.rb
@@ -1,6 +1,7 @@
require 'active_support/core_ext/module/attr_internal'
require 'active_support/core_ext/module/delegation'
require 'active_support/core_ext/class/attribute'
+require 'active_support/core_ext/class/attribute_accessors'
require 'active_support/ordered_options'
require 'action_view/log_subscriber'
diff --git a/actionpack/lib/action_view/context.rb b/actionpack/lib/action_view/context.rb
index 083856b2ca..245849d706 100644
--- a/actionpack/lib/action_view/context.rb
+++ b/actionpack/lib/action_view/context.rb
@@ -5,7 +5,7 @@ module ActionView
# = Action View Context
#
- # Action View contexts are supplied to Action Controller to render template.
+ # Action View contexts are supplied to Action Controller to render a template.
# The default Action View context is ActionView::Base.
#
# In order to work with ActionController, a Context must just include this module.
@@ -25,7 +25,7 @@ module ActionView
end
# Encapsulates the interaction with the view flow so it
- # returns the correct buffer on yield. This is usually
+ # returns the correct buffer on +yield+. This is usually
# overwriten by helpers to add more behavior.
# :api: plugin
def _layout_for(name=nil)
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
index adc62ec6a9..a7a4ce21ff 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
@@ -252,7 +252,6 @@ module ActionView
# The following call would generate such a tag:
#
# <%= favicon_link_tag 'mb-icon.png', :rel => 'apple-touch-icon', :type => 'image/png' %>
- #
def favicon_link_tag(source='favicon.ico', options={})
tag('link', {
:rel => 'shortcut icon',
@@ -261,13 +260,13 @@ module ActionView
}.merge(options.symbolize_keys))
end
- # Computes the path to an image asset in the public images directory.
+ # Computes the path to an image asset.
# Full paths from the document root will be passed through.
# Used internally by +image_tag+ to build the image path:
#
- # image_path("edit") # => "/images/edit"
- # image_path("edit.png") # => "/images/edit.png"
- # image_path("icons/edit.png") # => "/images/icons/edit.png"
+ # image_path("edit") # => "/assets/edit"
+ # image_path("edit.png") # => "/assets/edit.png"
+ # image_path("icons/edit.png") # => "/assets/icons/edit.png"
# image_path("/icons/edit.png") # => "/icons/edit.png"
# image_path("http://www.example.com/img/edit.png") # => "http://www.example.com/img/edit.png"
#
@@ -279,7 +278,7 @@ module ActionView
end
alias_method :path_to_image, :image_path # aliased to avoid conflicts with an image_path named route
- # Computes the full URL to an image asset in the public images directory.
+ # Computes the full URL to an image asset.
# This will use +image_path+ internally, so most of their behaviors will be the same.
def image_url(source)
URI.join(current_host, path_to_image(source)).to_s
@@ -290,7 +289,6 @@ module ActionView
# Full paths from the document root will be passed through.
# Used internally by +video_tag+ to build the video path.
#
- # ==== Examples
# video_path("hd") # => /videos/hd
# video_path("hd.avi") # => /videos/hd.avi
# video_path("trailers/hd.avi") # => /videos/trailers/hd.avi
@@ -312,7 +310,6 @@ module ActionView
# Full paths from the document root will be passed through.
# Used internally by +audio_tag+ to build the audio path.
#
- # ==== Examples
# audio_path("horse") # => /audios/horse
# audio_path("horse.wav") # => /audios/horse.wav
# audio_path("sounds/horse.wav") # => /audios/sounds/horse.wav
@@ -323,20 +320,19 @@ module ActionView
end
alias_method :path_to_audio, :audio_path # aliased to avoid conflicts with an audio_path named route
- # Computes the full URL to a audio asset in the public audios directory.
+ # Computes the full URL to an audio asset in the public audios directory.
# This will use +audio_path+ internally, so most of their behaviors will be the same.
def audio_url(source)
URI.join(current_host, path_to_audio(source)).to_s
end
alias_method :url_to_audio, :audio_url # aliased to avoid conflicts with an audio_url named route
- # Computes the path to a font asset in the public fonts directory.
+ # Computes the path to a font asset.
# Full paths from the document root will be passed through.
#
- # ==== Examples
- # font_path("font") # => /fonts/font
- # font_path("font.ttf") # => /fonts/font.ttf
- # font_path("dir/font.ttf") # => /fonts/dir/font.ttf
+ # font_path("font") # => /assets/font
+ # font_path("font.ttf") # => /assets/font.ttf
+ # font_path("dir/font.ttf") # => /assets/dir/font.ttf
# font_path("/dir/font.ttf") # => /dir/font.ttf
# font_path("http://www.example.com/dir/font.ttf") # => http://www.example.com/dir/font.ttf
def font_path(source)
@@ -344,7 +340,7 @@ module ActionView
end
alias_method :path_to_font, :font_path # aliased to avoid conflicts with an font_path named route
- # Computes the full URL to a font asset in the public fonts directory.
+ # Computes the full URL to a font asset.
# This will use +font_path+ internally, so most of their behaviors will be the same.
def font_url(source)
URI.join(current_host, path_to_font(source)).to_s
@@ -352,7 +348,7 @@ module ActionView
alias_method :url_to_font, :font_url # aliased to avoid conflicts with an font_url named route
# Returns an html image tag for the +source+. The +source+ can be a full
- # path or a file that exists in your public images directory.
+ # path or a file.
#
# ==== Options
# You can add HTML attributes using the +options+. The +options+ supports
@@ -363,33 +359,25 @@ module ActionView
# * <tt>:size</tt> - Supplied as "{Width}x{Height}", so "30x45" becomes
# width="30" and height="45". <tt>:size</tt> will be ignored if the
# value is not in the correct format.
- # * <tt>:mouseover</tt> - Set an alternate image to be used when the onmouseover
- # event is fired, and sets the original image to be replaced onmouseout.
- # This can be used to implement an easy image toggle that fires on onmouseover.
#
- # ==== Examples
# image_tag("icon") # =>
- # <img src="/images/icon" alt="Icon" />
+ # <img src="/assets/icon" alt="Icon" />
# image_tag("icon.png") # =>
- # <img src="/images/icon.png" alt="Icon" />
+ # <img src="/assets/icon.png" alt="Icon" />
# image_tag("icon.png", :size => "16x10", :alt => "Edit Entry") # =>
- # <img src="/images/icon.png" width="16" height="10" alt="Edit Entry" />
+ # <img src="/assets/icon.png" width="16" height="10" alt="Edit Entry" />
# image_tag("/icons/icon.gif", :size => "16x16") # =>
# <img src="/icons/icon.gif" width="16" height="16" alt="Icon" />
# image_tag("/icons/icon.gif", :height => '32', :width => '32') # =>
# <img alt="Icon" height="32" src="/icons/icon.gif" width="32" />
# image_tag("/icons/icon.gif", :class => "menu_icon") # =>
# <img alt="Icon" class="menu_icon" src="/icons/icon.gif" />
- # image_tag("mouse.png", :mouseover => "/images/mouse_over.png") # =>
- # <img src="/images/mouse.png" onmouseover="this.src='/images/mouse_over.png'" onmouseout="this.src='/images/mouse.png'" alt="Mouse" />
- # image_tag("mouse.png", :mouseover => image_path("mouse_over.png")) # =>
- # <img src="/images/mouse.png" onmouseover="this.src='/images/mouse_over.png'" onmouseout="this.src='/images/mouse.png'" alt="Mouse" />
def image_tag(source, options={})
options = options.symbolize_keys
src = options[:src] = path_to_image(source)
- unless src =~ /^cid:/
+ unless src =~ /^(?:cid|data):/
options[:alt] = options.fetch(:alt){ image_alt(src) }
end
@@ -397,11 +385,6 @@ module ActionView
options[:width], options[:height] = size.split("x") if size =~ %r{^\d+x\d+$}
end
- if mouseover = options.delete(:mouseover)
- options[:onmouseover] = "this.src='#{path_to_image(mouseover)}'"
- options[:onmouseout] = "this.src='#{src}'"
- end
-
tag("img", options)
end
@@ -425,7 +408,6 @@ module ActionView
# width="30" and height="45". <tt>:size</tt> will be ignored if the
# value is not in the correct format.
#
- # ==== Examples
# video_tag("trailer") # =>
# <video src="/videos/trailer" />
# video_tag("trailer.ogg") # =>
@@ -433,7 +415,7 @@ module ActionView
# video_tag("trailer.ogg", :controls => true, :autobuffer => true) # =>
# <video autobuffer="autobuffer" controls="controls" src="/videos/trailer.ogg" />
# video_tag("trailer.m4v", :size => "16x10", :poster => "screenshot.png") # =>
- # <video src="/videos/trailer.m4v" width="16" height="10" poster="/images/screenshot.png" />
+ # <video src="/videos/trailer.m4v" width="16" height="10" poster="/assets/screenshot.png" />
# video_tag("/trailers/hd.avi", :size => "16x16") # =>
# <video src="/trailers/hd.avi" width="16" height="16" />
# video_tag("/trailers/hd.avi", :height => '32', :width => '32') # =>
@@ -458,15 +440,14 @@ module ActionView
# The +source+ can be full path or file that exists in
# your public audios directory.
#
- # ==== Examples
- # audio_tag("sound") # =>
- # <audio src="/audios/sound" />
- # audio_tag("sound.wav") # =>
- # <audio src="/audios/sound.wav" />
- # audio_tag("sound.wav", :autoplay => true, :controls => true) # =>
- # <audio autoplay="autoplay" controls="controls" src="/audios/sound.wav" />
- # audio_tag("sound.wav", "sound.mid") # =>
- # <audio><source src="/audios/sound.wav" /><source src="/audios/sound.mid" /></audio>
+ # audio_tag("sound") # =>
+ # <audio src="/audios/sound" />
+ # audio_tag("sound.wav") # =>
+ # <audio src="/audios/sound.wav" />
+ # audio_tag("sound.wav", :autoplay => true, :controls => true) # =>
+ # <audio autoplay="autoplay" controls="controls" src="/audios/sound.wav" />
+ # audio_tag("sound.wav", "sound.mid") # =>
+ # <audio><source src="/audios/sound.wav" /><source src="/audios/sound.mid" /></audio>
def audio_tag(*sources)
multiple_sources_tag('audio', sources)
end
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb
index 7bff0c1149..4292d29f60 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb
@@ -76,7 +76,6 @@ module ActionView
# Full paths from the document root will be passed through.
# Used internally by javascript_include_tag to build the script path.
#
- # ==== Examples
# javascript_path "xmlhr" # => /javascripts/xmlhr.js
# javascript_path "dir/xmlhr.js" # => /javascripts/dir/xmlhr.js
# javascript_path "/dir/xmlhr" # => /dir/xmlhr.js
@@ -114,7 +113,6 @@ module ActionView
# You can modify the HTML attributes of the script tag by passing a hash as the
# last argument.
#
- # ==== Examples
# javascript_include_tag "xmlhr"
# # => <script src="/javascripts/xmlhr.js?1284139606"></script>
#
@@ -160,8 +158,6 @@ module ActionView
# <tt>config.perform_caching</tt> is set to true (which is the case by default for the Rails
# production environment, but not for the development environment).
#
- # ==== Examples
- #
# # assuming config.perform_caching is false
# javascript_include_tag :all, :cache => true
# # => <script src="/javascripts/jquery.js?1284139606"></script>
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb
index 4bcb8b9718..57b0627225 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb
@@ -54,7 +54,6 @@ module ActionView
# Full paths from the document root will be passed through.
# Used internally by +stylesheet_link_tag+ to build the stylesheet path.
#
- # ==== Examples
# stylesheet_path "style" # => /stylesheets/style.css
# stylesheet_path "dir/style.css" # => /stylesheets/dir/style.css
# stylesheet_path "/dir/style.css" # => /dir/style.css
@@ -79,7 +78,6 @@ module ActionView
# to "screen", so you must explicitely set it to "all" for the stylesheet(s) to
# apply to all media types.
#
- # ==== Examples
# stylesheet_link_tag "style" # =>
# <link href="/stylesheets/style.css" media="screen" rel="stylesheet" />
#
@@ -117,7 +115,6 @@ module ActionView
# is set to true (which is the case by default for the Rails production environment, but not for the development
# environment). Examples:
#
- # ==== Examples
# stylesheet_link_tag :all, :cache => true # when config.perform_caching is false =>
# <link href="/stylesheets/style1.css" media="screen" rel="stylesheet" />
# <link href="/stylesheets/styleB.css" media="screen" rel="stylesheet" />
diff --git a/actionpack/lib/action_view/helpers/cache_helper.rb b/actionpack/lib/action_view/helpers/cache_helper.rb
index 850dd5f448..33799d7d71 100644
--- a/actionpack/lib/action_view/helpers/cache_helper.rb
+++ b/actionpack/lib/action_view/helpers/cache_helper.rb
@@ -10,7 +10,6 @@ module ActionView
#
# See ActionController::Caching::Fragments for usage instructions.
#
- # ==== Examples
# If you want to cache a navigation menu, you can do following:
#
# <% cache do %>
diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb
index d9d6f90211..397738dd98 100644
--- a/actionpack/lib/action_view/helpers/capture_helper.rb
+++ b/actionpack/lib/action_view/helpers/capture_helper.rb
@@ -13,7 +13,6 @@ module ActionView
# The capture method allows you to extract part of a template into a
# variable. You can then use this variable anywhere in your templates or layout.
#
- # ==== Examples
# The capture method can be used in ERB templates...
#
# <% @greeting = capture do %>
diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb
index f0a593d2c1..659aacf6d7 100644
--- a/actionpack/lib/action_view/helpers/date_helper.rb
+++ b/actionpack/lib/action_view/helpers/date_helper.rb
@@ -64,7 +64,6 @@ module ActionView
# distance_of_time_in_words(from_time, to_time, :include_seconds => true) # => about 6 years
# distance_of_time_in_words(to_time, from_time, :include_seconds => true) # => about 6 years
# distance_of_time_in_words(Time.now, Time.now) # => less than a minute
- #
def distance_of_time_in_words(from_time, to_time = 0, include_seconds_or_options = {}, options = {})
if include_seconds_or_options.is_a?(Hash)
options = include_seconds_or_options
@@ -140,7 +139,6 @@ module ActionView
# 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
# time_ago_in_words(Time.now - 15.hours) # => about 15 hours
# time_ago_in_words(Time.now) # => less than a minute
@@ -148,7 +146,6 @@ module ActionView
#
# from_time = Time.now - 3.days - 14.minutes - 25.seconds
# time_ago_in_words(from_time) # => 3 days
- #
def time_ago_in_words(from_time, include_seconds_or_options = {})
distance_of_time_in_words(from_time, Time.now, include_seconds_or_options)
end
@@ -197,7 +194,6 @@ 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 article variable, in the written_on attribute.
# date_select("article", "written_on")
#
@@ -253,7 +249,6 @@ module ActionView
#
# 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 article variable in the sunrise attribute.
# time_select("article", "sunrise")
#
@@ -286,7 +281,6 @@ module ActionView
#
# If anything is passed in the html_options hash it will be applied to every select tag in the set.
#
- # ==== Examples
# # Generates a datetime select that, when POSTed, will be stored in the article variable in the written_on
# # attribute.
# datetime_select("article", "written_on")
@@ -325,7 +319,6 @@ module ActionView
#
# If anything is passed in the html_options hash it will be applied to every select tag in the set.
#
- # ==== 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).
@@ -362,7 +355,6 @@ module ActionView
# 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
- #
def select_datetime(datetime = Time.current, options = {}, html_options = {})
DateTimeSelector.new(datetime, options, html_options).select_datetime
end
@@ -374,7 +366,6 @@ module ActionView
#
# If anything is passed in the html_options hash it will be applied to every select tag in the set.
#
- # ==== Examples
# my_date = Time.now + 6.days
#
# # Generates a date select that defaults to the date in my_date (six days after today).
@@ -403,7 +394,6 @@ module ActionView
# 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
- #
def select_date(date = Date.current, options = {}, html_options = {})
DateTimeSelector.new(date, options, html_options).select_date
end
@@ -414,7 +404,6 @@ module ActionView
#
# If anything is passed in the html_options hash it will be applied to every select tag in the set.
#
- # ==== 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.
@@ -442,7 +431,6 @@ module ActionView
# 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
- #
def select_time(datetime = Time.current, options = {}, html_options = {})
DateTimeSelector.new(datetime, options, html_options).select_time
end
@@ -451,7 +439,6 @@ module ActionView
# The <tt>datetime</tt> can be either a +Time+ or +DateTime+ object or an integer.
# Override the field name using the <tt>:field_name</tt> option, 'second' by default.
#
- # ==== Examples
# my_time = Time.now + 16.minutes
#
# # Generates a select field for seconds that defaults to the seconds for the time in my_time.
@@ -467,7 +454,6 @@ module ActionView
# # Generates a select field for seconds with a custom prompt. Use <tt>:prompt => true</tt> for a
# # generic prompt.
# select_second(14, :prompt => 'Choose seconds')
- #
def select_second(datetime, options = {}, html_options = {})
DateTimeSelector.new(datetime, options, html_options).select_second
end
@@ -477,7 +463,6 @@ module ActionView
# selected. The <tt>datetime</tt> can be either a +Time+ or +DateTime+ object or an integer.
# Override the field name using the <tt>:field_name</tt> option, 'minute' by default.
#
- # ==== Examples
# my_time = Time.now + 6.hours
#
# # Generates a select field for minutes that defaults to the minutes for the time in my_time.
@@ -493,7 +478,6 @@ module ActionView
# # 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')
- #
def select_minute(datetime, options = {}, html_options = {})
DateTimeSelector.new(datetime, options, html_options).select_minute
end
@@ -502,7 +486,6 @@ module ActionView
# The <tt>datetime</tt> can be either a +Time+ or +DateTime+ object or an integer.
# Override the field name using the <tt>:field_name</tt> option, 'hour' by default.
#
- # ==== Examples
# my_time = Time.now + 6.hours
#
# # Generates a select field for hours that defaults to the hour for the time in my_time.
@@ -521,7 +504,6 @@ module ActionView
#
# # Generate a select field for hours in the AM/PM format
# select_hour(my_time, :ampm => true)
- #
def select_hour(datetime, options = {}, html_options = {})
DateTimeSelector.new(datetime, options, html_options).select_hour
end
@@ -531,7 +513,6 @@ module ActionView
# If you want to display days with a leading zero set the <tt>:use_two_digit_numbers</tt> key in +options+ to true.
# Override the field name using the <tt>:field_name</tt> option, 'day' by default.
#
- # ==== Examples
# my_date = Time.now + 2.days
#
# # Generates a select field for days that defaults to the day for the date in my_date.
@@ -550,7 +531,6 @@ module ActionView
# # 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')
- #
def select_day(date, options = {}, html_options = {})
DateTimeSelector.new(date, options, html_options).select_day
end
@@ -565,7 +545,6 @@ module ActionView
# If you want to display months with a leading zero set the <tt>:use_two_digit_numbers</tt> key in +options+ to true.
# Override the field name using the <tt>:field_name</tt> option, 'month' by default.
#
- # ==== Examples
# # Generates a select field for months that defaults to the current month that
# # will use keys like "January", "March".
# select_month(Date.today)
@@ -597,7 +576,6 @@ module ActionView
# # 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')
- #
def select_month(date, options = {}, html_options = {})
DateTimeSelector.new(date, options, html_options).select_month
end
@@ -608,7 +586,6 @@ module ActionView
# greater than <tt>:end_year</tt>. The <tt>date</tt> can also be substituted for a year given as a number.
# Override the field name using the <tt>:field_name</tt> option, 'year' by default.
#
- # ==== Examples
# # Generates a select field for years that defaults to the current year that
# # has ascending year values.
# select_year(Date.today, :start_year => 1992, :end_year => 2007)
@@ -628,14 +605,12 @@ module ActionView
# # 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')
- #
def select_year(date, options = {}, html_options = {})
DateTimeSelector.new(date, options, html_options).select_year
end
# Returns an html time tag for the given date or time.
#
- # ==== Examples
# time_tag Date.today # =>
# <time datetime="2010-11-04">November 04, 2010</time>
# time_tag Time.now # =>
@@ -649,7 +624,6 @@ module ActionView
# <span>Right now</span>
# <% end %>
# # => <time datetime="2010-11-04T17:55:45+01:00"><span>Right now</span></time>
- #
def time_tag(date_or_time, *args, &block)
options = args.extract_options!
format = options.delete(:format) || :long
diff --git a/actionpack/lib/action_view/helpers/debug_helper.rb b/actionpack/lib/action_view/helpers/debug_helper.rb
index c0cc7d347c..878a8734a4 100644
--- a/actionpack/lib/action_view/helpers/debug_helper.rb
+++ b/actionpack/lib/action_view/helpers/debug_helper.rb
@@ -8,8 +8,6 @@ module ActionView
# If the object cannot be converted to YAML using +to_yaml+, +inspect+ will be called instead.
# Useful for inspecting an object at the time of rendering.
#
- # ==== Example
- #
# @user = User.new({ :username => 'testing', :password => 'xyz', :age => 42}) %>
# debug(@user)
# # =>
@@ -25,7 +23,6 @@ module ActionView
#
# new_record: true
# </pre>
-
def debug(object)
begin
Marshal::dump(object)
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index 67f2abe509..cc1f133196 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -5,6 +5,7 @@ require 'action_view/helpers/form_tag_helper'
require 'action_view/helpers/active_model_helper'
require 'action_view/helpers/tags'
require 'active_support/core_ext/class/attribute'
+require 'active_support/core_ext/class/attribute_accessors'
require 'active_support/core_ext/hash/slice'
require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/string/output_safety'
@@ -899,7 +900,6 @@ module ActionView
# In that case it is preferable to either use +check_box_tag+ or to use
# hashes instead of arrays.
#
- # ==== Examples
# # Let's say that @post.validated? is 1:
# check_box("post", "validated")
# # => <input name="post[validated]" type="hidden" value="0" />
@@ -925,7 +925,6 @@ module ActionView
# To force the radio button to be checked pass <tt>:checked => true</tt> in the
# +options+ hash. You may pass HTML options there as well.
#
- # ==== Examples
# # Let's say that @post.category returns "rails":
# radio_button("post", "category", "rails")
# radio_button("post", "category", "java")
@@ -944,8 +943,6 @@ module ActionView
# assigned to the template (identified by +object_name+). Inputs of type "search" may be styled differently by
# some browsers.
#
- # ==== Examples
- #
# search_field(:user, :name)
# # => <input id="user_name" name="user[name]" type="search" />
# search_field(:user, :name, :autosave => false)
@@ -961,7 +958,6 @@ module ActionView
# # => <input autosave="false" id="user_name" incremental="true" name="user[name]" onsearch="true" type="search" />
# search_field(:user, :name, :autosave => true, :onsearch => true)
# # => <input autosave="com.example.www" id="user_name" incremental="true" name="user[name]" onsearch="true" results="10" type="search" />
- #
def search_field(object_name, method, options = {})
Tags::SearchField.new(object_name, method, self, options).render
end
diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb
index cafcd93f58..52eb1aa447 100644
--- a/actionpack/lib/action_view/helpers/form_options_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_options_helper.rb
@@ -264,7 +264,6 @@ module ActionView
# Finally, this method supports a <tt>:default</tt> option, which selects
# a default ActiveSupport::TimeZone if the object's time zone is +nil+.
#
- # Examples:
# time_zone_select( "user", "time_zone", nil, :include_blank => true)
#
# time_zone_select( "user", "time_zone", nil, :default => "Pacific Time (US & Canada)" )
@@ -461,8 +460,11 @@ module ActionView
# * +selected_key+ - A value equal to the +value+ attribute for one of the <tt><option></tt> tags,
# which will have the +selected+ attribute set. Note: It is possible for this value to match multiple options
# as you might have the same option in multiple groups. Each will then get <tt>selected="selected"</tt>.
- # * +prompt+ - set to true or a prompt string. When the select element doesn't have a value yet, this
+ #
+ # Options:
+ # * <tt>:prompt</tt> - set to true or a prompt string. When the select element doesn't have a value yet, this
# prepends an option with a generic prompt - "Please select" - or the given prompt string.
+ # * <tt>:divider</tt> - the divider for the options groups.
#
# Sample usage (Array):
# grouped_options = [
@@ -491,15 +493,51 @@ module ActionView
# <option value="Canada">Canada</option>
# </optgroup>
#
+ # Sample usage (divider):
+ # grouped_options = [
+ # [['United States','US'], 'Canada'],
+ # ['Denmark','Germany','France']
+ # ]
+ # grouped_options_for_select(grouped_options, divider: '---------')
+ #
+ # Possible output:
+ # <optgroup label="---------">
+ # <option value="Denmark">Denmark</option>
+ # <option value="Germany">Germany</option>
+ # <option value="France">France</option>
+ # </optgroup>
+ # <optgroup label="---------">
+ # <option value="US">United States</option>
+ # <option value="Canada">Canada</option>
+ # </optgroup>
+ #
# <b>Note:</b> Only the <tt><optgroup></tt> and <tt><option></tt> tags are returned, so you still have to
# wrap the output in an appropriate <tt><select></tt> tag.
- def grouped_options_for_select(grouped_options, selected_key = nil, prompt = nil)
+ def grouped_options_for_select(*args)
+ grouped_options = args.shift
+ options = args.extract_options!
+ selected_key = args.shift
+ if prompt = args.shift
+ ActiveSupport::Deprecation.warn 'Passing the prompt to grouped_options_for_select as an argument is deprecated. Please pass it in an options hash.'
+ else
+ prompt = options[:prompt]
+ divider = options[:divider]
+ end
+
body = "".html_safe
- body.safe_concat content_tag(:option, prompt, :value => "") if prompt
+
+ if prompt
+ body.safe_concat content_tag(:option, prompt_text(prompt), :value => "")
+ end
grouped_options = grouped_options.sort if grouped_options.is_a?(Hash)
- grouped_options.each do |label, container|
+ grouped_options.each do |container|
+ if divider
+ label, container = divider, container
+ else
+ label, container = container
+ end
body.safe_concat content_tag(:optgroup, options_for_select(container, selected_key), :label => label)
end
@@ -715,6 +753,10 @@ module ActionView
def value_for_collection(item, value)
value.respond_to?(:call) ? value.call(item) : item.send(value)
end
+
+ def prompt_text(prompt)
+ prompt = prompt.kind_of?(String) ? prompt : I18n.translate('helpers.select.prompt', :default => 'Please select')
+ end
end
class FormBuilder
diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb
index 248cc2f6a3..9e5c66f4a9 100644
--- a/actionpack/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb
@@ -386,9 +386,6 @@ module ActionView
# drivers will provide a prompt with the question specified. If the user accepts,
# the form is processed normally, otherwise no action is taken.
# * <tt>:disabled</tt> - If true, the user will not be able to use this input.
- # * <tt>:disable_with</tt> - Value of this parameter will be used as the value for a
- # disabled version of the submit button when the form is submitted. This feature is
- # provided by the unobtrusive JavaScript driver.
# * Any other key creates standard HTML options for the tag.
#
# ==== Examples
@@ -401,14 +398,14 @@ module ActionView
# submit_tag "Save edits", :disabled => true
# # => <input disabled="disabled" name="commit" type="submit" value="Save edits" />
#
- # submit_tag "Complete sale", :disable_with => "Please wait..."
+ # submit_tag "Complete sale", :data => { :disable_with => "Please wait..." }
# # => <input name="commit" data-disable-with="Please wait..." type="submit" value="Complete sale" />
#
# submit_tag nil, :class => "form_submit"
# # => <input class="form_submit" name="commit" type="submit" />
#
- # submit_tag "Edit", :disable_with => "Editing...", :class => "edit_button"
- # # => <input class="edit_button" data-disable-with="Editing..." name="commit" type="submit" value="Edit" />
+ # submit_tag "Edit", :class => "edit_button"
+ # # => <input class="edit_button" name="commit" type="submit" value="Edit" />
#
# submit_tag "Save", :confirm => "Are you sure?"
# # => <input name='commit' type='submit' value='Save' data-confirm="Are you sure?" />
@@ -416,10 +413,6 @@ module ActionView
def submit_tag(value = "Save changes", options = {})
options = options.stringify_keys
- if disable_with = options.delete("disable_with")
- options["data-disable-with"] = disable_with
- end
-
if confirm = options.delete("confirm")
options["data-confirm"] = confirm
end
@@ -441,10 +434,6 @@ module ActionView
# processed normally, otherwise no action is taken.
# * <tt>:disabled</tt> - If true, the user will not be able to
# use this input.
- # * <tt>:disable_with</tt> - Value of this parameter will be
- # used as the value for a disabled version of the submit
- # button when the form is submitted. This feature is provided
- # by the unobtrusive JavaScript driver.
# * Any other key creates standard HTML options for the tag.
#
# ==== Examples
@@ -458,18 +447,11 @@ module ActionView
# # <strong>Ask me!</strong>
# # </button>
#
- # button_tag "Checkout", :disable_with => "Please wait..."
- # # => <button data-disable-with="Please wait..." name="button" type="submit">Checkout</button>
- #
def button_tag(content_or_options = nil, options = nil, &block)
options = content_or_options if block_given? && content_or_options.is_a?(Hash)
options ||= {}
options = options.stringify_keys
- if disable_with = options.delete("disable_with")
- options["data-disable-with"] = disable_with
- end
-
if confirm = options.delete("confirm")
options["data-confirm"] = confirm
end
diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb
index dfc26acfad..62455b97f9 100644
--- a/actionpack/lib/action_view/helpers/number_helper.rb
+++ b/actionpack/lib/action_view/helpers/number_helper.rb
@@ -254,7 +254,7 @@ module ActionView
parts = number.to_s.to_str.split('.')
parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{options[:delimiter]}")
- safe_join(parts, options[:separator])
+ parts.join(options[:separator]).html_safe
end
# Formats a +number+ with the specified level of
diff --git a/actionpack/lib/action_view/helpers/sanitize_helper.rb b/actionpack/lib/action_view/helpers/sanitize_helper.rb
index 7768c8c151..a727b910e5 100644
--- a/actionpack/lib/action_view/helpers/sanitize_helper.rb
+++ b/actionpack/lib/action_view/helpers/sanitize_helper.rb
@@ -69,8 +69,6 @@ module ActionView
# html-scanner tokenizer and so its HTML parsing ability is limited by
# that of html-scanner.
#
- # ==== Examples
- #
# strip_tags("Strip <i>these</i> tags!")
# # => Strip these tags!
#
@@ -85,7 +83,6 @@ module ActionView
# Strips all link tags from +text+ leaving just the link text.
#
- # ==== Examples
# strip_links('<a href="http://www.rubyonrails.org">Ruby on Rails</a>')
# # => Ruby on Rails
#
diff --git a/actionpack/lib/action_view/helpers/tag_helper.rb b/actionpack/lib/action_view/helpers/tag_helper.rb
index f7afa48256..d5cd60e8a1 100644
--- a/actionpack/lib/action_view/helpers/tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/tag_helper.rb
@@ -103,7 +103,6 @@ module ActionView
# otherwise be recognized as markup. CDATA sections begin with the string
# <tt><![CDATA[</tt> and end with (and may not contain) the string <tt>]]></tt>.
#
- # ==== Examples
# cdata_section("<hello world>")
# # => <![CDATA[<hello world>]]>
#
@@ -119,7 +118,6 @@ module ActionView
# Returns an escaped version of +html+ without affecting existing escaped entities.
#
- # ==== Examples
# escape_once("1 < 2 &amp; 3")
# # => "1 &lt; 2 &amp; 3"
#
diff --git a/actionpack/lib/action_view/helpers/tags/base.rb b/actionpack/lib/action_view/helpers/tags/base.rb
index e4f431a6d7..e077cd5b3c 100644
--- a/actionpack/lib/action_view/helpers/tags/base.rb
+++ b/actionpack/lib/action_view/helpers/tags/base.rb
@@ -121,6 +121,7 @@ module ActionView
def select_content_tag(option_tags, options, html_options)
html_options = html_options.stringify_keys
add_default_name_and_id(html_options)
+ options[:include_blank] ||= true unless options[:prompt] || select_not_required?(html_options)
select = content_tag("select", add_options(option_tags, options, value(object)), html_options)
if html_options["multiple"] && options.fetch(:include_hidden, true)
@@ -130,13 +131,16 @@ module ActionView
end
end
+ def select_not_required?(html_options)
+ !html_options["required"] || html_options["multiple"] || html_options["size"].to_i > 1
+ end
+
def add_options(option_tags, options, value = nil)
if options[:include_blank]
option_tags = content_tag('option', options[:include_blank].kind_of?(String) ? options[:include_blank] : nil, :value => '') + "\n" + option_tags
end
if value.blank? && options[:prompt]
- prompt = options[:prompt].kind_of?(String) ? options[:prompt] : I18n.translate('helpers.select.prompt', :default => 'Please select')
- option_tags = content_tag('option', prompt, :value => '') + "\n" + option_tags
+ option_tags = content_tag('option', prompt_text(options[:prompt]), :value => '') + "\n" + option_tags
end
option_tags
end
diff --git a/actionpack/lib/action_view/helpers/tags/date_field.rb b/actionpack/lib/action_view/helpers/tags/date_field.rb
index bb968e9f39..0e79609d52 100644
--- a/actionpack/lib/action_view/helpers/tags/date_field.rb
+++ b/actionpack/lib/action_view/helpers/tags/date_field.rb
@@ -5,7 +5,6 @@ module ActionView
def render
options = @options.stringify_keys
options["value"] = @options.fetch("value") { value(object).try(:to_date) }
- options["size"] = nil
@options = options
super
end
diff --git a/actionpack/lib/action_view/helpers/tags/file_field.rb b/actionpack/lib/action_view/helpers/tags/file_field.rb
index 56442e1c14..59f2ff71b4 100644
--- a/actionpack/lib/action_view/helpers/tags/file_field.rb
+++ b/actionpack/lib/action_view/helpers/tags/file_field.rb
@@ -2,10 +2,6 @@ module ActionView
module Helpers
module Tags
class FileField < TextField #:nodoc:
- def render
- @options.update(:size => nil)
- super
- end
end
end
end
diff --git a/actionpack/lib/action_view/helpers/tags/hidden_field.rb b/actionpack/lib/action_view/helpers/tags/hidden_field.rb
index ea86596e0b..a8d13dc1b1 100644
--- a/actionpack/lib/action_view/helpers/tags/hidden_field.rb
+++ b/actionpack/lib/action_view/helpers/tags/hidden_field.rb
@@ -2,10 +2,6 @@ module ActionView
module Helpers
module Tags
class HiddenField < TextField #:nodoc:
- def render
- @options.update(:size => nil)
- super
- end
end
end
end
diff --git a/actionpack/lib/action_view/helpers/tags/number_field.rb b/actionpack/lib/action_view/helpers/tags/number_field.rb
index e89fdbec46..9cd04434f0 100644
--- a/actionpack/lib/action_view/helpers/tags/number_field.rb
+++ b/actionpack/lib/action_view/helpers/tags/number_field.rb
@@ -4,7 +4,6 @@ module ActionView
class NumberField < TextField #:nodoc:
def render
options = @options.stringify_keys
- options['size'] ||= nil
if range = options.delete("in") || options.delete("within")
options.update("min" => range.min, "max" => range.max)
diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb
index 698f4434ba..67117077dc 100644
--- a/actionpack/lib/action_view/helpers/text_helper.rb
+++ b/actionpack/lib/action_view/helpers/text_helper.rb
@@ -37,7 +37,6 @@ module ActionView
# do not operate as expected in an eRuby code block. If you absolutely must
# output text within a non-output code block (i.e., <% %>), you can use the concat method.
#
- # ==== Examples
# <%
# concat "hello"
# # is the equivalent of <%= "hello" %>
@@ -67,8 +66,6 @@ module ActionView
# used in views, unless wrapped by <tt>raw()</tt>. Care should be taken if +text+ contains HTML tags
# or entities, because truncation may produce invalid HTML (such as unbalanced or incomplete tags).
#
- # ==== Examples
- #
# truncate("Once upon a time in a world far far away")
# # => "Once upon a time in a world..."
#
@@ -93,7 +90,6 @@ module ActionView
# as a single-quoted string with <tt>\1</tt> where the phrase is to be inserted (defaults to
# '<mark>\1</mark>')
#
- # ==== Examples
# highlight('You searched for: rails', 'rails')
# # => You searched for: <mark>rails</mark>
#
@@ -133,7 +129,6 @@ module ActionView
# then the <tt>:omission</tt> option (which defaults to "...") will be prepended/appended accordingly. The resulting string
# will be stripped in any case. If the +phrase+ isn't found, nil is returned.
#
- # ==== Examples
# excerpt('This is an example', 'an', :radius => 5)
# # => ...s is an exam...
#
@@ -181,7 +176,6 @@ module ActionView
# +plural+ is supplied, it will use that when count is > 1, otherwise
# it will use the Inflector to determine the plural form
#
- # ==== Examples
# pluralize(1, 'person')
# # => 1 person
#
@@ -201,23 +195,23 @@ module ActionView
# breaks on the first whitespace character that does not exceed +line_width+
# (which is 80 by default).
#
- # ==== Examples
- #
# word_wrap('Once upon a time')
# # => Once upon a time
#
# word_wrap('Once upon a time, in a kingdom called Far Far Away, a king fell ill, and finding a successor to the throne turned out to be more trouble than anyone could have imagined...')
- # # => Once upon a time, in a kingdom called Far Far Away, a king fell ill, and finding\n a successor to the throne turned out to be more trouble than anyone could have\n imagined...
+ # # => Once upon a time, in a kingdom called Far Far Away, a king fell ill, and finding\na successor to the throne turned out to be more trouble than anyone could have\nimagined...
#
# word_wrap('Once upon a time', :line_width => 8)
- # # => Once upon\na time
+ # # => Once\nupon a\ntime
#
# word_wrap('Once upon a time', :line_width => 1)
# # => Once\nupon\na\ntime
#
# You can still use <tt>word_wrap</tt> with the old API that accepts the
# +line_width+ as its optional second parameter:
- # word_wrap('Once upon a time', 8) # => Once upon\na time
+ #
+ # word_wrap('Once upon a time', 8)
+ # # => Once\nupon a\ntime
def word_wrap(text, *args)
options = args.extract_options!
unless args.blank?
@@ -241,6 +235,7 @@ module ActionView
#
# ==== Options
# * <tt>:sanitize</tt> - If +false+, does not sanitize +text+.
+ # * <tt>:wrapper_tag</tt> - String representing the tag wrapper, defaults to <tt>"p"</tt>
#
# ==== Examples
# my_text = "Here is some basic text...\n...with a line break."
@@ -259,16 +254,17 @@ module ActionView
# simple_format("<span>I'm allowed!</span> It's true.", {}, :sanitize => false)
# # => "<p><span>I'm allowed!</span> It's true.</p>"
def simple_format(text, html_options={}, options={})
- text = '' if text.nil?
- text = text.dup
- start_tag = tag('p', html_options, true)
text = sanitize(text) unless options[:sanitize] == false
- text = text.to_str
- text.gsub!(/\r\n?/, "\n") # \r\n and \r -> \n
- text.gsub!(/\n\n+/, "</p>\n\n#{start_tag}") # 2+ newline -> paragraph
- text.gsub!(/([^\n]\n)(?=[^\n])/, '\1<br />') # 1 newline -> br
- text.insert 0, start_tag
- text.html_safe.safe_concat("</p>")
+ wrapper_tag = options.fetch(:wrapper_tag, :p)
+ paragraphs = split_paragraphs(text)
+
+ if paragraphs.empty?
+ content_tag(wrapper_tag, nil, html_options)
+ else
+ paragraphs.map { |paragraph|
+ content_tag(wrapper_tag, paragraph, html_options, options[:sanitize])
+ }.join("\n\n").html_safe
+ end
end
# Creates a Cycle object whose _to_s_ method cycles through elements of an
@@ -280,7 +276,6 @@ module ActionView
# and passing the name of the cycle. The current cycle string can be obtained
# anytime using the current_cycle method.
#
- # ==== Examples
# # Alternate CSS classes for even and odd numbers...
# @items = [1,2,3,4]
# <table>
@@ -326,7 +321,6 @@ module ActionView
# for complex table highlighting or any other design need which requires
# the current cycle string in more than one place.
#
- # ==== Example
# # Alternate background colors
# @items = [1,2,3,4]
# <% @items.each do |item| %>
@@ -342,7 +336,6 @@ module ActionView
# Resets a cycle so that it starts from the first element the next time
# it is called. Pass in +name+ to reset a named cycle.
#
- # ==== Example
# # Alternate CSS classes for even and odd numbers...
# @items = [[1,2,3,4], [5,6,3], [3,4,5,6,7,4]]
# <table>
@@ -413,6 +406,14 @@ module ActionView
@_cycles = Hash.new unless defined?(@_cycles)
@_cycles[name] = cycle_object
end
+
+ def split_paragraphs(text)
+ return [] if text.blank?
+
+ text.to_str.gsub(/\r\n?/, "\n").split(/\n\n+/).map! do |t|
+ t.gsub!(/([^\n]\n)(?=[^\n])/, '\1<br />') || t
+ end
+ end
end
end
end
diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb
index 1145f348c2..7e69547dab 100644
--- a/actionpack/lib/action_view/helpers/url_helper.rb
+++ b/actionpack/lib/action_view/helpers/url_helper.rb
@@ -108,7 +108,7 @@ module ActionView
options
when nil, Hash
options ||= {}
- options = options.symbolize_keys.reverse_merge!(:only_path => options[:host].nil?)
+ options = { :only_path => options[:host].nil? }.merge!(options.symbolize_keys)
super
when :back
controller.request.env["HTTP_REFERER"] || 'javascript:history.back()'
@@ -322,11 +322,11 @@ module ActionView
#
#
# <%= button_to('Destroy', 'http://www.example.com', :confirm => 'Are you sure?',
- # :method => "delete", :remote => true, :disable_with => 'loading...') %>
+ # :method => "delete", :remote => true) %>
# # => "<form class='button_to' method='post' action='http://www.example.com' data-remote='true'>
# # <div>
# # <input name='_method' value='delete' type='hidden' />
- # # <input value='Destroy' type='submit' disable_with='loading...' data-confirm='Are you sure?' />
+ # # <input value='Destroy' type='submit' data-confirm='Are you sure?' />
# # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6"/>
# # </div>
# # </form>"
@@ -616,11 +616,9 @@ module ActionView
html_options = html_options.stringify_keys
html_options['data-remote'] = 'true' if link_to_remote_options?(options) || link_to_remote_options?(html_options)
- disable_with = html_options.delete("disable_with")
confirm = html_options.delete('confirm')
method = html_options.delete('method')
- html_options["data-disable-with"] = disable_with if disable_with
html_options["data-confirm"] = confirm if confirm
add_method_to_attributes!(html_options, method) if method
@@ -670,11 +668,11 @@ module ActionView
end
def token_tag(token=nil)
- if token == false || !protect_against_forgery?
- ''
- else
+ if token != false && protect_against_forgery?
token ||= form_authenticity_token
tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => token)
+ else
+ ''
end
end
diff --git a/actionpack/lib/action_view/renderer/abstract_renderer.rb b/actionpack/lib/action_view/renderer/abstract_renderer.rb
index 52473cd222..72616b7463 100644
--- a/actionpack/lib/action_view/renderer/abstract_renderer.rb
+++ b/actionpack/lib/action_view/renderer/abstract_renderer.rb
@@ -14,12 +14,10 @@ module ActionView
protected
def extract_details(options)
- details = {}
- @lookup_context.registered_details.each do |key|
+ @lookup_context.registered_details.each_with_object({}) do |key, details|
next unless value = options[key]
details[key] = Array(value)
end
- details
end
def instrument(name, options={})
diff --git a/actionpack/lib/action_view/renderer/partial_renderer.rb b/actionpack/lib/action_view/renderer/partial_renderer.rb
index 87609fd5ff..9100545718 100644
--- a/actionpack/lib/action_view/renderer/partial_renderer.rb
+++ b/actionpack/lib/action_view/renderer/partial_renderer.rb
@@ -283,7 +283,7 @@ module ActionView
return nil if @collection.blank?
if @options.key?(:spacer_template)
- spacer = find_template(@options[:spacer_template]).render(@view, @locals)
+ spacer = find_template(@options[:spacer_template], @locals.keys).render(@view, @locals)
end
result = @template ? collection_with_template : collection_without_template
@@ -291,11 +291,11 @@ module ActionView
end
def render_partial
- locals, view, block = @locals, @view, @block
+ view, locals, block = @view, @locals, @block
object, as = @object, @variable
if !block && (layout = @options[:layout])
- layout = find_template(layout, @locals.keys + [@variable])
+ layout = find_template(layout, @template_keys)
end
object ||= locals[as]
@@ -337,6 +337,7 @@ module ActionView
if @path
@variable, @variable_counter = retrieve_variable(@path)
+ @template_keys = retrieve_template_keys
else
paths.map! { |path| retrieve_variable(path).unshift(path) }
end
@@ -358,62 +359,55 @@ module ActionView
end
def collection_from_object
- if @object.respond_to?(:to_ary)
- @object.to_ary
- end
+ @object.to_ary if @object.respond_to?(:to_ary)
end
def find_partial
if path = @path
- locals = @locals.keys
- locals << @variable
- locals << @variable_counter if @collection
- find_template(path, locals)
+ find_template(path, @template_keys)
end
end
- def find_template(path=@path, locals=@locals.keys)
+ def find_template(path, locals)
prefixes = path.include?(?/) ? [] : @lookup_context.prefixes
@lookup_context.find_template(path, prefixes, true, locals, @details)
end
def collection_with_template
- segments, locals, template = [], @locals, @template
+ view, locals, template = @view, @locals, @template
as, counter = @variable, @variable_counter
if layout = @options[:layout]
- layout = find_template(layout, @locals.keys + [@variable, @variable_counter])
+ layout = find_template(layout, @template_keys)
end
- locals[counter] = -1
-
- @collection.each do |object|
- locals[counter] += 1
- locals[as] = object
+ index = -1
+ @collection.map do |object|
+ locals[as] = object
+ locals[counter] = (index += 1)
- content = template.render(@view, locals)
- content = layout.render(@view, locals) { content } if layout
- segments << content
+ content = template.render(view, locals)
+ content = layout.render(view, locals) { content } if layout
+ content
end
-
- segments
end
def collection_without_template
- segments, locals, collection_data = [], @locals, @collection_data
- index, template, cache = -1, nil, {}
- keys = @locals.keys
+ view, locals, collection_data = @view, @locals, @collection_data
+ cache = {}
+ keys = @locals.keys
- @collection.each_with_index do |object, i|
- path, *data = collection_data[i]
- template = (cache[path] ||= find_template(path, keys + data))
- locals[data[0]] = object
- locals[data[1]] = (index += 1)
- segments << template.render(@view, locals)
- end
+ index = -1
+ @collection.map do |object|
+ index += 1
+ path, as, counter = collection_data[index]
- @template = template
- segments
+ locals[as] = object
+ locals[counter] = index
+
+ template = (cache[path] ||= find_template(path, keys + [as, counter]))
+ template.render(view, locals)
+ end
end
def partial_path(object = @object)
@@ -453,6 +447,13 @@ module ActionView
end
end
+ def retrieve_template_keys
+ keys = @locals.keys
+ keys << @variable
+ keys << @variable_counter if @collection
+ keys
+ end
+
def retrieve_variable(path)
variable = @options.fetch(:as) { path[%r'_?(\w+)(\.\w+)*$', 1] }.try(:to_sym)
variable_counter = :"#{variable}_counter" if @collection
diff --git a/actionpack/lib/action_view/template/handlers.rb b/actionpack/lib/action_view/template/handlers.rb
index 4e22bec6cc..41b14373a3 100644
--- a/actionpack/lib/action_view/template/handlers.rb
+++ b/actionpack/lib/action_view/template/handlers.rb
@@ -4,10 +4,12 @@ module ActionView #:nodoc:
module Handlers #:nodoc:
autoload :ERB, 'action_view/template/handlers/erb'
autoload :Builder, 'action_view/template/handlers/builder'
+ autoload :Raw, 'action_view/template/handlers/raw'
def self.extended(base)
base.register_default_template_handler :erb, ERB.new
base.register_template_handler :builder, Builder.new
+ base.register_template_handler :raw, Raw.new
end
@@template_handlers = {}
diff --git a/actionpack/lib/action_view/template/handlers/raw.rb b/actionpack/lib/action_view/template/handlers/raw.rb
new file mode 100644
index 0000000000..0c0d1fffcb
--- /dev/null
+++ b/actionpack/lib/action_view/template/handlers/raw.rb
@@ -0,0 +1,11 @@
+module ActionView
+ module Template::Handlers
+ class Raw
+ def call(template)
+ escaped = template.source.gsub(':', '\:')
+
+ '%q:' + escaped + ':;'
+ end
+ end
+ end
+end
diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb
index 8ea2e5bfe4..fa2038f78d 100644
--- a/actionpack/lib/action_view/template/resolver.rb
+++ b/actionpack/lib/action_view/template/resolver.rb
@@ -1,5 +1,6 @@
require "pathname"
require "active_support/core_ext/class"
+require "active_support/core_ext/class/attribute_accessors"
require "action_view/template"
module ActionView
@@ -170,7 +171,9 @@ module ActionView
def extract_handler_and_format(path, default_formats)
pieces = File.basename(path).split(".")
pieces.shift
- handler = Template.handler_for_extension(pieces.pop)
+ extension = pieces.pop
+ ActiveSupport::Deprecation.warn "The file #{path} did not specify a template handler. The default is currently ERB, but will change to RAW in the future." unless extension
+ handler = Template.handler_for_extension(extension)
format = pieces.last && Mime[pieces.last]
[handler, format]
end
diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb
index 22ba047328..ba06bcae51 100644
--- a/actionpack/test/abstract_unit.rb
+++ b/actionpack/test/abstract_unit.rb
@@ -1,11 +1,5 @@
require File.expand_path('../../../load_paths', __FILE__)
-lib = File.expand_path("#{File.dirname(__FILE__)}/../lib")
-$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib)
-
-activemodel_path = File.expand_path('../../../activemodel/lib', __FILE__)
-$:.unshift(activemodel_path) if File.directory?(activemodel_path) && !$:.include?(activemodel_path)
-
$:.unshift(File.dirname(__FILE__) + '/lib')
$:.unshift(File.dirname(__FILE__) + '/fixtures/helpers')
$:.unshift(File.dirname(__FILE__) + '/fixtures/alternate_helpers')
diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb
index 9f2dbda25f..fb41dcb33a 100644
--- a/actionpack/test/controller/integration_test.rb
+++ b/actionpack/test/controller/integration_test.rb
@@ -615,3 +615,83 @@ class EnvironmentFilterIntegrationTest < ActionDispatch::IntegrationTest
assert_equal '[FILTERED]', request.filtered_env['rack.request.form_vars']
end
end
+
+class UrlOptionsIntegrationTest < ActionDispatch::IntegrationTest
+ class FooController < ActionController::Base
+ def index
+ render :text => "foo#index"
+ end
+
+ def show
+ render :text => "foo#show"
+ end
+
+ def edit
+ render :text => "foo#show"
+ end
+ end
+
+ class BarController < ActionController::Base
+ def default_url_options
+ { :host => "bar.com" }
+ end
+
+ def index
+ render :text => "foo#index"
+ end
+ end
+
+ def self.routes
+ @routes ||= ActionDispatch::Routing::RouteSet.new
+ end
+
+ def self.call(env)
+ routes.call(env)
+ end
+
+ def app
+ self.class
+ end
+
+ routes.draw do
+ default_url_options :host => "foo.com"
+
+ scope :module => "url_options_integration_test" do
+ get "/foo" => "foo#index", :as => :foos
+ get "/foo/:id" => "foo#show", :as => :foo
+ get "/foo/:id/edit" => "foo#edit", :as => :edit_foo
+ get "/bar" => "bar#index", :as => :bars
+ end
+ end
+
+ test "session uses default url options from routes" do
+ assert_equal "http://foo.com/foo", foos_url
+ end
+
+ test "current host overrides default url options from routes" do
+ get "/foo"
+ assert_response :success
+ assert_equal "http://www.example.com/foo", foos_url
+ end
+
+ test "controller can override default url options from request" do
+ get "/bar"
+ assert_response :success
+ assert_equal "http://bar.com/foo", foos_url
+ end
+
+ test "test can override default url options" do
+ default_url_options[:host] = "foobar.com"
+ assert_equal "http://foobar.com/foo", foos_url
+
+ get "/bar"
+ assert_response :success
+ assert_equal "http://foobar.com/foo", foos_url
+ end
+
+ test "current request path parameters are recalled" do
+ get "/foo/1"
+ assert_response :success
+ assert_equal "/foo/1/edit", url_for(:action => 'edit', :only_path => true)
+ end
+end
diff --git a/actionpack/test/controller/new_base/render_text_test.rb b/actionpack/test/controller/new_base/render_text_test.rb
index e0b38b29fa..f8d02e8b6c 100644
--- a/actionpack/test/controller/new_base/render_text_test.rb
+++ b/actionpack/test/controller/new_base/render_text_test.rb
@@ -65,7 +65,7 @@ module RenderText
class RenderTextTest < Rack::TestCase
describe "Rendering text using render :text"
- test "rendering text from a action with default options renders the text with the layout" do
+ test "rendering text from an action with default options renders the text with the layout" do
with_routing do |set|
set.draw { get ':controller', :action => 'index' }
@@ -75,7 +75,7 @@ module RenderText
end
end
- test "rendering text from a action with default options renders the text without the layout" do
+ test "rendering text from an action with default options renders the text without the layout" do
with_routing do |set|
set.draw { get ':controller', :action => 'index' }
diff --git a/actionpack/test/dispatch/routing_assertions_test.rb b/actionpack/test/dispatch/routing_assertions_test.rb
index e953029456..517354ae58 100644
--- a/actionpack/test/dispatch/routing_assertions_test.rb
+++ b/actionpack/test/dispatch/routing_assertions_test.rb
@@ -47,7 +47,7 @@ class RoutingAssertionsTest < ActionController::TestCase
def test_assert_recognizes_with_extras
assert_recognizes({ :controller => 'articles', :action => 'index', :page => '1' }, '/articles', { :page => '1' })
end
-
+
def test_assert_recognizes_with_method
assert_recognizes({ :controller => 'articles', :action => 'create' }, { :path => '/articles', :method => :post })
assert_recognizes({ :controller => 'articles', :action => 'update', :id => '1' }, { :path => '/articles/1', :method => :put })
@@ -57,7 +57,7 @@ class RoutingAssertionsTest < ActionController::TestCase
assert_raise(ActionController::RoutingError) do
assert_recognizes({ :controller => 'secure_articles', :action => 'index' }, 'http://test.host/secure/articles')
end
- assert_recognizes({ :controller => 'secure_articles', :action => 'index' }, 'https://test.host/secure/articles')
+ assert_recognizes({ :controller => 'secure_articles', :action => 'index', :protocol => 'https://' }, 'https://test.host/secure/articles')
end
def test_assert_recognizes_with_block_constraint
@@ -90,7 +90,7 @@ class RoutingAssertionsTest < ActionController::TestCase
assert_raise(ActionController::RoutingError) do
assert_routing('http://test.host/secure/articles', { :controller => 'secure_articles', :action => 'index' })
end
- assert_routing('https://test.host/secure/articles', { :controller => 'secure_articles', :action => 'index' })
+ assert_routing('https://test.host/secure/articles', { :controller => 'secure_articles', :action => 'index', :protocol => 'https://' })
end
def test_assert_routing_with_block_constraint
diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index d356187ca8..1a8f40037f 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -2324,6 +2324,55 @@ class TestNamespaceWithControllerOption < ActionDispatch::IntegrationTest
end
end
+class TestDrawExternalFile < ActionDispatch::IntegrationTest
+ class ExternalController < ActionController::Base
+ def index
+ render :text => "external#index"
+ end
+ end
+
+ DRAW_PATH = Pathname.new(File.expand_path('../../fixtures/routes', __FILE__))
+
+ DefaultScopeRoutes = ActionDispatch::Routing::RouteSet.new.tap do |app|
+ app.draw_paths << DRAW_PATH
+ end
+
+ def app
+ DefaultScopeRoutes
+ end
+
+ def test_draw_external_file
+ DefaultScopeRoutes.draw do
+ scope :module => 'test_draw_external_file' do
+ draw :external
+ end
+ end
+
+ get '/external'
+ assert_equal "external#index", @response.body
+ end
+
+ def test_draw_nonexistent_file
+ exception = assert_raise ArgumentError do
+ DefaultScopeRoutes.draw do
+ draw :nonexistent
+ end
+ end
+ assert_match 'Your router tried to #draw the external file nonexistent.rb', exception.message
+ assert_match DRAW_PATH.to_s, exception.message
+ end
+
+ def test_draw_bogus_file
+ exception = assert_raise NoMethodError do
+ DefaultScopeRoutes.draw do
+ draw :bogus
+ end
+ end
+ assert_match "undefined method `wrong'", exception.message
+ assert_match 'test/fixtures/routes/bogus.rb:1', exception.backtrace.first
+ end
+end
+
class TestDefaultScope < ActionDispatch::IntegrationTest
module ::Blog
class PostsController < ActionController::Base
@@ -2571,3 +2620,80 @@ class TestOptimizedNamedRoutes < ActionDispatch::IntegrationTest
assert_equal '/foo', foo_path
end
end
+
+class TestNamedRouteUrlHelpers < ActionDispatch::IntegrationTest
+ class CategoriesController < ActionController::Base
+ def show
+ render :text => "categories#show"
+ end
+ end
+
+ class ProductsController < ActionController::Base
+ def show
+ render :text => "products#show"
+ end
+ end
+
+ Routes = ActionDispatch::Routing::RouteSet.new.tap do |app|
+ app.draw do
+ scope :module => "test_named_route_url_helpers" do
+ get "/categories/:id" => 'categories#show', :as => :category
+ get "/products/:id" => 'products#show', :as => :product
+ end
+ end
+ end
+
+ def app; Routes end
+
+ include Routes.url_helpers
+
+ test "url helpers do not ignore nil parameters when using non-optimized routes" do
+ Routes.stubs(:optimize_routes_generation?).returns(false)
+
+ get "/categories/1"
+ assert_response :success
+ assert_raises(ActionController::RoutingError) { product_path(nil) }
+ end
+end
+
+class TestUrlConstraints < ActionDispatch::IntegrationTest
+ Routes = ActionDispatch::Routing::RouteSet.new.tap do |app|
+ app.draw do
+ ok = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, []] }
+
+ constraints :subdomain => 'admin' do
+ get '/' => ok, :as => :admin_root
+ end
+
+ scope :constraints => { :protocol => 'https://' } do
+ get '/' => ok, :as => :secure_root
+ end
+
+ get '/' => ok, :as => :alternate_root, :constraints => { :port => 8080 }
+ end
+ end
+
+ include Routes.url_helpers
+ def app; Routes end
+
+ test "constraints are copied to defaults when using constraints method" do
+ assert_equal 'http://admin.example.com/', admin_root_url
+
+ get 'http://admin.example.com/'
+ assert_response :success
+ end
+
+ test "constraints are copied to defaults when using scope constraints hash" do
+ assert_equal 'https://www.example.com/', secure_root_url
+
+ get 'https://www.example.com/'
+ assert_response :success
+ end
+
+ test "constraints are copied to defaults when using route constraints hash" do
+ assert_equal 'http://www.example.com:8080/', alternate_root_url
+
+ get 'http://www.example.com:8080/'
+ assert_response :success
+ end
+end
diff --git a/actionpack/test/fixtures/plain_text.raw b/actionpack/test/fixtures/plain_text.raw
new file mode 100644
index 0000000000..b13985337f
--- /dev/null
+++ b/actionpack/test/fixtures/plain_text.raw
@@ -0,0 +1 @@
+<%= hello_world %>
diff --git a/actionpack/test/fixtures/plain_text_with_characters.raw b/actionpack/test/fixtures/plain_text_with_characters.raw
new file mode 100644
index 0000000000..1e86e44fb4
--- /dev/null
+++ b/actionpack/test/fixtures/plain_text_with_characters.raw
@@ -0,0 +1 @@
+Here are some characters: !@#$%^&*()-="'}{`
diff --git a/actionpack/test/fixtures/routes/bogus.rb b/actionpack/test/fixtures/routes/bogus.rb
new file mode 100644
index 0000000000..41fbf0cd64
--- /dev/null
+++ b/actionpack/test/fixtures/routes/bogus.rb
@@ -0,0 +1 @@
+wrong :route
diff --git a/actionpack/test/fixtures/routes/external.rb b/actionpack/test/fixtures/routes/external.rb
new file mode 100644
index 0000000000..d103c39f53
--- /dev/null
+++ b/actionpack/test/fixtures/routes/external.rb
@@ -0,0 +1 @@
+get '/external' => 'external#index'
diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb
index 2736f6eff0..bfcc9dc7fe 100644
--- a/actionpack/test/template/asset_tag_helper_test.rb
+++ b/actionpack/test/template/asset_tag_helper_test.rb
@@ -203,9 +203,8 @@ class AssetTagHelperTest < ActionView::TestCase
%(image_tag(".pdf.png")) => %(<img alt=".pdf" src="/images/.pdf.png" />),
%(image_tag("http://www.rubyonrails.com/images/rails.png")) => %(<img alt="Rails" src="http://www.rubyonrails.com/images/rails.png" />),
%(image_tag("//www.rubyonrails.com/images/rails.png")) => %(<img alt="Rails" src="//www.rubyonrails.com/images/rails.png" />),
- %(image_tag("mouse.png", :mouseover => "/images/mouse_over.png")) => %(<img alt="Mouse" onmouseover="this.src='/images/mouse_over.png'" onmouseout="this.src='/images/mouse.png'" src="/images/mouse.png" />),
- %(image_tag("mouse.png", :mouseover => image_path("mouse_over.png"))) => %(<img alt="Mouse" onmouseover="this.src='/images/mouse_over.png'" onmouseout="this.src='/images/mouse.png'" src="/images/mouse.png" />),
- %(image_tag("mouse.png", :alt => nil)) => %(<img src="/images/mouse.png" />)
+ %(image_tag("mouse.png", :alt => nil)) => %(<img src="/images/mouse.png" />),
+ %(image_tag("data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==", :alt => nil)) => %(<img src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" />),
}
FaviconLinkToTag = {
@@ -1323,8 +1322,6 @@ class AssetTagHelperNonVhostTest < ActionView::TestCase
assert_dom_equal(%(/collaboration/hieraki/javascripts/xmlhr.js), javascript_path("xmlhr"))
assert_dom_equal(%(/collaboration/hieraki/stylesheets/style.css), stylesheet_path("style"))
assert_dom_equal(%(/collaboration/hieraki/images/xml.png), image_path("xml.png"))
- assert_dom_equal(%(<img alt="Mouse" onmouseover="this.src='/collaboration/hieraki/images/mouse_over.png'" onmouseout="this.src='/collaboration/hieraki/images/mouse.png'" src="/collaboration/hieraki/images/mouse.png" />), image_tag("mouse.png", :mouseover => "/images/mouse_over.png"))
- assert_dom_equal(%(<img alt="Mouse2" onmouseover="this.src='/collaboration/hieraki/images/mouse_over2.png'" onmouseout="this.src='/collaboration/hieraki/images/mouse2.png'" src="/collaboration/hieraki/images/mouse2.png" />), image_tag("mouse2.png", :mouseover => image_path("mouse_over2.png")))
end
def test_should_ignore_relative_root_path_on_complete_url
@@ -1337,8 +1334,6 @@ class AssetTagHelperNonVhostTest < ActionView::TestCase
assert_dom_equal(%(gopher://assets.example.com/collaboration/hieraki/javascripts/xmlhr.js), javascript_path("xmlhr"))
assert_dom_equal(%(gopher://assets.example.com/collaboration/hieraki/stylesheets/style.css), stylesheet_path("style"))
assert_dom_equal(%(gopher://assets.example.com/collaboration/hieraki/images/xml.png), image_path("xml.png"))
- assert_dom_equal(%(<img alt="Mouse" onmouseover="this.src='gopher://assets.example.com/collaboration/hieraki/images/mouse_over.png'" onmouseout="this.src='gopher://assets.example.com/collaboration/hieraki/images/mouse.png'" src="gopher://assets.example.com/collaboration/hieraki/images/mouse.png" />), image_tag("mouse.png", :mouseover => "/images/mouse_over.png"))
- assert_dom_equal(%(<img alt="Mouse2" onmouseover="this.src='gopher://assets.example.com/collaboration/hieraki/images/mouse_over2.png'" onmouseout="this.src='gopher://assets.example.com/collaboration/hieraki/images/mouse2.png'" src="gopher://assets.example.com/collaboration/hieraki/images/mouse2.png" />), image_tag("mouse2.png", :mouseover => image_path("mouse_over2.png")))
end
def test_should_compute_proper_path_with_asset_host_and_default_protocol
@@ -1347,8 +1342,6 @@ class AssetTagHelperNonVhostTest < ActionView::TestCase
assert_dom_equal(%(gopher://assets.example.com/collaboration/hieraki/javascripts/xmlhr.js), javascript_path("xmlhr"))
assert_dom_equal(%(gopher://assets.example.com/collaboration/hieraki/stylesheets/style.css), stylesheet_path("style"))
assert_dom_equal(%(gopher://assets.example.com/collaboration/hieraki/images/xml.png), image_path("xml.png"))
- assert_dom_equal(%(<img alt="Mouse" onmouseover="this.src='gopher://assets.example.com/collaboration/hieraki/images/mouse_over.png'" onmouseout="this.src='gopher://assets.example.com/collaboration/hieraki/images/mouse.png'" src="gopher://assets.example.com/collaboration/hieraki/images/mouse.png" />), image_tag("mouse.png", :mouseover => "/images/mouse_over.png"))
- assert_dom_equal(%(<img alt="Mouse2" onmouseover="this.src='gopher://assets.example.com/collaboration/hieraki/images/mouse_over2.png'" onmouseout="this.src='gopher://assets.example.com/collaboration/hieraki/images/mouse2.png'" src="gopher://assets.example.com/collaboration/hieraki/images/mouse2.png" />), image_tag("mouse2.png", :mouseover => image_path("mouse_over2.png")))
end
def test_should_compute_proper_url_with_asset_host
diff --git a/actionpack/test/template/form_options_helper_test.rb b/actionpack/test/template/form_options_helper_test.rb
index 2c0da8473a..9b64bc9d81 100644
--- a/actionpack/test/template/form_options_helper_test.rb
+++ b/actionpack/test/template/form_options_helper_test.rb
@@ -296,10 +296,34 @@ class FormOptionsHelperTest < ActionView::TestCase
)
end
- def test_grouped_options_for_select_with_selected_and_prompt
+ def test_grouped_options_for_select_with_optional_divider
assert_dom_equal(
+ "<optgroup label=\"----------\"><option value=\"US\">US</option>\n<option value=\"Canada\">Canada</option></optgroup><optgroup label=\"----------\"><option value=\"GB\">GB</option>\n<option value=\"Germany\">Germany</option></optgroup>",
+
+ grouped_options_for_select([['US',"Canada"] , ["GB", "Germany"]], divider: "----------")
+ )
+ end
+
+ def test_grouped_options_for_select_with_selected_and_prompt_deprecated
+ assert_deprecated 'Passing the prompt to grouped_options_for_select as an argument is deprecated. Please pass it in an options hash.' do
+ assert_dom_equal(
"<option value=\"\">Choose a product...</option><optgroup label=\"Hats\"><option value=\"Baseball Cap\">Baseball Cap</option>\n<option selected=\"selected\" value=\"Cowboy Hat\">Cowboy Hat</option></optgroup>",
grouped_options_for_select([["Hats", ["Baseball Cap","Cowboy Hat"]]], "Cowboy Hat", "Choose a product...")
+ )
+ end
+ end
+
+ def test_grouped_options_for_select_with_selected_and_prompt
+ assert_dom_equal(
+ "<option value=\"\">Choose a product...</option><optgroup label=\"Hats\"><option value=\"Baseball Cap\">Baseball Cap</option>\n<option selected=\"selected\" value=\"Cowboy Hat\">Cowboy Hat</option></optgroup>",
+ grouped_options_for_select([["Hats", ["Baseball Cap","Cowboy Hat"]]], "Cowboy Hat", prompt: "Choose a product...")
+ )
+ end
+
+ def test_grouped_options_for_select_with_selected_and_prompt_true
+ assert_dom_equal(
+ "<option value=\"\">Please select</option><optgroup label=\"Hats\"><option value=\"Baseball Cap\">Baseball Cap</option>\n<option selected=\"selected\" value=\"Cowboy Hat\">Cowboy Hat</option></optgroup>",
+ grouped_options_for_select([["Hats", ["Baseball Cap","Cowboy Hat"]]], "Cowboy Hat", prompt: true)
)
end
@@ -307,10 +331,18 @@ class FormOptionsHelperTest < ActionView::TestCase
assert grouped_options_for_select([["Hats", ["Baseball Cap","Cowboy Hat"]]]).html_safe?
end
+ def test_grouped_options_for_select_with_prompt_returns_html_escaped_string_deprecated
+ ActiveSupport::Deprecation.silence do
+ assert_dom_equal(
+ "<option value=\"\">&lt;Choose One&gt;</option><optgroup label=\"Hats\"><option value=\"Baseball Cap\">Baseball Cap</option>\n<option value=\"Cowboy Hat\">Cowboy Hat</option></optgroup>",
+ grouped_options_for_select([["Hats", ["Baseball Cap","Cowboy Hat"]]], nil, '<Choose One>'))
+ end
+ end
+
def test_grouped_options_for_select_with_prompt_returns_html_escaped_string
assert_dom_equal(
"<option value=\"\">&lt;Choose One&gt;</option><optgroup label=\"Hats\"><option value=\"Baseball Cap\">Baseball Cap</option>\n<option value=\"Cowboy Hat\">Cowboy Hat</option></optgroup>",
- grouped_options_for_select([["Hats", ["Baseball Cap","Cowboy Hat"]]], nil, '<Choose One>'))
+ grouped_options_for_select([["Hats", ["Baseball Cap","Cowboy Hat"]]], nil, prompt: '<Choose One>'))
end
def test_optgroups_with_with_options_with_hash
@@ -634,6 +666,48 @@ class FormOptionsHelperTest < ActionView::TestCase
)
end
+ def test_required_select
+ assert_dom_equal(
+ %(<select id="post_category" name="post[category]" required="required"><option value=""></option>\n<option value="abe">abe</option>\n<option value="mus">mus</option>\n<option value="hest">hest</option></select>),
+ select("post", "category", %w(abe mus hest), {}, required: true)
+ )
+ end
+
+ def test_required_select_with_include_blank_prompt
+ assert_dom_equal(
+ %(<select id="post_category" name="post[category]" required="required"><option value="">Select one</option>\n<option value="abe">abe</option>\n<option value="mus">mus</option>\n<option value="hest">hest</option></select>),
+ select("post", "category", %w(abe mus hest), { include_blank: "Select one" }, required: true)
+ )
+ end
+
+ def test_required_select_with_prompt
+ assert_dom_equal(
+ %(<select id="post_category" name="post[category]" required="required"><option value="">Select one</option>\n<option value="abe">abe</option>\n<option value="mus">mus</option>\n<option value="hest">hest</option></select>),
+ select("post", "category", %w(abe mus hest), { prompt: "Select one" }, required: true)
+ )
+ end
+
+ def test_required_select_display_size_equals_to_one
+ assert_dom_equal(
+ %(<select id="post_category" name="post[category]" required="required" size="1"><option value=""></option>\n<option value="abe">abe</option>\n<option value="mus">mus</option>\n<option value="hest">hest</option></select>),
+ select("post", "category", %w(abe mus hest), {}, required: true, size: 1)
+ )
+ end
+
+ def test_required_select_with_display_size_bigger_than_one
+ assert_dom_equal(
+ %(<select id="post_category" name="post[category]" required="required" size="2"><option value="abe">abe</option>\n<option value="mus">mus</option>\n<option value="hest">hest</option></select>),
+ select("post", "category", %w(abe mus hest), {}, required: true, size: 2)
+ )
+ end
+
+ def test_required_select_with_multiple_option
+ assert_dom_equal(
+ %(<input name="post[category][]" type="hidden" value=""/><select id="post_category" multiple="multiple" name="post[category][]" required="required"><option value="abe">abe</option>\n<option value="mus">mus</option>\n<option value="hest">hest</option></select>),
+ select("post", "category", %w(abe mus hest), {}, required: true, multiple: true)
+ )
+ end
+
def test_select_with_fixnum
@post = Post.new
@post.category = ""
diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb
index 1e92ff99ff..7a645217b8 100644
--- a/actionpack/test/template/form_tag_helper_test.rb
+++ b/actionpack/test/template/form_tag_helper_test.rb
@@ -375,14 +375,7 @@ class FormTagHelperTest < ActionView::TestCase
def test_submit_tag
assert_dom_equal(
%(<input name='commit' data-disable-with="Saving..." onclick="alert('hello!')" type="submit" value="Save" />),
- submit_tag("Save", :disable_with => "Saving...", :onclick => "alert('hello!')")
- )
- end
-
- def test_submit_tag_with_no_onclick_options
- assert_dom_equal(
- %(<input name='commit' data-disable-with="Saving..." type="submit" value="Save" />),
- submit_tag("Save", :disable_with => "Saving...")
+ submit_tag("Save", 'data-disable-with' => "Saving...", :onclick => "alert('hello!')")
)
end
@@ -393,13 +386,6 @@ class FormTagHelperTest < ActionView::TestCase
)
end
- def test_submit_tag_with_confirmation_and_with_disable_with
- assert_dom_equal(
- %(<input name="commit" data-disable-with="Saving..." data-confirm="Are you sure?" type="submit" value="Save" />),
- submit_tag("Save", :disable_with => "Saving...", :confirm => "Are you sure?")
- )
- end
-
def test_button_tag
assert_dom_equal(
%(<button name="button" type="submit">Button</button>),
diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb
index e7f5f100bf..88ed8664c2 100644
--- a/actionpack/test/template/render_test.rb
+++ b/actionpack/test/template/render_test.rb
@@ -79,6 +79,14 @@ module RenderTestCases
assert_equal "<h1>No Comment</h1>\n", @view.render(:template => "comments/empty", :handlers => [:builder])
end
+ def test_render_raw_template_with_handlers
+ assert_equal "<%= hello_world %>\n", @view.render(:template => "plain_text")
+ end
+
+ def test_render_raw_template_with_quotes
+ assert_equal %q;Here are some characters: !@#$%^&*()-="'}{`; + "\n", @view.render(:template => "plain_text_with_characters")
+ end
+
def test_render_file_with_localization_on_context_level
old_locale, @view.locale = @view.locale, :da
assert_equal "Hey verden", @view.render(:file => "test/hello_world")
diff --git a/actionpack/test/template/template_test.rb b/actionpack/test/template/template_test.rb
index 8c57ada587..322bea3fb0 100644
--- a/actionpack/test/template/template_test.rb
+++ b/actionpack/test/template/template_test.rb
@@ -48,7 +48,7 @@ class TestERBTemplate < ActiveSupport::TestCase
end
def new_template(body = "<%= hello %>", details = {})
- ActionView::Template.new(body, "hello template", ERBHandler, {:virtual_path => "hello"}.merge!(details))
+ ActionView::Template.new(body, "hello template", details.fetch(:handler) { ERBHandler }, {:virtual_path => "hello"}.merge!(details))
end
def render(locals = {})
@@ -64,6 +64,11 @@ class TestERBTemplate < ActiveSupport::TestCase
assert_equal "Hello", render
end
+ def test_raw_template
+ @template = new_template("<%= hello %>", :handler => ActionView::Template::Handlers::Raw.new)
+ assert_equal "<%= hello %>", render
+ end
+
def test_template_loses_its_source_after_rendering
@template = new_template
render
diff --git a/actionpack/test/template/testing/fixture_resolver_test.rb b/actionpack/test/template/testing/fixture_resolver_test.rb
index de83540468..9649f349cb 100644
--- a/actionpack/test/template/testing/fixture_resolver_test.rb
+++ b/actionpack/test/template/testing/fixture_resolver_test.rb
@@ -8,8 +8,8 @@ class FixtureResolverTest < ActiveSupport::TestCase
end
def test_should_return_template_for_declared_path
- resolver = ActionView::FixtureResolver.new("arbitrary/path" => "this text")
- templates = resolver.find_all("path", "arbitrary", false, {:locale => [], :formats => [:html], :handlers => []})
+ resolver = ActionView::FixtureResolver.new("arbitrary/path.erb" => "this text")
+ templates = resolver.find_all("path", "arbitrary", false, {:locale => [], :formats => [:html], :handlers => [:erb]})
assert_equal 1, templates.size, "expected one template"
assert_equal "this text", templates.first.source
assert_equal "arbitrary/path", templates.first.virtual_path
diff --git a/actionpack/test/template/testing/null_resolver_test.rb b/actionpack/test/template/testing/null_resolver_test.rb
index e142506e6a..535ad3ab14 100644
--- a/actionpack/test/template/testing/null_resolver_test.rb
+++ b/actionpack/test/template/testing/null_resolver_test.rb
@@ -3,10 +3,10 @@ require 'abstract_unit'
class NullResolverTest < ActiveSupport::TestCase
def test_should_return_template_for_any_path
resolver = ActionView::NullResolver.new()
- templates = resolver.find_all("path", "arbitrary", false, {:locale => [], :formats => [:html], :handlers => []})
+ templates = resolver.find_all("path.erb", "arbitrary", false, {:locale => [], :formats => [:html], :handlers => []})
assert_equal 1, templates.size, "expected one template"
assert_equal "Template generated by Null Resolver", templates.first.source
- assert_equal "arbitrary/path", templates.first.virtual_path
+ assert_equal "arbitrary/path.erb", templates.first.virtual_path
assert_equal [:html], templates.first.formats
end
end
diff --git a/actionpack/test/template/text_helper_test.rb b/actionpack/test/template/text_helper_test.rb
index 5865b7f23c..e5cb273518 100644
--- a/actionpack/test/template/text_helper_test.rb
+++ b/actionpack/test/template/text_helper_test.rb
@@ -46,6 +46,14 @@ class TextHelperTest < ActionView::TestCase
assert_equal "<p><b> test with unsafe string </b><script>code!</script></p>", simple_format("<b> test with unsafe string </b><script>code!</script>", {}, :sanitize => false)
end
+ def test_simple_format_with_custom_wrapper
+ assert_equal "<div></div>", simple_format(nil, {}, :wrapper_tag => "div")
+ end
+
+ def test_simple_format_with_custom_wrapper_and_multi_line_breaks
+ assert_equal "<div>We want to put a wrapper...</div>\n\n<div>...right there.</div>", simple_format("We want to put a wrapper...\n\n...right there.", {}, :wrapper_tag => "div")
+ end
+
def test_simple_format_should_not_change_the_text_passed
text = "<b>Ok</b><script>code!</script>"
text_clone = text.dup
diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb
index eaa8bdbd26..fb5b35bac6 100644
--- a/actionpack/test/template/url_helper_test.rb
+++ b/actionpack/test/template/url_helper_test.rb
@@ -97,7 +97,7 @@ class UrlHelperTest < ActiveSupport::TestCase
def test_button_to_with_javascript_disable_with
assert_dom_equal(
"<form method=\"post\" action=\"http://www.example.com\" class=\"button_to\"><div><input data-disable-with=\"Greeting...\" type=\"submit\" value=\"Hello\" /></div></form>",
- button_to("Hello", "http://www.example.com", :disable_with => "Greeting...")
+ button_to("Hello", "http://www.example.com", 'data-disable-with' => "Greeting...")
)
end
@@ -112,20 +112,6 @@ class UrlHelperTest < ActiveSupport::TestCase
)
end
- def test_button_to_with_remote_and_javascript_disable_with
- assert_dom_equal(
- "<form method=\"post\" action=\"http://www.example.com\" class=\"button_to\" data-remote=\"true\"><div><input data-disable-with=\"Greeting...\" type=\"submit\" value=\"Hello\" /></div></form>",
- button_to("Hello", "http://www.example.com", :remote => true, :disable_with => "Greeting...")
- )
- end
-
- def test_button_to_with_remote_and_javascript_confirm_and_javascript_disable_with
- assert_dom_equal(
- "<form method=\"post\" action=\"http://www.example.com\" class=\"button_to\" data-remote=\"true\"><div><input data-disable-with=\"Greeting...\" data-confirm=\"Are you sure?\" type=\"submit\" value=\"Hello\" /></div></form>",
- button_to("Hello", "http://www.example.com", :remote => true, :confirm => "Are you sure?", :disable_with => "Greeting...")
- )
- end
-
def test_button_to_with_remote_false
assert_dom_equal(
"<form method=\"post\" action=\"http://www.example.com\" class=\"button_to\"><div><input type=\"submit\" value=\"Hello\" /></div></form>",
diff --git a/actionpack/test/ts_isolated.rb b/actionpack/test/ts_isolated.rb
index ae2a0c95f6..595b4018e9 100644
--- a/actionpack/test/ts_isolated.rb
+++ b/actionpack/test/ts_isolated.rb
@@ -1,6 +1,3 @@
-$:.unshift(File.dirname(__FILE__))
-$:.unshift(File.dirname(__FILE__) + '/../../activesupport/lib')
-
require 'minitest/autorun'
require 'rbconfig'
require 'abstract_unit'
diff --git a/activemodel/README.rdoc b/activemodel/README.rdoc
index 0c7089598c..b4565b5881 100644
--- a/activemodel/README.rdoc
+++ b/activemodel/README.rdoc
@@ -41,7 +41,7 @@ behavior out of the box:
include ActiveModel::AttributeMethods
attribute_method_prefix 'clear_'
- define_attribute_methods [:name, :age]
+ define_attribute_methods :name, :age
attr_accessor :name, :age
diff --git a/activemodel/lib/active_model.rb b/activemodel/lib/active_model.rb
index 2586147a20..ded1b752df 100644
--- a/activemodel/lib/active_model.rb
+++ b/activemodel/lib/active_model.rb
@@ -21,8 +21,6 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
-activesupport_path = File.expand_path('../../../activesupport/lib', __FILE__)
-$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
require 'active_support'
require 'active_model/version'
@@ -59,5 +57,6 @@ module ActiveModel
end
end
-require 'active_support/i18n'
-I18n.load_path << File.dirname(__FILE__) + '/active_model/locale/en.yml'
+ActiveSupport.on_load(:i18n) do
+ I18n.load_path << File.dirname(__FILE__) + '/active_model/locale/en.yml'
+end
diff --git a/activemodel/lib/active_model/attribute_methods.rb b/activemodel/lib/active_model/attribute_methods.rb
index 25d5d84ce6..99918fdb96 100644
--- a/activemodel/lib/active_model/attribute_methods.rb
+++ b/activemodel/lib/active_model/attribute_methods.rb
@@ -28,7 +28,7 @@ module ActiveModel
# attribute_method_affix :prefix => 'reset_', :suffix => '_to_default!'
# attribute_method_suffix '_contrived?'
# attribute_method_prefix 'clear_'
- # define_attribute_methods ['name']
+ # define_attribute_methods 'name'
#
# attr_accessor :name
#
@@ -86,7 +86,7 @@ module ActiveModel
# include ActiveModel::AttributeMethods
# attr_accessor :name
# attribute_method_prefix 'clear_'
- # define_attribute_methods [:name]
+ # define_attribute_methods :name
#
# private
#
@@ -124,7 +124,7 @@ module ActiveModel
# include ActiveModel::AttributeMethods
# attr_accessor :name
# attribute_method_suffix '_short?'
- # define_attribute_methods [:name]
+ # define_attribute_methods :name
#
# private
#
@@ -162,7 +162,7 @@ module ActiveModel
# include ActiveModel::AttributeMethods
# attr_accessor :name
# attribute_method_affix :prefix => 'reset_', :suffix => '_to_default!'
- # define_attribute_methods [:name]
+ # define_attribute_methods :name
#
# private
#
@@ -216,7 +216,7 @@ module ActiveModel
# # Call to define_attribute_methods must appear after the
# # attribute_method_prefix, attribute_method_suffix or
# # attribute_method_affix declares.
- # define_attribute_methods [:name, :age, :address]
+ # define_attribute_methods :name, :age, :address
#
# private
#
@@ -224,8 +224,8 @@ module ActiveModel
# ...
# end
# end
- def define_attribute_methods(attr_names)
- attr_names.each { |attr_name| define_attribute_method(attr_name) }
+ def define_attribute_methods(*attr_names)
+ attr_names.flatten.each { |attr_name| define_attribute_method(attr_name) }
end
def define_attribute_method(attr_name)
@@ -255,11 +255,7 @@ module ActiveModel
# Returns true if the attribute methods defined have been generated.
def generated_attribute_methods #:nodoc:
- @generated_attribute_methods ||= begin
- mod = Module.new
- include mod
- mod
- end
+ @generated_attribute_methods ||= Module.new.tap { |mod| include mod }
end
protected
diff --git a/activemodel/lib/active_model/dirty.rb b/activemodel/lib/active_model/dirty.rb
index 3d35b5bb6f..3f2fd12db7 100644
--- a/activemodel/lib/active_model/dirty.rb
+++ b/activemodel/lib/active_model/dirty.rb
@@ -30,7 +30,7 @@ module ActiveModel
#
# include ActiveModel::Dirty
#
- # define_attribute_methods [:name]
+ # define_attribute_methods :name
#
# def name
# @name
diff --git a/activemodel/lib/active_model/mass_assignment_security.rb b/activemodel/lib/active_model/mass_assignment_security.rb
index 5e5405fe27..893fbf92c3 100644
--- a/activemodel/lib/active_model/mass_assignment_security.rb
+++ b/activemodel/lib/active_model/mass_assignment_security.rb
@@ -229,7 +229,7 @@ module ActiveModel
protected
def sanitize_for_mass_assignment(attributes, role = nil)
- _mass_assignment_sanitizer.sanitize(attributes, mass_assignment_authorizer(role))
+ _mass_assignment_sanitizer.sanitize(self.class, attributes, mass_assignment_authorizer(role))
end
def mass_assignment_authorizer(role)
diff --git a/activemodel/lib/active_model/mass_assignment_security/sanitizer.rb b/activemodel/lib/active_model/mass_assignment_security/sanitizer.rb
index 4491e07a72..44ce5a489d 100644
--- a/activemodel/lib/active_model/mass_assignment_security/sanitizer.rb
+++ b/activemodel/lib/active_model/mass_assignment_security/sanitizer.rb
@@ -2,18 +2,18 @@ module ActiveModel
module MassAssignmentSecurity
class Sanitizer
# Returns all attributes not denied by the authorizer.
- def sanitize(attributes, authorizer)
+ def sanitize(klass, attributes, authorizer)
rejected = []
sanitized_attributes = attributes.reject do |key, value|
rejected << key if authorizer.deny?(key)
end
- process_removed_attributes(rejected) unless rejected.empty?
+ process_removed_attributes(klass, rejected) unless rejected.empty?
sanitized_attributes
end
protected
- def process_removed_attributes(attrs)
+ def process_removed_attributes(klass, attrs)
raise NotImplementedError, "#process_removed_attributes(attrs) suppose to be overwritten"
end
end
@@ -32,8 +32,21 @@ module ActiveModel
@target.respond_to?(:logger) && @target.logger
end
- def process_removed_attributes(attrs)
- logger.warn "Can't mass-assign protected attributes: #{attrs.join(', ')}" if logger?
+ def backtrace
+ if defined? Rails
+ Rails.backtrace_cleaner.clean(caller)
+ else
+ caller
+ end
+ end
+
+ def process_removed_attributes(klass, attrs)
+ if logger?
+ logger.warn do
+ "WARNING: Can't mass-assign protected attributes for #{klass.name}: #{attrs.join(', ')}\n" +
+ backtrace.map { |trace| "\t#{trace}" }.join("\n")
+ end
+ end
end
end
@@ -42,9 +55,9 @@ module ActiveModel
super()
end
- def process_removed_attributes(attrs)
+ def process_removed_attributes(klass, attrs)
return if (attrs - insensitive_attributes).empty?
- raise ActiveModel::MassAssignmentSecurity::Error.new(attrs)
+ raise ActiveModel::MassAssignmentSecurity::Error.new(klass, attrs)
end
def insensitive_attributes
@@ -53,8 +66,8 @@ module ActiveModel
end
class Error < StandardError
- def initialize(attrs)
- super("Can't mass-assign protected attributes: #{attrs.join(', ')}")
+ def initialize(klass, attrs)
+ super("Can't mass-assign protected attributes for #{klass.name}: #{attrs.join(', ')}")
end
end
end
diff --git a/activemodel/lib/active_model/secure_password.rb b/activemodel/lib/active_model/secure_password.rb
index 8711b24124..3eab745c89 100644
--- a/activemodel/lib/active_model/secure_password.rb
+++ b/activemodel/lib/active_model/secure_password.rb
@@ -6,8 +6,9 @@ module ActiveModel
# Adds methods to set and authenticate against a BCrypt password.
# This mechanism requires you to have a password_digest attribute.
#
- # Validations for presence of password, confirmation of password (using
+ # Validations for presence of password on create, confirmation of password (using
# a "password_confirmation" attribute) are automatically added.
+ # If you wish to turn off validations, pass 'validations: false' as an argument.
# You can add more validations by hand if need be.
#
# You need to add bcrypt-ruby (~> 3.0.0) to Gemfile to use has_secure_password:
@@ -31,16 +32,20 @@ module ActiveModel
# user.authenticate("mUc3m00RsqyRe") # => user
# User.find_by_name("david").try(:authenticate, "notright") # => false
# User.find_by_name("david").try(:authenticate, "mUc3m00RsqyRe") # => user
- def has_secure_password
+ def has_secure_password(options = {})
# Load bcrypt-ruby only when has_secure_password is used.
# This is to avoid ActiveModel (and by extension the entire framework) being dependent on a binary library.
gem 'bcrypt-ruby', '~> 3.0.0'
require 'bcrypt'
attr_reader :password
-
- validates_confirmation_of :password
- validates_presence_of :password_digest
+
+ if options.fetch(:validations, true)
+ validates_confirmation_of :password
+ validates_presence_of :password, :on => :create
+ end
+
+ before_create { raise "Password digest missing on new record" if password_digest.blank? }
include InstanceMethodsOnActivation
diff --git a/activemodel/lib/active_model/serialization.rb b/activemodel/lib/active_model/serialization.rb
index 4403ef060b..3751e4a741 100644
--- a/activemodel/lib/active_model/serialization.rb
+++ b/activemodel/lib/active_model/serialization.rb
@@ -64,7 +64,7 @@ module ActiveModel
# person.to_json # => "{\"name\":\"Bob\"}"
# person.to_xml # => "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<serial-person...
#
- # Valid options are <tt>:only</tt>, <tt>:except</tt>, <tt>:methods</tt> and <tt>include</tt>.
+ # Valid options are <tt>:only</tt>, <tt>:except</tt>, <tt>:methods</tt> and <tt>:include</tt>.
# The following are all valid examples:
#
# person.serializable_hash(:only => 'name')
@@ -87,8 +87,8 @@ module ActiveModel
Array(options[:methods]).each { |m| hash[m.to_s] = send(m) if respond_to?(m) }
serializable_add_includes(options) do |association, records, opts|
- hash[association.to_s] = if records.is_a?(Enumerable)
- records.map { |a| a.serializable_hash(opts) }
+ hash[association.to_s] = if records.respond_to?(:to_ary)
+ records.to_ary.map { |a| a.serializable_hash(opts) }
else
records.serializable_hash(opts)
end
diff --git a/activemodel/lib/active_model/serializers/xml.rb b/activemodel/lib/active_model/serializers/xml.rb
index 5084298210..b78f1ff3f3 100644
--- a/activemodel/lib/active_model/serializers/xml.rb
+++ b/activemodel/lib/active_model/serializers/xml.rb
@@ -115,7 +115,9 @@ module ActiveModel
merged_options = opts.merge(options.slice(:builder, :indent))
merged_options[:skip_instruct] = true
- if records.is_a?(Enumerable)
+ if records.respond_to?(:to_ary)
+ records = records.to_ary
+
tag = ActiveSupport::XmlMini.rename_key(association.to_s, options)
type = options[:skip_types] ? { } : {:type => "array"}
association_name = association.to_s.singularize
diff --git a/activemodel/lib/active_model/validations.rb b/activemodel/lib/active_model/validations.rb
index 3ed72bae3b..611e9ffd55 100644
--- a/activemodel/lib/active_model/validations.rb
+++ b/activemodel/lib/active_model/validations.rb
@@ -178,6 +178,12 @@ module ActiveModel
end
end
+ # Clean the +Errors+ object if instance is duped
+ def initialize_dup(other) # :nodoc:
+ @errors = nil
+ super
+ end
+
# Returns the +Errors+ object that holds all information about attribute error messages.
def errors
@errors ||= Errors.new(self)
diff --git a/activemodel/lib/active_model/validations/acceptance.rb b/activemodel/lib/active_model/validations/acceptance.rb
index e628c6f306..38abd0c1fa 100644
--- a/activemodel/lib/active_model/validations/acceptance.rb
+++ b/activemodel/lib/active_model/validations/acceptance.rb
@@ -23,7 +23,7 @@ module ActiveModel
module HelperMethods
# Encapsulates the pattern of wanting to validate the acceptance of a
- # terms of service check box (or similar agreement). Example:
+ # terms of service check box (or similar agreement).
#
# class Person < ActiveRecord::Base
# validates_acceptance_of :terms_of_service
@@ -59,7 +59,7 @@ module ActiveModel
# The method, proc or string should return or evaluate to a true or
# false value.
# * <tt>:strict</tt> - Specifies whether validation should be strict.
- # See <tt>ActiveModel::Validation#validates!</tt> for more information
+ # See <tt>ActiveModel::Validation#validates!</tt> for more information.
def validates_acceptance_of(*attr_names)
validates_with AcceptanceValidator, _merge_attributes(attr_names)
end
diff --git a/activemodel/lib/active_model/validations/confirmation.rb b/activemodel/lib/active_model/validations/confirmation.rb
index 69ab74734d..ede34d15bc 100644
--- a/activemodel/lib/active_model/validations/confirmation.rb
+++ b/activemodel/lib/active_model/validations/confirmation.rb
@@ -19,7 +19,7 @@ module ActiveModel
module HelperMethods
# Encapsulates the pattern of wanting to validate a password or email
- # address field with a confirmation. For example:
+ # address field with a confirmation.
#
# Model:
# class Person < ActiveRecord::Base
@@ -60,7 +60,7 @@ module ActiveModel
# <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
# * <tt>:strict</tt> - Specifies whether validation should be strict.
- # See <tt>ActiveModel::Validation#validates!</tt> for more information
+ # See <tt>ActiveModel::Validation#validates!</tt> for more information.
def validates_confirmation_of(*attr_names)
validates_with ConfirmationValidator, _merge_attributes(attr_names)
end
diff --git a/activemodel/lib/active_model/validations/exclusion.rb b/activemodel/lib/active_model/validations/exclusion.rb
index 5fedb1978b..4f09679541 100644
--- a/activemodel/lib/active_model/validations/exclusion.rb
+++ b/activemodel/lib/active_model/validations/exclusion.rb
@@ -15,34 +15,42 @@ module ActiveModel
end
module HelperMethods
- # Validates that the value of the specified attribute is not in a particular enumerable object.
+ # Validates that the value of the specified attribute is not in a
+ # particular enumerable object.
#
# class Person < ActiveRecord::Base
# validates_exclusion_of :username, :in => %w( admin superuser ), :message => "You don't belong here"
# validates_exclusion_of :age, :in => 30..60, :message => "This site is only for under 30 and over 60"
# validates_exclusion_of :format, :in => %w( mov avi ), :message => "extension %{value} is not allowed"
- # validates_exclusion_of :password, :in => lambda { |p| [p.username, p.first_name] }, :message => "should not be the same as your username or first name"
+ # validates_exclusion_of :password, :in => lambda { |p| [p.username, p.first_name] },
+ # :message => "should not be the same as your username or first name"
# end
#
# Configuration options:
- # * <tt>:in</tt> - An enumerable object of items that the value shouldn't be part of.
- # This can be supplied as a proc or lambda which returns an enumerable. If the enumerable
- # is a range the test is performed with <tt>Range#cover?</tt>
- # (backported in Active Support for 1.8), otherwise with <tt>include?</tt>.
- # * <tt>:message</tt> - Specifies a custom error message (default is: "is reserved").
- # * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute is +nil+ (default is +false+).
- # * <tt>:allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is +false+).
+ # * <tt>:in</tt> - An enumerable object of items that the value shouldn't be
+ # part of. This can be supplied as a proc or lambda which returns an
+ # enumerable. If the enumerable is a range the test is performed with
+ # <tt>Range#cover?</tt> (backported in Active Support for 1.8), otherwise
+ # with <tt>include?</tt>.
+ # * <tt>:message</tt> - Specifies a custom error message (default is: "is
+ # reserved").
+ # * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute
+ # is +nil+ (default is +false+).
+ # * <tt>:allow_blank</tt> - If set to true, skips this validation if the
+ # attribute is blank(default is +false+).
# * <tt>:on</tt> - Specifies when this validation is active. Runs in all
# validation contexts by default (+nil+), other options are <tt>:create</tt>
# and <tt>:update</tt>.
- # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
- # method, proc or string should return or evaluate to a true or false value.
- # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if
+ # the validation should occur (e.g. <tt>:if => :allow_validation</tt>, or
+ # <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The method, proc
+ # or string should return or evaluate to a true or false value.
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine
+ # if the validation should not occur (e.g. <tt>:unless => :skip_validation</tt>,
+ # or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
# * <tt>:strict</tt> - Specifies whether validation should be strict.
- # See <tt>ActiveModel::Validation#validates!</tt> for more information
+ # See <tt>ActiveModel::Validation#validates!</tt> for more information.
def validates_exclusion_of(*attr_names)
validates_with ExclusionValidator, _merge_attributes(attr_names)
end
diff --git a/activemodel/lib/active_model/validations/format.rb b/activemodel/lib/active_model/validations/format.rb
index d3faa8c6a6..dd87e312f9 100644
--- a/activemodel/lib/active_model/validations/format.rb
+++ b/activemodel/lib/active_model/validations/format.rb
@@ -42,50 +42,62 @@ module ActiveModel
end
module HelperMethods
- # Validates whether the value of the specified attribute is of the correct form, going by the regular expression provided.
- # You can require that the attribute matches the regular expression:
+ # Validates whether the value of the specified attribute is of the correct
+ # form, going by the regular expression provided.You can require that the
+ # attribute matches the regular expression:
#
# class Person < ActiveRecord::Base
# validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :create
# end
#
- # Alternatively, you can require that the specified attribute does _not_ match the regular expression:
+ # Alternatively, you can require that the specified attribute does _not_
+ # match the regular expression:
#
# class Person < ActiveRecord::Base
# validates_format_of :email, :without => /NOSPAM/
# end
#
- # You can also provide a proc or lambda which will determine the regular expression that will be used to validate the attribute
+ # You can also provide a proc or lambda which will determine the regular
+ # expression that will be used to validate the attribute.
#
# class Person < ActiveRecord::Base
# # Admin can have number as a first letter in their screen name
- # validates_format_of :screen_name, :with => lambda{ |person| person.admin? ? /\A[a-z0-9][a-z0-9_\-]*\Z/i : /\A[a-z][a-z0-9_\-]*\Z/i }
+ # validates_format_of :screen_name,
+ # :with => lambda{ |person| person.admin? ? /\A[a-z0-9][a-z0-9_\-]*\Z/i : /\A[a-z][a-z0-9_\-]*\Z/i }
# end
#
- # Note: use <tt>\A</tt> and <tt>\Z</tt> to match the start and end of the string, <tt>^</tt> and <tt>$</tt> match the start/end of a line.
+ # Note: use <tt>\A</tt> and <tt>\Z</tt> to match the start and end of the
+ # string, <tt>^</tt> and <tt>$</tt> match the start/end of a line.
#
- # You must pass either <tt>:with</tt> or <tt>:without</tt> as an option. In addition, both must be a regular expression
- # or a proc or lambda, or else an exception will be raised.
+ # You must pass either <tt>:with</tt> or <tt>:without</tt> as an option.
+ # In addition, both must be a regular expression or a proc or lambda, or
+ # else an exception will be raised.
#
# Configuration options:
# * <tt>:message</tt> - A custom error message (default is: "is invalid").
- # * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute is +nil+ (default is +false+).
- # * <tt>:allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is +false+).
- # * <tt>:with</tt> - Regular expression that if the attribute matches will result in a successful validation.
- # This can be provided as a proc or lambda returning regular expression which will be called at runtime.
- # * <tt>:without</tt> - Regular expression that if the attribute does not match will result in a successful validation.
- # This can be provided as a proc or lambda returning regular expression which will be called at runtime.
+ # * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute
+ # is +nil+ (default is +false+).
+ # * <tt>:allow_blank</tt> - If set to true, skips this validation if the
+ # attribute is blank (default is +false+).
+ # * <tt>:with</tt> - Regular expression that if the attribute matches will
+ # result in a successful validation. This can be provided as a proc or lambda
+ # returning regular expression which will be called at runtime.
+ # * <tt>:without</tt> - Regular expression that if the attribute does not match
+ # will result in a successful validation. This can be provided as a proc or
+ # lambda returning regular expression which will be called at runtime.
# * <tt>:on</tt> - Specifies when this validation is active. Runs in all
# validation contexts by default (+nil+), other options are <tt>:create</tt>
# and <tt>:update</tt>.
- # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
- # method, proc or string should return or evaluate to a true or false value.
- # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine
+ # if the validation should occur (e.g. <tt>:if => :allow_validation</tt>, or
+ # <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The method, proc
+ # or string should return or evaluate to a true or false value.
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine
+ # if the validation should not occur (e.g. <tt>:unless => :skip_validation</tt>,
+ # or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
# * <tt>:strict</tt> - Specifies whether validation should be strict.
- # See <tt>ActiveModel::Validation#validates!</tt> for more information
+ # See <tt>ActiveModel::Validation#validates!</tt> for more information.
def validates_format_of(*attr_names)
validates_with FormatValidator, _merge_attributes(attr_names)
end
diff --git a/activemodel/lib/active_model/validations/inclusion.rb b/activemodel/lib/active_model/validations/inclusion.rb
index 15ae7b1959..ffdbed0fc1 100644
--- a/activemodel/lib/active_model/validations/inclusion.rb
+++ b/activemodel/lib/active_model/validations/inclusion.rb
@@ -15,7 +15,8 @@ module ActiveModel
end
module HelperMethods
- # Validates whether the value of the specified attribute is available in a particular enumerable object.
+ # Validates whether the value of the specified attribute is available in a
+ # particular enumerable object.
#
# class Person < ActiveRecord::Base
# validates_inclusion_of :gender, :in => %w( m f )
@@ -29,20 +30,25 @@ module ActiveModel
# supplied as a proc or lambda which returns an enumerable. If the enumerable
# is a range the test is performed with <tt>Range#cover?</tt>
# (backported in Active Support for 1.8), otherwise with <tt>include?</tt>.
- # * <tt>:message</tt> - Specifies a custom error message (default is: "is not included in the list").
- # * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute is +nil+ (default is +false+).
- # * <tt>:allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is +false+).
+ # * <tt>:message</tt> - Specifies a custom error message (default is: "is not
+ # included in the list").
+ # * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute
+ # is +nil+ (default is +false+).
+ # * <tt>:allow_blank</tt> - If set to true, skips this validation if the
+ # attribute is blank (default is +false+).
# * <tt>:on</tt> - Specifies when this validation is active. Runs in all
# validation contexts by default (+nil+), other options are <tt>:create</tt>
# and <tt>:update</tt>.
- # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
- # method, proc or string should return or evaluate to a true or false value.
- # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if
+ # the validation should occur (e.g. <tt>:if => :allow_validation</tt>, or
+ # <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The method, proc
+ # or string should return or evaluate to a true or false value.
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine
+ # if the validation should not occur (e.g. <tt>:unless => :skip_validation</tt>,
+ # or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
# * <tt>:strict</tt> - Specifies whether validation should be strict.
- # See <tt>ActiveModel::Validation#validates!</tt> for more information
+ # See <tt>ActiveModel::Validation#validates!</tt> for more information.
def validates_inclusion_of(*attr_names)
validates_with InclusionValidator, _merge_attributes(attr_names)
end
diff --git a/activemodel/lib/active_model/validations/length.rb b/activemodel/lib/active_model/validations/length.rb
index 037f8c2db8..64b4fe2d74 100644
--- a/activemodel/lib/active_model/validations/length.rb
+++ b/activemodel/lib/active_model/validations/length.rb
@@ -72,35 +72,46 @@ module ActiveModel
# validates_length_of :user_name, :within => 6..20, :too_long => "pick a shorter name", :too_short => "pick a longer name"
# validates_length_of :zip_code, :minimum => 5, :too_short => "please enter at least 5 characters"
# validates_length_of :smurf_leader, :is => 4, :message => "papa is spelled with 4 characters... don't play me."
- # validates_length_of :essay, :minimum => 100, :too_short => "Your essay must be at least 100 words.", :tokenizer => lambda { |str| str.scan(/\w+/) }
+ # validates_length_of :essay, :minimum => 100, :too_short => "Your essay must be at least 100 words.",
+ # :tokenizer => lambda { |str| str.scan(/\w+/) }
# end
#
# Configuration options:
# * <tt>:minimum</tt> - The minimum size of the attribute.
# * <tt>:maximum</tt> - The maximum size of the attribute.
# * <tt>:is</tt> - The exact size of the attribute.
- # * <tt>:within</tt> - A range specifying the minimum and maximum size of the attribute.
+ # * <tt>:within</tt> - A range specifying the minimum and maximum size of the
+ # attribute.
# * <tt>:in</tt> - A synonym(or alias) for <tt>:within</tt>.
# * <tt>:allow_nil</tt> - Attribute may be +nil+; skip validation.
# * <tt>:allow_blank</tt> - Attribute may be blank; skip validation.
- # * <tt>:too_long</tt> - The error message if the attribute goes over the maximum (default is: "is too long (maximum is %{count} characters)").
- # * <tt>:too_short</tt> - The error message if the attribute goes under the minimum (default is: "is too short (min is %{count} characters)").
- # * <tt>:wrong_length</tt> - The error message if using the <tt>:is</tt> method and the attribute is the wrong size (default is: "is the wrong length (should be %{count} characters)").
- # * <tt>:message</tt> - The error message to use for a <tt>:minimum</tt>, <tt>:maximum</tt>, or <tt>:is</tt> violation. An alias of the appropriate <tt>too_long</tt>/<tt>too_short</tt>/<tt>wrong_length</tt> message.
+ # * <tt>:too_long</tt> - The error message if the attribute goes over the
+ # maximum (default is: "is too long (maximum is %{count} characters)").
+ # * <tt>:too_short</tt> - The error message if the attribute goes under the
+ # minimum (default is: "is too short (min is %{count} characters)").
+ # * <tt>:wrong_length</tt> - The error message if using the <tt>:is</tt> method
+ # and the attribute is the wrong size (default is: "is the wrong length
+ # (should be %{count} characters)").
+ # * <tt>:message</tt> - The error message to use for a <tt>:minimum</tt>,
+ # <tt>:maximum</tt>, or <tt>:is</tt> violation. An alias of the appropriate
+ # <tt>too_long</tt>/<tt>too_short</tt>/<tt>wrong_length</tt> message.
# * <tt>:on</tt> - Specifies when this validation is active. Runs in all
# validation contexts by default (+nil+), other options are <tt>:create</tt>
# and <tt>:update</tt>.
- # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
- # method, proc or string should return or evaluate to a true or false value.
- # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
- # method, proc or string should return or evaluate to a true or false value.
- # * <tt>:tokenizer</tt> - Specifies how to split up the attribute string. (e.g. <tt>:tokenizer => lambda {|str| str.scan(/\w+/)}</tt> to
- # count words as in above example.)
- # Defaults to <tt>lambda{ |value| value.split(//) }</tt> which counts individual characters.
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if
+ # the validation should occur (e.g. <tt>:if => :allow_validation</tt>, or
+ # <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The method, proc
+ # or string should return or evaluate to a true or false value.
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine
+ # if the validation should not occur (e.g. <tt>:unless => :skip_validation</tt>,
+ # or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The method,
+ # proc or string should return or evaluate to a true or false value.
+ # * <tt>:tokenizer</tt> - Specifies how to split up the attribute string.
+ # (e.g. <tt>:tokenizer => lambda {|str| str.scan(/\w+/)}</tt> to count words
+ # as in above example). Defaults to <tt>lambda{ |value| value.split(//) }</tt>
+ # which counts individual characters.
# * <tt>:strict</tt> - Specifies whether validation should be strict.
- # See <tt>ActiveModel::Validation#validates!</tt> for more information
+ # See <tt>ActiveModel::Validation#validates!</tt> for more information.
def validates_length_of(*attr_names)
validates_with LengthValidator, _merge_attributes(attr_names)
end
diff --git a/activemodel/lib/active_model/validations/numericality.rb b/activemodel/lib/active_model/validations/numericality.rb
index bb9f9679fc..40b5b92b84 100644
--- a/activemodel/lib/active_model/validations/numericality.rb
+++ b/activemodel/lib/active_model/validations/numericality.rb
@@ -79,9 +79,10 @@ module ActiveModel
end
module HelperMethods
- # Validates whether the value of the specified attribute is numeric by trying to convert it to
- # a float with Kernel.Float (if <tt>only_integer</tt> is false) or applying it to the regular expression
- # <tt>/\A[\+\-]?\d+\Z/</tt> (if <tt>only_integer</tt> is set to true).
+ # Validates whether the value of the specified attribute is numeric by trying
+ # to convert it to a float with Kernel.Float (if <tt>only_integer</tt> is false)
+ # or applying it to the regular expression <tt>/\A[\+\-]?\d+\Z/</tt> (if
+ # <tt>only_integer</tt> is set to true).
#
# class Person < ActiveRecord::Base
# validates_numericality_of :value, :on => :create
@@ -92,37 +93,50 @@ module ActiveModel
# * <tt>:on</tt> - Specifies when this validation is active. Runs in all
# validation contexts by default (+nil+), other options are <tt>:create</tt>
# and <tt>:update</tt>.
- # * <tt>:only_integer</tt> - Specifies whether the value has to be an integer, e.g. an integral value (default is +false+).
- # * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+ (default is +false+). Notice that for fixnum and float columns empty strings are converted to +nil+.
- # * <tt>:greater_than</tt> - Specifies the value must be greater than the supplied value.
- # * <tt>:greater_than_or_equal_to</tt> - Specifies the value must be greater than or equal the supplied value.
+ # * <tt>:only_integer</tt> - Specifies whether the value has to be an integer,
+ # e.g. an integral value (default is +false+).
+ # * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+ (default is
+ # +false+). Notice that for fixnum and float columns empty strings are
+ # converted to +nil+.
+ # * <tt>:greater_than</tt> - Specifies the value must be greater than the
+ # supplied value.
+ # * <tt>:greater_than_or_equal_to</tt> - Specifies the value must be greater
+ # than or equal the supplied value.
# * <tt>:equal_to</tt> - Specifies the value must be equal to the supplied value.
- # * <tt>:less_than</tt> - Specifies the value must be less than the supplied value.
- # * <tt>:less_than_or_equal_to</tt> - Specifies the value must be less than or equal the supplied value.
- # * <tt>:other_than</tt> - Specifies the value must be other than the supplied value.
+ # * <tt>:less_than</tt> - Specifies the value must be less than the supplied
+ # value.
+ # * <tt>:less_than_or_equal_to</tt> - Specifies the value must be less than or
+ # equal the supplied value.
+ # * <tt>:other_than</tt> - Specifies the value must be other than the supplied
+ # value.
# * <tt>:odd</tt> - Specifies the value must be an odd number.
# * <tt>:even</tt> - Specifies the value must be an even number.
- # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
- # method, proc or string should return or evaluate to a true or false value.
- # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if
+ # the validation should occur (e.g. <tt>:if => :allow_validation</tt>, or
+ # <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The method, proc
+ # or string should return or evaluate to a true or false value.
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine
+ # if the validation should not occur (e.g. <tt>:unless => :skip_validation</tt>,
+ # or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
# * <tt>:strict</tt> - Specifies whether validation should be strict.
- # See <tt>ActiveModel::Validation#validates!</tt> for more information
+ # See <tt>ActiveModel::Validation#validates!</tt> for more information.
+ #
+ # The following checks can also be supplied with a proc or a symbol which
+ # corresponds to a method:
#
- # The following checks can also be supplied with a proc or a symbol which corresponds to a method:
# * <tt>:greater_than</tt>
# * <tt>:greater_than_or_equal_to</tt>
# * <tt>:equal_to</tt>
# * <tt>:less_than</tt>
# * <tt>:less_than_or_equal_to</tt>
#
+ # For example:
+ #
# class Person < ActiveRecord::Base
# validates_numericality_of :width, :less_than => Proc.new { |person| person.height }
# validates_numericality_of :width, :greater_than => :minimum_weight
# end
- #
def validates_numericality_of(*attr_names)
validates_with NumericalityValidator, _merge_attributes(attr_names)
end
diff --git a/activemodel/lib/active_model/validations/presence.rb b/activemodel/lib/active_model/validations/presence.rb
index 9a643a6f5c..018ef1e733 100644
--- a/activemodel/lib/active_model/validations/presence.rb
+++ b/activemodel/lib/active_model/validations/presence.rb
@@ -11,7 +11,8 @@ module ActiveModel
end
module HelperMethods
- # Validates that the specified attributes are not blank (as defined by Object#blank?). Happens by default on save. Example:
+ # Validates that the specified attributes are not blank (as defined by
+ # Object#blank?). Happens by default on save.
#
# class Person < ActiveRecord::Base
# validates_presence_of :first_name
@@ -19,25 +20,28 @@ module ActiveModel
#
# The first_name attribute must be in the object and it cannot be blank.
#
- # If you want to validate the presence of a boolean field (where the real values are true and false),
- # you will want to use <tt>validates_inclusion_of :field_name, :in => [true, false]</tt>.
+ # If you want to validate the presence of a boolean field (where the real values
+ # are true and false), you will want to use
+ # <tt>validates_inclusion_of :field_name, :in => [true, false]</tt>.
#
- # This is due to the way Object#blank? handles boolean values: <tt>false.blank? # => true</tt>.
+ # This is due to the way Object#blank? handles boolean values:
+ # <tt>false.blank? # => true</tt>.
#
# Configuration options:
# * <tt>:message</tt> - A custom error message (default is: "can't be blank").
# * <tt>:on</tt> - Specifies when this validation is active. Runs in all
# validation contexts by default (+nil+), other options are <tt>:create</tt>
# and <tt>:update</tt>.
- # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>).
- # The method, proc or string should return or evaluate to a true or false value.
- # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>).
- # The method, proc or string should return or evaluate to a true or false value.
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if
+ # the validation should occur (e.g. <tt>:if => :allow_validation</tt>, or
+ # <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The method, proc
+ # or string should return or evaluate to a true or false value.
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine
+ # if the validation should not occur (e.g. <tt>:unless => :skip_validation</tt>,
+ # or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The method,
+ # proc or string should return or evaluate to a true or false value.
# * <tt>:strict</tt> - Specifies whether validation should be strict.
- # See <tt>ActiveModel::Validation#validates!</tt> for more information
- #
+ # See <tt>ActiveModel::Validation#validates!</tt> for more information.
def validates_presence_of(*attr_names)
validates_with PresenceValidator, _merge_attributes(attr_names)
end
diff --git a/activemodel/lib/active_model/validations/with.rb b/activemodel/lib/active_model/validations/with.rb
index 991c5f7b82..66cc9daa2c 100644
--- a/activemodel/lib/active_model/validations/with.rb
+++ b/activemodel/lib/active_model/validations/with.rb
@@ -62,8 +62,8 @@ module ActiveModel
# <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>).
# The method, proc or string should return or evaluate to a true or false value.
# * <tt>:strict</tt> - Specifies whether validation should be strict.
- # See <tt>ActiveModel::Validation#validates!</tt> for more information
-
+ # See <tt>ActiveModel::Validation#validates!</tt> for more information.
+ #
# If you pass any additional configuration options, they will be passed
# to the class and available as <tt>options</tt>:
#
@@ -77,7 +77,6 @@ module ActiveModel
# options[:my_custom_key] # => "my custom value"
# end
# end
- #
def validates_with(*args, &block)
options = args.extract_options!
args.each do |klass|
@@ -128,12 +127,11 @@ module ActiveModel
# Standard configuration options (:on, :if and :unless), which are
# available on the class version of +validates_with+, should instead be
# placed on the +validates+ method as these are applied and tested
- # in the callback
+ # in the callback.
#
# If you pass any additional configuration options, they will be passed
# to the class and available as +options+, please refer to the
- # class version of this method for more information
- #
+ # class version of this method for more information.
def validates_with(*args, &block)
options = args.extract_options!
args.each do |klass|
diff --git a/activemodel/test/cases/attribute_methods_test.rb b/activemodel/test/cases/attribute_methods_test.rb
index 34298d31c2..a9db29ee21 100644
--- a/activemodel/test/cases/attribute_methods_test.rb
+++ b/activemodel/test/cases/attribute_methods_test.rb
@@ -10,7 +10,7 @@ class ModelWithAttributes
end
def attributes
- { :foo => 'value of foo' }
+ { :foo => 'value of foo', :baz => 'value of baz' }
end
private
@@ -127,29 +127,36 @@ class AttributeMethodsTest < ActiveModel::TestCase
assert_equal "value of a?b", ModelWithWeirdNamesAttributes.new.send('a?b')
end
+ test '#define_attribute_methods works passing multiple arguments' do
+ ModelWithAttributes.define_attribute_methods(:foo, :baz)
+
+ assert_equal "value of foo", ModelWithAttributes.new.foo
+ assert_equal "value of baz", ModelWithAttributes.new.baz
+ end
+
test '#define_attribute_methods generates attribute methods' do
- ModelWithAttributes.define_attribute_methods([:foo])
+ ModelWithAttributes.define_attribute_methods(:foo)
assert_respond_to ModelWithAttributes.new, :foo
assert_equal "value of foo", ModelWithAttributes.new.foo
end
test '#define_attribute_methods generates attribute methods with spaces in their names' do
- ModelWithAttributesWithSpaces.define_attribute_methods([:'foo bar'])
+ ModelWithAttributesWithSpaces.define_attribute_methods(:'foo bar')
assert_respond_to ModelWithAttributesWithSpaces.new, :'foo bar'
assert_equal "value of foo bar", ModelWithAttributesWithSpaces.new.send(:'foo bar')
end
test '#alias_attribute works with attributes with spaces in their names' do
- ModelWithAttributesWithSpaces.define_attribute_methods([:'foo bar'])
+ ModelWithAttributesWithSpaces.define_attribute_methods(:'foo bar')
ModelWithAttributesWithSpaces.alias_attribute(:'foo_bar', :'foo bar')
assert_equal "value of foo bar", ModelWithAttributesWithSpaces.new.foo_bar
end
test '#undefine_attribute_methods removes attribute methods' do
- ModelWithAttributes.define_attribute_methods([:foo])
+ ModelWithAttributes.define_attribute_methods(:foo)
ModelWithAttributes.undefine_attribute_methods
assert !ModelWithAttributes.new.respond_to?(:foo)
@@ -170,7 +177,7 @@ class AttributeMethodsTest < ActiveModel::TestCase
assert_deprecated { klass.attribute_method_suffix '' }
assert_deprecated { klass.attribute_method_prefix '' }
- klass.define_attribute_methods([:foo])
+ klass.define_attribute_methods(:foo)
assert_equal 'value of foo', klass.new.foo
end
diff --git a/activemodel/test/cases/dirty_test.rb b/activemodel/test/cases/dirty_test.rb
index 98244a6290..eaaf910bac 100644
--- a/activemodel/test/cases/dirty_test.rb
+++ b/activemodel/test/cases/dirty_test.rb
@@ -3,7 +3,7 @@ require "cases/helper"
class DirtyTest < ActiveModel::TestCase
class DirtyModel
include ActiveModel::Dirty
- define_attribute_methods [:name, :color]
+ define_attribute_methods :name, :color
def initialize
@name = nil
diff --git a/activemodel/test/cases/helper.rb b/activemodel/test/cases/helper.rb
index 4347b17cbc..7d6f11b5a5 100644
--- a/activemodel/test/cases/helper.rb
+++ b/activemodel/test/cases/helper.rb
@@ -1,8 +1,5 @@
require File.expand_path('../../../../load_paths', __FILE__)
-lib = File.expand_path("#{File.dirname(__FILE__)}/../../lib")
-$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib)
-
require 'config'
require 'active_model'
require 'active_support/core_ext/string/access'
diff --git a/activemodel/test/cases/mass_assignment_security/sanitizer_test.rb b/activemodel/test/cases/mass_assignment_security/sanitizer_test.rb
index 3660b9b1e5..418a24294a 100644
--- a/activemodel/test/cases/mass_assignment_security/sanitizer_test.rb
+++ b/activemodel/test/cases/mass_assignment_security/sanitizer_test.rb
@@ -19,7 +19,7 @@ class SanitizerTest < ActiveModel::TestCase
test "sanitize attributes" do
original_attributes = { 'first_name' => 'allowed', 'admin' => 'denied' }
- attributes = @logger_sanitizer.sanitize(original_attributes, @authorizer)
+ attributes = @logger_sanitizer.sanitize(self.class, original_attributes, @authorizer)
assert attributes.key?('first_name'), "Allowed key shouldn't be rejected"
assert !attributes.key?('admin'), "Denied key should be rejected"
@@ -29,14 +29,14 @@ class SanitizerTest < ActiveModel::TestCase
original_attributes = { 'first_name' => 'allowed', 'admin' => 'denied' }
log = StringIO.new
self.logger = ActiveSupport::Logger.new(log)
- @logger_sanitizer.sanitize(original_attributes, @authorizer)
+ @logger_sanitizer.sanitize(self.class, original_attributes, @authorizer)
assert_match(/admin/, log.string, "Should log removed attributes: #{log.string}")
end
test "debug mass assignment removal with StrictSanitizer" do
original_attributes = { 'first_name' => 'allowed', 'admin' => 'denied' }
assert_raise ActiveModel::MassAssignmentSecurity::Error do
- @strict_sanitizer.sanitize(original_attributes, @authorizer)
+ @strict_sanitizer.sanitize(self.class, original_attributes, @authorizer)
end
end
@@ -44,7 +44,7 @@ class SanitizerTest < ActiveModel::TestCase
original_attributes = {'id' => 1, 'first_name' => 'allowed'}
assert_nothing_raised do
- @strict_sanitizer.sanitize(original_attributes, @authorizer)
+ @strict_sanitizer.sanitize(self.class, original_attributes, @authorizer)
end
end
diff --git a/activemodel/test/cases/mass_assignment_security_test.rb b/activemodel/test/cases/mass_assignment_security_test.rb
index a197dbe748..0c6352cd71 100644
--- a/activemodel/test/cases/mass_assignment_security_test.rb
+++ b/activemodel/test/cases/mass_assignment_security_test.rb
@@ -4,7 +4,7 @@ require 'models/mass_assignment_specific'
class CustomSanitizer < ActiveModel::MassAssignmentSecurity::Sanitizer
- def process_removed_attributes(attrs)
+ def process_removed_attributes(klass, attrs)
raise StandardError
end
diff --git a/activemodel/test/cases/secure_password_test.rb b/activemodel/test/cases/secure_password_test.rb
index c451cc1aca..5f18909301 100644
--- a/activemodel/test/cases/secure_password_test.rb
+++ b/activemodel/test/cases/secure_password_test.rb
@@ -7,16 +7,19 @@ class SecurePasswordTest < ActiveModel::TestCase
setup do
@user = User.new
+ @visitor = Visitor.new
end
test "blank password" do
- @user.password = ''
- assert !@user.valid?, 'user should be invalid'
+ @user.password = @visitor.password = ''
+ assert !@user.valid?(:create), 'user should be invalid'
+ assert @visitor.valid?(:create), 'visitor should be valid'
end
test "nil password" do
- @user.password = nil
- assert !@user.valid?, 'user should be invalid'
+ @user.password = @visitor.password = nil
+ assert !@user.valid?(:create), 'user should be invalid'
+ assert @visitor.valid?(:create), 'visitor should be valid'
end
test "blank password doesn't override previous password" do
@@ -26,15 +29,16 @@ class SecurePasswordTest < ActiveModel::TestCase
end
test "password must be present" do
- assert !@user.valid?
+ assert !@user.valid?(:create)
assert_equal 1, @user.errors.size
end
- test "password must match confirmation" do
- @user.password = "thiswillberight"
- @user.password_confirmation = "wrong"
+ test "match confirmation" do
+ @user.password = @visitor.password = "thiswillberight"
+ @user.password_confirmation = @visitor.password_confirmation = "wrong"
assert !@user.valid?
+ assert @visitor.valid?
@user.password_confirmation = "thiswillberight"
@@ -59,4 +63,14 @@ class SecurePasswordTest < ActiveModel::TestCase
assert !active_authorizer.include?(:password_digest)
assert active_authorizer.include?(:name)
end
+
+ test "User should not be created with blank digest" do
+ assert_raise RuntimeError do
+ @user.run_callbacks :create
+ end
+ @user.password = "supersecretpassword"
+ assert_nothing_raised do
+ @user.run_callbacks :create
+ end
+ end
end
diff --git a/activemodel/test/cases/serialization_test.rb b/activemodel/test/cases/serialization_test.rb
index 66b18d65e5..d2ba9fd95d 100644
--- a/activemodel/test/cases/serialization_test.rb
+++ b/activemodel/test/cases/serialization_test.rb
@@ -105,6 +105,24 @@ class SerializationTest < ActiveModel::TestCase
assert_equal expected, @user.serializable_hash(:include => :friends)
end
+ class FriendList
+ def initialize(friends)
+ @friends = friends
+ end
+
+ def to_ary
+ @friends
+ end
+ end
+
+ def test_include_option_with_ary
+ @user.friends = FriendList.new(@user.friends)
+ expected = {"email"=>"david@example.com", "gender"=>"male", "name"=>"David",
+ "friends"=>[{"name"=>'Joe', "email"=>'joe@example.com', "gender"=>'male'},
+ {"name"=>'Sue', "email"=>'sue@example.com', "gender"=>'female'}]}
+ assert_equal expected, @user.serializable_hash(:include => :friends)
+ end
+
def test_multiple_includes
expected = {"email"=>"david@example.com", "gender"=>"male", "name"=>"David",
"address"=>{"street"=>"123 Lane", "city"=>"Springfield", "state"=>"CA", "zip"=>11111},
diff --git a/activemodel/test/cases/serializers/xml_serialization_test.rb b/activemodel/test/cases/serializers/xml_serialization_test.rb
index 38aecf51ff..5fa227e0e0 100644
--- a/activemodel/test/cases/serializers/xml_serialization_test.rb
+++ b/activemodel/test/cases/serializers/xml_serialization_test.rb
@@ -188,6 +188,23 @@ class XmlSerializationTest < ActiveModel::TestCase
assert_match %r{<friend type="Contact">}, xml
end
+ class FriendList
+ def initialize(friends)
+ @friends = friends
+ end
+
+ def to_ary
+ @friends
+ end
+ end
+
+ test "include option with ary" do
+ @contact.friends = FriendList.new(@contact.friends)
+ xml = @contact.to_xml :include => :friends, :indent => 0
+ assert_match %r{<friends type="array">}, xml
+ assert_match %r{<friend type="Contact">}, xml
+ end
+
test "multiple includes" do
xml = @contact.to_xml :indent => 0, :skip_instruct => true, :include => [ :address, :friends ]
assert xml.include?(@contact.address.to_xml(:indent => 0, :skip_instruct => true))
diff --git a/activemodel/test/cases/validations_test.rb b/activemodel/test/cases/validations_test.rb
index a716d0896e..1f5023bf76 100644
--- a/activemodel/test/cases/validations_test.rb
+++ b/activemodel/test/cases/validations_test.rb
@@ -344,4 +344,19 @@ class ValidationsTest < ActiveModel::TestCase
Topic.validates :title, options
assert_equal({ :presence => true }, options)
end
+
+ def test_dup_validity_is_independent
+ Topic.validates_presence_of :title
+ topic = Topic.new("title" => "Litterature")
+ topic.valid?
+
+ duped = topic.dup
+ duped.title = nil
+ assert duped.invalid?
+
+ topic.title = nil
+ duped.title = 'Mathematics'
+ assert topic.invalid?
+ assert duped.valid?
+ end
end
diff --git a/activemodel/test/models/administrator.rb b/activemodel/test/models/administrator.rb
index a48f8b064f..2d6d34b3e2 100644
--- a/activemodel/test/models/administrator.rb
+++ b/activemodel/test/models/administrator.rb
@@ -1,7 +1,10 @@
class Administrator
+ extend ActiveModel::Callbacks
include ActiveModel::Validations
include ActiveModel::SecurePassword
include ActiveModel::MassAssignmentSecurity
+
+ define_model_callbacks :create
attr_accessor :name, :password_digest
attr_accessible :name
diff --git a/activemodel/test/models/user.rb b/activemodel/test/models/user.rb
index e221bb8091..4b11df12bf 100644
--- a/activemodel/test/models/user.rb
+++ b/activemodel/test/models/user.rb
@@ -1,6 +1,9 @@
class User
+ extend ActiveModel::Callbacks
include ActiveModel::Validations
include ActiveModel::SecurePassword
+
+ define_model_callbacks :create
has_secure_password
diff --git a/activemodel/test/models/visitor.rb b/activemodel/test/models/visitor.rb
index 36c0a16688..d15f448516 100644
--- a/activemodel/test/models/visitor.rb
+++ b/activemodel/test/models/visitor.rb
@@ -1,9 +1,12 @@
class Visitor
+ extend ActiveModel::Callbacks
include ActiveModel::Validations
include ActiveModel::SecurePassword
include ActiveModel::MassAssignmentSecurity
+
+ define_model_callbacks :create
- has_secure_password
+ has_secure_password(validations: false)
- attr_accessor :password_digest
+ attr_accessor :password_digest, :password_confirmation
end
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 31886c8212..11fd0e7047 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,5 +1,24 @@
## Rails 4.0.0 (unreleased) ##
+* It's not possible anymore to destroy a model marked as read only.
+
+ *Johannes Barre*
+
+
+* Added ability to ActiveRecord::Relation#from to accept other ActiveRecord::Relation objects
+
+ Record.from(subquery)
+ Record.from(subquery, :a)
+
+ *Radoslav Stankov*
+
+* Added custom coders support for ActiveRecord::Store. Now you can set
+ your custom coder like this:
+
+ store :settings, accessors: [ :color, :homepage ], coder: JSON
+
+ *Andrey Voronkov*
+
* `mysql` and `mysql2` connections will set `SQL_MODE=STRICT_ALL_TABLES` by
default to avoid silent data loss. This can be disabled by specifying
`strict: false` in your `database.yml`.
@@ -626,7 +645,7 @@
has_one :account
end
- user.build_account{ |a| a.credit_limit => 100.0 }
+ user.build_account{ |a| a.credit_limit = 100.0 }
The block is called after the instance has been initialized. *Andrew White*
@@ -3999,7 +4018,7 @@
* Fixed that adding a record to a has_and_belongs_to collection would always save it -- now it only saves if its a new record #1203 *Alisdair McDiarmid*
-* Fixed saving of in-memory association structures to happen as a after_create/after_update callback instead of after_save -- that way you can add new associations in after_create/after_update callbacks without getting them saved twice
+* Fixed saving of in-memory association structures to happen as an after_create/after_update callback instead of after_save -- that way you can add new associations in after_create/after_update callbacks without getting them saved twice
* Allow any Enumerable, not just Array, to work as bind variables #1344 *Jeremy Kemper*
@@ -5512,7 +5531,7 @@
* Fixed that adding a record to a has_and_belongs_to collection would always save it -- now it only saves if its a new record #1203 *Alisdair McDiarmid*
-* Fixed saving of in-memory association structures to happen as a after_create/after_update callback instead of after_save -- that way you can add new associations in after_create/after_update callbacks without getting them saved twice
+* Fixed saving of in-memory association structures to happen as an after_create/after_update callback instead of after_save -- that way you can add new associations in after_create/after_update callbacks without getting them saved twice
* Allow any Enumerable, not just Array, to work as bind variables #1344 *Jeremy Kemper*
@@ -6434,7 +6453,7 @@
post.categories.push_with_attributes(category, :added_on => Date.today)
post.categories.first.added_on # => Date.today
- NOTE: The categories table doesn't have a added_on column, it's the categories_post join table that does!
+ NOTE: The categories table doesn't have an added_on column, it's the categories_post join table that does!
* Fixed that :exclusively_dependent and :dependent can't be activated at the same time on has_many associations *Jeremy Kemper*
diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb
index ed26b4899f..210820062b 100644
--- a/activerecord/lib/active_record.rb
+++ b/activerecord/lib/active_record.rb
@@ -22,7 +22,6 @@
#++
require 'active_support'
-require 'active_support/i18n'
require 'active_model'
require 'arel'
require 'active_record_deprecated_finders'
@@ -145,4 +144,6 @@ ActiveSupport.on_load(:active_record) do
Arel::Table.engine = self
end
-I18n.load_path << File.dirname(__FILE__) + '/active_record/locale/en.yml'
+ActiveSupport.on_load(:i18n) do
+ I18n.load_path << File.dirname(__FILE__) + '/active_record/locale/en.yml'
+end
diff --git a/activerecord/lib/active_record/aggregations.rb b/activerecord/lib/active_record/aggregations.rb
index a4db627535..c7a329d74d 100644
--- a/activerecord/lib/active_record/aggregations.rb
+++ b/activerecord/lib/active_record/aggregations.rb
@@ -71,7 +71,7 @@ module ActiveRecord
# Now it's possible to access attributes from the database through the value objects instead. If
# you choose to name the composition the same as the attribute's name, it will be the only way to
# access that attribute. That's the case with our +balance+ attribute. You interact with the value
- # objects just like you would any other attribute, though:
+ # objects just like you would with any other attribute:
#
# customer.balance = Money.new(20) # sets the Money value object and the attribute
# customer.balance # => Money value object
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index c30e8e08b8..68f8bbeb1c 100644
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -543,7 +543,7 @@ module ActiveRecord
# end
#
# @group = Group.first
- # @group.users.collect { |u| u.avatar }.flatten # select all avatars for all users in the group
+ # @group.users.collect { |u| u.avatar }.compact # select all avatars for all users in the group
# @group.avatars # selects all avatars by going through the User join model.
#
# An important caveat with going through +has_one+ or +has_many+ associations on the
diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb
index 14aa557b6c..3af5ff3eab 100644
--- a/activerecord/lib/active_record/associations/collection_association.rb
+++ b/activerecord/lib/active_record/associations/collection_association.rb
@@ -16,12 +16,6 @@ module ActiveRecord
# If you need to work on all current children, new and existing records,
# +load_target+ and the +loaded+ flag are your friends.
class CollectionAssociation < Association #:nodoc:
- attr_reader :proxy
-
- def initialize(owner, reflection)
- super
- @proxy = CollectionProxy.new(self)
- end
# Implements the reader method, e.g. foo.items for Foo.has_many :items
def reader(force_reload = false)
@@ -31,7 +25,7 @@ module ActiveRecord
reload
end
- proxy
+ CollectionProxy.new(self)
end
# Implements the writer method, e.g. foo.items= for Foo.has_many :items
@@ -248,8 +242,12 @@ module ActiveRecord
# This method is abstract in the sense that it relies on
# +count_records+, which is a method descendants have to provide.
def size
- if !find_target? || (loaded? && !options[:uniq])
- target.size
+ if !find_target? || loaded?
+ if options[:uniq]
+ target.uniq.size
+ else
+ target.size
+ end
elsif !loaded? && options[:group]
load_target.size
elsif !loaded? && !options[:uniq] && target.is_a?(Array)
@@ -474,6 +472,8 @@ module ActiveRecord
raise RecordNotSaved, "Failed to replace #{reflection.name} because one or more of the " \
"new records could not be saved."
end
+
+ new_target
end
def concat_records(records)
diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb
index 261a829281..cf4cc98f38 100644
--- a/activerecord/lib/active_record/associations/collection_proxy.rb
+++ b/activerecord/lib/active_record/associations/collection_proxy.rb
@@ -33,14 +33,7 @@ module ActiveRecord
#
# is computed directly through SQL and does not trigger by itself the
# instantiation of the actual post records.
- class CollectionProxy # :nodoc:
- alias :proxy_extend :extend
-
- instance_methods.each { |m| undef_method m unless m.to_s =~ /^(?:nil\?|send|object_id|to_a)$|^__|^respond_to|proxy_/ }
-
- delegate :group, :order, :limit, :joins, :where, :preload, :eager_load, :includes, :from,
- :lock, :readonly, :having, :pluck, :to => :scoped
-
+ class CollectionProxy < Relation # :nodoc:
delegate :target, :load_target, :loaded?, :to => :@association
delegate :select, :find, :first, :last,
@@ -52,7 +45,8 @@ module ActiveRecord
def initialize(association)
@association = association
- Array(association.options[:extend]).each { |ext| proxy_extend(ext) }
+ super association.klass, association.klass.arel_table
+ merge! association.scoped
end
alias_method :new, :build
@@ -61,54 +55,28 @@ module ActiveRecord
@association
end
- def scoped(options = nil)
- association = @association
- scope = association.scoped
-
- scope.extending! do
- define_method(:proxy_association) { association }
- end
- scope.merge!(options) if options
- scope
+ # We don't want this object to be put on the scoping stack, because
+ # that could create an infinite loop where we call an @association
+ # method, which gets the current scope, which is this object, which
+ # delegates to @association, and so on.
+ def scoping
+ @association.scoped.scoping { yield }
end
- def respond_to?(name, include_private = false)
- super ||
- (load_target && target.respond_to?(name, include_private)) ||
- proxy_association.klass.respond_to?(name, include_private)
+ def spawn
+ scoped
end
- def method_missing(method, *args, &block)
- match = DynamicMatchers::Method.match(self, method)
- if match && match.is_a?(DynamicMatchers::Instantiator)
- scoped.send(method, *args) do |r|
- proxy_association.send :set_owner_attributes, r
- proxy_association.send :add_to_target, r
- yield(r) if block_given?
- end
-
- elsif target.respond_to?(method) || (!proxy_association.klass.respond_to?(method) && Class.respond_to?(method))
- if load_target
- if target.respond_to?(method)
- target.send(method, *args, &block)
- else
- begin
- super
- rescue NoMethodError => e
- raise e, e.message.sub(/ for #<.*$/, " via proxy for #{target}")
- end
- end
- end
+ def scoped(options = nil)
+ association = @association
- else
- scoped.readonly(nil).public_send(method, *args, &block)
+ super.extending! do
+ define_method(:proxy_association) { association }
end
end
- # Forwards <tt>===</tt> explicitly to the \target because the instance method
- # removal above doesn't catch it. Loads the \target if needed.
- def ===(other)
- other === load_target
+ def ==(other)
+ load_target == other
end
def to_ary
@@ -130,19 +98,6 @@ module ActiveRecord
proxy_association.reload
self
end
-
- # Define array public methods because we know it should be invoked over
- # the target, so we can have a performance improvement using those methods
- # in association collections
- Array.public_instance_methods.each do |m|
- unless method_defined?(m)
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
- def #{m}(*args, &block)
- target.public_send(:#{m}, *args, &block) if load_target
- end
- RUBY
- end
- end
end
end
end
diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb
index 3005bef092..d545e7799d 100644
--- a/activerecord/lib/active_record/autosave_association.rb
+++ b/activerecord/lib/active_record/autosave_association.rb
@@ -350,7 +350,7 @@ module ActiveRecord
end
records_to_destroy.each do |record|
- association.proxy.destroy(record)
+ association.destroy(record)
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
index f0b6ae2b7d..df78ba6c5a 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
@@ -23,7 +23,7 @@ module ActiveRecord
end
def sql_type
- base.type_to_sql(type.to_sym, limit, precision, scale) rescue type
+ base.type_to_sql(type.to_sym, limit, precision, scale)
end
def to_sql
@@ -262,7 +262,7 @@ module ActiveRecord
# Adds index options to the indexes hash, keyed by column name
# This is primarily used to track indexes that need to be created after the table
- # === Examples
+ #
# index(:account_id, :name => 'index_projects_on_account_id')
def index(column_name, options = {})
indexes[column_name] = options
@@ -348,7 +348,7 @@ module ActiveRecord
# Adds a new column to the named table.
# See TableDefinition#column for details of the options you can use.
- # ===== Example
+ #
# ====== Creating a simple column
# t.column(:name, :string)
def column(column_name, type, options = {})
@@ -363,7 +363,6 @@ module ActiveRecord
# Adds a new index to the table. +column_name+ can be a single Symbol, or
# an Array of Symbols. See SchemaStatements#add_index
#
- # ===== Examples
# ====== Creating a simple index
# t.index(:name)
# ====== Creating a unique index
@@ -380,7 +379,7 @@ module ActiveRecord
end
# Adds timestamps (+created_at+ and +updated_at+) columns to the table. See SchemaStatements#add_timestamps
- # ===== Example
+ #
# t.timestamps
def timestamps
@base.add_timestamps(@table_name)
@@ -388,7 +387,7 @@ module ActiveRecord
# Changes the column's definition according to the new options.
# See TableDefinition#column for details of the options you can use.
- # ===== Examples
+ #
# t.change(:name, :string, :limit => 80)
# t.change(:description, :text)
def change(column_name, type, options = {})
@@ -396,7 +395,7 @@ module ActiveRecord
end
# Sets a new default value for a column. See SchemaStatements#change_column_default
- # ===== Examples
+ #
# t.change_default(:qualification, 'new')
# t.change_default(:authorized, 1)
def change_default(column_name, default)
@@ -404,7 +403,7 @@ module ActiveRecord
end
# Removes the column(s) from the table definition.
- # ===== Examples
+ #
# t.remove(:qualification)
# t.remove(:qualification, :experience)
def remove(*column_names)
@@ -413,7 +412,6 @@ module ActiveRecord
# Removes the given index from the table.
#
- # ===== Examples
# ====== Remove the index_table_name_on_column in the table_name table
# t.remove_index :column
# ====== Remove the index named index_table_name_on_branch_id in the table_name table
@@ -427,14 +425,14 @@ module ActiveRecord
end
# Removes the timestamp columns (+created_at+ and +updated_at+) from the table.
- # ===== Example
+ #
# t.remove_timestamps
def remove_timestamps
@base.remove_timestamps(@table_name)
end
# Renames a column.
- # ===== Example
+ #
# t.rename(:description, :name)
def rename(column_name, new_column_name)
@base.rename_column(@table_name, column_name, new_column_name)
@@ -442,7 +440,7 @@ module ActiveRecord
# Adds a reference. Optionally adds a +type+ column, if <tt>:polymorphic</tt> option is provided.
# <tt>references</tt> and <tt>belongs_to</tt> are acceptable.
- # ===== Examples
+ #
# t.references(:goat)
# t.references(:goat, :polymorphic => true)
# t.belongs_to(:goat)
@@ -460,7 +458,7 @@ module ActiveRecord
# Removes a reference. Optionally removes a +type+ column.
# <tt>remove_references</tt> and <tt>remove_belongs_to</tt> are acceptable.
- # ===== Examples
+ #
# t.remove_references(:goat)
# t.remove_references(:goat, :polymorphic => true)
# t.remove_belongs_to(:goat)
@@ -475,7 +473,7 @@ module ActiveRecord
alias :remove_belongs_to :remove_references
# Adds a column or columns of a specified type
- # ===== Examples
+ #
# t.string(:goat)
# t.string(:goat, :sheep)
%w( string text integer float decimal datetime timestamp time date binary boolean ).each do |column_type|
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
index e7a4f061fd..62b0f51bb2 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -21,7 +21,6 @@ module ActiveRecord
# Checks to see if the table +table_name+ exists on the database.
#
- # === Example
# table_exists?(:developers)
def table_exists?(table_name)
tables.include?(table_name.to_s)
@@ -32,7 +31,6 @@ module ActiveRecord
# Checks to see if an index exists on a table for a given index definition.
#
- # === Examples
# # Check an index exists
# index_exists?(:suppliers, :company_id)
#
@@ -126,7 +124,6 @@ module ActiveRecord
# Set to true to drop the table before creating it.
# Defaults to false.
#
- # ===== Examples
# ====== Add a backend specific option to the generated SQL (MySQL)
# create_table(:suppliers, :options => 'ENGINE=InnoDB DEFAULT CHARSET=utf8')
# generates:
@@ -193,7 +190,6 @@ module ActiveRecord
# Set to true to drop the table before creating it.
# Defaults to false.
#
- # ===== Examples
# ====== Add a backend specific option to the generated SQL (MySQL)
# create_join_table(:assemblies, :parts, :options => 'ENGINE=InnoDB DEFAULT CHARSET=utf8')
# generates:
@@ -215,7 +211,6 @@ module ActiveRecord
# A block for changing columns in +table+.
#
- # === Example
# # change_table() yields a Table instance
# change_table(:suppliers) do |t|
# t.column :name, :string, :limit => 60
@@ -229,7 +224,6 @@ module ActiveRecord
#
# Defaults to false.
#
- # ===== Examples
# ====== Add a column
# change_table(:suppliers) do |t|
# t.column :name, :string, :limit => 60
@@ -288,7 +282,7 @@ module ActiveRecord
end
# Renames a table.
- # ===== Example
+ #
# rename_table('octopuses', 'octopi')
def rename_table(table_name, new_name)
raise NotImplementedError, "rename_table is not implemented"
@@ -308,7 +302,7 @@ module ActiveRecord
end
# Removes the column(s) from the table definition.
- # ===== Examples
+ #
# remove_column(:suppliers, :qualification)
# remove_columns(:suppliers, :qualification, :experience)
def remove_column(table_name, *column_names)
@@ -318,7 +312,7 @@ module ActiveRecord
# Changes the column's definition according to the new options.
# See TableDefinition#column for details of the options you can use.
- # ===== Examples
+ #
# change_column(:suppliers, :name, :string, :limit => 80)
# change_column(:accounts, :description, :text)
def change_column(table_name, column_name, type, options = {})
@@ -326,7 +320,7 @@ module ActiveRecord
end
# Sets a new default value for a column.
- # ===== Examples
+ #
# change_column_default(:suppliers, :qualification, 'new')
# change_column_default(:accounts, :authorized, 1)
# change_column_default(:users, :email, nil)
@@ -335,7 +329,7 @@ module ActiveRecord
end
# Renames a column.
- # ===== Example
+ #
# rename_column(:suppliers, :description, :name)
def rename_column(table_name, column_name, new_column_name)
raise NotImplementedError, "rename_column is not implemented"
@@ -347,8 +341,6 @@ module ActiveRecord
# The index will be named after the table and the column name(s), unless
# you pass <tt>:name</tt> as an option.
#
- # ===== Examples
- #
# ====== Creating a simple index
# add_index(:suppliers, :name)
# generates
@@ -537,7 +529,7 @@ module ActiveRecord
end
# Adds timestamps (created_at and updated_at) columns to the named table.
- # ===== Examples
+ #
# add_timestamps(:suppliers)
def add_timestamps(table_name)
add_column table_name, :created_at, :datetime
@@ -545,7 +537,7 @@ module ActiveRecord
end
# Removes the timestamp columns (created_at and updated_at) from the table definition.
- # ===== Examples
+ #
# remove_timestamps(:suppliers)
def remove_timestamps(table_name)
remove_column table_name, :updated_at
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
index a848838a4e..9794c5663e 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -251,7 +251,7 @@ module ActiveRecord
end
# MysqlAdapter has to free a result after using it, so we use this method to write
- # stuff in a abstract way without concerning ourselves about whether it needs to be
+ # stuff in an abstract way without concerning ourselves about whether it needs to be
# explicitly freed or not.
def execute_and_free(sql, name = nil) #:nodoc:
yield execute(sql, name)
diff --git a/activerecord/lib/active_record/connection_adapters/column.rb b/activerecord/lib/active_record/connection_adapters/column.rb
index 1933ce2b46..01bd3ae26c 100644
--- a/activerecord/lib/active_record/connection_adapters/column.rb
+++ b/activerecord/lib/active_record/connection_adapters/column.rb
@@ -124,6 +124,7 @@ module ActiveRecord
when :binary then "#{klass}.binary_to_string(#{var_name})"
when :boolean then "#{klass}.value_to_boolean(#{var_name})"
when :hstore then "#{klass}.string_to_hstore(#{var_name})"
+ when :inet, :cidr then "#{klass}.string_to_cidr(#{var_name})"
else var_name
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
index c82afc232c..df3d5e4657 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
@@ -137,6 +137,14 @@ module ActiveRecord
end
end
+ class Cidr < Type
+ def type_cast(value)
+ return if value.nil?
+
+ ConnectionAdapters::PostgreSQLColumn.string_to_cidr value
+ end
+ end
+
class TypeMap
def initialize
@mapping = {}
@@ -212,11 +220,9 @@ module ActiveRecord
# FIXME: why are we keeping these types as strings?
alias_type 'tsvector', 'text'
alias_type 'interval', 'text'
- alias_type 'cidr', 'text'
- alias_type 'inet', 'text'
- alias_type 'macaddr', 'text'
alias_type 'bit', 'text'
alias_type 'varbit', 'text'
+ alias_type 'macaddr', 'text'
# FIXME: I don't think this is correct. We should probably be returning a parsed date,
# but the tests pass with a string returned.
@@ -237,6 +243,9 @@ module ActiveRecord
register_type 'polygon', OID::Identity.new
register_type 'circle', OID::Identity.new
register_type 'hstore', OID::Hstore.new
+
+ register_type 'cidr', OID::Cidr.new
+ alias_type 'inet', 'cidr'
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 5ec1ffd704..14bc95abfe 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -8,6 +8,8 @@ require 'arel/visitors/bind_visitor'
gem 'pg', '~> 0.11'
require 'pg'
+require 'ipaddr'
+
module ActiveRecord
module ConnectionHandling
# Establishes a connection to the database that's used by all Active Record objects
@@ -79,6 +81,25 @@ module ActiveRecord
end
end
+ def string_to_cidr(string)
+ if string.nil?
+ nil
+ elsif String === string
+ IPAddr.new(string)
+ else
+ string
+ end
+
+ end
+
+ def cidr_to_string(object)
+ if IPAddr === object
+ "#{object.to_s}/#{object.instance_variable_get(:@mask_addr).to_s(2).count('1')}"
+ else
+ object
+ end
+ end
+
private
HstorePair = begin
quoted_string = /"[^"\\]*(?:\\.[^"\\]*)*"/
@@ -197,6 +218,13 @@ module ActiveRecord
:decimal
when 'hstore'
:hstore
+ # Network address types
+ when 'inet'
+ :inet
+ when 'cidr'
+ :cidr
+ when 'macaddr'
+ :macaddr
# Character types
when /^(?:character varying|bpchar)(?:\(\d+\))?$/
:string
@@ -211,9 +239,6 @@ module ActiveRecord
# Geometric types
when /^(?:point|line|lseg|box|"?path"?|polygon|circle)$/
:string
- # Network address types
- when /^(?:cidr|inet|macaddr)$/
- :string
# Bit strings
when /^bit(?: varying)?(?:\(\d+\))?$/
:string
@@ -282,6 +307,18 @@ module ActiveRecord
def hstore(name, options = {})
column(name, 'hstore', options)
end
+
+ def inet(name, options = {})
+ column(name, 'inet', options)
+ end
+
+ def cidr(name, options = {})
+ column(name, 'cidr', options)
+ end
+
+ def macaddr(name, options = {})
+ column(name, 'macaddr', options)
+ end
end
ADAPTER_NAME = 'PostgreSQL'
@@ -301,7 +338,10 @@ module ActiveRecord
:boolean => { :name => "boolean" },
:xml => { :name => "xml" },
:tsvector => { :name => "tsvector" },
- :hstore => { :name => "hstore" }
+ :hstore => { :name => "hstore" },
+ :inet => { :name => "inet" },
+ :cidr => { :name => "cidr" },
+ :macaddr => { :name => "macaddr" }
}
# Returns 'PostgreSQL' as adapter name for identification purposes.
@@ -510,6 +550,11 @@ module ActiveRecord
when 'hstore' then super(PostgreSQLColumn.hstore_to_string(value), column)
else super
end
+ when IPAddr
+ case column.sql_type
+ when 'inet', 'cidr' then super(PostgreSQLColumn.cidr_to_string(value), column)
+ else super
+ end
when Float
if value.infinite? && column.type == :datetime
"'#{value.to_s.downcase}'"
@@ -549,6 +594,9 @@ module ActiveRecord
when Hash
return super unless 'hstore' == column.sql_type
PostgreSQLColumn.hstore_to_string(value)
+ when IPAddr
+ return super unless ['inet','cidr'].includes? column.sql_type
+ PostgreSQLColumn.cidr_to_string(value)
else
super
end
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
index 44e407a561..d4ffa82b17 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
@@ -21,10 +21,6 @@ module ActiveRecord
config[:database] = File.expand_path(config[:database], Rails.root)
end
- unless 'sqlite3' == config[:adapter]
- raise ArgumentError, 'adapter name should be "sqlite3"'
- end
-
db = SQLite3::Database.new(
config[:database],
:results_as_hash => true
@@ -195,7 +191,7 @@ module ActiveRecord
:decimal => { :name => "decimal" },
:datetime => { :name => "datetime" },
:timestamp => { :name => "datetime" },
- :time => { :name => "time" },
+ :time => { :name => "datetime" },
:date => { :name => "date" },
:binary => { :name => "blob" },
:boolean => { :name => "boolean" }
@@ -522,7 +518,11 @@ module ActiveRecord
end
def copy_table(from, to, options = {}) #:nodoc:
- options = options.merge(:id => (!columns(from).detect{|c| c.name == 'id'}.nil? && 'id' == primary_key(from).to_s))
+ from_primary_key = primary_key(from)
+ options[:primary_key] = from_primary_key if from_primary_key != 'id'
+ unless options[:primary_key]
+ options[:id] = columns(from).detect{|c| c.name == 'id'}.present? && from_primary_key == 'id'
+ end
create_table(to, options) do |definition|
@definition = definition
columns(from).each do |column|
@@ -536,7 +536,7 @@ module ActiveRecord
:precision => column.precision, :scale => column.scale,
:null => column.null)
end
- @definition.primary_key(primary_key(from)) if primary_key(from)
+ @definition.primary_key(from_primary_key) if from_primary_key
yield @definition if block_given?
end
diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb
index a869ed8c04..b2ed606e5f 100644
--- a/activerecord/lib/active_record/core.rb
+++ b/activerecord/lib/active_record/core.rb
@@ -77,7 +77,7 @@ module ActiveRecord
##
# :singleton-method:
- # Specifies wether or not has_many or has_one association option
+ # Specifies whether or not has_many or has_one association option
# :dependent => :restrict raises an exception. If set to true, the
# ActiveRecord::DeleteRestrictionError exception will be raised
# along with a DEPRECATION WARNING. If set to false, an error would
@@ -127,10 +127,16 @@ module ActiveRecord
object.is_a?(self)
end
+ # Returns an instance of <tt>Arel::Table</tt> loaded with the curent table name.
+ #
+ # class Post < ActiveRecord::Base
+ # scope :published_and_commented, published.and(self.arel_table[:comments_count].gt(0))
+ # end
def arel_table
@arel_table ||= Arel::Table.new(table_name, arel_engine)
end
+ # Returns the Arel engine.
def arel_engine
@arel_engine ||= connection_handler.retrieve_connection_pool(self) ? self : active_record_super.arel_engine
end
@@ -205,13 +211,34 @@ module ActiveRecord
self
end
+ ##
+ # :method: clone
+ # Identical to Ruby's clone method. This is a "shallow" copy. Be warned that your attributes are not copied.
+ # That means that modifying attributes of the clone will modify the original, since they will both point to the
+ # same attributes hash. If you need a copy of your attributes hash, please use the #dup method.
+ #
+ # user = User.first
+ # new_user = user.clone
+ # user.name # => "Bob"
+ # new_user.name = "Joe"
+ # user.name # => "Joe"
+ #
+ # user.object_id == new_user.object_id # => false
+ # user.name.object_id == new_user.name.object_id # => true
+ #
+ # user.name.object_id == user.dup.name.object_id # => false
+
+ ##
+ # :method: dup
# Duped objects have no id assigned and are treated as new records. Note
# that this is a "shallow" copy as it copies the object's attributes
# only, not its associations. The extent of a "deep" copy is application
# specific and is therefore left to the application to implement according
# to its need.
# The dup method does not preserve the timestamps (created|updated)_(at|on).
- def initialize_dup(other)
+
+ ##
+ def initialize_dup(other) # :nodoc:
cloned_attributes = other.clone_attributes(:read_attribute_before_type_cast)
self.class.initialize_attributes(cloned_attributes)
diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb
index a01e2f74ff..7e6512501c 100644
--- a/activerecord/lib/active_record/fixtures.rb
+++ b/activerecord/lib/active_record/fixtures.rb
@@ -83,7 +83,7 @@ module ActiveRecord
# end
#
# test "find_alt_method_2" do
- # assert_equal "Ruby on Rails", @rubyonrails.news
+ # assert_equal "Ruby on Rails", @rubyonrails.name
# end
#
# In order to use these methods to access fixtured data within your testcases, you must specify one of the
@@ -372,19 +372,23 @@ module ActiveRecord
#
# Any fixture labeled "DEFAULTS" is safely ignored.
class Fixtures
+ #--
+ # NOTE: an instance of Fixtures can be called fixture_set, it is normally stored in a single YAML file and possibly in a folder with the same name.
+ #++
MAX_ID = 2 ** 30 - 1
@@all_cached_fixtures = Hash.new { |h,k| h[k] = {} }
- def self.default_fixture_model_name(fixture_name) # :nodoc:
+ def self.default_fixture_model_name(fixture_set_name) # :nodoc:
ActiveRecord::Base.pluralize_table_names ?
- fixture_name.singularize.camelize :
- fixture_name.camelize
+ fixture_set_name.singularize.camelize :
+ fixture_set_name.camelize
end
- def self.default_fixture_table_name(fixture_name) # :nodoc:
- "#{ActiveRecord::Base.table_name_prefix}"\
- "#{fixture_name.tr('/', '_')}#{ActiveRecord::Base.table_name_suffix}".to_sym
+ def self.default_fixture_table_name(fixture_set_name) # :nodoc:
+ "#{ ActiveRecord::Base.table_name_prefix }"\
+ "#{ fixture_set_name.tr('/', '_') }"\
+ "#{ ActiveRecord::Base.table_name_suffix }".to_sym
end
def self.reset_cache
@@ -411,11 +415,11 @@ module ActiveRecord
cache_for_connection(connection).update(fixtures_map)
end
- def self.instantiate_fixtures(object, fixture_name, fixtures, load_instances = true)
+ def self.instantiate_fixtures(object, fixture_set, load_instances = true)
if load_instances
- fixtures.each do |name, fixture|
+ fixture_set.each do |fixture_name, fixture|
begin
- object.instance_variable_set "@#{name}", fixture.find
+ object.instance_variable_set "@#{fixture_name}", fixture.find
rescue FixtureClassNotFound
nil
end
@@ -424,61 +428,59 @@ module ActiveRecord
end
def self.instantiate_all_loaded_fixtures(object, load_instances = true)
- all_loaded_fixtures.each do |table_name, fixtures|
- ActiveRecord::Fixtures.instantiate_fixtures(object, table_name, fixtures, load_instances)
+ all_loaded_fixtures.each_value do |fixture_set|
+ instantiate_fixtures(object, fixture_set, load_instances)
end
end
cattr_accessor :all_loaded_fixtures
self.all_loaded_fixtures = {}
- def self.create_fixtures(fixtures_directory, table_names, class_names = {})
- table_names = Array(table_names).map(&:to_s)
+ def self.create_fixtures(fixtures_directory, fixture_set_names, class_names = {})
+ fixture_set_names = Array(fixture_set_names).map(&:to_s)
class_names = class_names.stringify_keys
# FIXME: Apparently JK uses this.
connection = block_given? ? yield : ActiveRecord::Base.connection
- files_to_read = table_names.reject { |table_name|
- fixture_is_cached?(connection, table_name)
+ files_to_read = fixture_set_names.reject { |fs_name|
+ fixture_is_cached?(connection, fs_name)
}
unless files_to_read.empty?
connection.disable_referential_integrity do
fixtures_map = {}
- fixture_files = files_to_read.map do |path|
- fixture_name = path
-
- fixtures_map[fixture_name] = new( # ActiveRecord::Fixtures.new
+ fixture_sets = files_to_read.map do |fs_name|
+ fixtures_map[fs_name] = new( # ActiveRecord::Fixtures.new
connection,
- fixture_name,
- class_names[fixture_name.to_s] || default_fixture_model_name(fixture_name),
- ::File.join(fixtures_directory, path))
+ fs_name,
+ class_names[fs_name] || default_fixture_model_name(fs_name),
+ ::File.join(fixtures_directory, fs_name))
end
all_loaded_fixtures.update(fixtures_map)
connection.transaction(:requires_new => true) do
- fixture_files.each do |ff|
- conn = ff.model_class.respond_to?(:connection) ? ff.model_class.connection : connection
- table_rows = ff.table_rows
+ fixture_sets.each do |fs|
+ conn = fs.model_class.respond_to?(:connection) ? fs.model_class.connection : connection
+ table_rows = fs.table_rows
table_rows.keys.each do |table|
conn.delete "DELETE FROM #{conn.quote_table_name(table)}", 'Fixture Delete'
end
- table_rows.each do |table_name,rows|
+ table_rows.each do |fixture_set_name, rows|
rows.each do |row|
- conn.insert_fixture(row, table_name)
+ conn.insert_fixture(row, fixture_set_name)
end
end
end
# Cap primary key sequences to max(pk).
if connection.respond_to?(:reset_pk_sequence!)
- fixture_files.each do |ff|
- connection.reset_pk_sequence!(ff.table_name)
+ fixture_sets.each do |fs|
+ connection.reset_pk_sequence!(fs.table_name)
end
end
end
@@ -486,7 +488,7 @@ module ActiveRecord
cache_fixtures(connection, fixtures_map)
end
end
- cached_fixtures(connection, table_names)
+ cached_fixtures(connection, fixture_set_names)
end
# Returns a consistent, platform-independent identifier for +label+.
@@ -497,26 +499,23 @@ module ActiveRecord
attr_reader :table_name, :name, :fixtures, :model_class
- def initialize(connection, fixture_name, class_name, fixture_path)
- @connection = connection
- @fixture_path = fixture_path
- @name = fixture_name
- @class_name = class_name
-
- @fixtures = {}
+ def initialize(connection, name, class_name, path)
+ @fixtures = {} # Ordered hash
+ @name = name
+ @path = path
- # Should be an AR::Base type class
- if class_name.is_a?(Class)
+ if class_name.is_a?(Class) # TODO: Should be an AR::Base type class, or any?
@model_class = class_name
else
@model_class = class_name.constantize rescue nil
end
- @connection = model_class.connection if model_class && model_class.respond_to?(:connection)
+ @connection = ( model_class.respond_to?(:connection) ?
+ model_class.connection : connection )
@table_name = ( model_class.respond_to?(:table_name) ?
model_class.table_name :
- self.class.default_fixture_table_name(fixture_name) )
+ self.class.default_fixture_table_name(name) )
read_fixture_files
end
@@ -555,8 +554,8 @@ module ActiveRecord
if model_class && model_class < ActiveRecord::Model
# fill in timestamp columns if they aren't specified and the model is set to record_timestamps
if model_class.record_timestamps
- timestamp_column_names.each do |name|
- row[name] = now unless row.key?(name)
+ timestamp_column_names.each do |c_name|
+ row[c_name] = now unless row.key?(c_name)
end
end
@@ -634,26 +633,23 @@ module ActiveRecord
end
def read_fixture_files
- yaml_files = Dir["#{@fixture_path}/**/*.yml"].select { |f|
+ yaml_files = Dir["#{@path}/**/*.yml"].select { |f|
::File.file?(f)
} + [yaml_file_path]
yaml_files.each do |file|
Fixtures::File.open(file) do |fh|
- fh.each do |name, row|
- fixtures[name] = ActiveRecord::Fixture.new(row, model_class)
+ fh.each do |fixture_name, row|
+ fixtures[fixture_name] = ActiveRecord::Fixture.new(row, model_class)
end
end
end
end
def yaml_file_path
- "#{@fixture_path}.yml"
+ "#{@path}.yml"
end
- def yaml_fixtures_key(path)
- ::File.basename(@fixture_path).split(".").first
- end
end
class Fixture #:nodoc:
@@ -708,7 +704,7 @@ module ActiveRecord
class_attribute :fixture_table_names
class_attribute :fixture_class_names
class_attribute :use_transactional_fixtures
- class_attribute :use_instantiated_fixtures # true, false, or :no_instances
+ class_attribute :use_instantiated_fixtures # true, false, or :no_instances
class_attribute :pre_loaded_fixtures
self.fixture_table_names = []
@@ -716,9 +712,8 @@ module ActiveRecord
self.use_instantiated_fixtures = false
self.pre_loaded_fixtures = false
- self.fixture_class_names = Hash.new do |h, fixture_name|
- fixture_name = fixture_name.to_s
- h[fixture_name] = ActiveRecord::Fixtures.default_fixture_model_name(fixture_name)
+ self.fixture_class_names = Hash.new do |h, fixture_set_name|
+ h[fixture_set_name] = ActiveRecord::Fixtures.default_fixture_model_name(fixture_set_name)
end
end
@@ -742,18 +737,18 @@ module ActiveRecord
self.fixture_class_names = self.fixture_class_names.merge(class_names.stringify_keys)
end
- def fixtures(*fixture_names)
- if fixture_names.first == :all
- fixture_names = Dir["#{fixture_path}/**/*.yml"].map { |f|
+ def fixtures(*fixture_set_names)
+ if fixture_set_names.first == :all
+ fixture_set_names = Dir["#{fixture_path}/**/*.yml"].map { |f|
File.basename f, '.yml'
}
else
- fixture_names = fixture_names.flatten.map { |n| n.to_s }
+ fixture_set_names = fixture_set_names.flatten.map { |n| n.to_s }
end
- self.fixture_table_names |= fixture_names
- require_fixture_classes(fixture_names)
- setup_fixture_accessors(fixture_names)
+ self.fixture_table_names |= fixture_set_names
+ require_fixture_classes(fixture_set_names)
+ setup_fixture_accessors(fixture_set_names)
end
def try_to_load_dependency(file_name)
@@ -768,33 +763,39 @@ module ActiveRecord
end
end
- def require_fixture_classes(fixture_names = nil)
- (fixture_names || fixture_table_names).each do |fixture_name|
- file_name = fixture_name.to_s
+ def require_fixture_classes(fixture_set_names = nil)
+ if fixture_set_names
+ fixture_set_names = fixture_set_names.map { |n| n.to_s }
+ else
+ fixture_set_names = fixture_table_names
+ end
+
+ fixture_set_names.each do |file_name|
file_name = file_name.singularize if ActiveRecord::Base.pluralize_table_names
try_to_load_dependency(file_name)
end
end
- def setup_fixture_accessors(fixture_names = nil)
- fixture_names = Array(fixture_names || fixture_table_names)
+ def setup_fixture_accessors(fixture_set_names = nil)
+ fixture_set_names = Array(fixture_set_names || fixture_table_names)
methods = Module.new do
- fixture_names.each do |fixture_name|
- fixture_name = fixture_name.to_s
- accessor_name = fixture_name.tr('/', '_').to_sym
+ fixture_set_names.each do |fs_name|
+ fs_name = fs_name.to_s
+ accessor_name = fs_name.tr('/', '_').to_sym
- define_method(accessor_name) do |*fixtures|
- force_reload = fixtures.pop if fixtures.last == true || fixtures.last == :reload
+ define_method(accessor_name) do |*fixture_names|
+ force_reload = fixture_names.pop if fixture_names.last == true || fixture_names.last == :reload
- @fixture_cache[fixture_name] ||= {}
+ @fixture_cache[fs_name] ||= {}
- instances = fixtures.map do |fixture|
- @fixture_cache[fixture_name].delete(fixture) if force_reload
+ instances = fixture_names.map do |f_name|
+ f_name = f_name.to_s
+ @fixture_cache[fs_name].delete(f_name) if force_reload
- if @loaded_fixtures[fixture_name][fixture.to_s]
- @fixture_cache[fixture_name][fixture] ||= @loaded_fixtures[fixture_name][fixture.to_s].find
+ if @loaded_fixtures[fs_name][f_name]
+ @fixture_cache[fs_name][f_name] ||= @loaded_fixtures[fs_name][f_name].find
else
- raise StandardError, "No entry named '#{fixture}' found for fixture collection '#{fixture_name}'"
+ raise StandardError, "No fixture named '#{f_name}' found for fixture set '#{fs_name}'"
end
end
@@ -901,8 +902,8 @@ module ActiveRecord
ActiveRecord::Fixtures.instantiate_all_loaded_fixtures(self, load_instances?)
else
raise RuntimeError, 'Load fixtures before instantiating them.' if @loaded_fixtures.nil?
- @loaded_fixtures.each do |fixture_name, fixtures|
- ActiveRecord::Fixtures.instantiate_fixtures(self, fixture_name, fixtures, load_instances?)
+ @loaded_fixtures.each_value do |fixture_set|
+ ActiveRecord::Fixtures.instantiate_fixtures(self, fixture_set, load_instances?)
end
end
end
diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb
index 32a1dae6bc..95a2ddcc11 100644
--- a/activerecord/lib/active_record/nested_attributes.rb
+++ b/activerecord/lib/active_record/nested_attributes.rb
@@ -19,10 +19,10 @@ module ActiveRecord
# = Active Record Nested Attributes
#
# Nested attributes allow you to save attributes on associated records
- # through the parent. By default nested attribute updating is turned off,
- # you can enable it using the accepts_nested_attributes_for class method.
- # When you enable nested attributes an attribute writer is defined on
- # the model.
+ # through the parent. By default nested attribute updating is turned off
+ # and you can enable it using the accepts_nested_attributes_for class
+ # method. When you enable nested attributes an attribute writer is
+ # defined on the model.
#
# The attribute writer is named after the association, which means that
# in the following example, two new methods are added to your model:
diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb
index 4a987c2343..a1bc39a32d 100644
--- a/activerecord/lib/active_record/persistence.rb
+++ b/activerecord/lib/active_record/persistence.rb
@@ -123,6 +123,7 @@ module ActiveRecord
# Deletes the record in the database and freezes this instance to reflect
# that no changes should be made (since they can't be persisted).
def destroy
+ raise ReadOnlyRecord if readonly?
destroy_associations
destroy_row if persisted?
@destroyed = true
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index 3ce9995031..31d99f0192 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -108,34 +108,57 @@ module ActiveRecord
0
end
- # This method is designed to perform select by a single column as direct SQL query
- # Returns <tt>Array</tt> with values of the specified column name
- # The values has same data type as column.
+ # Use <tt>pluck</tt> as a shortcut to select a single attribute without
+ # loading a bunch of records just to grab one attribute you want.
+ #
+ # Person.pluck(:name)
+ #
+ # instead of
+ #
+ # Person.all.map(&:name)
+ #
+ # Pluck returns an <tt>Array</tt> of attribute values type-casted to match
+ # the plucked column name, if it can be deduced. Plucking a SQL fragment
+ # returns String values by default.
#
# Examples:
#
- # Person.pluck(:id) # SELECT people.id FROM people
- # Person.uniq.pluck(:role) # SELECT DISTINCT role FROM people
- # Person.where(:age => 21).limit(5).pluck(:id) # SELECT people.id FROM people WHERE people.age = 21 LIMIT 5
+ # Person.pluck(:id)
+ # # SELECT people.id FROM people
+ # # => [1, 2, 3]
+ #
+ # Person.uniq.pluck(:role)
+ # # SELECT DISTINCT role FROM people
+ # # => ['admin', 'member', 'guest']
+ #
+ # Person.where(:age => 21).limit(5).pluck(:id)
+ # # SELECT people.id FROM people WHERE people.age = 21 LIMIT 5
+ # # => [2, 3]
+ #
+ # Person.pluck('DATEDIFF(updated_at, created_at)')
+ # # SELECT DATEDIFF(updated_at, created_at) FROM people
+ # # => ['0', '27761', '173']
#
def pluck(column_name)
- key = column_name.to_s.split('.', 2).last
-
if column_name.is_a?(Symbol) && column_names.include?(column_name.to_s)
column_name = "#{table_name}.#{column_name}"
end
result = klass.connection.select_all(select(column_name).arel, nil, bind_values)
- types = result.column_types.merge klass.column_types
- column = types[key]
+
+ key = result.columns.first
+ column = klass.column_types.fetch(key) {
+ result.column_types.fetch(key) {
+ Class.new { def type_cast(v); v; end }.new
+ }
+ }
result.map do |attributes|
- value = klass.initialize_attributes(attributes)[key]
- if column
- column.type_cast value
- else
- value
- end
+ raise ArgumentError, "Pluck expects to select just one attribute: #{attributes.inspect}" unless attributes.one?
+
+ value = klass.initialize_attributes(attributes).values.first
+
+ column.type_cast(value)
end
end
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index cc716bbfd1..4fedd33d64 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -170,9 +170,8 @@ module ActiveRecord
# Person.exists?(['name LIKE ?', "%#{query}%"])
# Person.exists?
def exists?(id = false)
- return false if id.nil?
-
id = id.id if ActiveRecord::Model === id
+ return false if id.nil?
join_dependency = construct_join_dependency_for_association_find
relation = construct_relation_for_association_find(join_dependency)
diff --git a/activerecord/lib/active_record/relation/merger.rb b/activerecord/lib/active_record/relation/merger.rb
index 3f880ce5e9..36f98c6480 100644
--- a/activerecord/lib/active_record/relation/merger.rb
+++ b/activerecord/lib/active_record/relation/merger.rb
@@ -43,7 +43,7 @@ module ActiveRecord
def normal_values
Relation::SINGLE_VALUE_METHODS +
Relation::MULTI_VALUE_METHODS -
- [:where, :order, :bind, :reverse_order, :lock, :create_with, :reordering]
+ [:where, :order, :bind, :reverse_order, :lock, :create_with, :reordering, :from]
end
def merge
@@ -76,6 +76,7 @@ module ActiveRecord
end
def merge_single_values
+ relation.from_value = values[:from] unless relation.from_value
relation.lock_value = values[:lock] unless relation.lock_value
relation.reverse_order_value = values[:reverse_order]
diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb
index b40bf2b3cf..6a0cdd5917 100644
--- a/activerecord/lib/active_record/relation/predicate_builder.rb
+++ b/activerecord/lib/active_record/relation/predicate_builder.rb
@@ -34,9 +34,6 @@ module ActiveRecord
private
def self.build(attribute, value)
case value
- when ActiveRecord::Relation
- value = value.select(value.klass.arel_table[value.klass.primary_key]) if value.select_values.empty?
- attribute.in(value.arel.ast)
when Array, ActiveRecord::Associations::CollectionProxy
values = value.to_a.map {|x| x.is_a?(ActiveRecord::Model) ? x.id : x}
ranges, values = values.partition {|v| v.is_a?(Range)}
@@ -59,6 +56,9 @@ module ActiveRecord
array_predicates = ranges.map { |range| attribute.in(range) }
array_predicates << values_predicate
array_predicates.inject { |composite, predicate| composite.or(predicate) }
+ when ActiveRecord::Relation
+ value = value.select(value.klass.arel_table[value.klass.primary_key]) if value.select_values.empty?
+ attribute.in(value.arel.ast)
when Range
attribute.in(value)
when ActiveRecord::Model
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index 855477eaed..19fe8155d9 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -40,7 +40,7 @@ module ActiveRecord
alias extensions extending_values
def includes(*args)
- args.empty? ? self : clone.includes!(*args)
+ args.empty? ? self : spawn.includes!(*args)
end
def includes!(*args)
@@ -51,7 +51,7 @@ module ActiveRecord
end
def eager_load(*args)
- args.blank? ? self : clone.eager_load!(*args)
+ args.blank? ? self : spawn.eager_load!(*args)
end
def eager_load!(*args)
@@ -60,7 +60,7 @@ module ActiveRecord
end
def preload(*args)
- args.blank? ? self : clone.preload!(*args)
+ args.blank? ? self : spawn.preload!(*args)
end
def preload!(*args)
@@ -79,7 +79,7 @@ module ActiveRecord
# User.includes(:posts).where("posts.name = 'foo'").references(:posts)
# # => Query now knows the string references posts, so adds a JOIN
def references(*args)
- args.blank? ? self : clone.references!(*args)
+ args.blank? ? self : spawn.references!(*args)
end
def references!(*args)
@@ -120,7 +120,7 @@ module ActiveRecord
if block_given?
to_a.select { |*block_args| value.call(*block_args) }
else
- clone.select!(value)
+ spawn.select!(value)
end
end
@@ -130,7 +130,7 @@ module ActiveRecord
end
def group(*args)
- args.blank? ? self : clone.group!(*args)
+ args.blank? ? self : spawn.group!(*args)
end
def group!(*args)
@@ -139,7 +139,7 @@ module ActiveRecord
end
def order(*args)
- args.blank? ? self : clone.order!(*args)
+ args.blank? ? self : spawn.order!(*args)
end
def order!(*args)
@@ -165,7 +165,7 @@ module ActiveRecord
# generates a query with 'ORDER BY id ASC, name ASC'.
#
def reorder(*args)
- args.blank? ? self : clone.reorder!(*args)
+ args.blank? ? self : spawn.reorder!(*args)
end
def reorder!(*args)
@@ -175,7 +175,7 @@ module ActiveRecord
end
def joins(*args)
- args.compact.blank? ? self : clone.joins!(*args)
+ args.compact.blank? ? self : spawn.joins!(*args)
end
def joins!(*args)
@@ -186,7 +186,7 @@ module ActiveRecord
end
def bind(value)
- clone.bind!(value)
+ spawn.bind!(value)
end
def bind!(value)
@@ -195,7 +195,7 @@ module ActiveRecord
end
def where(opts, *rest)
- opts.blank? ? self : clone.where!(opts, *rest)
+ opts.blank? ? self : spawn.where!(opts, *rest)
end
def where!(opts, *rest)
@@ -206,7 +206,7 @@ module ActiveRecord
end
def having(opts, *rest)
- opts.blank? ? self : clone.having!(opts, *rest)
+ opts.blank? ? self : spawn.having!(opts, *rest)
end
def having!(opts, *rest)
@@ -217,7 +217,7 @@ module ActiveRecord
end
def limit(value)
- clone.limit!(value)
+ spawn.limit!(value)
end
def limit!(value)
@@ -226,7 +226,7 @@ module ActiveRecord
end
def offset(value)
- clone.offset!(value)
+ spawn.offset!(value)
end
def offset!(value)
@@ -235,7 +235,7 @@ module ActiveRecord
end
def lock(locks = true)
- clone.lock!(locks)
+ spawn.lock!(locks)
end
def lock!(locks = true)
@@ -283,7 +283,7 @@ module ActiveRecord
end
def readonly(value = true)
- clone.readonly!(value)
+ spawn.readonly!(value)
end
def readonly!(value = true)
@@ -292,7 +292,7 @@ module ActiveRecord
end
def create_with(value)
- clone.create_with!(value)
+ spawn.create_with!(value)
end
def create_with!(value)
@@ -300,12 +300,25 @@ module ActiveRecord
self
end
- def from(value)
- clone.from!(value)
+ # Specifies table from which the records will be fetched. For example:
+ #
+ # Topic.select('title').from('posts')
+ # #=> SELECT title FROM posts
+ #
+ # Can accept other relation objects. For example:
+ #
+ # Topic.select('title').from(Topics.approved)
+ # # => SELECT title FROM (SELECT * FROM topics WHERE approved = 't') subquery
+ #
+ # Topics.select('a.title').from(Topics.approved, :a)
+ # # => SELECT a.title FROM (SELECT * FROM topics WHERE approved = 't') a
+ #
+ def from(value, subquery_name = nil)
+ spawn.from!(value, subquery_name)
end
- def from!(value)
- self.from_value = value
+ def from!(value, subquery_name = nil)
+ self.from_value = [value, subquery_name]
self
end
@@ -320,7 +333,7 @@ module ActiveRecord
# User.select(:name).uniq.uniq(false)
# # => You can also remove the uniqueness
def uniq(value = true)
- clone.uniq!(value)
+ spawn.uniq!(value)
end
def uniq!(value = true)
@@ -366,7 +379,7 @@ module ActiveRecord
# end
def extending(*modules, &block)
if modules.any? || block
- clone.extending!(*modules, &block)
+ spawn.extending!(*modules, &block)
else
self
end
@@ -382,7 +395,7 @@ module ActiveRecord
end
def reverse_order
- clone.reverse_order!
+ spawn.reverse_order!
end
def reverse_order!
@@ -415,7 +428,7 @@ module ActiveRecord
build_select(arel, select_values.uniq)
arel.distinct(uniq_value)
- arel.from(from_value) if from_value
+ arel.from(build_from) if from_value
arel.lock(lock_value) if lock_value
arel
@@ -464,6 +477,17 @@ module ActiveRecord
end
end
+ def build_from
+ opts, name = from_value
+ case opts
+ when Relation
+ name ||= 'subquery'
+ opts.arel.as(name.to_s)
+ else
+ opts
+ end
+ end
+
def build_joins(manager, joins)
buckets = joins.group_by do |join|
case join
diff --git a/activerecord/lib/active_record/relation/spawn_methods.rb b/activerecord/lib/active_record/relation/spawn_methods.rb
index f6d178db7a..80d087a9ea 100644
--- a/activerecord/lib/active_record/relation/spawn_methods.rb
+++ b/activerecord/lib/active_record/relation/spawn_methods.rb
@@ -5,7 +5,12 @@ require 'active_record/relation/merger'
module ActiveRecord
module SpawnMethods
-
+
+ # This is overridden by Associations::CollectionProxy
+ def spawn #:nodoc:
+ clone
+ end
+
# Merges in the conditions from <tt>other</tt>, if <tt>other</tt> is an <tt>ActiveRecord::Relation</tt>.
# Returns an array representing the intersection of the resulting records with <tt>other</tt>, if <tt>other</tt> is an array.
#
@@ -23,7 +28,7 @@ module ActiveRecord
if other.is_a?(Array)
to_a & other
elsif other
- clone.merge!(other)
+ spawn.merge!(other)
else
self
end
@@ -42,7 +47,7 @@ module ActiveRecord
# Post.where('id > 10').order('id asc').except(:where) # discards the where condition but keeps the order
#
def except(*skips)
- result = self.class.new(@klass, table, values.except(*skips))
+ result = Relation.new(klass, table, values.except(*skips))
result.default_scoped = default_scoped
result.extend(*extending_values) if extending_values.any?
result
@@ -56,7 +61,7 @@ module ActiveRecord
# Post.order('id asc').only(:where, :order) # uses the specified order
#
def only(*onlies)
- result = self.class.new(@klass, table, values.slice(*onlies))
+ result = Relation.new(klass, table, values.slice(*onlies))
result.default_scoped = default_scoped
result.extend(*extending_values) if extending_values.any?
result
diff --git a/activerecord/lib/active_record/schema.rb b/activerecord/lib/active_record/schema.rb
index d815ab05ac..599e68379a 100644
--- a/activerecord/lib/active_record/schema.rb
+++ b/activerecord/lib/active_record/schema.rb
@@ -34,6 +34,15 @@ module ActiveRecord
ActiveRecord::Migrator.migrations_paths
end
+ def define(info, &block)
+ instance_eval(&block)
+
+ unless info[:version].blank?
+ initialize_schema_migrations_table
+ assume_migrated_upto_version(info[:version], migrations_paths)
+ end
+ end
+
# Eval the given block. All methods available to the current connection
# adapter are available within the block, so you can easily use the
# database definition DSL to build up your schema (+create_table+,
@@ -46,13 +55,7 @@ module ActiveRecord
# ...
# end
def self.define(info={}, &block)
- schema = new
- schema.instance_eval(&block)
-
- unless info[:version].blank?
- initialize_schema_migrations_table
- assume_migrated_upto_version(info[:version], schema.migrations_paths)
- end
+ new.define(info, &block)
end
end
end
diff --git a/activerecord/lib/active_record/session_store.rb b/activerecord/lib/active_record/session_store.rb
index ed47a26749..5a256b040b 100644
--- a/activerecord/lib/active_record/session_store.rb
+++ b/activerecord/lib/active_record/session_store.rb
@@ -201,10 +201,10 @@ module ActiveRecord
class << self
alias :data_column_name :data_column
-
+
# Use the ActiveRecord::Base.connection by default.
attr_writer :connection
-
+
# Use the ActiveRecord::Base.connection_pool by default.
attr_writer :connection_pool
@@ -218,12 +218,12 @@ module ActiveRecord
# Look up a session by id and unmarshal its data if found.
def find_by_session_id(session_id)
- if record = connection.select_one("SELECT * FROM #{@@table_name} WHERE #{@@session_id_column}=#{connection.quote(session_id)}")
+ if record = connection.select_one("SELECT * FROM #{@@table_name} WHERE #{@@session_id_column}=#{connection.quote(session_id.to_s)}")
new(:session_id => session_id, :marshaled_data => record['data'])
end
end
end
-
+
delegate :connection, :connection=, :connection_pool, :connection_pool=, :to => self
attr_reader :session_id, :new_record
@@ -241,6 +241,11 @@ module ActiveRecord
@new_record = @marshaled_data.nil?
end
+ # Returns true if the record is persisted, i.e. it's not a new record
+ def persisted?
+ !@new_record
+ end
+
# Lazy-unmarshal session state.
def data
unless @data
@@ -287,7 +292,7 @@ module ActiveRecord
connect = connection
connect.delete <<-end_sql, 'Destroy session'
DELETE FROM #{table_name}
- WHERE #{connect.quote_column_name(session_id_column)}=#{connect.quote(session_id)}
+ WHERE #{connect.quote_column_name(session_id_column)}=#{connect.quote(session_id.to_s)}
end_sql
end
end
diff --git a/activerecord/lib/active_record/store.rb b/activerecord/lib/active_record/store.rb
index 1c7b839e5e..ce2ea85ef9 100644
--- a/activerecord/lib/active_record/store.rb
+++ b/activerecord/lib/active_record/store.rb
@@ -10,15 +10,21 @@ module ActiveRecord
# Make sure that you declare the database column used for the serialized store as a text, so there's
# plenty of room.
#
+ # You can set custom coder to encode/decode your serialized attributes to/from different formats.
+ # JSON, YAML, Marshal are supported out of the box. Generally it can be any wrapper that provides +load+ and +dump+.
+ #
+ # String keys should be used for direct access to virtual attributes because of most of the coders do not
+ # distinguish symbols and strings as keys.
+ #
# Examples:
#
# class User < ActiveRecord::Base
- # store :settings, accessors: [ :color, :homepage ]
+ # store :settings, accessors: [ :color, :homepage ], coder: JSON
# end
#
# u = User.new(color: 'black', homepage: '37signals.com')
- # u.color # Accessor stored attribute
- # u.settings[:country] = 'Denmark' # Any attribute, even if not specified with an accessor
+ # u.color # Accessor stored attribute
+ # u.settings['country'] = 'Denmark' # Any attribute, even if not specified with an accessor
#
# # Add additional accessors to an existing store through store_accessor
# class SuperUser < User
@@ -29,7 +35,7 @@ module ActiveRecord
module ClassMethods
def store(store_attribute, options = {})
- serialize store_attribute, Hash
+ serialize store_attribute, options.fetch(:coder, Hash)
store_accessor(store_attribute, options[:accessors]) if options.has_key? :accessors
end
@@ -37,13 +43,13 @@ module ActiveRecord
keys.flatten.each do |key|
define_method("#{key}=") do |value|
send("#{store_attribute}=", {}) unless send(store_attribute).is_a?(Hash)
- send(store_attribute)[key] = value
+ send(store_attribute)[key.to_s] = value
send("#{store_attribute}_will_change!")
end
define_method(key) do
send("#{store_attribute}=", {}) unless send(store_attribute).is_a?(Hash)
- send(store_attribute)[key]
+ send(store_attribute)[key.to_s]
end
end
end
diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb
index 64e5640791..30e1035300 100644
--- a/activerecord/lib/active_record/transactions.rb
+++ b/activerecord/lib/active_record/transactions.rb
@@ -290,7 +290,15 @@ module ActiveRecord
status = nil
self.class.transaction do
add_to_transaction
- status = yield
+ begin
+ status = yield
+ rescue ActiveRecord::Rollback
+ if defined?(@_start_transaction_state)
+ @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
+ end
+ status = nil
+ end
+
raise ActiveRecord::Rollback unless status
end
status
diff --git a/activerecord/test/cases/adapters/postgresql/datatype_test.rb b/activerecord/test/cases/adapters/postgresql/datatype_test.rb
index ce08e4c6a7..34660577da 100644
--- a/activerecord/test/cases/adapters/postgresql/datatype_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/datatype_test.rb
@@ -86,9 +86,9 @@ class PostgresqlDataTypeTest < ActiveRecord::TestCase
end
def test_data_type_of_network_address_types
- assert_equal :string, @first_network_address.column_for_attribute(:cidr_address).type
- assert_equal :string, @first_network_address.column_for_attribute(:inet_address).type
- assert_equal :string, @first_network_address.column_for_attribute(:mac_address).type
+ assert_equal :cidr, @first_network_address.column_for_attribute(:cidr_address).type
+ assert_equal :inet, @first_network_address.column_for_attribute(:inet_address).type
+ assert_equal :macaddr, @first_network_address.column_for_attribute(:mac_address).type
end
def test_data_type_of_bit_string_types
@@ -134,9 +134,12 @@ class PostgresqlDataTypeTest < ActiveRecord::TestCase
assert_equal '-1 years -2 days', @first_time.time_interval
end
- def test_network_address_values
- assert_equal '192.168.0.0/24', @first_network_address.cidr_address
- assert_equal '172.16.1.254', @first_network_address.inet_address
+ def test_network_address_values_ipaddr
+ cidr_address = IPAddr.new '192.168.0.0/24'
+ inet_address = IPAddr.new '172.16.1.254'
+
+ assert_equal cidr_address, @first_network_address.cidr_address
+ assert_equal inet_address, @first_network_address.inet_address
assert_equal '01:23:45:67:89:0a', @first_network_address.mac_address
end
@@ -200,8 +203,8 @@ class PostgresqlDataTypeTest < ActiveRecord::TestCase
end
def test_update_network_address
- new_cidr_address = '10.1.2.3/32'
- new_inet_address = '10.0.0.0/8'
+ new_inet_address = '10.1.2.3/32'
+ new_cidr_address = '10.0.0.0/8'
new_mac_address = 'bc:de:f0:12:34:56'
assert @first_network_address.cidr_address = new_cidr_address
assert @first_network_address.inet_address = new_inet_address
diff --git a/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb b/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb
index 575b4806c1..7eef4ace81 100644
--- a/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb
+++ b/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb
@@ -57,6 +57,14 @@ class CopyTableTest < ActiveRecord::TestCase
end
end
+ def test_copy_table_with_unconventional_primary_key
+ test_copy_table('owners', 'owners_unconventional') do |from, to, options|
+ original_pk = @connection.primary_key('owners')
+ copied_pk = @connection.primary_key('owners_unconventional')
+ assert_equal original_pk, copied_pk
+ end
+ end
+
protected
def copy_table(from, to, options = {})
@connection.copy_table(from, to, {:temporary => true}.merge(options))
diff --git a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
index 17bde6cb62..8a7f44d0a3 100644
--- a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
+++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
@@ -35,6 +35,11 @@ module ActiveRecord
assert(!result.rows.first.include?("blob"), "should not store blobs")
end
+ def test_time_column
+ owner = Owner.create!(:eats_at => Time.utc(1995,1,1,6,0))
+ assert_match(/1995-01-01/, owner.reload.eats_at.to_s)
+ end
+
def test_exec_insert
column = @conn.columns('items').find { |col| col.name == 'number' }
vals = [[column, 10]]
@@ -58,18 +63,6 @@ module ActiveRecord
end
end
- def test_connection_no_adapter
- assert_raises(ArgumentError) do
- Base.sqlite3_connection :database => ':memory:'
- end
- end
-
- def test_connection_wrong_adapter
- assert_raises(ArgumentError) do
- Base.sqlite3_connection :database => ':memory:',:adapter => 'vuvuzela'
- end
- end
-
def test_bad_timeout
assert_raises(TypeError) do
Base.sqlite3_connection :database => ':memory:',
diff --git a/activerecord/test/cases/ar_schema_test.rb b/activerecord/test/cases/ar_schema_test.rb
index 588adc38e3..b2eac0349b 100644
--- a/activerecord/test/cases/ar_schema_test.rb
+++ b/activerecord/test/cases/ar_schema_test.rb
@@ -37,6 +37,13 @@ if ActiveRecord::Base.connection.supports_migrations?
end
end
end
+
+ def test_schema_subclass
+ Class.new(ActiveRecord::Schema).define(:version => 9) do
+ create_table :fruits
+ end
+ assert_nothing_raised { @connection.select_all "SELECT * FROM fruits" }
+ end
end
end
diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb
index 2e44005847..08467900f9 100644
--- a/activerecord/test/cases/associations/eager_test.rb
+++ b/activerecord/test/cases/associations/eager_test.rb
@@ -189,7 +189,7 @@ class EagerAssociationTest < ActiveRecord::TestCase
author = assert_queries(3) { Author.scoped(:includes => {:posts_with_comments => :comments}).find(author_id) } # find the author, then find the posts, then find the comments
author.posts_with_comments.each do |post_with_comments|
assert_equal post_with_comments.comments.length, post_with_comments.comments.count
- assert_nil post_with_comments.comments.uniq!
+ assert_nil post_with_comments.comments.to_a.uniq!
end
end
diff --git a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
index 22fd80df28..a6daf54c01 100644
--- a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
@@ -123,11 +123,6 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
assert active_record.developers.include?(david)
end
- def test_triple_equality
- assert !(Array === Developer.find(1).projects)
- assert Developer.find(1).projects === Array
- end
-
def test_adding_single
jamis = Developer.find(2)
jamis.projects.reload # causing the collection to load
@@ -338,6 +333,12 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
assert_equal 3, project.developers.size
end
+ def test_uniq_when_association_already_loaded
+ project = projects(:active_record)
+ project.developers << [ developers(:jamis), developers(:david), developers(:jamis), developers(:david) ]
+ assert_equal 3, Project.includes(:developers).find(project.id).developers.size
+ end
+
def test_deleting
david = Developer.find(1)
active_record = Project.find(1)
@@ -497,7 +498,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
def test_include_uses_array_include_after_loaded
project = projects(:active_record)
- project.developers.class # force load target
+ project.developers.load_target
developer = project.developers.first
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb
index f74fe42dc2..2e24f8ebe1 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -326,12 +326,6 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
authors(:david).readonly_comments.each { |c| assert c.readonly? }
end
- def test_triple_equality
- # sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first
- assert !(Array === Firm.scoped(:order => "id").first.clients)
- assert Firm.scoped(:order => "id").first.clients === Array
- end
-
def test_finding_default_orders
assert_equal "Summit", Firm.scoped(:order => "id").first.clients.first.name
end
@@ -892,12 +886,11 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
client_id = firm.clients_of_firm.first.id
assert_equal 1, firm.clients_of_firm.size
- cleared = firm.clients_of_firm.clear
+ firm.clients_of_firm.clear
assert_equal 0, firm.clients_of_firm.size
assert_equal 0, firm.clients_of_firm(true).size
assert_equal [], Client.destroyed_client_ids[firm.id]
- assert_equal firm.clients_of_firm.object_id, cleared.object_id
# Should not be destroyed since the association is not dependent.
assert_nothing_raised do
@@ -1359,7 +1352,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_include_uses_array_include_after_loaded
firm = companies(:first_firm)
- firm.clients.class # force load target
+ firm.clients.load_target
client = firm.clients.first
@@ -1409,7 +1402,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
def test_calling_first_or_last_on_loaded_association_should_not_fetch_with_query
firm = companies(:first_firm)
- firm.clients.class # force load target
+ firm.clients.load_target
assert firm.clients.loaded?
assert_no_queries do
@@ -1692,6 +1685,18 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal [bulb2], car.reload.bulbs
end
+ def test_replace_returns_new_target
+ car = Car.create(:name => 'honda')
+ bulb1 = car.bulbs.create
+ bulb2 = car.bulbs.create
+ bulb3 = Bulb.create
+
+ assert_equal [bulb1, bulb2], car.bulbs
+ result = car.bulbs.replace([bulb1, bulb3])
+ assert_equal [bulb1, bulb3], car.bulbs
+ assert_equal [bulb1, bulb3], result
+ end
+
def test_building_has_many_association_with_restrict_dependency
option_before = ActiveRecord::Base.dependent_restrict_raises
ActiveRecord::Base.dependent_restrict_raises = true
@@ -1708,4 +1713,18 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
firm = companies(:first_firm)
assert_equal [accounts(:signals37)], firm.accounts.open
end
+
+ test "first_or_initialize adds the record to the association" do
+ firm = Firm.create! name: 'omg'
+ client = firm.clients_of_firm.first_or_initialize
+ assert_equal [client], firm.clients_of_firm
+ end
+
+ test "first_or_create adds the record to the association" do
+ firm = Firm.create! name: 'omg'
+ firm.clients_of_firm.load_target
+ client = firm.clients_of_firm.first_or_create name: 'lol'
+ assert_equal [client], firm.clients_of_firm
+ assert_equal [client], firm.reload.clients_of_firm
+ end
end
diff --git a/activerecord/test/cases/associations/join_model_test.rb b/activerecord/test/cases/associations/join_model_test.rb
index 3606ce691c..20b0eeb5ea 100644
--- a/activerecord/test/cases/associations/join_model_test.rb
+++ b/activerecord/test/cases/associations/join_model_test.rb
@@ -676,7 +676,7 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
def test_has_many_through_include_uses_array_include_after_loaded
david = authors(:david)
- david.categories.class # force load target
+ david.categories.load_target
category = david.categories.first
diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb
index c93c91803e..8ef3bfef15 100644
--- a/activerecord/test/cases/autosave_association_test.rb
+++ b/activerecord/test/cases/autosave_association_test.rb
@@ -872,7 +872,7 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase
2.times { |i| @pirate.parrots.create!(:name => "parrots_#{i}") }
before = @pirate.parrots.map { |c| c.mark_for_destruction ; c }
- class << @pirate.parrots
+ class << @pirate.association(:parrots)
def destroy(*args)
super
raise 'Oh noes!'
@@ -1277,7 +1277,7 @@ module AutosaveAssociationOnACollectionAssociationTests
def test_should_not_load_the_associated_models_if_they_were_not_loaded_yet
assert_queries(1) { @pirate.catchphrase = 'Arr'; @pirate.save! }
- @pirate.send(@association_name).class # hack to load the target
+ @pirate.send(@association_name).load_target
assert_queries(3) do
@pirate.catchphrase = 'Yarr'
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index c1b0cb8886..66a16d8b5f 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -522,7 +522,7 @@ class BasicsTest < ActiveRecord::TestCase
end
# Oracle, and Sybase do not have a TIME datatype.
- unless current_adapter?(:OracleAdapter, :SybaseAdapter)
+ unless current_adapter?(:OracleAdapter, :SybaseAdapter, :SQLite3Adapter)
def test_utc_as_time_zone
Topic.default_timezone = :utc
attributes = { "bonus_time" => "5:42:00AM" }
@@ -764,6 +764,9 @@ class BasicsTest < ActiveRecord::TestCase
end
def test_multiparameter_attributes_on_time_will_ignore_hour_if_missing
+ ActiveRecord::Base.time_zone_aware_attributes = false
+ ActiveRecord::Base.default_timezone = :local
+ Time.zone = nil
attributes = {
"written_on(1i)" => "2004", "written_on(2i)" => "12", "written_on(3i)" => "12",
"written_on(5i)" => "12", "written_on(6i)" => "02"
@@ -870,7 +873,7 @@ class BasicsTest < ActiveRecord::TestCase
end
# Oracle, and Sybase do not have a TIME datatype.
- unless current_adapter?(:OracleAdapter, :SybaseAdapter)
+ unless current_adapter?(:OracleAdapter, :SybaseAdapter, :SQLite3Adapter)
def test_multiparameter_attributes_on_time_only_column_with_time_zone_aware_attributes_does_not_do_time_zone_conversion
ActiveRecord::Base.time_zone_aware_attributes = true
ActiveRecord::Base.default_timezone = :utc
@@ -891,6 +894,9 @@ class BasicsTest < ActiveRecord::TestCase
end
def test_multiparameter_attributes_on_time_with_empty_seconds
+ ActiveRecord::Base.time_zone_aware_attributes = false
+ ActiveRecord::Base.default_timezone = :local
+ Time.zone = nil
attributes = {
"written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
"written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => ""
@@ -946,7 +952,7 @@ class BasicsTest < ActiveRecord::TestCase
def test_attributes_on_dummy_time
# Oracle, and Sybase do not have a TIME datatype.
- return true if current_adapter?(:OracleAdapter, :SybaseAdapter)
+ return true if current_adapter?(:OracleAdapter, :SybaseAdapter, :SQLite3Adapter)
attributes = {
"bonus_time" => "5:42:00AM"
@@ -1514,11 +1520,7 @@ class BasicsTest < ActiveRecord::TestCase
after_seq = Joke.sequence_name
assert_not_equal before_columns, after_columns
- unless before_seq.nil? && after_seq.nil?
- assert_not_equal before_seq, after_seq
- assert_equal "cold_jokes_id_seq", before_seq
- assert_equal "funny_jokes_id_seq", after_seq
- end
+ assert_not_equal before_seq, after_seq unless before_seq.nil? && after_seq.nil?
end
def test_dont_clear_sequence_name_when_setting_explicitly
diff --git a/activerecord/test/cases/bind_parameter_test.rb b/activerecord/test/cases/bind_parameter_test.rb
index 3652255c38..03aa9fdb27 100644
--- a/activerecord/test/cases/bind_parameter_test.rb
+++ b/activerecord/test/cases/bind_parameter_test.rb
@@ -23,6 +23,8 @@ module ActiveRecord
@listener = LogListener.new
@pk = Topic.columns.find { |c| c.primary }
ActiveSupport::Notifications.subscribe('sql.active_record', @listener)
+
+ skip_if_prepared_statement_caching_is_not_supported
end
def teardown
@@ -30,9 +32,6 @@ module ActiveRecord
end
def test_binds_are_logged
- # FIXME: use skip with minitest
- return unless @connection.supports_statement_cache?
-
sub = @connection.substitute_at(@pk, 0)
binds = [[@pk, 1]]
sql = "select * from topics where id = #{sub}"
@@ -44,9 +43,6 @@ module ActiveRecord
end
def test_find_one_uses_binds
- # FIXME: use skip with minitest
- return unless @connection.supports_statement_cache?
-
Topic.find(1)
binds = [[@pk, 1]]
message = @listener.calls.find { |args| args[4][:binds] == binds }
@@ -54,9 +50,6 @@ module ActiveRecord
end
def test_logs_bind_vars
- # FIXME: use skip with minitest
- return unless @connection.supports_statement_cache?
-
pk = Topic.columns.find { |x| x.primary }
payload = {
@@ -86,5 +79,11 @@ module ActiveRecord
logger.sql event
assert_match([[pk.name, 10]].inspect, logger.debugs.first)
end
+
+ private
+
+ def skip_if_prepared_statement_caching_is_not_supported
+ skip('prepared statement caching is not supported') unless @connection.supports_statement_cache?
+ end
end
end
diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb
index e096585f62..041f8ffb7c 100644
--- a/activerecord/test/cases/calculations_test.rb
+++ b/activerecord/test/cases/calculations_test.rb
@@ -466,6 +466,21 @@ class CalculationsTest < ActiveRecord::TestCase
assert_equal [7], Company.joins(:contracts).pluck(:developer_id)
end
+ def test_pluck_with_selection_clause
+ assert_equal [50, 53, 55, 60], Account.pluck('DISTINCT credit_limit').sort
+ assert_equal [50, 53, 55, 60], Account.pluck('DISTINCT accounts.credit_limit').sort
+ assert_equal [50, 53, 55, 60], Account.pluck('DISTINCT(credit_limit)').sort
+
+ # MySQL returns "SUM(DISTINCT(credit_limit))" as the column name unless
+ # an alias is provided. Without the alias, the column cannot be found
+ # and properly typecast.
+ assert_equal [50 + 53 + 55 + 60], Account.pluck('SUM(DISTINCT(credit_limit)) as credit_limit')
+ end
+
+ def test_pluck_expects_a_single_selection
+ assert_raise(ArgumentError) { Account.pluck 'id, credit_limit' }
+ end
+
def test_plucks_with_ids
assert_equal Company.all.map(&:id).sort, Company.ids.sort
end
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index 630acdbc46..c960773284 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -32,6 +32,7 @@ class FinderTest < ActiveRecord::TestCase
assert Topic.exists?(:author_name => "Mary", :approved => true)
assert Topic.exists?(["parent_id = ?", 1])
assert !Topic.exists?(45)
+ assert !Topic.exists?(Topic.new)
begin
assert !Topic.exists?("foo")
diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb
index 345ae0b582..20279f814b 100644
--- a/activerecord/test/cases/helper.rb
+++ b/activerecord/test/cases/helper.rb
@@ -80,8 +80,8 @@ class ActiveSupport::TestCase
self.use_instantiated_fixtures = false
self.use_transactional_fixtures = true
- def create_fixtures(*table_names, &block)
- ActiveRecord::Fixtures.create_fixtures(ActiveSupport::TestCase.fixture_path, table_names, fixture_class_names, &block)
+ def create_fixtures(*fixture_set_names, &block)
+ ActiveRecord::Fixtures.create_fixtures(ActiveSupport::TestCase.fixture_path, fixture_set_names, fixture_class_names, &block)
end
end
diff --git a/activerecord/test/cases/migration/change_schema_test.rb b/activerecord/test/cases/migration/change_schema_test.rb
index f0b1f74bd3..ab61a4dcef 100644
--- a/activerecord/test/cases/migration/change_schema_test.rb
+++ b/activerecord/test/cases/migration/change_schema_test.rb
@@ -83,7 +83,6 @@ module ActiveRecord
t.column :one_int, :integer, :limit => 1
t.column :four_int, :integer, :limit => 4
t.column :eight_int, :integer, :limit => 8
- t.column :eleven_int, :integer, :limit => 11
end
columns = connection.columns(:testings)
@@ -94,20 +93,17 @@ module ActiveRecord
one = columns.detect { |c| c.name == "one_int" }
four = columns.detect { |c| c.name == "four_int" }
eight = columns.detect { |c| c.name == "eight_int" }
- eleven = columns.detect { |c| c.name == "eleven_int" }
if current_adapter?(:PostgreSQLAdapter)
assert_equal 'integer', default.sql_type
assert_equal 'smallint', one.sql_type
assert_equal 'integer', four.sql_type
assert_equal 'bigint', eight.sql_type
- assert_equal 'integer', eleven.sql_type
elsif current_adapter?(:MysqlAdapter) or current_adapter?(:Mysql2Adapter)
assert_match 'int(11)', default.sql_type
assert_match 'tinyint', one.sql_type
assert_match 'int', four.sql_type
assert_match 'bigint', eight.sql_type
- assert_match 'int(11)', eleven.sql_type
elsif current_adapter?(:OracleAdapter)
assert_equal 'NUMBER(38)', default.sql_type
assert_equal 'NUMBER(1)', one.sql_type
diff --git a/activerecord/test/cases/migration/column_attributes_test.rb b/activerecord/test/cases/migration/column_attributes_test.rb
index 409a558f5c..18f8d82bfe 100644
--- a/activerecord/test/cases/migration/column_attributes_test.rb
+++ b/activerecord/test/cases/migration/column_attributes_test.rb
@@ -183,6 +183,16 @@ module ActiveRecord
assert_instance_of TrueClass, bob.male?
assert_kind_of BigDecimal, bob.wealth
end
+
+ def test_out_of_range_limit_should_raise
+ skip("MySQL and PostgreSQL only") unless current_adapter?(:MysqlAdapter, :Mysql2Adapter, :PostgreSQLAdapter)
+
+ assert_raise(ActiveRecordError) { add_column :test_models, :integer_too_big, :integer, :limit => 10 }
+
+ unless current_adapter?(:PostgreSQLAdapter)
+ assert_raise(ActiveRecordError) { add_column :test_models, :text_too_big, :integer, :limit => 0xfffffffff }
+ end
+ end
end
end
end
diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb
index f788690b0d..cad93936c9 100644
--- a/activerecord/test/cases/migration_test.rb
+++ b/activerecord/test/cases/migration_test.rb
@@ -375,6 +375,27 @@ class MigrationTest < ActiveRecord::TestCase
end
end
+ def test_out_of_range_limit_should_raise
+ skip("MySQL and PostgreSQL only") unless current_adapter?(:MysqlAdapter, :Mysql2Adapter, :PostgreSQLAdapter)
+
+ Person.connection.drop_table :test_limits rescue nil
+ assert_raise(ActiveRecord::ActiveRecordError, "integer limit didn't raise") do
+ Person.connection.create_table :test_integer_limits, :force => true do |t|
+ t.column :bigone, :integer, :limit => 10
+ end
+ end
+
+ unless current_adapter?(:PostgreSQLAdapter)
+ assert_raise(ActiveRecord::ActiveRecordError, "text limit didn't raise") do
+ Person.connection.create_table :test_text_limits, :force => true do |t|
+ t.column :bigtext, :text, :limit => 0xfffffffff
+ end
+ end
+ end
+
+ Person.connection.drop_table :test_limits rescue nil
+ end
+
protected
def with_env_tz(new_tz = 'US/Eastern')
old_tz, ENV['TZ'] = ENV['TZ'], new_tz
@@ -883,8 +904,8 @@ class CopyMigrationsTest < ActiveRecord::TestCase
def test_skipping_migrations
@migrations_path = MIGRATIONS_ROOT + "/valid_with_timestamps"
@existing_migrations = Dir[@migrations_path + "/*.rb"]
-
- sources = {}
+
+ sources = {}
sources[:bukkits] = MIGRATIONS_ROOT + "/to_copy_with_timestamps"
sources[:omg] = MIGRATIONS_ROOT + "/to_copy_with_name_collision"
diff --git a/activerecord/test/cases/readonly_test.rb b/activerecord/test/cases/readonly_test.rb
index 39b66b3399..df0399f548 100644
--- a/activerecord/test/cases/readonly_test.rb
+++ b/activerecord/test/cases/readonly_test.rb
@@ -23,6 +23,7 @@ class ReadOnlyTest < ActiveRecord::TestCase
end
assert_raise(ActiveRecord::ReadOnlyRecord) { dev.save }
assert_raise(ActiveRecord::ReadOnlyRecord) { dev.save! }
+ assert_raise(ActiveRecord::ReadOnlyRecord) { dev.destroy }
end
diff --git a/activerecord/test/cases/relation_scoping_test.rb b/activerecord/test/cases/relation_scoping_test.rb
index 342f7a86fa..3462fd99bd 100644
--- a/activerecord/test/cases/relation_scoping_test.rb
+++ b/activerecord/test/cases/relation_scoping_test.rb
@@ -84,7 +84,7 @@ class RelationScopingTest < ActiveRecord::TestCase
def test_scope_select_concatenates
Developer.select("id, name").scoping do
- developer = Developer.select('id, salary').where("name = 'David'").first
+ developer = Developer.select('salary').where("name = 'David'").first
assert_equal 80000, developer.salary
assert developer.has_attribute?(:id)
assert developer.has_attribute?(:name)
diff --git a/activerecord/test/cases/relation_test.rb b/activerecord/test/cases/relation_test.rb
index 8a7a2441d4..89f818a689 100644
--- a/activerecord/test/cases/relation_test.rb
+++ b/activerecord/test/cases/relation_test.rb
@@ -203,13 +203,18 @@ module ActiveRecord
assert_equal [], relation.extending_values
end
- (Relation::SINGLE_VALUE_METHODS - [:lock, :reordering, :reverse_order, :create_with]).each do |method|
+ (Relation::SINGLE_VALUE_METHODS - [:from, :lock, :reordering, :reverse_order, :create_with]).each do |method|
test "##{method}!" do
assert relation.public_send("#{method}!", :foo).equal?(relation)
assert_equal :foo, relation.public_send("#{method}_value")
end
end
+ test '#from!' do
+ assert relation.from!('foo').equal?(relation)
+ assert_equal ['foo', nil], relation.from_value
+ end
+
test '#lock!' do
assert relation.lock!('foo').equal?(relation)
assert_equal 'foo', relation.lock_value
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index 8cef4423c5..dee31f4772 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -133,6 +133,13 @@ class RelationTest < ActiveRecord::TestCase
assert topics.loaded?
end
+ def test_finiding_with_subquery
+ relation = Topic.where(:approved => true)
+ assert_equal relation.to_a, Topic.select('*').from(relation).to_a
+ assert_equal relation.to_a, Topic.select('subquery.*').from(relation).to_a
+ assert_equal relation.to_a, Topic.select('a.*').from(relation, :a).to_a
+ end
+
def test_finding_with_conditions
assert_equal ["David"], Author.where(:name => 'David').map(&:name)
assert_equal ['Mary'], Author.where(["name = ?", 'Mary']).map(&:name)
@@ -644,6 +651,7 @@ class RelationTest < ActiveRecord::TestCase
assert ! davids.exists?(authors(:mary).id)
assert ! davids.exists?("42")
assert ! davids.exists?(42)
+ assert ! davids.exists?(davids.new)
fake = Author.where(:name => 'fake author')
assert ! fake.exists?
diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb
index 15ceaa1fcc..ab80dd1d6d 100644
--- a/activerecord/test/cases/schema_dumper_test.rb
+++ b/activerecord/test/cases/schema_dumper_test.rb
@@ -236,6 +236,27 @@ class SchemaDumperTest < ActiveRecord::TestCase
end
end
+ def test_schema_dump_includes_inet_shorthand_definition
+ output = standard_dump
+ if %r{create_table "postgresql_network_address"} =~ output
+ assert_match %r{t.inet "inet_address"}, output
+ end
+ end
+
+ def test_schema_dump_includes_cidr_shorthand_definition
+ output = standard_dump
+ if %r{create_table "postgresql_network_address"} =~ output
+ assert_match %r{t.cidr "cidr_address"}, output
+ end
+ end
+
+ def test_schema_dump_includes_macaddr_shorthand_definition
+ output = standard_dump
+ if %r{create_table "postgresql_network_address"} =~ output
+ assert_match %r{t.macaddr "macaddr_address"}, output
+ end
+ end
+
def test_schema_dump_includes_hstores_shorthand_definition
output = standard_dump
if %r{create_table "postgresql_hstores"} =~ output
diff --git a/activerecord/test/cases/session_store/sql_bypass.rb b/activerecord/test/cases/session_store/sql_bypass_test.rb
index 7402b2afd6..6749d4ce98 100644
--- a/activerecord/test/cases/session_store/sql_bypass.rb
+++ b/activerecord/test/cases/session_store/sql_bypass_test.rb
@@ -18,6 +18,11 @@ module ActiveRecord
assert !Session.table_exists?
end
+ def test_new_record?
+ s = SqlBypass.new :data => 'foo', :session_id => 10
+ assert s.new_record?, 'this is a new record!'
+ end
+
def test_persisted?
s = SqlBypass.new :data => 'foo', :session_id => 10
assert !s.persisted?, 'this is a new record!'
diff --git a/activerecord/test/cases/store_test.rb b/activerecord/test/cases/store_test.rb
index 40520d6da2..e1d0f1f799 100644
--- a/activerecord/test/cases/store_test.rb
+++ b/activerecord/test/cases/store_test.rb
@@ -4,7 +4,7 @@ require 'models/admin/user'
class StoreTest < ActiveRecord::TestCase
setup do
- @john = Admin::User.create(:name => 'John Doe', :color => 'black', :remember_login => true)
+ @john = Admin::User.create(:name => 'John Doe', :color => 'black', :remember_login => true, :height => 'tall', :is_a_good_guy => true)
end
test "reading store attributes through accessors" do
@@ -40,4 +40,38 @@ class StoreTest < ActiveRecord::TestCase
@john.remember_login = false
assert_equal false, @john.remember_login
end
+
+ test "reading store attributes through accessors encoded with JSON" do
+ assert_equal 'tall', @john.height
+ assert_nil @john.weight
+ end
+
+ test "writing store attributes through accessors encoded with JSON" do
+ @john.height = 'short'
+ @john.weight = 'heavy'
+
+ assert_equal 'short', @john.height
+ assert_equal 'heavy', @john.weight
+ end
+
+ test "accessing attributes not exposed by accessors encoded with JSON" do
+ @john.json_data['somestuff'] = 'somecoolstuff'
+ @john.save
+
+ assert_equal 'somecoolstuff', @john.reload.json_data['somestuff']
+ end
+
+ test "updating the store will mark it as changed encoded with JSON" do
+ @john.height = 'short'
+ assert @john.json_data_changed?
+ end
+
+ test "object initialization with not nullable column encoded with JSON" do
+ assert_equal true, @john.is_a_good_guy
+ end
+
+ test "writing with not nullable column encoded with JSON" do
+ @john.is_a_good_guy = false
+ assert_equal false, @john.is_a_good_guy
+ end
end
diff --git a/activerecord/test/cases/transaction_callbacks_test.rb b/activerecord/test/cases/transaction_callbacks_test.rb
index 9846f5b12d..961ba8d9ba 100644
--- a/activerecord/test/cases/transaction_callbacks_test.rb
+++ b/activerecord/test/cases/transaction_callbacks_test.rb
@@ -287,8 +287,45 @@ class TransactionObserverCallbacksTest < ActiveRecord::TestCase
raise ActiveRecord::Rollback
end
+ assert topic.id.nil?
+ assert !topic.persisted?
assert_equal %w{ after_rollback }, topic.history
end
+
+ class TopicWithManualRollbackObserverAttached < ActiveRecord::Base
+ self.table_name = :topics
+ def history
+ @history ||= []
+ end
+ end
+
+ class TopicWithManualRollbackObserverAttachedObserver < ActiveRecord::Observer
+ def after_save(record)
+ record.history.push "after_save"
+ raise ActiveRecord::Rollback
+ end
+ end
+
+ def test_after_save_called_with_manual_rollback
+ assert TopicWithManualRollbackObserverAttachedObserver.instance, 'should have observer'
+
+ topic = TopicWithManualRollbackObserverAttached.new
+
+ assert !topic.save
+ assert_equal nil, topic.id
+ assert !topic.persisted?
+ assert_equal %w{ after_save }, topic.history
+ end
+ def test_after_save_called_with_manual_rollback_bang
+ assert TopicWithManualRollbackObserverAttachedObserver.instance, 'should have observer'
+
+ topic = TopicWithManualRollbackObserverAttached.new
+
+ topic.save!
+ assert_equal nil, topic.id
+ assert !topic.persisted?
+ assert_equal %w{ after_save }, topic.history
+ end
end
class SaveFromAfterCommitBlockTest < ActiveRecord::TestCase
diff --git a/activerecord/test/models/admin/user.rb b/activerecord/test/models/admin/user.rb
index d0e628bd50..ad30039304 100644
--- a/activerecord/test/models/admin/user.rb
+++ b/activerecord/test/models/admin/user.rb
@@ -2,4 +2,6 @@ class Admin::User < ActiveRecord::Base
belongs_to :account
store :settings, :accessors => [ :color, :homepage ]
store :preferences, :accessors => [ :remember_login ]
+ store :json_data, :accessors => [ :height, :weight ], :coder => JSON
+ store :json_data_empty, :accessors => [ :is_a_good_guy ], :coder => JSON
end
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index b18f9779be..5bcb9652cd 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -41,6 +41,8 @@ ActiveRecord::Schema.define do
# MySQL does not allow default values for blobs. Fake it out with a
# big varchar below.
t.string :preferences, :null => false, :default => '', :limit => 1024
+ t.string :json_data, :null => true, :limit => 1024
+ t.string :json_data_empty, :null => false, :default => "", :limit => 1024
t.references :account
end
@@ -430,6 +432,7 @@ ActiveRecord::Schema.define do
t.string :name
t.column :updated_at, :datetime
t.column :happy_at, :datetime
+ t.column :eats_at, :time
t.string :essay_id
end
diff --git a/activerecord/test/schema/sqlite_specific_schema.rb b/activerecord/test/schema/sqlite_specific_schema.rb
index ea05b35fe0..e9ddeb32cf 100644
--- a/activerecord/test/schema/sqlite_specific_schema.rb
+++ b/activerecord/test/schema/sqlite_specific_schema.rb
@@ -1,5 +1,5 @@
ActiveRecord::Schema.define do
- # For sqlite 3.1.0+, make a table with a autoincrement column
+ # For sqlite 3.1.0+, make a table with an autoincrement column
if supports_autoincrement?
create_table :table_with_autoincrement, :force => true do |t|
t.column :name, :string
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index c0d780789a..636aca2b8f 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,5 +1,9 @@
## Rails 4.0.0 (unreleased) ##
+* `Object#try` can't call private methods. *Vasiliy Ermolovich*
+
+* `AS::Callbacks#run_callbacks` remove `key` argument. *Francesco Rodriguez*
+
* `deep_dup` works more expectedly now and duplicates also values in +Hash+ instances and elements in +Array+ instances. *Alexey Gaziev*
* Inflector no longer applies ice -> ouse to words like slice, police, ets *Wes Morgan*
diff --git a/activesupport/lib/active_support/backtrace_cleaner.rb b/activesupport/lib/active_support/backtrace_cleaner.rb
index e97bb25b9f..7c3a41288b 100644
--- a/activesupport/lib/active_support/backtrace_cleaner.rb
+++ b/activesupport/lib/active_support/backtrace_cleaner.rb
@@ -8,8 +8,6 @@ module ActiveSupport
# instead of the file system root. The typical silencer use case is to exclude the output of a noisy library from the
# backtrace, so that you can focus on the rest.
#
- # ==== Example:
- #
# bc = BacktraceCleaner.new
# bc.add_filter { |line| line.gsub(Rails.root, '') }
# bc.add_silencer { |line| line =~ /mongrel|rubygems/ }
@@ -42,8 +40,6 @@ module ActiveSupport
# Adds a filter from the block provided. Each line in the backtrace will be mapped against this filter.
#
- # Example:
- #
# # Will turn "/my/rails/root/app/models/person.rb" into "/app/models/person.rb"
# backtrace_cleaner.add_filter { |line| line.gsub(Rails.root, '') }
def add_filter(&block)
@@ -53,8 +49,6 @@ module ActiveSupport
# Adds a silencer from the block provided. If the silencer returns true for a given line, it will be excluded from
# the clean backtrace.
#
- # Example:
- #
# # Will reject all lines that include the word "mongrel", like "/gems/mongrel/server.rb" or "/app/my_mongrel_server/rb"
# backtrace_cleaner.add_silencer { |line| line =~ /mongrel/ }
def add_silencer(&block)
diff --git a/activesupport/lib/active_support/cache/file_store.rb b/activesupport/lib/active_support/cache/file_store.rb
index e7316b23b3..89bdb741d0 100644
--- a/activesupport/lib/active_support/cache/file_store.rb
+++ b/activesupport/lib/active_support/cache/file_store.rb
@@ -1,7 +1,7 @@
require 'active_support/core_ext/file/atomic'
require 'active_support/core_ext/string/conversions'
require 'active_support/core_ext/object/inclusion'
-require 'rack/utils'
+require 'uri/common'
module ActiveSupport
module Cache
@@ -126,7 +126,7 @@ module ActiveSupport
# Translate a key into a file path.
def key_file_path(key)
- fname = Rack::Utils.escape(key)
+ fname = URI.encode_www_form_component(key)
hash = Zlib.adler32(fname)
hash, dir_1 = hash.divmod(0x1000)
dir_2 = hash.modulo(0x1000)
@@ -144,7 +144,7 @@ module ActiveSupport
# Translate a file path into a key.
def file_path_key(path)
fname = path[cache_path.to_s.size..-1].split(File::SEPARATOR, 4).last
- Rack::Utils.unescape(fname)
+ URI.decode_www_form_component(fname, Encoding::UTF_8)
end
# Delete empty directories in the cache.
diff --git a/activesupport/lib/active_support/cache/memory_store.rb b/activesupport/lib/active_support/cache/memory_store.rb
index b15bb42c88..7fd5e3b53d 100644
--- a/activesupport/lib/active_support/cache/memory_store.rb
+++ b/activesupport/lib/active_support/cache/memory_store.rb
@@ -137,6 +137,7 @@ module ActiveSupport
def write_entry(key, entry, options) # :nodoc:
synchronize do
old_entry = @data[key]
+ return false if @data.key?(key) && options[:unless_exist]
@cache_size -= old_entry.size if old_entry
@cache_size += entry.size
@key_access[key] = Time.now.to_f
diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb
index cbeba3139a..af683d37ed 100644
--- a/activesupport/lib/active_support/callbacks.rb
+++ b/activesupport/lib/active_support/callbacks.rb
@@ -23,8 +23,6 @@ module ActiveSupport
# methods, procs or lambdas, or callback objects that respond to certain predetermined
# methods. See +ClassMethods.set_callback+ for details.
#
- # ==== Example
- #
# class Record
# include ActiveSupport::Callbacks
# define_callbacks :save
@@ -54,7 +52,6 @@ module ActiveSupport
# saving...
# - save
# saved
- #
module Callbacks
extend Concern
@@ -73,9 +70,7 @@ module ActiveSupport
# run_callbacks :save do
# save
# end
- #
- def run_callbacks(kind, key = nil, &block)
- #TODO: deprecate key argument
+ def run_callbacks(kind, &block)
runner_name = self.class.__define_callbacks(kind, self)
send(runner_name, &block)
end
@@ -199,7 +194,6 @@ module ActiveSupport
# yield self
# end
# end
- #
def define_conditional_callback
name = "_conditional_callback_#{@kind}_#{next_id}"
@klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
@@ -253,7 +247,6 @@ module ActiveSupport
# Objects::
# a method is created that calls the before_foo method
# on the object.
- #
def _compile_filter(filter)
method_name = "_callback_#{@kind}_#{next_id}"
case filter
@@ -317,13 +310,13 @@ module ActiveSupport
method << "value = nil"
method << "halted = false"
- callbacks = "value = yield if block_given? && !halted"
+ callbacks = "value = !halted && (!block_given? || yield)"
reverse_each do |callback|
callbacks = callback.apply(callbacks)
end
method << callbacks
- method << "halted ? false : (block_given? ? value : true)"
+ method << "value"
method.join("\n")
end
@@ -335,26 +328,17 @@ module ActiveSupport
# if it was not yet defined.
# This generated method plays caching role.
def __define_callbacks(kind, object) #:nodoc:
- name = __callback_runner_name(kind)
+ chain = object.send("_#{kind}_callbacks")
+ name = "_run_callbacks_#{chain.object_id}"
unless object.respond_to?(name, true)
- str = object.send("_#{kind}_callbacks").compile
class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
- def #{name}() #{str} end
+ def #{name}() #{chain.compile} end
protected :#{name}
RUBY_EVAL
end
name
end
- def __reset_runner(symbol)
- name = __callback_runner_name(symbol)
- undef_method(name) if method_defined?(name)
- end
-
- def __callback_runner_name(kind)
- "_run__#{self.name.hash.abs}__#{kind}__callbacks"
- end
-
# This is used internally to append, prepend and skip callbacks to the
# CallbackChain.
#
@@ -366,7 +350,6 @@ module ActiveSupport
([self] + ActiveSupport::DescendantsTracker.descendants(self)).reverse.each do |target|
chain = target.send("_#{name}_callbacks")
yield target, chain.dup, type, filters, options
- target.__reset_runner(name)
end
end
@@ -405,7 +388,6 @@ module ActiveSupport
# will be called only when it returns a false value.
# * <tt>:prepend</tt> - If true, the callback will be prepended to the existing
# chain rather than appended.
- #
def set_callback(name, *filter_list, &block)
mapped = nil
@@ -430,7 +412,6 @@ module ActiveSupport
# class Writer < Person
# skip_callback :validate, :before, :check_membership, :if => lambda { self.age > 18 }
# end
- #
def skip_callback(name, *filter_list, &block)
__update_callbacks(name, filter_list, block) do |target, chain, type, filters, options|
filters.each do |filter|
@@ -449,7 +430,6 @@ module ActiveSupport
end
# Remove all set callbacks for the given event.
- #
def reset_callbacks(symbol)
callbacks = send("_#{symbol}_callbacks")
@@ -457,12 +437,9 @@ module ActiveSupport
chain = target.send("_#{symbol}_callbacks").dup
callbacks.each { |c| chain.delete(c) }
target.send("_#{symbol}_callbacks=", chain)
- target.__reset_runner(symbol)
end
self.send("_#{symbol}_callbacks=", callbacks.dup.clear)
-
- __reset_runner(symbol)
end
# Define sets of events in the object lifecycle that support callbacks.
@@ -530,7 +507,6 @@ module ActiveSupport
# define_callbacks :save, :scope => [:name]
#
# would call <tt>Audit#save</tt>.
- #
def define_callbacks(*callbacks)
config = callbacks.last.is_a?(Hash) ? callbacks.pop : {}
callbacks.each do |callback|
diff --git a/activesupport/lib/active_support/core_ext/array/wrap.rb b/activesupport/lib/active_support/core_ext/array/wrap.rb
index 4834eca8b1..9ea93d7226 100644
--- a/activesupport/lib/active_support/core_ext/array/wrap.rb
+++ b/activesupport/lib/active_support/core_ext/array/wrap.rb
@@ -25,9 +25,6 @@ class Array
# Array(:foo => :bar) # => [[:foo, :bar]]
# Array.wrap(:foo => :bar) # => [{:foo => :bar}]
#
- # Array("foo\nbar") # => ["foo\n", "bar"], in Ruby 1.8
- # Array.wrap("foo\nbar") # => ["foo\nbar"]
- #
# There's also a related idiom that uses the splat operator:
#
# [*object]
diff --git a/activesupport/lib/active_support/core_ext/date/calculations.rb b/activesupport/lib/active_support/core_ext/date/calculations.rb
index 323126fcfa..3e36c54eba 100644
--- a/activesupport/lib/active_support/core_ext/date/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/date/calculations.rb
@@ -107,8 +107,6 @@ class Date
# Returns a new Date where one or more of the elements have been changed according to the +options+ parameter.
#
- # Examples:
- #
# Date.new(2007, 5, 12).change(:day => 1) # => Date.new(2007, 5, 1)
# Date.new(2007, 5, 12).change(:year => 2005, :month => 1) # => Date.new(2005, 1, 12)
def change(options)
diff --git a/activesupport/lib/active_support/core_ext/date/conversions.rb b/activesupport/lib/active_support/core_ext/date/conversions.rb
index 97e3c71992..81f969e786 100644
--- a/activesupport/lib/active_support/core_ext/date/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/date/conversions.rb
@@ -26,7 +26,6 @@ class Date
#
# This method is aliased to <tt>to_s</tt>.
#
- # ==== Examples
# date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007
#
# date.to_formatted_s(:db) # => "2007-11-10"
@@ -69,7 +68,6 @@ class Date
# Converts a Date instance to a Time, where the time is set to the beginning of the day.
# The timezone can be either :local or :utc (default :local).
#
- # ==== Examples
# date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007
#
# date.to_time # => Sat Nov 10 00:00:00 0800 2007
diff --git a/activesupport/lib/active_support/core_ext/date_time/calculations.rb b/activesupport/lib/active_support/core_ext/date_time/calculations.rb
index 020fa1a06d..fd78044b5d 100644
--- a/activesupport/lib/active_support/core_ext/date_time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/date_time/calculations.rb
@@ -104,8 +104,6 @@ class DateTime
# Adjusts DateTime to UTC by adding its offset value; offset is set to 0
#
- # Example:
- #
# DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)) # => Mon, 21 Feb 2005 10:11:12 -0600
# DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)).utc # => Mon, 21 Feb 2005 16:11:12 +0000
def utc
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 6338dc6397..19925198c0 100644
--- a/activesupport/lib/active_support/core_ext/date_time/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/date_time/conversions.rb
@@ -42,7 +42,6 @@ class DateTime
alias_method :to_default_s, :to_s unless (instance_methods(false) & [:to_s, 'to_s']).empty?
alias_method :to_s, :to_formatted_s
- # Returns the +utc_offset+ as an +HH:MM formatted string. Examples:
#
# datetime = DateTime.civil(2000, 1, 1, 0, 0, 0, Rational(-6, 24))
# datetime.formatted_offset # => "-06:00"
diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb
index b9c632e4f5..02d5a7080f 100644
--- a/activesupport/lib/active_support/core_ext/enumerable.rb
+++ b/activesupport/lib/active_support/core_ext/enumerable.rb
@@ -1,5 +1,5 @@
module Enumerable
- # Calculates a sum from the elements. Examples:
+ # Calculates a sum from the elements.
#
# payments.sum { |p| p.price * p.tax_rate }
# payments.sum(&:price)
@@ -26,7 +26,7 @@ module Enumerable
end
end
- # Convert an enumerable to a hash. Examples:
+ # Convert an enumerable to a hash.
#
# people.index_by(&:login)
# => { "nextangle" => <Person ...>, "chade-" => <Person ...>, ...}
diff --git a/activesupport/lib/active_support/core_ext/hash/deep_merge.rb b/activesupport/lib/active_support/core_ext/hash/deep_merge.rb
index af771c86ff..023bf68a87 100644
--- a/activesupport/lib/active_support/core_ext/hash/deep_merge.rb
+++ b/activesupport/lib/active_support/core_ext/hash/deep_merge.rb
@@ -1,11 +1,16 @@
class Hash
# Returns a new hash with +self+ and +other_hash+ merged recursively.
+ #
+ # h1 = {x: {y: [4,5,6]}, z: [7,8,9]}
+ # h2 = {x: {y: [7,8,9]}, z: "xyz"}
+ #
+ # h1.deep_merge(h2) #=> {:x => {:y => [7, 8, 9]}, :z => "xyz"}
+ # h2.deep_merge(h1) #=> {:x => {:y => [4, 5, 6]}, :z => [7, 8, 9]}
def deep_merge(other_hash)
dup.deep_merge!(other_hash)
end
- # Returns a new hash with +self+ and +other_hash+ merged recursively.
- # Modifies the receiver in place.
+ # Same as +deep_merge+, but modifies +self+.
def deep_merge!(other_hash)
other_hash.each_pair do |k,v|
tv = self[k]
diff --git a/activesupport/lib/active_support/core_ext/hash/diff.rb b/activesupport/lib/active_support/core_ext/hash/diff.rb
index 855dcb38bc..831dee8ecb 100644
--- a/activesupport/lib/active_support/core_ext/hash/diff.rb
+++ b/activesupport/lib/active_support/core_ext/hash/diff.rb
@@ -1,8 +1,6 @@
class Hash
# Returns a hash that represents the difference between two hashes.
#
- # Examples:
- #
# {1 => 2}.diff(1 => 2) # => {}
# {1 => 2}.diff(1 => 3) # => {1 => 2}
# {}.diff(1 => 2) # => {1 => 2}
diff --git a/activesupport/lib/active_support/core_ext/hash/keys.rb b/activesupport/lib/active_support/core_ext/hash/keys.rb
index 230a84dabc..be4d611ce7 100644
--- a/activesupport/lib/active_support/core_ext/hash/keys.rb
+++ b/activesupport/lib/active_support/core_ext/hash/keys.rb
@@ -1,5 +1,8 @@
class Hash
# Return a new hash with all keys converted to strings.
+ #
+ # { :name => 'Rob', :years => '28' }.stringify_keys
+ # #=> { "name" => "Rob", "years" => "28" }
def stringify_keys
result = {}
keys.each do |key|
@@ -8,7 +11,8 @@ class Hash
result
end
- # Destructively convert all keys to strings.
+ # Destructively convert all keys to strings. Same as
+ # +stringify_keys+, but modifies +self+.
def stringify_keys!
keys.each do |key|
self[key.to_s] = delete(key)
@@ -18,6 +22,9 @@ class Hash
# Return a new hash with all keys converted to symbols, as long as
# they respond to +to_sym+.
+ #
+ # { 'name' => 'Rob', 'years' => '28' }.symbolize_keys
+ # #=> { :name => "Rob", :years => "28" }
def symbolize_keys
result = {}
keys.each do |key|
@@ -28,7 +35,7 @@ class Hash
alias_method :to_options, :symbolize_keys
# Destructively convert all keys to symbols, as long as they respond
- # to +to_sym+.
+ # to +to_sym+. Same as +symbolize_keys+, but modifies +self+.
def symbolize_keys!
keys.each do |key|
self[(key.to_sym rescue key)] = delete(key)
@@ -41,7 +48,6 @@ class Hash
# Note that keys are NOT treated indifferently, meaning if you use strings for keys but assert symbols
# as keys, this will fail.
#
- # ==== Examples
# { :name => 'Rob', :years => '28' }.assert_valid_keys(:name, :age) # => raises "ArgumentError: Unknown key: years"
# { :name => 'Rob', :age => '28' }.assert_valid_keys('name', 'age') # => raises "ArgumentError: Unknown key: name"
# { :name => 'Rob', :age => '28' }.assert_valid_keys(:name, :age) # => passes, raises nothing
diff --git a/activesupport/lib/active_support/core_ext/integer/multiple.rb b/activesupport/lib/active_support/core_ext/integer/multiple.rb
index 8dff217ddc..7c6c2f1ca7 100644
--- a/activesupport/lib/active_support/core_ext/integer/multiple.rb
+++ b/activesupport/lib/active_support/core_ext/integer/multiple.rb
@@ -1,5 +1,9 @@
class Integer
# Check whether the integer is evenly divisible by the argument.
+ #
+ # 0.multiple_of?(0) #=> true
+ # 6.multiple_of?(5) #=> false
+ # 10.multiple_of?(2) #=> true
def multiple_of?(number)
number != 0 ? self % number == 0 : zero?
end
diff --git a/activesupport/lib/active_support/core_ext/module/aliasing.rb b/activesupport/lib/active_support/core_ext/module/aliasing.rb
index 382156ecd8..580cb80413 100644
--- a/activesupport/lib/active_support/core_ext/module/aliasing.rb
+++ b/activesupport/lib/active_support/core_ext/module/aliasing.rb
@@ -45,8 +45,6 @@ class Module
# Allows you to make aliases for attributes, which includes
# getter, setter, and query methods.
#
- # Example:
- #
# class Content < ActiveRecord::Base
# # has a title attribute
# end
diff --git a/activesupport/lib/active_support/core_ext/object/deep_dup.rb b/activesupport/lib/active_support/core_ext/object/deep_dup.rb
index 2c4383ac94..883f5f556c 100644
--- a/activesupport/lib/active_support/core_ext/object/deep_dup.rb
+++ b/activesupport/lib/active_support/core_ext/object/deep_dup.rb
@@ -1,5 +1,13 @@
class Object
- # Returns a deep copy of object if it's duplicable.
+ # Returns a deep copy of object if it's duplicable. If it's
+ # not duplicable, returns +self+.
+ #
+ # object = Object.new
+ # dup = object.deep_dup
+ # dup.instance_variable_set(:@a, 1)
+ #
+ # object.instance_variable_defined?(:@a) #=> false
+ # dup.instance_variable_defined?(:@a) #=> true
def deep_dup
duplicable? ? dup : self
end
@@ -7,6 +15,13 @@ end
class Array
# Returns a deep copy of array.
+ #
+ # array = [1, [2, 3]]
+ # dup = array.deep_dup
+ # dup[1][2] = 4
+ #
+ # array[1][2] #=> nil
+ # dup[1][2] #=> 4
def deep_dup
map { |it| it.deep_dup }
end
@@ -14,6 +29,13 @@ end
class Hash
# Returns a deep copy of hash.
+ #
+ # hash = { a: { b: 'b' } }
+ # dup = hash.deep_dup
+ # dup[:a][:c] = 'c'
+ #
+ # hash[:a][:c] #=> nil
+ # dup[:a][:c] #=> "c"
def deep_dup
each_with_object(dup) do |(key, value), hash|
hash[key.deep_dup] = value.deep_dup
diff --git a/activesupport/lib/active_support/core_ext/object/duplicable.rb b/activesupport/lib/active_support/core_ext/object/duplicable.rb
index 9d1630bb7c..f1b755c2c4 100644
--- a/activesupport/lib/active_support/core_ext/object/duplicable.rb
+++ b/activesupport/lib/active_support/core_ext/object/duplicable.rb
@@ -19,7 +19,7 @@
class Object
# Can you safely dup this object?
#
- # False for +nil+, +false+, +true+, symbols, numbers, class and module objects;
+ # False for +nil+, +false+, +true+, symbol, and number objects;
# true otherwise.
def duplicable?
true
@@ -81,30 +81,6 @@ class Numeric
end
end
-class Class
- # Classes are not duplicable:
- #
- # c = Class.new # => #<Class:0x10328fd80>
- # c.dup # => #<Class:0x10328fd80>
- #
- # Note +dup+ returned the same class object.
- def duplicable?
- false
- end
-end
-
-class Module
- # Modules are not duplicable:
- #
- # m = Module.new # => #<Module:0x10328b6e0>
- # m.dup # => #<Module:0x10328b6e0>
- #
- # Note +dup+ returned the same module object.
- def duplicable?
- false
- end
-end
-
require 'bigdecimal'
class BigDecimal
begin
diff --git a/activesupport/lib/active_support/core_ext/object/instance_variables.rb b/activesupport/lib/active_support/core_ext/object/instance_variables.rb
index 91fdf93eb2..40821fd619 100644
--- a/activesupport/lib/active_support/core_ext/object/instance_variables.rb
+++ b/activesupport/lib/active_support/core_ext/object/instance_variables.rb
@@ -1,6 +1,6 @@
class Object
- # Returns a hash that maps instance variable names without "@" to their
- # corresponding values. Keys are strings both in Ruby 1.8 and 1.9.
+ # Returns a hash with string keys that maps instance variable names without "@" to their
+ # corresponding values.
#
# class C
# def initialize(x, y)
@@ -9,12 +9,11 @@ class Object
# end
#
# C.new(0, 1).instance_values # => {"x" => 0, "y" => 1}
- def instance_values #:nodoc:
+ def instance_values
Hash[instance_variables.map { |name| [name[1..-1], instance_variable_get(name)] }]
end
- # Returns an array of instance variable names including "@". They are strings
- # both in Ruby 1.8 and 1.9.
+ # Returns an array of instance variable names including "@".
#
# class C
# def initialize(x, y)
diff --git a/activesupport/lib/active_support/core_ext/object/try.rb b/activesupport/lib/active_support/core_ext/object/try.rb
index e77a9da0ec..48eb546a7d 100644
--- a/activesupport/lib/active_support/core_ext/object/try.rb
+++ b/activesupport/lib/active_support/core_ext/object/try.rb
@@ -1,6 +1,6 @@
class Object
- # Invokes the method identified by the symbol +method+, passing it any arguments
- # and/or the block specified, just like the regular Ruby <tt>Object#send</tt> does.
+ # Invokes the public method identified by the symbol +method+, passing it any arguments
+ # and/or the block specified, just like the regular Ruby <tt>Object#public_send</tt> does.
#
# *Unlike* that method however, a +NoMethodError+ exception will *not* be raised
# and +nil+ will be returned instead, if the receiving object is a +nil+ object or NilClass.
@@ -24,12 +24,12 @@ class Object
# Without a method argument try will yield to the block unless the receiver is nil.
# @person.try { |p| "#{p.first_name} #{p.last_name}" }
#--
- # +try+ behaves like +Object#send+, unless called on +NilClass+.
+ # +try+ behaves like +Object#public_send+, unless called on +NilClass+.
def try(*a, &b)
if a.empty? && block_given?
yield self
else
- __send__(*a, &b)
+ public_send(*a, &b)
end
end
end
diff --git a/activesupport/lib/active_support/core_ext/range.rb b/activesupport/lib/active_support/core_ext/range.rb
index c0736f3a44..1d8b1ede5a 100644
--- a/activesupport/lib/active_support/core_ext/range.rb
+++ b/activesupport/lib/active_support/core_ext/range.rb
@@ -1,4 +1,3 @@
-require 'active_support/core_ext/range/blockless_step'
require 'active_support/core_ext/range/conversions'
require 'active_support/core_ext/range/include_range'
require 'active_support/core_ext/range/overlaps'
diff --git a/activesupport/lib/active_support/core_ext/range/blockless_step.rb b/activesupport/lib/active_support/core_ext/range/blockless_step.rb
deleted file mode 100644
index f687287f0d..0000000000
--- a/activesupport/lib/active_support/core_ext/range/blockless_step.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-require 'active_support/core_ext/module/aliasing'
-
-class Range
- def step_with_blockless(*args, &block) #:nodoc:
- if block_given?
- step_without_blockless(*args, &block)
- else
- step_without_blockless(*args).to_a
- end
- end
-
- alias_method_chain :step, :blockless
-end
diff --git a/activesupport/lib/active_support/core_ext/range/conversions.rb b/activesupport/lib/active_support/core_ext/range/conversions.rb
index 43134b4314..b1a12781f3 100644
--- a/activesupport/lib/active_support/core_ext/range/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/range/conversions.rb
@@ -5,8 +5,6 @@ class Range
# Gives a human readable format of the range.
#
- # ==== Example
- #
# (1..100).to_formatted_s # => "1..100"
def to_formatted_s(format = :default)
if formatter = RANGE_FORMATS[format]
diff --git a/activesupport/lib/active_support/core_ext/string.rb b/activesupport/lib/active_support/core_ext/string.rb
index ab49af55bf..fb36262528 100644
--- a/activesupport/lib/active_support/core_ext/string.rb
+++ b/activesupport/lib/active_support/core_ext/string.rb
@@ -6,7 +6,6 @@ require 'active_support/core_ext/string/inflections'
require 'active_support/core_ext/string/access'
require 'active_support/core_ext/string/xchar'
require 'active_support/core_ext/string/behavior'
-require 'active_support/core_ext/string/interpolation'
require 'active_support/core_ext/string/output_safety'
require 'active_support/core_ext/string/exclude'
require 'active_support/core_ext/string/strip'
diff --git a/activesupport/lib/active_support/core_ext/string/access.rb b/activesupport/lib/active_support/core_ext/string/access.rb
index 23aaee9c43..5c32a2453d 100644
--- a/activesupport/lib/active_support/core_ext/string/access.rb
+++ b/activesupport/lib/active_support/core_ext/string/access.rb
@@ -1,18 +1,79 @@
require 'active_support/multibyte'
class String
+ # If you pass a single Fixnum, returns a substring of one character at that
+ # position. The first character of the string is at position 0, the next at
+ # position 1, and so on. If a range is supplied, a substring containing
+ # characters at offsets given by the range is returned. In both cases, if an
+ # offset is negative, it is counted from the end of the string. Returns nil
+ # if the initial offset falls outside the string. Returns an empty string if
+ # the beginning of the range is greater than the end of the string.
+ #
+ # str = "hello"
+ # str.at(0) #=> "h"
+ # str.at(1..3) #=> "ell"
+ # str.at(-2) #=> "l"
+ # str.at(-2..-1) #=> "lo"
+ # str.at(5) #=> nil
+ # str.at(5..-1) #=> ""
+ #
+ # If a Regexp is given, the matching portion of the string is returned.
+ # If a String is given, that given string is returned if it occurs in
+ # the string. In both cases, nil is returned if there is no match.
+ #
+ # str = "hello"
+ # str.at(/lo/) #=> "lo"
+ # str.at(/ol/) #=> nil
+ # str.at("lo") #=> "lo"
+ # str.at("ol") #=> nil
def at(position)
self[position]
end
+ # Returns a substring from the given position to the end of the string.
+ # If the position is negative, it is counted from the end of the string.
+ #
+ # str = "hello"
+ # str.from(0) #=> "hello"
+ # str.from(3) #=> "lo"
+ # str.from(-2) #=> "lo"
+ #
+ # You can mix it with +to+ method and do fun things like:
+ #
+ # str = "hello"
+ # str.from(0).to(-1) #=> "hello"
+ # str.from(1).to(-2) #=> "ell"
def from(position)
self[position..-1]
end
+ # Returns a substring from the beginning of the string to the given position.
+ # If the position is negative, it is counted from the end of the string.
+ #
+ # str = "hello"
+ # str.to(0) #=> "h"
+ # str.to(3) #=> "hell"
+ # str.to(-2) #=> "hell"
+ #
+ # You can mix it with +from+ method and do fun things like:
+ #
+ # str = "hello"
+ # str.from(0).to(-1) #=> "hello"
+ # str.from(1).to(-2) #=> "ell"
def to(position)
self[0..position]
end
+ # Returns the first character. If a limit is supplied, returns a substring
+ # from the beginning of the string until it reaches the limit value. If the
+ # given limit is greater than or equal to the string length, returns self.
+ #
+ # str = "hello"
+ # str.first #=> "h"
+ # str.first(1) #=> "h"
+ # str.first(2) #=> "he"
+ # str.first(0) #=> ""
+ # str.first(6) #=> "hello"
def first(limit = 1)
if limit == 0
''
@@ -23,6 +84,16 @@ class String
end
end
+ # Returns the last character of the string. If a limit is supplied, returns a substring
+ # from the end of the string until it reaches the limit value (counting backwards). If
+ # the given limit is greater than or equal to the string length, returns self.
+ #
+ # str = "hello"
+ # str.last #=> "o"
+ # str.last(1) #=> "o"
+ # str.last(2) #=> "lo"
+ # str.last(0) #=> ""
+ # str.last(6) #=> "hello"
def last(limit = 1)
if limit == 0
''
diff --git a/activesupport/lib/active_support/core_ext/string/conversions.rb b/activesupport/lib/active_support/core_ext/string/conversions.rb
index 9084bbee32..022b376aec 100644
--- a/activesupport/lib/active_support/core_ext/string/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/string/conversions.rb
@@ -15,6 +15,12 @@ class String
end
end
+ # Converts a string to a Date value.
+ #
+ # "1-1-2012".to_date #=> Sun, 01 Jan 2012
+ # "01/01/2012".to_date #=> Sun, 01 Jan 2012
+ # "2012-12-13".to_date #=> Thu, 13 Dec 2012
+ # "12/13/2012".to_date #=> ArgumentError: invalid date
def to_date
unless blank?
date_values = ::Date._parse(self, false).values_at(:year, :mon, :mday)
@@ -23,6 +29,12 @@ class String
end
end
+ # Converts a string to a DateTime value.
+ #
+ # "1-1-2012".to_datetime #=> Sun, 01 Jan 2012 00:00:00 +0000
+ # "01/01/2012 23:59:59".to_datetime #=> Sun, 01 Jan 2012 23:59:59 +0000
+ # "2012-12-13 12:50".to_datetime #=> Thu, 13 Dec 2012 12:50:00 +0000
+ # "12/13/2012".to_datetime #=> ArgumentError: invalid date
def to_datetime
unless blank?
date_values = ::Date._parse(self, false).
diff --git a/activesupport/lib/active_support/core_ext/string/exclude.rb b/activesupport/lib/active_support/core_ext/string/exclude.rb
index 5e184ec1b3..114bcb87f0 100644
--- a/activesupport/lib/active_support/core_ext/string/exclude.rb
+++ b/activesupport/lib/active_support/core_ext/string/exclude.rb
@@ -1,5 +1,10 @@
class String
- # The inverse of <tt>String#include?</tt>. 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.
+ #
+ # "hello".exclude? "lo" #=> false
+ # "hello".exclude? "ol" #=> true
+ # "hello".exclude? ?h #=> false
def exclude?(string)
!include?(string)
end
diff --git a/activesupport/lib/active_support/core_ext/string/filters.rb b/activesupport/lib/active_support/core_ext/string/filters.rb
index 32a37296d5..2478f42290 100644
--- a/activesupport/lib/active_support/core_ext/string/filters.rb
+++ b/activesupport/lib/active_support/core_ext/string/filters.rb
@@ -5,7 +5,6 @@ class String
# the string, and then changing remaining consecutive whitespace
# groups into one space each.
#
- # Examples:
# %{ Multi-line
# string }.squish # => "Multi-line string"
# " foo bar \n \t boo".squish # => "foo bar boo"
diff --git a/activesupport/lib/active_support/core_ext/string/inflections.rb b/activesupport/lib/active_support/core_ext/string/inflections.rb
index 049ffe7986..070bfd7af6 100644
--- a/activesupport/lib/active_support/core_ext/string/inflections.rb
+++ b/activesupport/lib/active_support/core_ext/string/inflections.rb
@@ -13,7 +13,6 @@ class String
# the singular form will be returned if <tt>count == 1</tt>.
# For any other value of +count+ the plural will be returned.
#
- # ==== Examples
# 'post'.pluralize # => "posts"
# 'octopus'.pluralize # => "octopi"
# 'sheep'.pluralize # => "sheep"
@@ -46,7 +45,6 @@ class String
# in the string. It raises a NameError when the name is not in CamelCase
# or is not initialized. See ActiveSupport::Inflector.constantize
#
- # Examples
# 'Module'.constantize # => Module
# 'Class'.constantize # => Class
# 'blargle'.constantize # => NameError: wrong constant name blargle
@@ -58,7 +56,6 @@ class String
# in the string. It returns nil when the name is not in CamelCase
# or is not initialized. See ActiveSupport::Inflector.safe_constantize
#
- # Examples
# 'Module'.safe_constantize # => Module
# 'Class'.safe_constantize # => Class
# 'blargle'.safe_constantize # => nil
@@ -140,8 +137,6 @@ class String
# Replaces special characters in a string so that it may be used as part of a 'pretty' URL.
#
- # ==== Examples
- #
# class Person
# def to_param
# "#{id}-#{name.parameterize}"
@@ -194,7 +189,6 @@ class String
# +separate_class_name_and_id_with_underscore+ sets whether
# the method should put '_' between the name and 'id'.
#
- # Examples
# 'Message'.foreign_key # => "message_id"
# 'Message'.foreign_key(false) # => "messageid"
# 'Admin::Post'.foreign_key # => "post_id"
diff --git a/activesupport/lib/active_support/core_ext/string/inquiry.rb b/activesupport/lib/active_support/core_ext/string/inquiry.rb
index 2562a7cef6..1dcd949536 100644
--- a/activesupport/lib/active_support/core_ext/string/inquiry.rb
+++ b/activesupport/lib/active_support/core_ext/string/inquiry.rb
@@ -2,7 +2,7 @@ require 'active_support/string_inquirer'
class String
# Wraps the current string in the <tt>ActiveSupport::StringInquirer</tt> class,
- # which gives you a prettier way to test for equality. Example:
+ # which gives you a prettier way to test for equality.
#
# env = 'production'.inquiry
# env.production? # => true
diff --git a/activesupport/lib/active_support/core_ext/string/interpolation.rb b/activesupport/lib/active_support/core_ext/string/interpolation.rb
deleted file mode 100644
index 7f764e9de1..0000000000
--- a/activesupport/lib/active_support/core_ext/string/interpolation.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-require 'active_support/i18n'
-require 'i18n/core_ext/string/interpolate'
diff --git a/activesupport/lib/active_support/core_ext/string/output_safety.rb b/activesupport/lib/active_support/core_ext/string/output_safety.rb
index 215ba87ca9..f98d5b3777 100644
--- a/activesupport/lib/active_support/core_ext/string/output_safety.rb
+++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb
@@ -14,7 +14,6 @@ class ERB
# In your ERB templates, use this method to escape any unsafe content. For example:
# <%=h @person.name %>
#
- # ==== Example:
# puts html_escape('is a > 0 & a < 10?')
# # => is a &gt; 0 &amp; a &lt; 10?
def html_escape(s)
@@ -37,7 +36,6 @@ class ERB
# A utility method for escaping HTML without affecting existing escaped entities.
#
- # ==== Examples
# html_escape_once('1 < 2 &amp; 3')
# # => "1 &lt; 2 &amp; 3"
#
@@ -152,6 +150,20 @@ module ActiveSupport #:nodoc:
dup.concat(other)
end
+ def %(args)
+ args = Array(args)
+
+ args.map! do |arg|
+ if !html_safe? || arg.html_safe?
+ arg
+ else
+ ERB::Util.h(arg)
+ end
+ end
+
+ self.class.new(super(args))
+ end
+
def html_safe?
defined?(@html_safe) && @html_safe
end
diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb
index 745a131524..66f3af7002 100644
--- a/activesupport/lib/active_support/dependencies.rb
+++ b/activesupport/lib/active_support/dependencies.rb
@@ -371,10 +371,6 @@ module ActiveSupport #:nodoc:
Object.qualified_const_defined?(path.sub(/^::/, ''), false)
end
- def local_const_defined?(mod, const) #:nodoc:
- mod.const_defined?(const, false)
- end
-
# Given +path+, a filesystem path to a ruby file, return an array of constant
# paths which would cause Dependencies to attempt to load this file.
def loadable_constants_for_path(path, bases = autoload_paths)
@@ -475,7 +471,7 @@ module ActiveSupport #:nodoc:
raise ArgumentError, "A copy of #{from_mod} has been removed from the module tree but is still active!"
end
- raise NameError, "#{from_mod} is not missing constant #{const_name}!" if local_const_defined?(from_mod, const_name)
+ raise NameError, "#{from_mod} is not missing constant #{const_name}!" if from_mod.const_defined?(const_name, false)
qualified_name = qualified_name_for from_mod, const_name
path_suffix = qualified_name.underscore
@@ -484,12 +480,12 @@ module ActiveSupport #:nodoc:
if file_path && ! loaded.include?(File.expand_path(file_path)) # We found a matching file to load
require_or_load file_path
- raise LoadError, "Expected #{file_path} to define #{qualified_name}" unless local_const_defined?(from_mod, const_name)
+ raise LoadError, "Expected #{file_path} to define #{qualified_name}" unless from_mod.const_defined?(const_name, false)
return from_mod.const_get(const_name)
elsif mod = autoload_module!(from_mod, const_name, qualified_name, path_suffix)
return mod
elsif (parent = from_mod.parent) && parent != from_mod &&
- ! from_mod.parents.any? { |p| local_const_defined?(p, const_name) }
+ ! from_mod.parents.any? { |p| p.const_defined?(const_name, false) }
# If our parents do not have a constant named +const_name+ then we are free
# to attempt to load upwards. If they do have such a constant, then this
# const_missing must be due to from_mod::const_name, which should not
diff --git a/activesupport/lib/active_support/deprecation/behaviors.rb b/activesupport/lib/active_support/deprecation/behaviors.rb
index 9102537810..fc962dcb57 100644
--- a/activesupport/lib/active_support/deprecation/behaviors.rb
+++ b/activesupport/lib/active_support/deprecation/behaviors.rb
@@ -16,9 +16,9 @@ module ActiveSupport
#
# Available behaviors:
#
- # [+stderr+] Log all deprecation warnings to +$stderr+.
+ # [+stderr+] Log all deprecation warnings to <tt>$stderr</tt>.
# [+log+] Log all deprecation warnings to +Rails.logger+.
- # [+notify] Use +ActiveSupport::Notifications+ to notify +deprecation.rails+.
+ # [+notify+] Use <tt>ActiveSupport::Notifications</tt> to notify +deprecation.rails+.
# [+silence+] Do nothing.
#
# Setting behaviors only affects deprecations that happen after boot time.
diff --git a/activesupport/lib/active_support/duration.rb b/activesupport/lib/active_support/duration.rb
index 00c67a470d..2cdc991120 100644
--- a/activesupport/lib/active_support/duration.rb
+++ b/activesupport/lib/active_support/duration.rb
@@ -5,7 +5,6 @@ require 'active_support/core_ext/object/acts_like'
module ActiveSupport
# Provides accurate date and time measurements using Date#advance and
# Time#advance, respectively. It mainly supports the methods on Numeric.
- # Example:
#
# 1.month.ago # equivalent to Time.now.advance(:months => -1)
class Duration < BasicObject
diff --git a/activesupport/lib/active_support/i18n.rb b/activesupport/lib/active_support/i18n.rb
index f9c5e5e2f8..188653bd9b 100644
--- a/activesupport/lib/active_support/i18n.rb
+++ b/activesupport/lib/active_support/i18n.rb
@@ -6,4 +6,5 @@ rescue LoadError => e
raise e
end
+ActiveSupport.run_load_hooks(:i18n)
I18n.load_path << "#{File.dirname(__FILE__)}/locale/en.yml"
diff --git a/activesupport/lib/active_support/inflections.rb b/activesupport/lib/active_support/inflections.rb
index 7eb61cd1a0..c04c2ed15b 100644
--- a/activesupport/lib/active_support/inflections.rb
+++ b/activesupport/lib/active_support/inflections.rb
@@ -26,7 +26,7 @@ module ActiveSupport
inflect.singular(/(ss)$/i, '\1')
inflect.singular(/(n)ews$/i, '\1ews')
inflect.singular(/([ti])a$/i, '\1um')
- inflect.singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i, '\1\2sis')
+ inflect.singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i, '\1sis')
inflect.singular(/(^analy)(sis|ses)$/i, '\1sis')
inflect.singular(/([^f])ves$/i, '\1fe')
inflect.singular(/(hive)s$/i, '\1')
diff --git a/activesupport/lib/active_support/inflector/inflections.rb b/activesupport/lib/active_support/inflector/inflections.rb
index 13b23d627a..600e353812 100644
--- a/activesupport/lib/active_support/inflector/inflections.rb
+++ b/activesupport/lib/active_support/inflector/inflections.rb
@@ -3,7 +3,7 @@ require 'active_support/core_ext/array/prepend_and_append'
module ActiveSupport
module Inflector
# A singleton instance of this class is yielded by Inflector.inflections, which can then be used to specify additional
- # inflection rules. Examples:
+ # inflection rules.
#
# ActiveSupport::Inflector.inflections do |inflect|
# inflect.plural /^(ox)$/i, '\1\2en'
@@ -40,7 +40,6 @@ module ActiveSupport
# A camelized string that contains the acronym will maintain the acronym when titleized or humanized, and will
# convert the acronym into a non-delimited single lowercase word when passed to +underscore+.
#
- # Examples:
# acronym 'HTML'
# titleize 'html' #=> 'HTML'
# camelize 'html' #=> 'HTML'
@@ -70,7 +69,6 @@ module ActiveSupport
# `acronym` may be used to specify any word that contains an acronym or otherwise needs to maintain a non-standard
# capitalization. The only restriction is that the word must begin with a capital letter.
#
- # Examples:
# acronym 'RESTful'
# underscore 'RESTful' #=> 'restful'
# underscore 'RESTfulController' #=> 'restful_controller'
@@ -105,7 +103,6 @@ module ActiveSupport
# Specifies a new irregular that applies to both pluralization and singularization at the same time. This can only be used
# for strings, not regular expressions. You simply pass the irregular in singular and plural form.
#
- # Examples:
# irregular 'octopus', 'octopi'
# irregular 'person', 'people'
def irregular(singular, plural)
@@ -127,7 +124,6 @@ module ActiveSupport
# Add uncountable words that shouldn't be attempted inflected.
#
- # Examples:
# uncountable "money"
# uncountable "money", "information"
# uncountable %w( money information rice )
@@ -139,7 +135,6 @@ module ActiveSupport
# When using a regular expression based replacement, the normal humanize formatting is called after the replacement.
# When a string is used, the human form should be specified as desired (example: 'The name', not 'the_name')
#
- # Examples:
# human /_cnt$/i, '\1_count'
# human "legacy_col_person_name", "Name"
def human(rule, replacement)
@@ -150,7 +145,6 @@ module ActiveSupport
# Give the scope as a symbol of the inflection type, the options are: <tt>:plurals</tt>,
# <tt>:singulars</tt>, <tt>:uncountables</tt>, <tt>:humans</tt>.
#
- # Examples:
# clear :all
# clear :plurals
def clear(scope = :all)
@@ -166,7 +160,6 @@ module ActiveSupport
# Yields a singleton instance of Inflector::Inflections so you can specify additional
# inflector rules.
#
- # Example:
# ActiveSupport::Inflector.inflections do |inflect|
# inflect.uncountable "rails"
# end
diff --git a/activesupport/lib/active_support/inflector/methods.rb b/activesupport/lib/active_support/inflector/methods.rb
index 4fcd32edf2..48296841aa 100644
--- a/activesupport/lib/active_support/inflector/methods.rb
+++ b/activesupport/lib/active_support/inflector/methods.rb
@@ -16,7 +16,6 @@ module ActiveSupport
# Returns the plural form of the word in the string.
#
- # Examples:
# "post".pluralize # => "posts"
# "octopus".pluralize # => "octopi"
# "sheep".pluralize # => "sheep"
@@ -28,7 +27,6 @@ module ActiveSupport
# The reverse of +pluralize+, returns the singular form of a word in a string.
#
- # Examples:
# "posts".singularize # => "post"
# "octopi".singularize # => "octopus"
# "sheep".singularize # => "sheep"
@@ -43,7 +41,6 @@ module ActiveSupport
#
# +camelize+ will also convert '/' to '::' which is useful for converting paths to namespaces.
#
- # Examples:
# "active_model".camelize # => "ActiveModel"
# "active_model".camelize(:lower) # => "activeModel"
# "active_model/errors".camelize # => "ActiveModel::Errors"
@@ -67,7 +64,6 @@ module ActiveSupport
#
# Changes '::' to '/' to convert namespaces to paths.
#
- # Examples:
# "ActiveModel".underscore # => "active_model"
# "ActiveModel::Errors".underscore # => "active_model/errors"
#
@@ -89,7 +85,6 @@ module ActiveSupport
# Capitalizes the first word and turns underscores into spaces and strips a
# trailing "_id", if any. Like +titleize+, this is meant for creating pretty output.
#
- # Examples:
# "employee_salary" # => "Employee salary"
# "author_id" # => "Author"
def humanize(lower_case_and_underscored_word)
@@ -108,7 +103,6 @@ module ActiveSupport
#
# +titleize+ is also aliased as +titlecase+.
#
- # Examples:
# "man from the boondocks".titleize # => "Man From The Boondocks"
# "x-men: the last stand".titleize # => "X Men: The Last Stand"
# "TheManWithoutAPast".titleize # => "The Man Without A Past"
@@ -120,7 +114,6 @@ module ActiveSupport
# Create the name of a table like Rails does for models to table names. This method
# uses the +pluralize+ method on the last word in the string.
#
- # Examples
# "RawScaledScorer".tableize # => "raw_scaled_scorers"
# "egg_and_ham".tableize # => "egg_and_hams"
# "fancyCategory".tableize # => "fancy_categories"
@@ -132,7 +125,6 @@ module ActiveSupport
# Note that this returns a string and not a Class. (To convert to an actual class
# follow +classify+ with +constantize+.)
#
- # Examples:
# "egg_and_hams".classify # => "EggAndHam"
# "posts".classify # => "Post"
#
@@ -145,7 +137,6 @@ module ActiveSupport
# Replaces underscores with dashes in the string.
#
- # Example:
# "puni_puni".dasherize # => "puni-puni"
def dasherize(underscored_word)
underscored_word.tr('_', '-')
@@ -183,7 +174,6 @@ module ActiveSupport
# +separate_class_name_and_id_with_underscore+ sets whether
# the method should put '_' between the name and 'id'.
#
- # Examples:
# "Message".foreign_key # => "message_id"
# "Message".foreign_key(false) # => "messageid"
# "Admin::Post".foreign_key # => "post_id"
@@ -253,7 +243,6 @@ module ActiveSupport
# Returns the suffix that should be added to a number to denote the position
# in an ordered sequence such as 1st, 2nd, 3rd, 4th.
#
- # Examples:
# ordinal(1) # => "st"
# ordinal(2) # => "nd"
# ordinal(1002) # => "nd"
@@ -276,7 +265,6 @@ module ActiveSupport
# Turns a number into an ordinal string used to denote the position in an
# ordered sequence such as 1st, 2nd, 3rd, 4th.
#
- # Examples:
# ordinalize(1) # => "1st"
# ordinalize(2) # => "2nd"
# ordinalize(1002) # => "1002nd"
@@ -302,7 +290,6 @@ module ActiveSupport
# Applies inflection rules for +singularize+ and +pluralize+.
#
- # Examples:
# apply_inflections("post", inflections.plurals) # => "posts"
# apply_inflections("posts", inflections.singulars) # => "post"
def apply_inflections(word, rules)
diff --git a/activesupport/lib/active_support/inflector/transliterate.rb b/activesupport/lib/active_support/inflector/transliterate.rb
index 40e7a0e389..a372b6d1f7 100644
--- a/activesupport/lib/active_support/inflector/transliterate.rb
+++ b/activesupport/lib/active_support/inflector/transliterate.rb
@@ -66,8 +66,6 @@ module ActiveSupport
# Replaces special characters in a string so that it may be used as part of a 'pretty' URL.
#
- # ==== Examples
- #
# class Person
# def to_param
# "#{id}-#{name.parameterize}"
diff --git a/activesupport/lib/active_support/json/encoding.rb b/activesupport/lib/active_support/json/encoding.rb
index ab12f3f454..a6e4e7ced2 100644
--- a/activesupport/lib/active_support/json/encoding.rb
+++ b/activesupport/lib/active_support/json/encoding.rb
@@ -136,7 +136,7 @@ module ActiveSupport
end
self.use_standard_json_time_format = true
- self.escape_html_entities_in_json = false
+ self.escape_html_entities_in_json = true
self.encode_big_decimal_as_string = true
end
end
diff --git a/activesupport/lib/active_support/log_subscriber/test_helper.rb b/activesupport/lib/active_support/log_subscriber/test_helper.rb
index 7b7fc81e6c..b65ea6208c 100644
--- a/activesupport/lib/active_support/log_subscriber/test_helper.rb
+++ b/activesupport/lib/active_support/log_subscriber/test_helper.rb
@@ -61,8 +61,12 @@ module ActiveSupport
@logged = Hash.new { |h,k| h[k] = [] }
end
- def method_missing(level, message)
- @logged[level] << message
+ def method_missing(level, message = nil)
+ if block_given?
+ @logged[level] << yield
+ else
+ @logged[level] << message
+ end
end
def logged(level)
diff --git a/activesupport/lib/active_support/multibyte.rb b/activesupport/lib/active_support/multibyte.rb
index 5efe13c537..977fe95dbe 100644
--- a/activesupport/lib/active_support/multibyte.rb
+++ b/activesupport/lib/active_support/multibyte.rb
@@ -7,7 +7,6 @@ module ActiveSupport #:nodoc:
# class so you can support other encodings. See the ActiveSupport::Multibyte::Chars implementation for
# an example how to do this.
#
- # Example:
# ActiveSupport::Multibyte.proxy_class = CharsForUTF32
def self.proxy_class=(klass)
@proxy_class = klass
@@ -18,4 +17,4 @@ module ActiveSupport #:nodoc:
@proxy_class ||= ActiveSupport::Multibyte::Chars
end
end
-end \ No newline at end of file
+end
diff --git a/activesupport/lib/active_support/multibyte/chars.rb b/activesupport/lib/active_support/multibyte/chars.rb
index b20c980f36..4fe925f7f4 100644
--- a/activesupport/lib/active_support/multibyte/chars.rb
+++ b/activesupport/lib/active_support/multibyte/chars.rb
@@ -74,7 +74,6 @@ module ActiveSupport #:nodoc:
# Works just like <tt>String#split</tt>, with the exception that the items in the resulting list are Chars
# instances instead of String. This makes chaining methods easier.
#
- # Example:
# 'Café périferôl'.mb_chars.split(/é/).map { |part| part.upcase.to_s } # => ["CAF", " P", "RIFERÔL"]
def split(*args)
@wrapped_string.split(*args).map { |i| i.mb_chars }
@@ -88,7 +87,6 @@ module ActiveSupport #:nodoc:
# Reverses all characters in the string.
#
- # Example:
# 'Café'.mb_chars.reverse.to_s # => 'éfaC'
def reverse
chars(Unicode.unpack_graphemes(@wrapped_string).reverse.flatten.pack('U*'))
@@ -97,7 +95,6 @@ module ActiveSupport #:nodoc:
# Limits the byte size of the string to a number of bytes without breaking characters. Usable
# when the storage for a string is limited for some reason.
#
- # Example:
# 'こんにちは'.mb_chars.limit(7).to_s # => "こん"
def limit(limit)
slice(0...translate_offset(limit))
@@ -105,7 +102,6 @@ module ActiveSupport #:nodoc:
# Converts characters in the string to uppercase.
#
- # Example:
# 'Laurent, où sont les tests ?'.mb_chars.upcase.to_s # => "LAURENT, OÙ SONT LES TESTS ?"
def upcase
chars Unicode.upcase(@wrapped_string)
@@ -113,7 +109,6 @@ module ActiveSupport #:nodoc:
# Converts characters in the string to lowercase.
#
- # Example:
# 'VĚDA A VÝZKUM'.mb_chars.downcase.to_s # => "věda a výzkum"
def downcase
chars Unicode.downcase(@wrapped_string)
@@ -121,7 +116,6 @@ module ActiveSupport #:nodoc:
# Converts characters in the string to the opposite case.
#
- # Example:
# 'El Cañón".mb_chars.swapcase.to_s # => "eL cAÑÓN"
def swapcase
chars Unicode.swapcase(@wrapped_string)
@@ -129,7 +123,6 @@ module ActiveSupport #:nodoc:
# Converts the first character to uppercase and the remainder to lowercase.
#
- # Example:
# 'über'.mb_chars.capitalize.to_s # => "Über"
def capitalize
(slice(0) || chars('')).upcase + (slice(1..-1) || chars('')).downcase
@@ -137,7 +130,6 @@ module ActiveSupport #:nodoc:
# Capitalizes the first letter of every word, when possible.
#
- # Example:
# "ÉL QUE SE ENTERÓ".mb_chars.titleize # => "Él Que Se Enteró"
# "日本語".mb_chars.titleize # => "日本語"
def titleize
@@ -157,7 +149,6 @@ module ActiveSupport #:nodoc:
# Performs canonical decomposition on all the characters.
#
- # Example:
# 'é'.length # => 2
# 'é'.mb_chars.decompose.to_s.length # => 3
def decompose
@@ -166,7 +157,6 @@ module ActiveSupport #:nodoc:
# Performs composition on all the characters.
#
- # Example:
# 'é'.length # => 3
# 'é'.mb_chars.compose.to_s.length # => 2
def compose
@@ -175,7 +165,6 @@ module ActiveSupport #:nodoc:
# Returns the number of grapheme clusters in the string.
#
- # Example:
# 'क्षि'.mb_chars.length # => 4
# 'क्षि'.mb_chars.grapheme_length # => 3
def grapheme_length
diff --git a/activesupport/lib/active_support/multibyte/unicode.rb b/activesupport/lib/active_support/multibyte/unicode.rb
index cb89d45c92..678f551193 100644
--- a/activesupport/lib/active_support/multibyte/unicode.rb
+++ b/activesupport/lib/active_support/multibyte/unicode.rb
@@ -15,7 +15,6 @@ module ActiveSupport
# The default normalization used for operations that require normalization. It can be set to any of the
# normalizations in NORMALIZATION_FORMS.
#
- # Example:
# ActiveSupport::Multibyte::Unicode.default_normalization_form = :c
attr_accessor :default_normalization_form
@default_normalization_form = :kc
@@ -72,7 +71,6 @@ module ActiveSupport
# Unpack the string at grapheme boundaries. Returns a list of character lists.
#
- # Example:
# Unicode.unpack_graphemes('क्षि') # => [[2325, 2381], [2359], [2367]]
# Unicode.unpack_graphemes('Café') # => [[67], [97], [102], [233]]
def unpack_graphemes(string)
@@ -107,7 +105,6 @@ module ActiveSupport
# Reverse operation of unpack_graphemes.
#
- # Example:
# Unicode.pack_graphemes(Unicode.unpack_graphemes('क्षि')) # => 'क्षि'
def pack_graphemes(unpacked)
unpacked.flatten.pack('U*')
diff --git a/activesupport/lib/active_support/ordered_hash.rb b/activesupport/lib/active_support/ordered_hash.rb
index 8edd3960c7..1a3693f766 100644
--- a/activesupport/lib/active_support/ordered_hash.rb
+++ b/activesupport/lib/active_support/ordered_hash.rb
@@ -5,16 +5,20 @@ YAML.add_builtin_type("omap") do |type, val|
end
module ActiveSupport
- # The order of iteration over hashes in Ruby 1.8 is undefined. For example, you do not know the
- # order in which +keys+ will return keys, or +each+ yield pairs. <tt>ActiveSupport::OrderedHash</tt>
- # implements a hash that preserves insertion order, as in Ruby 1.9:
+ # <tt>ActiveSupport::OrderedHash</tt> implements a hash that preserves
+ # insertion order.
#
# oh = ActiveSupport::OrderedHash.new
# oh[:a] = 1
# oh[:b] = 2
# oh.keys # => [:a, :b], this order is guaranteed
#
- # <tt>ActiveSupport::OrderedHash</tt> is namespaced to prevent conflicts with other implementations.
+ # Also, maps the +omap+ feature for YAML files
+ # (See http://yaml.org/type/omap.html) to support ordered items
+ # when loading from yaml.
+ #
+ # <tt>ActiveSupport::OrderedHash</tt> is namespaced to prevent conflicts
+ # with other implementations.
class OrderedHash < ::Hash
def to_yaml_type
"!tag:yaml.org,2002:omap"
diff --git a/activesupport/lib/active_support/railtie.rb b/activesupport/lib/active_support/railtie.rb
index d1c62c5087..30ac881090 100644
--- a/activesupport/lib/active_support/railtie.rb
+++ b/activesupport/lib/active_support/railtie.rb
@@ -24,5 +24,12 @@ module ActiveSupport
Time.zone_default = zone_default
end
+
+ initializer "active_support.set_configs" do |app|
+ app.config.active_support.each do |k, v|
+ k = "#{k}="
+ ActiveSupport.send(k, v) if ActiveSupport.respond_to? k
+ end
+ end
end
end
diff --git a/activesupport/lib/active_support/ruby/shim.rb b/activesupport/lib/active_support/ruby/shim.rb
deleted file mode 100644
index 13e96b3596..0000000000
--- a/activesupport/lib/active_support/ruby/shim.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-# Backported Ruby builtins so you can code with the latest & greatest
-# but still run on any Ruby 1.8.x.
-#
-# Date next_year, next_month
-# DateTime to_date, to_datetime, xmlschema
-# Enumerable group_by, none?
-# String ord
-# Time to_date, to_time, to_datetime
-require 'active_support'
-require 'active_support/core_ext/date/calculations'
-require 'active_support/core_ext/date_time/conversions'
-require 'active_support/core_ext/enumerable'
-require 'active_support/core_ext/string/conversions'
-require 'active_support/core_ext/string/interpolation'
-require 'active_support/core_ext/time/conversions'
diff --git a/activesupport/lib/active_support/tagged_logging.rb b/activesupport/lib/active_support/tagged_logging.rb
index 538a36f6d9..5e080df518 100644
--- a/activesupport/lib/active_support/tagged_logging.rb
+++ b/activesupport/lib/active_support/tagged_logging.rb
@@ -3,7 +3,7 @@ require 'logger'
require 'active_support/logger'
module ActiveSupport
- # Wraps any standard Logger object to provide tagging capabilities. Examples:
+ # Wraps any standard Logger object to provide tagging capabilities.
#
# logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
# logger.tagged("BCX") { logger.info "Stuff" } # Logs "[BCX] Stuff"
diff --git a/activesupport/lib/active_support/testing/performance.rb b/activesupport/lib/active_support/testing/performance.rb
index 244ee1a224..ec6986654e 100644
--- a/activesupport/lib/active_support/testing/performance.rb
+++ b/activesupport/lib/active_support/testing/performance.rb
@@ -61,7 +61,7 @@ module ActiveSupport
ensure
begin
teardown
- run_callbacks :teardown, :enumerator => :reverse_each
+ run_callbacks :teardown
rescue Exception => e
result = @runner.puke(self.class, method_name, e)
end
@@ -126,7 +126,7 @@ module ActiveSupport
def record; end
end
- class Benchmarker < Performer
+ class Benchmarker < Performer
def initialize(*args)
super
@supported = @metric.respond_to?('measure')
@@ -207,7 +207,7 @@ module ActiveSupport
@name ||= self.class.name.demodulize.underscore
end
- def benchmark
+ def benchmark
with_gc_stats do
before = measure
yield
diff --git a/activesupport/lib/active_support/testing/performance/ruby.rb b/activesupport/lib/active_support/testing/performance/ruby.rb
index b7a34ea279..1104fc0a03 100644
--- a/activesupport/lib/active_support/testing/performance/ruby.rb
+++ b/activesupport/lib/active_support/testing/performance/ruby.rb
@@ -36,7 +36,7 @@ module ActiveSupport
RubyProf.pause
full_profile_options[:runs].to_i.times { run_test(@metric, :profile) }
@data = RubyProf.stop
- @total = @data.threads.values.sum(0) { |method_infos| method_infos.max.total_time }
+ @total = @data.threads.sum(0) { |thread| thread.methods.max.total_time }
end
def record
diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb
index cd07c24257..67ac1b6ccd 100644
--- a/activesupport/lib/active_support/time_with_zone.rb
+++ b/activesupport/lib/active_support/time_with_zone.rb
@@ -8,7 +8,6 @@ module ActiveSupport
#
# You shouldn't ever need to create a TimeWithZone instance directly via <tt>new</tt> . Instead use methods
# +local+, +parse+, +at+ and +now+ on TimeZone instances, and +in_time_zone+ on Time and DateTime instances.
- # Examples:
#
# Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
# Time.zone.local(2007, 2, 10, 15, 30, 45) # => Sat, 10 Feb 2007 15:30:45 EST -05:00
@@ -20,7 +19,6 @@ module ActiveSupport
# See Time and TimeZone for further documentation of these methods.
#
# TimeWithZone instances implement the same API as Ruby Time instances, so that Time and TimeWithZone instances are interchangeable.
- # Examples:
#
# t = Time.zone.now # => Sun, 18 May 2008 13:27:25 EDT -04:00
# t.hour # => 13
@@ -122,8 +120,6 @@ module ActiveSupport
# %Y/%m/%d %H:%M:%S +offset style by setting <tt>ActiveSupport::JSON::Encoding.use_standard_json_time_format</tt>
# to false.
#
- # ==== Examples
- #
# # With ActiveSupport::JSON::Encoding.use_standard_json_time_format = true
# Time.utc(2005,2,1,15,15,10).in_time_zone.to_json
# # => "2005-02-01T15:15:10Z"
diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb
index 9543e50395..28bc06f103 100644
--- a/activesupport/lib/active_support/values/time_zone.rb
+++ b/activesupport/lib/active_support/values/time_zone.rb
@@ -176,7 +176,7 @@ module ActiveSupport
UTC_OFFSET_WITHOUT_COLON = UTC_OFFSET_WITH_COLON.sub(':', '')
# Assumes self represents an offset from UTC in seconds (as returned from Time#utc_offset)
- # and turns this into an +HH:MM formatted string. Example:
+ # and turns this into an +HH:MM formatted string.
#
# TimeZone.seconds_to_utc_offset(-21_600) # => "-06:00"
def self.seconds_to_utc_offset(seconds, colon = true)
@@ -239,7 +239,7 @@ module ActiveSupport
"(GMT#{formatted_offset}) #{name}"
end
- # Method for creating new ActiveSupport::TimeWithZone instance in time zone of +self+ from given values. Example:
+ # Method for creating new ActiveSupport::TimeWithZone instance in time zone of +self+ from given values.
#
# Time.zone = "Hawaii" # => "Hawaii"
# Time.zone.local(2007, 2, 1, 15, 30, 45) # => Thu, 01 Feb 2007 15:30:45 HST -10:00
@@ -248,7 +248,7 @@ module ActiveSupport
ActiveSupport::TimeWithZone.new(nil, self, time)
end
- # Method for creating new ActiveSupport::TimeWithZone instance in time zone of +self+ from number of seconds since the Unix epoch. Example:
+ # Method for creating new ActiveSupport::TimeWithZone instance in time zone of +self+ from number of seconds since the Unix epoch.
#
# Time.zone = "Hawaii" # => "Hawaii"
# Time.utc(2000).to_f # => 946684800.0
@@ -258,7 +258,7 @@ module ActiveSupport
utc.in_time_zone(self)
end
- # Method for creating new ActiveSupport::TimeWithZone instance in time zone of +self+ from parsed string. Example:
+ # Method for creating new ActiveSupport::TimeWithZone instance in time zone of +self+ from parsed string.
#
# Time.zone = "Hawaii" # => "Hawaii"
# Time.zone.parse('1999-12-31 14:00:00') # => Fri, 31 Dec 1999 14:00:00 HST -10:00
@@ -271,7 +271,12 @@ module ActiveSupport
date_parts = Date._parse(str)
return if date_parts.empty?
time = Time.parse(str, now) rescue DateTime.parse(str)
+
if date_parts[:offset].nil?
+ if date_parts[:hour] && time.hour != date_parts[:hour]
+ time = DateTime.parse(str)
+ end
+
ActiveSupport::TimeWithZone.new(nil, self, time)
else
time.in_time_zone(self)
@@ -279,7 +284,7 @@ module ActiveSupport
end
# Returns an ActiveSupport::TimeWithZone instance representing the current time
- # in the time zone represented by +self+. Example:
+ # in the time zone represented by +self+.
#
# Time.zone = 'Hawaii' # => "Hawaii"
# Time.zone.now # => Wed, 23 Jan 2008 20:24:27 HST -10:00
diff --git a/activesupport/test/abstract_unit.rb b/activesupport/test/abstract_unit.rb
index 40e25ce0cd..57ed4a6b60 100644
--- a/activesupport/test/abstract_unit.rb
+++ b/activesupport/test/abstract_unit.rb
@@ -7,9 +7,6 @@ ensure
$VERBOSE = old
end
-lib = File.expand_path("#{File.dirname(__FILE__)}/../lib")
-$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib)
-
require 'active_support/core_ext/kernel/reporting'
require 'active_support/core_ext/string/encoding'
diff --git a/activesupport/test/caching_test.rb b/activesupport/test/caching_test.rb
index bb9ce23276..d62b782e2d 100644
--- a/activesupport/test/caching_test.rb
+++ b/activesupport/test/caching_test.rb
@@ -684,6 +684,13 @@ class MemoryStoreTest < ActiveSupport::TestCase
assert @cache.exist?(2)
assert !@cache.exist?(1)
end
+
+ def test_write_with_unless_exist
+ assert_equal true, @cache.write(1, "aaaaaaaaaa")
+ assert_equal false, @cache.write(1, "aaaaaaaaaa", :unless_exist => true)
+ @cache.write(1, nil)
+ assert_equal false, @cache.write(1, "aaaaaaaaaa", :unless_exist => true)
+ end
end
uses_memcached 'memcached backed store' do
diff --git a/activesupport/test/callback_inheritance_test.rb b/activesupport/test/callback_inheritance_test.rb
index e5ac9511df..6be8ea8b84 100644
--- a/activesupport/test/callback_inheritance_test.rb
+++ b/activesupport/test/callback_inheritance_test.rb
@@ -29,7 +29,7 @@ class GrandParent
end
def dispatch
- run_callbacks(:dispatch, action_name) do
+ run_callbacks :dispatch do
@log << action_name
end
self
diff --git a/activesupport/test/callbacks_test.rb b/activesupport/test/callbacks_test.rb
index 25688a9da5..b7c3b130c3 100644
--- a/activesupport/test/callbacks_test.rb
+++ b/activesupport/test/callbacks_test.rb
@@ -112,7 +112,7 @@ module CallbacksTest
end
def dispatch
- run_callbacks :dispatch, action_name do
+ run_callbacks :dispatch do
@logger << "Done"
end
self
@@ -153,7 +153,7 @@ module CallbacksTest
end
def save
- run_callbacks :save, :action
+ run_callbacks :save
end
end
@@ -338,7 +338,7 @@ module CallbacksTest
end
def save
- run_callbacks :save, "hyphen-ated" do
+ run_callbacks :save do
@stuff
end
end
diff --git a/activesupport/test/core_ext/duplicable_test.rb b/activesupport/test/core_ext/duplicable_test.rb
index 1105353e45..e0566e012c 100644
--- a/activesupport/test/core_ext/duplicable_test.rb
+++ b/activesupport/test/core_ext/duplicable_test.rb
@@ -5,8 +5,8 @@ require 'active_support/core_ext/numeric/time'
class DuplicableTest < ActiveSupport::TestCase
RAISE_DUP = [nil, false, true, :symbol, 1, 2.3, 5.seconds]
- YES = ['1', Object.new, /foo/, [], {}, Time.now]
- NO = [Class.new, Module.new]
+ YES = ['1', Object.new, /foo/, [], {}, Time.now, Class.new, Module.new]
+ NO = []
begin
bd = BigDecimal.new('4.56')
diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb
index 1cd10eb6e2..8239054117 100644
--- a/activesupport/test/core_ext/hash_ext_test.rb
+++ b/activesupport/test/core_ext/hash_ext_test.rb
@@ -491,15 +491,21 @@ class HashExtTest < ActiveSupport::TestCase
original = { :a => 'x', :b => 'y', :c => 10 }
expected = { :a => 'x', :b => 'y' }
- # Should return a new hash with only the given keys.
+ # Should return a new hash without the given keys.
assert_equal expected, original.except(:c)
assert_not_equal expected, original
- # Should replace the hash with only the given keys.
+ # Should replace the hash without the given keys.
assert_equal expected, original.except!(:c)
assert_equal expected, original
end
+ def test_except_with_more_than_one_argument
+ original = { :a => 'x', :b => 'y', :c => 10 }
+ expected = { :a => 'x' }
+ assert_equal expected, original.except(:b, :c)
+ end
+
def test_except_with_original_frozen
original = { :a => 'x', :b => 'y' }
original.freeze
diff --git a/activesupport/test/core_ext/object_and_class_ext_test.rb b/activesupport/test/core_ext/object_and_class_ext_test.rb
index b027fccab3..98ab82609e 100644
--- a/activesupport/test/core_ext/object_and_class_ext_test.rb
+++ b/activesupport/test/core_ext/object_and_class_ext_test.rb
@@ -101,7 +101,7 @@ class ObjectTryTest < ActiveSupport::TestCase
assert !@string.respond_to?(method)
assert_raise(NoMethodError) { @string.try(method) }
end
-
+
def test_nonexisting_method_with_arguments
method = :undefined_method
assert !@string.respond_to?(method)
@@ -138,4 +138,16 @@ class ObjectTryTest < ActiveSupport::TestCase
nil.try { ran = true }
assert_equal false, ran
end
+
+ def test_try_with_private_method
+ klass = Class.new do
+ private
+
+ def private_method
+ 'private method'
+ end
+ end
+
+ assert_raise(NoMethodError) { klass.new.try(:private_method) }
+ end
end
diff --git a/activesupport/test/core_ext/range_ext_test.rb b/activesupport/test/core_ext/range_ext_test.rb
index 9c3389ba82..f0cdc0bfd4 100644
--- a/activesupport/test/core_ext/range_ext_test.rb
+++ b/activesupport/test/core_ext/range_ext_test.rb
@@ -69,16 +69,6 @@ class RangeTest < ActiveSupport::TestCase
assert((1.0...10.0).include?(1.0...10.0))
end
- def test_blockless_step
- assert_equal [1,3,5,7,9], (1..10).step(2)
- end
-
- def test_original_step
- array = []
- (1..10).step(2) {|i| array << i }
- assert_equal [1,3,5,7,9], array
- end
-
def test_cover_is_not_override
range = (1..3)
assert range.method(:include?) != range.method(:cover?)
diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb
index 9010a4a716..eee2caa60e 100644
--- a/activesupport/test/core_ext/string_ext_test.rb
+++ b/activesupport/test/core_ext/string_ext_test.rb
@@ -439,6 +439,30 @@ class OutputSafetyTest < ActiveSupport::TestCase
assert @other_string.html_safe?
end
+ test "Concatting safe onto unsafe with % yields unsafe" do
+ @other_string = "other%s"
+ string = @string.html_safe
+
+ @other_string = @other_string % string
+ assert !@other_string.html_safe?
+ end
+
+ test "Concatting unsafe onto safe with % yields escaped safe" do
+ @other_string = "other%s".html_safe
+ string = @other_string % "<foo>"
+
+ assert_equal "other&lt;foo&gt;", string
+ assert string.html_safe?
+ end
+
+ test "Concatting safe onto safe with % yields safe" do
+ @other_string = "other%s".html_safe
+ string = @string.html_safe
+
+ @other_string = @other_string % string
+ assert @other_string.html_safe?
+ end
+
test "Concatting a fixnum to safe always yields safe" do
string = @string.html_safe
string = string.concat(13)
diff --git a/activesupport/test/inflector_test_cases.rb b/activesupport/test/inflector_test_cases.rb
index 4d10cfca25..9fa1f417e4 100644
--- a/activesupport/test/inflector_test_cases.rb
+++ b/activesupport/test/inflector_test_cases.rb
@@ -47,6 +47,7 @@ module InflectorTestCases
"medium" => "media",
"stadium" => "stadia",
"analysis" => "analyses",
+ "my_analysis" => "my_analyses",
"node_child" => "node_children",
"child" => "children",
diff --git a/activesupport/test/log_subscriber_test.rb b/activesupport/test/log_subscriber_test.rb
index 8e160714b1..2a0e8d20ed 100644
--- a/activesupport/test/log_subscriber_test.rb
+++ b/activesupport/test/log_subscriber_test.rb
@@ -11,7 +11,7 @@ class MyLogSubscriber < ActiveSupport::LogSubscriber
def foo(event)
debug "debug"
- info "info"
+ info { "info" }
warn "warn"
end
diff --git a/activesupport/test/time_zone_test.rb b/activesupport/test/time_zone_test.rb
index d14d01dc30..b9434489bb 100644
--- a/activesupport/test/time_zone_test.rb
+++ b/activesupport/test/time_zone_test.rb
@@ -203,6 +203,24 @@ class TimeZoneTest < ActiveSupport::TestCase
assert_equal Time.utc(1999,12,31,19), twz.time
end
+ def test_parse_should_not_black_out_system_timezone_dst_jump
+ zone = ActiveSupport::TimeZone['Pacific Time (US & Canada)']
+ zone.stubs(:now).returns(zone.now)
+ Time.stubs(:parse).with('2012-03-25 03:29', zone.now).
+ returns(Time.local(0,29,4,25,3,2012,nil,nil,true,"+03:00"))
+ twz = zone.parse('2012-03-25 03:29')
+ assert_equal [0, 29, 3, 25, 3, 2012], twz.to_a[0,6]
+ end
+
+ def test_parse_should_black_out_app_timezone_dst_jump
+ zone = ActiveSupport::TimeZone['Pacific Time (US & Canada)']
+ zone.stubs(:now).returns(zone.now)
+ Time.stubs(:parse).with('2012-03-11 02:29', zone.now).
+ returns(Time.local(0,29,2,11,3,2012,nil,nil,false,"+02:00"))
+ twz = zone.parse('2012-03-11 02:29')
+ assert_equal [0, 29, 3, 11, 3, 2012], twz.to_a[0,6]
+ end
+
def test_utc_offset_lazy_loaded_from_tzinfo_when_not_passed_in_to_initialize
tzinfo = TZInfo::Timezone.get('America/New_York')
zone = ActiveSupport::TimeZone.create(tzinfo.name, nil, tzinfo)
diff --git a/activesupport/test/ts_isolated.rb b/activesupport/test/ts_isolated.rb
index 1d96c20bb6..938bb4ee99 100644
--- a/activesupport/test/ts_isolated.rb
+++ b/activesupport/test/ts_isolated.rb
@@ -1,5 +1,3 @@
-$:.unshift(File.dirname(__FILE__) + '/../../activesupport/lib')
-
require 'minitest/autorun'
require 'active_support/test_case'
require 'rbconfig'
diff --git a/guides/code/getting_started/config/boot.rb b/guides/code/getting_started/config/boot.rb
index 4489e58688..3596736667 100644
--- a/guides/code/getting_started/config/boot.rb
+++ b/guides/code/getting_started/config/boot.rb
@@ -1,5 +1,3 @@
-require 'rubygems'
-
# Set up gems listed in the Gemfile.
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
diff --git a/guides/code/getting_started/public/robots.txt b/guides/code/getting_started/public/robots.txt
index 085187fa58..1a3a5e4dd2 100644
--- a/guides/code/getting_started/public/robots.txt
+++ b/guides/code/getting_started/public/robots.txt
@@ -1,5 +1,5 @@
# See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file
#
# To ban all spiders from the entire site uncomment the next two lines:
-# User-Agent: *
+# User-agent: *
# Disallow: /
diff --git a/guides/code/getting_started/test/performance/browsing_test.rb b/guides/code/getting_started/test/performance/browsing_test.rb
index 3fea27b916..2a849b7f2b 100644
--- a/guides/code/getting_started/test/performance/browsing_test.rb
+++ b/guides/code/getting_started/test/performance/browsing_test.rb
@@ -3,7 +3,7 @@ require 'rails/performance_test_help'
class BrowsingTest < ActionDispatch::PerformanceTest
# Refer to the documentation for all available options
- # self.profile_options = { :runs => 5, :metrics => [:wall_time, :memory]
+ # self.profile_options = { :runs => 5, :metrics => [:wall_time, :memory],
# :output => 'tmp/performance', :formats => [:flat] }
def test_homepage
diff --git a/guides/rails_guides.rb b/guides/rails_guides.rb
index e662ad2ed9..1955309865 100644
--- a/guides/rails_guides.rb
+++ b/guides/rails_guides.rb
@@ -8,9 +8,6 @@ def bundler?
File.exists?('Gemfile')
end
-# Loading Action Pack requires rack and erubis.
-require 'rubygems'
-
begin
# Guides generation in the Rails repo.
as_lib = File.join(pwd, "../activesupport/lib")
diff --git a/guides/source/action_view_overview.textile b/guides/source/action_view_overview.textile
index fd1b6c5fc2..bde30ba21c 100644
--- a/guides/source/action_view_overview.textile
+++ b/guides/source/action_view_overview.textile
@@ -59,7 +59,6 @@ Now we'll create a simple "Hello World" application that uses the +titleize+ met
*hello_world.rb:*
<ruby>
-require 'rubygems'
require 'active_support/core_ext/string/inflections'
require 'rack'
@@ -94,7 +93,6 @@ Now we'll create the same "Hello World" application in Sinatra.
*hello_world.rb:*
<ruby>
-require 'rubygems'
require 'action_view'
require 'sinatra'
diff --git a/guides/source/active_model_basics.textile b/guides/source/active_model_basics.textile
index 98b3533000..d373f4ac85 100644
--- a/guides/source/active_model_basics.textile
+++ b/guides/source/active_model_basics.textile
@@ -20,7 +20,7 @@ class Person
attribute_method_prefix 'reset_'
attribute_method_suffix '_highest?'
- define_attribute_methods ['age']
+ define_attribute_methods 'age'
attr_accessor :age
@@ -95,12 +95,11 @@ h4. Dirty
An object becomes dirty when an object is gone through one or more changes to its attributes and not yet saved. This gives the ability to check whether an object has been changed or not. It also has attribute based accessor methods. Lets consider a Person class with attributes first_name and last_name
<ruby>
-require 'rubygems'
require 'active_model'
class Person
include ActiveModel::Dirty
- define_attribute_methods [:first_name, :last_name]
+ define_attribute_methods :first_name, :last_name
def first_name
@first_name
diff --git a/guides/source/active_record_querying.textile b/guides/source/active_record_querying.textile
index a9cb424eaa..294ef25b33 100644
--- a/guides/source/active_record_querying.textile
+++ b/guides/source/active_record_querying.textile
@@ -1260,6 +1260,24 @@ with
Client.pluck(:id)
</ruby>
+h3. +ids+
+
++ids+ can be used to pluck all the IDs for the relation using the table's primary key.
+
+<ruby>
+Person.ids
+# SELECT id FROM people
+</ruby>
+
+<ruby>
+class Person < ActiveRecord::Base
+ self.primary_key = "person_id"
+end
+
+Person.ids
+# SELECT person_id FROM people
+</ruby>
+
h3. Existence of Objects
If you simply want to check for the existence of the object there's a method called +exists?+. This method will query the database using the same query as +find+, but instead of returning an object or collection of objects it will return either +true+ or +false+.
diff --git a/guides/source/active_support_core_extensions.textile b/guides/source/active_support_core_extensions.textile
index 8045316e98..6443255f5d 100644
--- a/guides/source/active_support_core_extensions.textile
+++ b/guides/source/active_support_core_extensions.textile
@@ -1277,20 +1277,6 @@ The <tt>inquiry</tt> method converts a string into a +StringInquirer+ object mak
"active".inquiry.inactive? # => false
</ruby>
-h4. Key-based Interpolation
-
-In Ruby 1.9 the <tt>%</tt> string operator supports key-based interpolation, both formatted and unformatted:
-
-<ruby>
-"Total is %<total>.02f" % {:total => 43.1} # => Total is 43.10
-"I say %{foo}" % {:foo => "wadus"} # => "I say wadus"
-"I say %{woo}" % {:foo => "wadus"} # => KeyError
-</ruby>
-
-Active Support adds that functionality to <tt>%</tt> in previous versions of Ruby.
-
-NOTE: Defined in +active_support/core_ext/string/interpolation.rb+.
-
h4. +starts_with?+ and +ends_with?+
Active Support defines 3rd person aliases of +String#start_with?+ and +String#end_with?+:
@@ -1337,7 +1323,7 @@ Returns the character of the string at position +position+:
"hello".at(0) # => "h"
"hello".at(4) # => "o"
"hello".at(-1) # => "o"
-"hello".at(10) # => ERROR if < 1.9, nil in 1.9
+"hello".at(10) # => nil
</ruby>
NOTE: Defined in +active_support/core_ext/string/access.rb+.
@@ -1819,7 +1805,7 @@ NOTE: Defined in +active_support/core_ext/numeric/bytes.rb+.
h4. Time
-Enables the use of time calculations and declarations, like 45.minutes + 2.hours + 4.years.
+Enables the use of time calculations and declarations, like @45.minutes <plus> 2.hours <plus> 4.years@.
These methods use Time#advance for precise date calculations when using from_now, ago, etc.
as well as adding or subtracting their results from a Time object. For example:
@@ -2767,18 +2753,6 @@ As the example depicts, the +:db+ format generates a +BETWEEN+ SQL clause. That
NOTE: Defined in +active_support/core_ext/range/conversions.rb+.
-h4. +step+
-
-Active Support extends the method +Range#step+ so that it can be invoked without a block:
-
-<ruby>
-(1..10).step(2) # => [1, 3, 5, 7, 9]
-</ruby>
-
-As the example shows, in that case the method returns an array with the corresponding elements.
-
-NOTE: Defined in +active_support/core_ext/range/blockless_step.rb+.
-
h4. +include?+
The methods +Range#include?+ and +Range#===+ say whether some value falls between the ends of a given instance:
diff --git a/guides/source/ajax_on_rails.textile b/guides/source/ajax_on_rails.textile
index cda9c64460..bfd007490a 100644
--- a/guides/source/ajax_on_rails.textile
+++ b/guides/source/ajax_on_rails.textile
@@ -78,7 +78,7 @@ will produce
<ruby>
button_to('Destroy', 'http://www.example.com', :confirm => 'Are you sure?',
- :method => "delete", :remote => true, :disable_with => 'loading...')
+ :method => "delete", :remote => true, 'data-disable-with' => 'loading...')
</ruby>
will produce
@@ -87,7 +87,7 @@ will produce
<form class='button_to' method='post' action='http://www.example.com' data-remote='true'>
<div>
<input name='_method' value='delete' type='hidden' />
- <input value='Destroy' type='submit' disable_with='loading...' data-confirm='Are you sure?' />
+ <input value='Destroy' type='submit' data-disable-with='loading...' data-confirm='Are you sure?' />
</div>
</form>
</html>
diff --git a/guides/source/asset_pipeline.textile b/guides/source/asset_pipeline.textile
index 010154f1d1..105efe229e 100644
--- a/guides/source/asset_pipeline.textile
+++ b/guides/source/asset_pipeline.textile
@@ -396,7 +396,7 @@ Rails comes bundled with a rake task to compile the asset manifests and other fi
Compiled assets are written to the location specified in +config.assets.prefix+. By default, this is the +public/assets+ directory.
-You can call this task on the server during deployment to create compiled versions of your assets directly on the server. If you do not have write access to your production file system, you can call this task locally and then deploy the compiled assets.
+You can call this task on the server during deployment to create compiled versions of your assets directly on the server. See the next section for information on compiling locally.
The rake task is:
@@ -516,6 +516,41 @@ If you're compiling nginx with Phusion Passenger you'll need to pass that option
A robust configuration for Apache is possible but tricky; please Google around. (Or help update this Guide if you have a good example configuration for Apache.)
+h4. Local Precompilation
+
+There are several reasons why you might want to precompile your assets locally. Among them are:
+
+* You may not have write access to your production file system.
+* You may be deploying to more than one server, and want to avoid the duplication of work.
+* You may be doing frequent deploys that do not include asset changes.
+
+Local compilation allows you to commit the compiled files into source control, and deploy as normal.
+
+There are two caveats:
+
+* You must not run the Capistrano deployment task that precompiles assets.
+* You must change the following two application configuration settings.
+
+In <tt>config/environments/development.rb</tt>, place the following line:
+
+<erb>
+config.assets.prefix = "/dev-assets"
+</erb>
+
+You will also need this in application.rb:
+
+<erb>
+config.assets.initialize_on_precompile = false
+</erb>
+
+The +prefix+ change makes Rails use a different URL for serving assets in development mode, and pass all requests to Sprockets. The prefix is still set to +/assets+ in the production environment. Without this change, the application would serve the precompiled assets from +public/assets+ in development, and you would not see any local changes until you compile assets again.
+
+The +initialize_on_precompile+ change tells the precompile task to run without invoking Rails. This is because the precompile task runs in production mode by default, and will attempt to connect to your specified production database. Please note that you cannot have code in pipeline files that relies on Rails resources (such as the database) when compiling locally with this option.
+
+You will also need to ensure that any compressors or minifiers are available on your development system.
+
+In practice, this will allow you to precompile locally, have those files in your working tree, and commit those files to source control when needed. Development mode will work as expected.
+
h4. Live Compilation
In some circumstances you may wish to use live compilation. In this mode all requests for assets in the pipeline are handled by Sprockets directly.
diff --git a/guides/source/caching_with_rails.textile b/guides/source/caching_with_rails.textile
index e455b504ce..34a100cd3a 100644
--- a/guides/source/caching_with_rails.textile
+++ b/guides/source/caching_with_rails.textile
@@ -229,6 +229,42 @@ class ProductsController < ActionController
end
</ruby>
+Sometimes it is necessary to disambiguate the controller when you call +expire_action+, such as when there are two identically named controllers in separate namespaces:
+
+<ruby>
+class ProductsController < ActionController
+ caches_action :index
+
+ def index
+ @products = Product.all
+ end
+end
+
+module Admin
+ class ProductsController < ActionController
+ cache_sweeper :product_sweeper
+
+ def new
+ @product = Product.new
+ end
+
+ def create
+ @product = Product.create(params[:product])
+ end
+ end
+end
+
+class ProductSweeper < ActionController::Caching::Sweeper
+ observe Product
+
+ def after_create(product)
+ expire_action(:controller => '/products', :action => 'index')
+ end
+end
+</ruby>
+
+Note the use of '/products' here rather than 'products'. If you wanted to expire an action cache for the +Admin::ProductsController+, you would use 'admin/products' instead.
+
h4. SQL Caching
Query caching is a Rails feature that caches the result set returned by each query so that if Rails encounters the same query again for that request, it will use the cached result set as opposed to running the query against the database again.
diff --git a/guides/source/configuring.textile b/guides/source/configuring.textile
index c4e54348d4..f114075cae 100644
--- a/guides/source/configuring.textile
+++ b/guides/source/configuring.textile
@@ -448,9 +448,9 @@ There are a few configuration options available in Active Support:
* +config.active_support.bare+ enables or disables the loading of +active_support/all+ when booting Rails. Defaults to +nil+, which means +active_support/all+ is loaded.
-* +config.active_support.escape_html_entities_in_json+ enables or disables the escaping of HTML entities in JSON serialization. Defaults to +true+.
+* +config.active_support.escape_html_entities_in_json+ enables or disables the escaping of HTML entities in JSON serialization. Defaults to +false+.
-* +config.active_support.use_standard_json_time_format+ enables or disables serializing dates to ISO 8601 format. Defaults to +false+.
+* +config.active_support.use_standard_json_time_format+ enables or disables serializing dates to ISO 8601 format. Defaults to +true+.
* +ActiveSupport::BufferedLogger.silencer+ is set to +false+ to disable the ability to silence logging in a block. The default is +true+.
@@ -597,7 +597,7 @@ Rails has 5 initialization events which can be hooked into (listed in the order
* +to_prepare+: Run after the initializers are run for all Railties (including the application itself), but before eager loading and the middleware stack is built. More importantly, will run upon every request in +development+, but only once (during boot-up) in +production+ and +test+.
-* +before_eager_load+: This is run directly before eager loading occurs, which is the default behaviour for the _production_ environment and not for the +development+ environment.
+* +before_eager_load+: This is run directly before eager loading occurs, which is the default behaviour for the +production+ environment and not for the +development+ environment.
* +after_initialize+: Run directly after the initialization of the application, but before the application initializers are run.
diff --git a/guides/source/engines.textile b/guides/source/engines.textile
index 71bcf6b713..880be57fb5 100644
--- a/guides/source/engines.textile
+++ b/guides/source/engines.textile
@@ -448,6 +448,8 @@ rake db:migrate SCOPE=blorgh VERSION=0
h4. Using a class provided by the application
+h5. Using a model provided by the application
+
When an engine is created, it may want to use specific classes from an application to provide links between the pieces of the engine and the pieces of the application. In the case of the +blorgh+ engine, making posts and comments have authors would make a lot of sense.
Usually, an application would have a +User+ class that would provide the objects that would represent the posts' and comments' authors, but there could be a case where the application calls this class something different, such as +Person+. It's because of this reason that the engine should not hardcode the associations to be exactly for a +User+ class, but should allow for some flexibility around what the class is called.
@@ -544,6 +546,19 @@ end
Now instead of the ugly Ruby object output the author's name will be displayed.
+h5. Using a controller provided by the application
+
+Because Rails controllers generally share code for things like authentication and accessing session variables, by default they inherit from <tt>ApplicationController</tt>. Rails engines, however are scoped to run independently from the main application, so each engine gets a scoped +ApplicationController+. This namespace prevents code collisions, but often engine controllers should access methods in the main application's +ApplicationController+. An easy way to provide this access is to change the engine's scoped +ApplicationController+ to inherit from the main application's +ApplicationController+. For our Blorgh engine this would be done by changing +app/controllers/blorgh/application_controller.rb+ to look like:
+
+<ruby>
+class Blorgh::ApplicationController < ApplicationController
+end
+</ruby>
+
+By default, the engine's controllers inherit from <tt>Blorgh::ApplicationController</tt>. So, after making this change they will have access to the main applications +ApplicationController+ as though they were part of the main application.
+
+This change does require that the engine is run from a Rails application that has an +ApplicationController+.
+
h4. Configuring an engine
This section covers firstly how you can make the +user_class+ setting of the Blorgh engine configurable, followed by general configuration tips for the engine.
diff --git a/guides/source/form_helpers.textile b/guides/source/form_helpers.textile
index b6420db798..711ed3d859 100644
--- a/guides/source/form_helpers.textile
+++ b/guides/source/form_helpers.textile
@@ -405,6 +405,8 @@ Whenever Rails sees that the internal value of an option being generated matches
TIP: The second argument to +options_for_select+ must be exactly equal to the desired internal value. In particular if the value is the integer 2 you cannot pass "2" to +options_for_select+ -- you must pass 2. Be aware of values extracted from the +params+ hash as they are all strings.
+WARNING: when +:inlude_blank+ or +:prompt:+ are not present, +:include_blank+ is forced true if the select attribute +required+ is true, display +size+ is one and +multiple+ is not true.
+
h4. Select Boxes for Dealing with Models
In most cases form controls will be tied to a specific database model and as you might expect Rails provides helpers tailored for that purpose. Consistent with other form helpers, when dealing with models you drop the +_tag+ suffix from +select_tag+:
diff --git a/guides/source/getting_started.textile b/guides/source/getting_started.textile
index 947abd7ba0..19bd106ff0 100644
--- a/guides/source/getting_started.textile
+++ b/guides/source/getting_started.textile
@@ -183,9 +183,9 @@ Rails will create several files for you. Most important of these are of course t
Open the +app/views/welcome/index.html.erb+ file in your text editor and edit it to contain a single line of code:
-<code class="html">
+<html>
<h1>Hello, Rails!</h1>
-</code>
+</html>
h4. Setting the Application Home Page
@@ -193,7 +193,7 @@ Now that we have made the controller and view, we need to tell Rails when we wan
To fix this, delete the +index.html+ file located inside the +public+ directory of the application.
-You need to do this because Rails will serve any static file in the +public+ directory that matches a route in preference to any dynamic content you generate from the controllers.
+You need to do this because Rails will serve any static file in the +public+ directory that matches a route in preference to any dynamic content you generate from the controllers. The +index.html+ file is special: it will be served if a request comes in at the root route, e.g. http://localhost:3000. If another request such as http://localhost:3000/welcome happened, a static file at <tt>public/welcome.html</tt> would be served first, but only if it existed.
Next, you have to tell Rails where your actual home page is located.
@@ -210,7 +210,7 @@ Blog::Application.routes.draw do
The +root :to => "welcome#index"+ tells Rails to map requests to the root of the application to the welcome controller's index action. This was created earlier when you ran the controller generator (+rails generate controller welcome index+).
-If you navigate to "http://localhost:3000":http://localhost:3000 in your browser, you'll see +Hello, Rails!+.
+If you navigate to "http://localhost:3000":http://localhost:3000 in your browser, you'll see the +Hello, Rails!+ message you put into +app/views/welcome/index.html.erb+, indicating that this new route is indeed going to +WelcomeController+'s +index+ action and is rendering the view correctly.
NOTE. For more information about routing, refer to "Rails Routing from the Outside In":routing.html.
@@ -220,7 +220,7 @@ Now that you've seen how to create a controller, an action and a view, let's cre
In the Blog application, you will now create a new _resource_. A resource is the term used for a collection of similar objects, such as posts, people or animals. You can create, read, update and destroy items for a resource and these operations are referred to as _CRUD_ operations.
-In the next section, you will add the ability to create new posts in your application and be able to view them. This is the "CR" from CRUD. The form for doing this will look like this:
+In the next section, you will add the ability to create new posts in your application and be able to view them. This is the "C" and the "R" from CRUD: creation and reading. The form for doing this will look like this:
!images/getting_started/new_post.png(The new post form)!
@@ -232,7 +232,7 @@ The first thing that you are going to need to create a new post within the appli
!images/getting_started/routing_error_no_route_matches.png(A routing error, no route matches /posts/new)!
-This is because there is nowhere inside the routes for the application -- defined inside +config/routes.rb+ -- that defines this route. By default, Rails has no routes configured at all, and so you must define your routes as you need them.
+This is because there is nowhere inside the routes for the application -- defined inside +config/routes.rb+ -- that defines this route. By default, Rails has no routes configured at all, besides the root route you defined earlier, and so you must define your routes as you need them.
To do this, you're going to need to create a route inside +config/routes.rb+ file, on a new line between the +do+ and the +end+ for the +draw+ method:
@@ -282,9 +282,9 @@ You're getting this error now because Rails expects plain actions like this one
In the above image, the bottom line has been truncated. Let's see what the full thing looks like:
-<text>
+<blockquote>
Missing template posts/new, application/new with {:locale=>[:en], :formats=>[:html], :handlers=>[:erb, :builder, :coffee]}. Searched in: * "/path/to/blog/app/views"
-</text>
+</blockquote>
That's quite a lot of text! Let's quickly go through and understand what each part of it does.
@@ -330,11 +330,17 @@ method called +form_for+. To use this method, add this code into +app/views/post
If you refresh the page now, you'll see the exact same form as in the example. Building forms in Rails is really just that easy!
-When you call +form_for+, you pass it an identifying object for this form. In this case, it's the symbol +:post+. This tells the +form_for+ helper what this form is for. Inside the block for this method, the FormBuilder object -- represented by +f+ -- is used to build two labels and two text fields, one each for the title and text of a post. Finally, a call to +submit+ on the +f+ object will create a submit button for the form.
+When you call +form_for+, you pass it an identifying object for this
+form. In this case, it's the symbol +:post+. This tells the +form_for+
+helper what this form is for. Inside the block for this method, the
++FormBuilder+ object -- represented by +f+ -- is used to build two labels and two text fields, one each for the title and text of a post. Finally, a call to +submit+ on the +f+ object will create a submit button for the form.
There's one problem with this form though. If you inspect the HTML that is generated, by viewing the source of the page, you will see that the +action+ attribute for the form is pointing at +/posts/new+. This is a problem because this route goes to the very page that you're on right at the moment, and that route should only be used to display the form for a new post.
-So the form needs to use a different URL in order to go somewhere else. This can be done quite simply with the +:url+ option of +form_for+. Typically in Rails, the action that is used for new form submissions like this is called "create", and so the form should be pointed to this action.
+The form needs to use a different URL in order to go somewhere else.
+This can be done quite simply with the +:url+ option of +form_for+.
+Typically in Rails, the action that is used for new form submissions
+like this is called "create", and so the form should be pointed to that action.
Edit the +form_for+ line inside +app/views/posts/new.html.erb+ to look like this:
@@ -350,11 +356,11 @@ post "posts/create"
By using the +post+ method rather than the +get+ method, Rails will define a route that will only respond to POST methods. The POST method is the typical method used by forms all over the web.
-With the form and the route for it defined now, you will be able to fill in the form and then click the submit button to begin the process of creating a new post, so go ahead and do that. When you submit the form, you should see a familiar error:
+With the form and its associated route defined, you will be able to fill in the form and then click the submit button to begin the process of creating a new post, so go ahead and do that. When you submit the form, you should see a familiar error:
!images/getting_started/unknown_action_create_for_posts.png(Unknown action create for PostsController)!
-You will now need to create the +create+ action within the +PostsController+ for this to work.
+You now need to create the +create+ action within the +PostsController+ for this to work.
h4. Creating posts
@@ -381,7 +387,7 @@ def create
end
</ruby>
-The +render+ method here is taking a very simple hash with the key of +text+ and the value of +params[:post].inspect+. The +params+ method here is the object which represents the parameters (or fields) coming in from the form. The +params+ method returns a +HashWithIndifferentAccess+ object, which allows you to access the keys of the hash using either strings or symbols. In this situation, the only parameters that matter are the ones from the form.
+The +render+ method here is taking a very simple hash with a key of +text+ and value of +params[:post].inspect+. The +params+ method is the object which represents the parameters (or fields) coming in from the form. The +params+ method returns a +HashWithIndifferentAccess+ object, which allows you to access the keys of the hash using either strings or symbols. In this situation, the only parameters that matter are the ones from the form.
If you re-submit the form one more time you'll now no longer get the missing template error. Instead, you'll see something that looks like the following:
@@ -402,16 +408,22 @@ To create the new model, run this command in your terminal:
$ rails generate model Post title:string text:text
</shell>
-With that command we told Rails that we want a +Post+ model, which in
-turn should have a title attribute of type string, and a text attribute
+With that command we told Rails that we want a +Post+ model, together
+with a _title_ attribute of type string, and a _text_ attribute
of type text. Those attributes are automatically added to the +posts+
table in the database and mapped to the +Post+ model.
-Rails in turn responded by creating a bunch of files. For
+Rails responded by creating a bunch of files. For
now, we're only interested in +app/models/post.rb+ and
-+db/migrate/20120419084633_create_posts.rb+. The latter is responsible
++db/migrate/20120419084633_create_posts.rb+ (your name could be a bit
+different). The latter is responsible
for creating the database structure, which is what we'll look at next.
+TIP: Active Record is smart enough to automatically map column names to
+model attributes, which means you don't have to declare attributes
+inside Rails models, as that will be done automatically by Active
+Record.
+
h4. Running a Migration
As we've just seen, +rails generate model+ created a _database
@@ -472,8 +484,8 @@ invoking the command: +rake db:migrate RAILS_ENV=production+.
h4. Saving data in the controller
Back in +posts_controller+, we need to change the +create+ action
-to use the new +Post+ model to save data in the database. Open that file
-and change the +create+ action to look like the following:
+to use the new +Post+ model to save the data in the database. Open that file
+and change the +create+ action to look like this:
<ruby>
def create
@@ -485,22 +497,21 @@ end
</ruby>
Here's what's going on: every Rails model can be initialized with its
-respective attributes, which are automatically mapped to its
+respective attributes, which are automatically mapped to the respective
database columns. In the first line we do just that (remember that
+params[:post]+ contains the attributes we're interested in). Then,
+@post.save+ is responsible for saving the model in the database.
-Finally, on the last line we redirect the user to the +show+ action,
-wich we have not defined yet.
+Finally, we redirect the user to the +show+ action,
+wich we'll define later.
TIP: As we'll see later, +@post.save+ returns a boolean indicating
-wherever the model was saved or not, and you can (and usually do) take
-different actions depending on the result of calling +@post.save+.
+wherever the model was saved or not.
-h4. Showing posts
+h4. Showing Posts
-Before trying to create a new post, let's add the +show+ action, which
-will be responsible for showing our posts. Open +config/routes.rb+
-and add the following route:
+If you submit the form again now, Rails will complain about not finding
+the +show+ action. That's not very useful though, so let's add the
++show+ action before proceeding. Open +config/routes.rb+ and add the following route:
<ruby>
get "posts/:id" => "posts#show"
@@ -549,19 +560,21 @@ be able to create a post. Try it!
h4. Listing all posts
We still need a way to list all our posts, so let's do that. As usual,
-we'll need a route, a controller action, and a view:
+we'll need a route placed into +config/routes.rb+:
<ruby>
-# Add to config/routes.rb
get "posts" => "posts#index"
+</ruby>
+
+And an action for that route inside the +PostsController+ in the +app/controllers/posts_controller.rb+ file:
-# Add to app/controllers/posts_controller.rb
+<ruby>
def index
@posts = Post.all
end
</ruby>
-+app/view/posts/index.html.erb+:
+And then finally a view for this action, located at +app/views/posts/index.html.erb+:
<erb>
<h1>Listing posts</h1>
@@ -572,15 +585,17 @@ end
<th>Text</th>
</tr>
-<% @posts.each do |post| %>
- <tr>
- <td><%= post.title %></td>
- <td><%= post.text %></td>
- </tr>
-<% end %>
+ <% @posts.each do |post| %>
+ <tr>
+ <td><%= post.title %></td>
+ <td><%= post.text %></td>
+ </tr>
+ <% end %>
</table>
</erb>
+Now if you go to +http://localhost:3000/posts+ you will see a list of all the posts that you have created.
+
h4. Adding links
You can now create, show, and list posts. Now let's add some links to
@@ -597,41 +612,25 @@ The +link_to+ method is one of Rails' built-in view helpers. It creates a
hyperlink based on text to display and where to go - in this case, to the path
for posts.
-Let's add links to the other views as well.
+Let's add links to the other views as well, starting with adding this "New Post" link to +app/views/posts/index.html.erb+, placing it above the +<table>+ tag:
<erb>
-# app/views/posts/index.html.erb
-
-<h1>Listing posts</h1>
-
<%= link_to 'New post', :action => :new %>
+</erb>
-<table>
- <tr>
- <th>Title</th>
- <th>Text</th>
- <th></th>
- </tr>
-
-<% @posts.each do |post| %>
- <tr>
- <td><%= post.title %></td>
- <td><%= post.text %></td>
- <td><%= link_to 'Show', :action => :show, :id => post.id %></td>
- </tr>
-<% end %>
-</table>
-
-# app/views/posts/new.html.erb
+This link will allow you to bring up the form that lets you create a new post. You should also add a link to this template -- +app/views/posts/new.html.erb+ -- to go back to the +index+ action. Do this by adding this underneath the form in this template:
+<erb>
<%= form_for :post do |f| %>
...
<% end %>
<%= link_to 'Back', :action => :index %>
+</erb>
-# app/views/posts/show.html.erb
+Finally, add another link to the +app/views/posts/show.html.erb+ template to go back to the +index+ action as well, so that people who are viewing a single post can go back and view the whole list again:
+<erb>
<p>
<strong>Title:</strong>
<%= @post.title %>
@@ -653,7 +652,7 @@ TIP: In development mode (which is what you're working in by default), Rails
reloads your application with every browser request, so there's no need to stop
and restart the web server when a change is made.
-h4. Adding Some Validation
+h4. Allowing the update of fields
The model file, +app/models/post.rb+ is about as simple as it can get:
@@ -668,11 +667,28 @@ your Rails models for free, including basic database CRUD (Create, Read, Update,
Destroy) operations, data validation, as well as sophisticated search support
and the ability to relate multiple models to one another.
+Rails includes methods to help you secure some of your model fields.
+Open the +app/models/post.rb+ file and edit it:
+
+<ruby>
+class Post < ActiveRecord::Base
+ attr_accessible :text, :title
+end
+</ruby>
+
+This change will ensure that all changes made through HTML forms can edit the content of the text and title fields.
+It will not be possible to define any other field value through forms. You can still define them by calling the `field=` method of course.
+Accessible attributes and the mass assignment probem is covered in details in the "Security guide":security.html#mass-assignment
+
+h4. Adding Some Validation
+
Rails includes methods to help you validate the data that you send to models.
Open the +app/models/post.rb+ file and edit it:
<ruby>
class Post < ActiveRecord::Base
+ attr_accessible :text, :title
+
validates :title, :presence => true,
:length => { :minimum => 5 }
end
@@ -684,9 +700,12 @@ format, and the existence of associated objects. Validations are covered in deta
in "Active Record Validations and
Callbacks":active_record_validations_callbacks.html#validations-overview
-If you open +posts_controller+ again, you'll notice that we don't check
-the result of calling +@post.save+. We need to change its behavior to
-show the form back to the user if any error occur:
+With the validation now in place, when you call +@post.save+ on an invalid
+post, it will return +false+. If you open +app/controllers/posts_controller.rb+
+again, you'll notice that we don't check the result of calling +@post.save+
+inside the +create+ action. If +@post.save+ fails in this situation, we need to
+show the form back to the user. To do this, change the +new+ and +create+
+actions inside +app/controllers/posts_controller.rb+ to these:
<ruby>
def new
@@ -704,20 +723,18 @@ def create
end
</ruby>
-Notice that I've also added +@post = Post.new+ to the +new+ action. I'll
-explain why I did that in the next section, for now add that to your
-controller as well.
+The +new+ action is now creating a new instance variable called +@post+, and
+you'll see why that is in just a few moments.
-Also notice that we use +render+ instead of +redirect_to+ when +save+
-returns false. We can use +render+ so that the +@post+ object is passed
-back to the view.
+Notice that inside the +create+ action we use +render+ instead of +redirect_to+ when +save+
+returns +false+. The +render+ method is used so that the +@post+ object is passed back to the +new+ template when it is rendered. This rendering is done within the same request as the form submission, whereas the +redirect_to+ will tell the browser to issue another request.
If you reload
"http://localhost:3000/posts/new":http://localhost:3000/posts/new and
try to save a post without a title, Rails will send you back to the
form, but that's not very useful. You need to tell the user that
something went wrong. To do that, you'll modify
-+app/views/posts/index.html.erb+ to check for error messages:
++app/views/posts/new.html.erb+ to check for error messages:
<erb>
<%= form_for :post, :url => { :action => :create } do |f| %>
@@ -754,9 +771,8 @@ A few things are going on. We check if there are any errors with
+@post.errors.any?+, and in that case we show a list of all
errors with +@post.errors.full_messages+.
-+pluralize+ is a rails helper
-that takes a number and a string as its arguments. If the number is
-greater than one, the string will be automatically pluralized.
++pluralize+ is a rails helper that takes a number and a string as its
+arguments. If the number is greater than one, the string will be automatically pluralized.
The reason why we added +@post = Post.new+ in +posts_controller+ is that
otherwise +@post+ would be +nil+ in our view, and calling
@@ -766,7 +782,8 @@ TIP: Rails automatically wraps fields that contain an error with a div
with class +field_with_errors+. You can define a css rule to make them
standout.
-Now you'll get a nice error message when saving a post without title:
+Now you'll get a nice error message when saving a post without title when you
+attempt to do just that on the "new post form(http://localhost:3000/posts/new)":http://localhost:3000/posts/new.
!images/getting_started/form_with_errors.png(Form With Errors)!
@@ -830,21 +847,23 @@ it look as follows:
<%= link_to 'Back', :action => :index %>
</erb>
-This time we point the form to the +update+ action (not defined yet).
+This time we point the form to the +update+ action, which is not defined yet
+but will be very soon.
+
The +:method => :put+ option tells Rails that we want this form to be
-submitted via +put+, which is the http method you're expected to use to
+submitted via the +PUT+, HTTP method which is the HTTP method you're expected to use to
*update* resources according to the REST protocol.
TIP: By default forms built with the +form_for_ helper are sent via +POST+.
-Moving on, we need to add the +update+ action. The file
+Next, we need to add the +update+ action. The file
+config/routes.rb+ will need just one more line:
<ruby>
put "posts/:id" => "posts#update"
</ruby>
-And the +update+ action in +posts_controller+ itself should not look too complicated by now:
+And then create the +update+ action in +app/controllers/posts_controller.rb+:
<ruby>
def update
@@ -858,7 +877,7 @@ def update
end
</ruby>
-The new method +update_attributes+ is used when you want to update a record
+The new method, +update_attributes+, is used when you want to update a record
that already exists, and it accepts an hash containing the attributes
that you want to update. As before, if there was an error updating the
post we want to show the form back to the user.
@@ -868,11 +887,11 @@ example, if you'd call +@post.update_attributes(:title => 'A new title')+
Rails would only update the +title+ attribute, leaving all other
attributes untouched.
-Finally, we want to show a link to the +edit+ action in the +index+ and
-+show+ views:
+Finally, we want to show a link to the +edit+ action in the list of all the
+posts, so let's add that now to +app/views/posts/index.html.erb+ to make it
+appear next to the "Show" link:
<erb>
-# app/view/posts/index.html.erb
<table>
<tr>
@@ -891,11 +910,16 @@ Finally, we want to show a link to the +edit+ action in the +index+ and
</tr>
<% end %>
</table>
+</erb>
-# app/view/posts/show.html.erb
+And we'll also add one to the +app/views/posts/show.html.erb+ template as well,
+so that there's also an "Edit" link on a post's page. Add this at the bottom of
+the template:
+<erb>
...
+
<%= link_to 'Back', :action => :index %>
| <%= link_to 'Edit', :action => :edit, :id => @post.id %>
</erb>
@@ -924,8 +948,8 @@ simple example:
<%= @user.about_me %>
</erb>
-The +show+ view will automatically include the content of the
-+_user_details+ view. Note that partials are prefixed by an underscore,
+The +users/show+ template will automatically include the content of the
++users/_user_details+ template. Note that partials are prefixed by an underscore,
as to not be confused with regular views. However, you don't include the
underscore when including them with the +helper+ method.
@@ -934,7 +958,7 @@ Rails":layouts_and_rendering.html guide.
Our +edit+ action looks very similar to the +new+ action, in fact they
both share the same code for displaying the form. Lets clean them up by
-using a +_form+ partial.
+using a partial.
Create a new file +app/views/posts/_form.html.erb+ with the following
content:
@@ -944,7 +968,7 @@ content:
<% if @post.errors.any? %>
<div id="errorExplanation">
<h2><%= pluralize(@post.errors.count, "error") %> prohibited
- this post from being saved:</h2>
+ this post from being saved:</h2>
<ul>
<% @post.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
@@ -968,23 +992,23 @@ content:
<% end %>
</erb>
-Everything except for the +form_for+ declaration remained the same. I'll
-explain later how +form_for+ can figure out the right +action+ and
-+method+ attributes when building the form, for now let's update the
-+new+ and +edit+ views:
+Everything except for the +form_for+ declaration remained the same.
+How +form_for+ can figure out the right +action+ and +method+ attributes
+when building the form will be explained in just a moment. For now, let's update the
++app/views/posts/new.html.erb+ view to use this new partial, rewriting it
+completely:
<erb>
-# app/views/posts/new.html.erb
-
<h1>New post</h1>
<%= render 'form' %>
<%= link_to 'Back', :action => :index %>
+</erb>
+Then do the same for the +app/views/posts/edit.html.erb+ view:
-# app/views/posts/edit.html.erb
-
+<erb>
<h1>Edit post</h1>
<%= render 'form' %>
@@ -992,8 +1016,7 @@ explain later how +form_for+ can figure out the right +action+ and
<%= link_to 'Back', :action => :index %>
</erb>
-Point your browser to
-"http://localhost:3000/posts/new":http://localhost:3000/posts/new and
+Point your browser to "http://localhost:3000/posts/new":http://localhost:3000/posts/new and
try creating a new post. Everything still works. Now try editing the
post and you'll receive the following error:
@@ -1011,7 +1034,8 @@ knows that it should create new objects via POST and update them via
PUT.
If you run +rake routes+ from the console you'll see that we already
-have a +posts_path+ route, which was created automatically by Rails.
+have a +posts_path+ route, which was created automatically by Rails when we
+defined the route for the index action.
However, we don't have a +post_path+ yet, which is the reason why we
received an error before.
@@ -1034,26 +1058,37 @@ line like this:
get "posts/:id" => "posts#show", :as => :post
</ruby>
-Now you'll be able to update posts again.
+The +:as+ option tells the +get+ method that we want to make routing helpers
+called +post_url+ and +post_path+ available to our application. These are
+precisely the methods that the +form_for+ needs when editing a post, and so now
+you'll be able to update posts again.
+
+NOTE: The +:as+ option is available on the +post+, +put+, +delete+ and +match+
+routing methods also.
h4. Deleting Posts
We're now ready to cover the "D" part of CRUD, deleting posts from the
database. Following the REST convention, we're going to add a route for
-deleting posts:
+deleting posts to +config/routes.rb+:
<ruby>
-# config/routes.rb
-
delete "posts/:id" => "posts#destroy"
</ruby>
-We use the +delete+ method for destroying resources, which is mapped to
-the +destroy+ action, which is provided below:
+The +delete+ routing method should be used for routes that destroy
+resources. If this was left as a typical +get+ route, it could be possible for
+people to craft malicious URLs like this:
-<ruby>
-# app/controllers/posts_controller.rb
+<html>
+<a href='http://yoursite.com/posts/1/destroy'>look at this cat!</a>
+</html>
+We use the +delete+ method for destroying resources, and this route is mapped to
+the +destroy+ action inside +app/controllers/posts_controller.rb+, which doesn't exist yet, but is
+provided below:
+
+<ruby>
def destroy
@post = Post.find(params[:id])
@post.destroy
@@ -1063,13 +1098,15 @@ end
</ruby>
You can call +destroy+ on Active Record objects when you want to delete
-them from the dabase. Note that we don't need to add a view for this
+them from the database. Note that we don't need to add a view for this
action since we're redirecting to the +index+ action.
-Finally, add a 'destroy' link to your +index+ action to wrap everything
+Finally, add a 'destroy' link to your +index+ action template
+(+app/views/posts/index.html.erb) to wrap everything
together.
<erb>
+<h1>Listing Posts</h1>
<table>
<tr>
<th>Title</th>
@@ -1092,11 +1129,14 @@ together.
</erb>
Here we're using +link_to+ in a different way. We wrap the
-+:action+ and +:id+ attributes in a hash so that we can pass other
-arguments to +link_to+. The +:method+ and +:confirm+
++:action+ and +:id+ attributes in a hash so that we can pass those two keys in
+first as one argument, and then the final two keys as another argument. The +:method+ and +:confirm+
options are used as html5 attributes so that when the click is linked,
Rails will first show a confirm dialog to the user, and then submit the
-link with method +delete+. This is done via javascript automatically.
+link with method +delete+. This is done via the JavaScript file +jquery_ujs+
+which is automatically included into your application's layout
+(+app/views/layouts/application.html.erb+) when you generated the application.
+Without this file, the confirmation dialog box wouldn't appear.
!images/getting_started/confirm_dialog.png(Confirm Dialog)!
@@ -1136,7 +1176,7 @@ end
</ruby>
If you run +rake routes+, you'll see that all the routes that we
-declared before are still available, and the app still works as before.
+declared before are still available:
<shell>
# rake routes
@@ -1150,18 +1190,22 @@ edit_post GET /posts/:id/edit(.:format) posts#edit
root / welcome#index
</shell>
+Also, if you go through the motions of creating, updating and deleting
+posts the app still works as before.
+
TIP: In general, Rails encourages the use of resources objects in place
-of declaring routes manually. For more information about routing, see
+of declaring routes manually. It was only done in this guide as a learning
+exercise. For more information about routing, see
"Rails Routing from the Outside In":routing.html.
h3. Adding a Second Model
It's time to add a second model to the application. The second model will handle comments on
-blog posts.
+posts.
h4. Generating a Model
-We're going to se the same generator that we used before when creating
+We're going to see the same generator that we used before when creating
the +Post+ model. This time we'll create a +Comment+ model to hold
reference of post comments. Run this command in your terminal:
@@ -1321,7 +1365,7 @@ So first, we'll wire up the Post show template
<p>
<strong>Text:</strong>
- <%= @post.texthttp://beginningruby.org/ %>
+ <%= @post.text %>
</p>
<h2>Add a comment:</h2>
@@ -1344,7 +1388,10 @@ So first, we'll wire up the Post show template
</erb>
This adds a form on the +Post+ show page that creates a new comment by
-calling the +CommentsController+ +create+ action. Let's wire that up:
+calling the +CommentsController+ +create+ action. The +form_for+ call here uses
+an array, which will build a nested route, such as +/posts/1/comments+.
+
+Let's wire up the +create+:
<ruby>
class CommentsController < ApplicationController
@@ -1380,7 +1427,7 @@ template. This is where we want the comment to show, so let's add that to the
<p>
<strong>Text:</strong>
- <%= @post.texthttp://beginningruby.org/ %>
+ <%= @post.text %>
</p>
<h2>Comments</h2>
@@ -1428,7 +1475,7 @@ use partials to clean it up.
h4. Rendering Partial Collections
-First we will make a comment partial to extract showing all the comments for the
+First, we will make a comment partial to extract showing all the comments for the
post. Create the file +app/views/comments/_comment.html.erb+ and put the
following into it:
@@ -1455,7 +1502,7 @@ following:
<p>
<strong>Text:</strong>
- <%= @post.texthttp://beginningruby.org/ %>
+ <%= @post.text %>
</p>
<h2>Comments</h2>
@@ -1517,7 +1564,7 @@ Then you make the +app/views/posts/show.html.erb+ look like the following:
<p>
<strong>Text:</strong>
- <%= @post.texthttp://beginningruby.org/ %>
+ <%= @post.text %>
</p>
<h2>Add a comment:</h2>
diff --git a/guides/source/i18n.textile b/guides/source/i18n.textile
index 6179694c40..ee7176a6c8 100644
--- a/guides/source/i18n.textile
+++ b/guides/source/i18n.textile
@@ -127,7 +127,7 @@ If you want to translate your Rails application to a *single language other than
However, you would probably like to *provide support for more locales* in your application. In such case, you need to set and pass the locale between requests.
-WARNING: You may be tempted to store the chosen locale in a _session_ or a <em>cookie</em>. *Do not do so*. The locale should be transparent and a part of the URL. This way you don't break people's basic assumptions about the web itself: if you send a URL of some page to a friend, she should see the same page, same content. A fancy word for this would be that you're being "<em>RESTful</em>":http://en.wikipedia.org/wiki/Representational_State_Transfer. Read more about the RESTful approach in "Stefan Tilkov's articles":http://www.infoq.com/articles/rest-introduction. There may be some exceptions to this rule, which are discussed below.
+WARNING: You may be tempted to store the chosen locale in a _session_ or a <em>cookie</em>, however *do not do this*. The locale should be transparent and a part of the URL. This way you won't break people's basic assumptions about the web itself: if you send a URL to a friend, they should see the same page and content as you. A fancy word for this would be that you're being "<em>RESTful</em>":http://en.wikipedia.org/wiki/Representational_State_Transfer. Read more about the RESTful approach in "Stefan Tilkov's articles":http://www.infoq.com/articles/rest-introduction. Sometimes there are exceptions to this rule and those are discussed below.
The _setting part_ is easy. You can set the locale in a +before_filter+ in the +ApplicationController+ like this:
@@ -220,7 +220,7 @@ Every helper method dependent on +url_for+ (e.g. helpers for named routes like +
You may be satisfied with this. It does impact the readability of URLs, though, when the locale "hangs" at the end of every URL in your application. Moreover, from the architectural standpoint, locale is usually hierarchically above the other parts of the application domain: and URLs should reflect this.
-You probably want URLs to look like this: +www.example.com/en/books+ (which loads the English locale) and +www.example.com/nl/books+ (which loads the Netherlands locale). This is achievable with the "over-riding +default_url_options+" strategy from above: you just have to set up your routes with "+path_prefix+":http://api.rubyonrails.org/classes/ActionController/Resources.html#M000354 option in this way:
+You probably want URLs to look like this: +www.example.com/en/books+ (which loads the English locale) and +www.example.com/nl/books+ (which loads the Dutch locale). This is achievable with the "over-riding +default_url_options+" strategy from above: you just have to set up your routes with "+path_prefix+":http://api.rubyonrails.org/classes/ActionController/Resources.html#M000354 option in this way:
<ruby>
# config/routes.rb
@@ -229,7 +229,7 @@ scope "/:locale" do
end
</ruby>
-Now, when you call the +books_path+ method you should get +"/en/books"+ (for the default locale). An URL like +http://localhost:3001/nl/books+ should load the Netherlands locale, then, and following calls to +books_path+ should return +"/nl/books"+ (because the locale changed).
+Now, when you call the +books_path+ method you should get +"/en/books"+ (for the default locale). An URL like +http://localhost:3001/nl/books+ should load the Dutch locale, then, and following calls to +books_path+ should return +"/nl/books"+ (because the locale changed).
If you don't want to force the use of a locale in your routes you can use an optional path scope (denoted by the parentheses) like so:
diff --git a/guides/source/initialization.textile b/guides/source/initialization.textile
index 69e5c1edcc..155a439e64 100644
--- a/guides/source/initialization.textile
+++ b/guides/source/initialization.textile
@@ -137,8 +137,6 @@ h4. +config/boot.rb+
+config/boot.rb+ contains this:
<ruby>
-require 'rubygems'
-
# Set up gems listed in the Gemfile.
gemfile = File.expand_path('../../Gemfile', __FILE__)
begin
diff --git a/guides/source/layouts_and_rendering.textile b/guides/source/layouts_and_rendering.textile
index e4a1fd6951..b0a87a5981 100644
--- a/guides/source/layouts_and_rendering.textile
+++ b/guides/source/layouts_and_rendering.textile
@@ -860,12 +860,6 @@ You can supply a hash of additional HTML options:
<%= image_tag "icons/delete.gif", {:height => 45} %>
</erb>
-You can also supply an alternate image to show on mouseover:
-
-<erb>
-<%= image_tag "home.gif", :onmouseover => "menu/home_highlight.gif" %>
-</erb>
-
You can supply alternate text for the image which will be used if the user has images turned off in their browser. If you do not specify an alt text explicitly, it defaults to the file name of the file, capitalized and with no extension. For example, these two image tags would return the same code:
<erb>
diff --git a/guides/source/migrations.textile b/guides/source/migrations.textile
index f855072fd8..52dba76e68 100644
--- a/guides/source/migrations.textile
+++ b/guides/source/migrations.textile
@@ -737,9 +737,7 @@ column.
class AddFlagToProduct < ActiveRecord::Migration
def change
add_column :products, :flag, :boolean
- Product.all.each do |product|
- product.update_attributes!(:flag => false)
- end
+ Product.update_all :flag => false
end
end
</ruby>
@@ -762,9 +760,7 @@ column.
class AddFuzzToProduct < ActiveRecord::Migration
def change
add_column :products, :fuzz, :string
- Product.all.each do |product|
- product.update_attributes! :fuzz => 'fuzzy'
- end
+ Product.update_all :fuzz => 'fuzzy'
end
end
</ruby>
@@ -816,9 +812,7 @@ class AddFlagToProduct < ActiveRecord::Migration
def change
add_column :products, :flag, :boolean
Product.reset_column_information
- Product.all.each do |product|
- product.update_attributes!(:flag => false)
- end
+ Product.update_all :flag => false
end
end
</ruby>
@@ -833,9 +827,7 @@ class AddFuzzToProduct < ActiveRecord::Migration
def change
add_column :products, :fuzz, :string
Product.reset_column_information
- Product.all.each do |product|
- product.update_attributes!(:fuzz => 'fuzzy')
- end
+ Product.update_all :fuzz => 'fuzzy'
end
end
</ruby>
diff --git a/guides/source/security.textile b/guides/source/security.textile
index ac64b82bf6..ac55d60368 100644
--- a/guides/source/security.textile
+++ b/guides/source/security.textile
@@ -627,7 +627,7 @@ h4. Whitelists versus Blacklists
-- _When sanitizing, protecting or verifying something, whitelists over blacklists._
-A blacklist can be a list of bad e-mail addresses, non-public actions or bad HTML tags. This is opposed to a whitelist which lists the good e-mail addresses, public actions, good HTML tags and so on. Although, sometimes it is not possible to create a whitelist (in a SPAM filter, for example), _(highlight)prefer to use whitelist approaches_:
+A blacklist can be a list of bad e-mail addresses, non-public actions or bad HTML tags. This is opposed to a whitelist which lists the good e-mail addresses, public actions, good HTML tags and so on. Although sometimes it is not possible to create a whitelist (in a SPAM filter, for example), _(highlight)prefer to use whitelist approaches_:
* Use before_filter :only => [...] instead of :except => [...]. This way you don't forget to turn it off for newly added actions.
* Use attr_accessible instead of attr_protected. See the mass-assignment section for details
diff --git a/guides/w3c_validator.rb b/guides/w3c_validator.rb
index 84f34f9293..5e340499c4 100644
--- a/guides/w3c_validator.rb
+++ b/guides/w3c_validator.rb
@@ -26,7 +26,6 @@
#
# ---------------------------------------------------------------------------
-require 'rubygems'
require 'w3c_validators'
include W3CValidators
diff --git a/load_paths.rb b/load_paths.rb
index 6b224d4ad5..0ad8fcfeda 100644
--- a/load_paths.rb
+++ b/load_paths.rb
@@ -1,4 +1,3 @@
# bust gem prelude
-require 'rubygems' unless defined? Gem
require 'bundler'
Bundler.setup
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index 01df2c5b64..1f88843ee9 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -1,5 +1,7 @@
## Rails 4.0.0 (unreleased) ##
+* Load all environments available in `config.paths["config/environments"]`. *Piotr Sarnacki*
+
* The application generator generates `public/humans.txt` with some basic data. *Paul Campbell*
* Add `config.queue_consumer` to allow the default consumer to be configurable. *Carlos Antonio da Silva*
diff --git a/railties/Rakefile b/railties/Rakefile
index 108413235a..993ba840ff 100644
--- a/railties/Rakefile
+++ b/railties/Rakefile
@@ -20,7 +20,8 @@ namespace :test do
'test',
'lib',
"#{File.dirname(__FILE__)}/../activesupport/lib",
- "#{File.dirname(__FILE__)}/../actionpack/lib"
+ "#{File.dirname(__FILE__)}/../actionpack/lib",
+ "#{File.dirname(__FILE__)}/../activemodel/lib"
]
ruby "-I#{dash_i.join ':'}", file
end
diff --git a/railties/lib/rails.rb b/railties/lib/rails.rb
index 59c3c56e59..670477f91a 100644
--- a/railties/lib/rails.rb
+++ b/railties/lib/rails.rb
@@ -107,14 +107,11 @@ module Rails
# * The environment variable RAILS_GROUPS;
# * The optional envs given as argument and the hash with group dependencies;
#
- # == Examples
- #
# groups :assets => [:development, :test]
#
# # Returns
# # => [:default, :development, :assets] for Rails.env == "development"
# # => [:default, :production] for Rails.env == "production"
- #
def groups(*groups)
hash = groups.extract_options!
env = Rails.env
diff --git a/railties/lib/rails/commands/application.rb b/railties/lib/rails/commands/application.rb
index 60d1aed73a..2cb6d5ca2e 100644
--- a/railties/lib/rails/commands/application.rb
+++ b/railties/lib/rails/commands/application.rb
@@ -19,7 +19,6 @@ else
end
end
-require 'rubygems' if ARGV.include?("--dev")
require 'rails/generators'
require 'rails/generators/rails/app/app_generator'
diff --git a/railties/lib/rails/commands/plugin_new.rb b/railties/lib/rails/commands/plugin_new.rb
index 0287ba0638..4d7bf3c9f3 100644
--- a/railties/lib/rails/commands/plugin_new.rb
+++ b/railties/lib/rails/commands/plugin_new.rb
@@ -1,5 +1,3 @@
-require 'rubygems' if ARGV.include?("--dev")
-
if ARGV.first != "new"
ARGV[0] = "--help"
else
diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb
index 9bf9cbe022..47856c87c6 100644
--- a/railties/lib/rails/engine.rb
+++ b/railties/lib/rails/engine.rb
@@ -39,8 +39,6 @@ module Rails
# and <tt>autoload_once_paths</tt>, which, differently from a <tt>Railtie</tt>, are scoped to
# the current engine.
#
- # Example:
- #
# class MyEngine < Rails::Engine
# # Add a load path for this specific Engine
# config.autoload_paths << File.expand_path("../lib/some/path", __FILE__)
@@ -336,11 +334,8 @@ module Rails
# It will affect the priority of loading views, helpers, assets and all the other files
# related to engine or application.
#
- # Example:
- #
# # load Blog::Engine with highest priority, followed by application and other railties
# config.railties_order = [Blog::Engine, :main_app, :all]
- #
class Engine < Railtie
autoload :Configuration, "rails/engine/configuration"
autoload :Railties, "rails/engine/railties"
@@ -572,8 +567,9 @@ module Rails
end
initializer :load_environment_config, :before => :load_environment_hook, :group => :all do
- environment = paths["config/environments"].existent.first
- require environment if environment
+ paths["config/environments"].existent.each do |environment|
+ require environment
+ end
end
initializer :append_assets_path, :group => :all do |app|
diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb
index 55642f8140..4fa990171d 100644
--- a/railties/lib/rails/generators.rb
+++ b/railties/lib/rails/generators.rb
@@ -95,7 +95,6 @@ module Rails
# some of them are not available by adding a fallback:
#
# Rails::Generators.fallbacks[:shoulda] = :test_unit
- #
def self.fallbacks
@fallbacks ||= {}
end
@@ -115,8 +114,6 @@ module Rails
# Generators names must end with "_generator.rb". This is required because Rails
# looks in load paths and loads the generator just before it's going to be used.
#
- # ==== Examples
- #
# find_by_namespace :webrat, :rails, :integration
#
# Will search for the following generators:
@@ -125,7 +122,6 @@ module Rails
#
# Notice that "rails:generators:webrat" could be loaded as well, what
# Rails looks for is the first and last parts of the namespace.
- #
def self.find_by_namespace(name, base=nil, context=nil) #:nodoc:
lookups = []
lookups << "#{base}:#{name}" if base
diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb
index 9b0649e456..6cd2ea2bbd 100644
--- a/railties/lib/rails/generators/actions.rb
+++ b/railties/lib/rails/generators/actions.rb
@@ -8,12 +8,9 @@ module Rails
# Adds an entry into Gemfile for the supplied gem. If env
# is specified, add the gem to the given environment.
#
- # ==== Example
- #
# gem "rspec", :group => :test
# gem "technoweenie-restful-authentication", :lib => "restful-authentication", :source => "http://gems.github.com/"
# gem "rails", "3.0", :git => "git://github.com/rails/rails"
- #
def gem(*args)
options = args.extract_options!
name, version = args
@@ -43,12 +40,9 @@ module Rails
# Wraps gem entries inside a group.
#
- # ==== Example
- #
# gem_group :development, :test do
# gem "rspec-rails"
# end
- #
def gem_group(*names, &block)
name = names.map(&:inspect).join(", ")
log :gemfile, "group #{name}"
@@ -66,10 +60,7 @@ module Rails
# Add the given source to Gemfile
#
- # ==== Example
- #
# add_source "http://gems.github.com/"
- #
def add_source(source, options={})
log :source, source
@@ -83,8 +74,6 @@ module Rails
# If options :env is specified, the line is appended to the corresponding
# file in config/environments.
#
- # ==== Examples
- #
# environment do
# "config.autoload_paths += %W(#{config.root}/extras)"
# end
@@ -92,7 +81,6 @@ module Rails
# environment(nil, :env => "development") do
# "config.active_record.observers = :cacher"
# end
- #
def environment(data=nil, options={}, &block)
sentinel = /class [a-z_:]+ < Rails::Application/i
env_file_sentinel = /::Application\.configure do/
@@ -112,12 +100,9 @@ module Rails
# Run a command in git.
#
- # ==== Examples
- #
# git :init
# git :add => "this.file that.rb"
# git :add => "onefile.rb", :rm => "badfile.cxx"
- #
def git(commands={})
if commands.is_a?(Symbol)
run "git #{commands}"
@@ -131,15 +116,12 @@ module Rails
# Create a new file in the vendor/ directory. Code can be specified
# in a block or a data string can be given.
#
- # ==== Examples
- #
# vendor("sekrit.rb") do
# sekrit_salt = "#{Time.now}--#{3.years.ago}--#{rand}--"
# "salt = '#{sekrit_salt}'"
# end
#
# vendor("foreign.rb", "# Foreign code is fun")
- #
def vendor(filename, data=nil, &block)
log :vendor, filename
create_file("vendor/#{filename}", data, :verbose => false, &block)
@@ -148,14 +130,11 @@ module Rails
# Create a new file in the lib/ directory. Code can be specified
# in a block or a data string can be given.
#
- # ==== Examples
- #
# lib("crypto.rb") do
# "crypted_special_value = '#{rand}--#{Time.now}--#{rand(1337)}--'"
# end
#
# lib("foreign.rb", "# Foreign code is fun")
- #
def lib(filename, data=nil, &block)
log :lib, filename
create_file("lib/#{filename}", data, :verbose => false, &block)
@@ -163,8 +142,6 @@ module Rails
# Create a new Rakefile with the provided code (either in a block or a string).
#
- # ==== Examples
- #
# rakefile("bootstrap.rake") do
# project = ask("What is the UNIX name of your project?")
#
@@ -178,7 +155,6 @@ module Rails
# end
#
# rakefile('seed.rake', 'puts "Planting seeds"')
- #
def rakefile(filename, data=nil, &block)
log :rakefile, filename
create_file("lib/tasks/#{filename}", data, :verbose => false, &block)
@@ -186,8 +162,6 @@ module Rails
# Create a new initializer with the provided code (either in a block or a string).
#
- # ==== Examples
- #
# initializer("globals.rb") do
# data = ""
#
@@ -199,7 +173,6 @@ module Rails
# end
#
# initializer("api.rb", "API_KEY = '123456'")
- #
def initializer(filename, data=nil, &block)
log :initializer, filename
create_file("config/initializers/#{filename}", data, :verbose => false, &block)
@@ -209,10 +182,7 @@ module Rails
# The second parameter is the argument string that is passed to
# the generator or an Array that is joined.
#
- # ==== Example
- #
# generate(:authenticated, "user session")
- #
def generate(what, *args)
log :generate, what
argument = args.map {|arg| arg.to_s }.flatten.join(" ")
@@ -222,12 +192,9 @@ module Rails
# Runs the supplied rake task
#
- # ==== Example
- #
# rake("db:migrate")
# rake("db:migrate", :env => "production")
# rake("gems:install", :sudo => true)
- #
def rake(command, options={})
log :rake, command
env = options[:env] || ENV["RAILS_ENV"] || 'development'
@@ -237,10 +204,7 @@ module Rails
# Just run the capify command in root
#
- # ==== Example
- #
# capify!
- #
def capify!
log :capify, ""
in_root { run("#{extify(:capify)} .", :verbose => false) }
@@ -248,10 +212,7 @@ module Rails
# Make an entry in Rails routing file config/routes.rb
#
- # === Example
- #
# route "root :to => 'welcome#index'"
- #
def route(routing_code)
log :route, routing_code
sentinel = /\.routes\.draw do\s*$/
@@ -263,10 +224,7 @@ module Rails
# Reads the given file at the source root and prints it in the console.
#
- # === Example
- #
# readme "README"
- #
def readme(path)
log File.read(find_in_source_paths(path))
end
diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb
index 6df33d65e9..10ad475d55 100644
--- a/railties/lib/rails/generators/app_base.rb
+++ b/railties/lib/rails/generators/app_base.rb
@@ -246,8 +246,17 @@ module Rails
# is easier to silence stdout in the existing test suite this way. The
# end-user gets the bundler commands called anyway, so no big deal.
#
+ # We unset temporary bundler variables to load proper bundler and Gemfile.
+ #
# Thanks to James Tucker for the Gem tricks involved in this call.
- print `"#{Gem.ruby}" -rubygems "#{Gem.bin_path('bundler', 'bundle')}" #{command}`
+ _bundle_command = Gem.bin_path('bundler', 'bundle')
+
+ bundle_bin_path, bundle_gemfile, rubyopt = ENV['BUNDLE_BIN_PATH'], ENV['BUNDLE_GEMFILE'], ENV['RUBYOPT']
+ ENV['BUNDLE_BIN_PATH'], ENV['BUNDLE_GEMFILE'], ENV['RUBYOPT'] = "", "", ""
+
+ print `"#{Gem.ruby}" "#{_bundle_command}" #{command}`
+
+ ENV['BUNDLE_BIN_PATH'], ENV['BUNDLE_GEMFILE'], ENV['RUBYOPT'] = bundle_bin_path, bundle_gemfile, rubyopt
end
def run_bundle
diff --git a/railties/lib/rails/generators/base.rb b/railties/lib/rails/generators/base.rb
index 1648b9674a..28d7680669 100644
--- a/railties/lib/rails/generators/base.rb
+++ b/railties/lib/rails/generators/base.rb
@@ -187,10 +187,7 @@ module Rails
# Remove a previously added hook.
#
- # ==== Examples
- #
# remove_hook_for :orm
- #
def self.remove_hook_for(*names)
remove_invocation(*names)
diff --git a/railties/lib/rails/generators/migration.rb b/railties/lib/rails/generators/migration.rb
index 0c5c4f6e09..5bf98bb6e0 100644
--- a/railties/lib/rails/generators/migration.rb
+++ b/railties/lib/rails/generators/migration.rb
@@ -3,7 +3,6 @@ module Rails
# Holds common methods for migrations. It assumes that migrations has the
# [0-9]*_name format and can be used by another frameworks (like Sequel)
# just by implementing the next migration version method.
- #
module Migration
attr_reader :migration_number, :migration_file_name, :migration_class_name
@@ -38,10 +37,7 @@ module Rails
# The migration version, migration file name, migration class name are
# available as instance variables in the template to be rendered.
#
- # ==== Examples
- #
# migration_template "migration.rb", "db/migrate/add_foo_to_bar.rb"
- #
def migration_template(source, destination=nil, config={})
destination = File.expand_path(destination || source, self.destination_root)
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 3b5cc6648e..3192ec897b 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
@@ -10,4 +10,4 @@
*
*= require_self
*= require_tree .
-*/
+ */
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 c8a3c13b95..d816f973e6 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/application.rb
+++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb
@@ -55,7 +55,7 @@ module <%= app_const_base %>
# parameters by using an attr_accessible or attr_protected declaration.
<%= comment_if :skip_active_record %>config.active_record.whitelist_attributes = true
- # Specifies wether or not has_many or has_one association option :dependent => :restrict raises
+ # Specifies whether or not has_many or has_one association option :dependent => :restrict raises
# an exception. If set to true, then an ActiveRecord::DeleteRestrictionError exception would be
# raised. If set to false, then an error will be added on the model instead.
<%= comment_if :skip_active_record %>config.active_record.dependent_restrict_raises = false
diff --git a/railties/lib/rails/generators/rails/app/templates/config/boot.rb b/railties/lib/rails/generators/rails/app/templates/config/boot.rb
index 4489e58688..3596736667 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/boot.rb
+++ b/railties/lib/rails/generators/rails/app/templates/config/boot.rb
@@ -1,5 +1,3 @@
-require 'rubygems'
-
# Set up gems listed in the Gemfile.
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
diff --git a/railties/lib/rails/generators/rails/app/templates/public/humans.txt.tt b/railties/lib/rails/generators/rails/app/templates/public/humans.txt.tt
index 1c49e5c70a..f081e08b6c 100644
--- a/railties/lib/rails/generators/rails/app/templates/public/humans.txt.tt
+++ b/railties/lib/rails/generators/rails/app/templates/public/humans.txt.tt
@@ -1,9 +1,7 @@
# See more about this file at: http://humanstxt.org/
# For format suggestions, see: http://humanstxt.org/Standard.html
/* TEAM */
- <%= ENV['USER'].titlecase %>
/* APP */
Name: <%= app_const_base %>
- Date Created: <%= Date.today.strftime("%B %d, %Y") %>
Software: Ruby on Rails
diff --git a/railties/lib/rails/generators/rails/app/templates/public/robots.txt b/railties/lib/rails/generators/rails/app/templates/public/robots.txt
index 085187fa58..1a3a5e4dd2 100644
--- a/railties/lib/rails/generators/rails/app/templates/public/robots.txt
+++ b/railties/lib/rails/generators/rails/app/templates/public/robots.txt
@@ -1,5 +1,5 @@
# See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file
#
# To ban all spiders from the entire site uncomment the next two lines:
-# User-Agent: *
+# User-agent: *
# Disallow: /
diff --git a/railties/lib/rails/generators/rails/app/templates/test/performance/browsing_test.rb b/railties/lib/rails/generators/rails/app/templates/test/performance/browsing_test.rb
index 3fea27b916..2a849b7f2b 100644
--- a/railties/lib/rails/generators/rails/app/templates/test/performance/browsing_test.rb
+++ b/railties/lib/rails/generators/rails/app/templates/test/performance/browsing_test.rb
@@ -3,7 +3,7 @@ require 'rails/performance_test_help'
class BrowsingTest < ActionDispatch::PerformanceTest
# Refer to the documentation for all available options
- # self.profile_options = { :runs => 5, :metrics => [:wall_time, :memory]
+ # self.profile_options = { :runs => 5, :metrics => [:wall_time, :memory],
# :output => 'tmp/performance', :formats => [:flat] }
def test_homepage
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 f4263d1b98..722e37e20b 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
@@ -302,7 +302,7 @@ task :default => :test
dummy_application_path = File.expand_path("#{dummy_path}/config/application.rb", destination_root)
unless options[:pretend] || !File.exists?(dummy_application_path)
contents = File.read(dummy_application_path)
- contents[(contents.index("module Dummy"))..-1]
+ contents[(contents.index(/module ([\w]+)\n(.*)class Application/m))..-1]
end
end
end
diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/rails/boot.rb b/railties/lib/rails/generators/rails/plugin_new/templates/rails/boot.rb
index eba0681370..c78bfb7f63 100644
--- a/railties/lib/rails/generators/rails/plugin_new/templates/rails/boot.rb
+++ b/railties/lib/rails/generators/rails/plugin_new/templates/rails/boot.rb
@@ -1,4 +1,3 @@
-require 'rubygems'
gemfile = File.expand_path('../../../../Gemfile', __FILE__)
if File.exist?(gemfile)
diff --git a/railties/lib/rails/generators/test_unit/plugin/templates/test_helper.rb b/railties/lib/rails/generators/test_unit/plugin/templates/test_helper.rb
index e82e321914..c9af2ca832 100644
--- a/railties/lib/rails/generators/test_unit/plugin/templates/test_helper.rb
+++ b/railties/lib/rails/generators/test_unit/plugin/templates/test_helper.rb
@@ -1,3 +1,2 @@
-require 'rubygems'
require 'minitest/autorun'
require 'active_support'
diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb
index a0c308a3b8..26e912fd9e 100644
--- a/railties/test/generators/app_generator_test.rb
+++ b/railties/test/generators/app_generator_test.rb
@@ -89,7 +89,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
output = Dir.chdir(app_root) do
`rails new --help`
end
- assert_match /rails new APP_PATH \[options\]/, output
+ assert_match(/rails new APP_PATH \[options\]/, output)
assert_equal true, $?.success?
end
@@ -146,9 +146,9 @@ class AppGeneratorTest < Rails::Generators::TestCase
run_generator
assert_file "config/database.yml", /sqlite3/
unless defined?(JRUBY_VERSION)
- assert_file "Gemfile", /^gem\s+["']sqlite3["']$/
+ assert_gem "sqlite3"
else
- assert_file "Gemfile", /^gem\s+["']activerecord-jdbcsqlite3-adapter["']$/
+ assert_gem "activerecord-jdbcsqlite3-adapter"
end
end
@@ -156,9 +156,9 @@ class AppGeneratorTest < Rails::Generators::TestCase
run_generator([destination_root, "-d", "mysql"])
assert_file "config/database.yml", /mysql/
unless defined?(JRUBY_VERSION)
- assert_file "Gemfile", /^gem\s+["']mysql2["']$/
+ assert_gem "mysql2"
else
- assert_file "Gemfile", /^gem\s+["']activerecord-jdbcmysql-adapter["']$/
+ assert_gem "activerecord-jdbcmysql-adapter"
end
end
@@ -166,45 +166,45 @@ class AppGeneratorTest < Rails::Generators::TestCase
run_generator([destination_root, "-d", "postgresql"])
assert_file "config/database.yml", /postgresql/
unless defined?(JRUBY_VERSION)
- assert_file "Gemfile", /^gem\s+["']pg["']$/
+ assert_gem "pg"
else
- assert_file "Gemfile", /^gem\s+["']activerecord-jdbcpostgresql-adapter["']$/
+ assert_gem "activerecord-jdbcpostgresql-adapter"
end
end
def test_config_jdbcmysql_database
run_generator([destination_root, "-d", "jdbcmysql"])
assert_file "config/database.yml", /mysql/
- assert_file "Gemfile", /^gem\s+["']activerecord-jdbcmysql-adapter["']$/
+ assert_gem "activerecord-jdbcmysql-adapter"
# TODO: When the JRuby guys merge jruby-openssl in
# jruby this will be removed
- assert_file "Gemfile", /^gem\s+["']jruby-openssl["']$/ if defined?(JRUBY_VERSION)
+ assert_gem "jruby-openssl" if defined?(JRUBY_VERSION)
end
def test_config_jdbcsqlite3_database
run_generator([destination_root, "-d", "jdbcsqlite3"])
assert_file "config/database.yml", /sqlite3/
- assert_file "Gemfile", /^gem\s+["']activerecord-jdbcsqlite3-adapter["']$/
+ assert_gem "activerecord-jdbcsqlite3-adapter"
end
def test_config_jdbcpostgresql_database
run_generator([destination_root, "-d", "jdbcpostgresql"])
assert_file "config/database.yml", /postgresql/
- assert_file "Gemfile", /^gem\s+["']activerecord-jdbcpostgresql-adapter["']$/
+ assert_gem "activerecord-jdbcpostgresql-adapter"
end
def test_config_jdbc_database
run_generator([destination_root, "-d", "jdbc"])
assert_file "config/database.yml", /jdbc/
assert_file "config/database.yml", /mssql/
- assert_file "Gemfile", /^gem\s+["']activerecord-jdbc-adapter["']$/
+ assert_gem "activerecord-jdbc-adapter"
end
def test_config_jdbc_database_when_no_option_given
if defined?(JRUBY_VERSION)
run_generator([destination_root])
assert_file "config/database.yml", /sqlite3/
- assert_file "Gemfile", /^gem\s+["']activerecord-jdbcsqlite3-adapter["']$/
+ assert_gem "activerecord-jdbcsqlite3-adapter"
end
end
@@ -244,7 +244,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
def test_inclusion_of_javascript_runtime
run_generator([destination_root])
if defined?(JRUBY_VERSION)
- assert_file "Gemfile", /gem\s+["']therubyrhino["']$/
+ assert_gem "therubyrhino"
else
assert_file "Gemfile", /# gem\s+["']therubyracer["']+, platform: :ruby$/
end
@@ -278,9 +278,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
assert_match %r{^//= require jquery}, contents
assert_match %r{^//= require jquery_ujs}, contents
end
- assert_file 'Gemfile' do |contents|
- assert_match(/^gem 'jquery-rails'/, contents)
- end
+ assert_gem "jquery-rails"
end
def test_other_javascript_libraries
@@ -289,9 +287,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
assert_match %r{^//= require prototype}, contents
assert_match %r{^//= require prototype_ujs}, contents
end
- assert_file 'Gemfile' do |contents|
- assert_match(/^gem 'prototype-rails'/, contents)
- end
+ assert_gem "prototype-rails"
end
def test_javascript_is_skipped_if_required
@@ -303,9 +299,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
def test_inclusion_of_debugger
run_generator
- assert_file "Gemfile" do |contents|
- assert_match(/gem 'debugger'/, contents)
- end
+ assert_file "Gemfile", /# gem 'debugger'/
end
def test_template_from_dir_pwd
@@ -384,9 +378,8 @@ class AppGeneratorTest < Rails::Generators::TestCase
end
def test_humans_txt_file
- date = Date.today.strftime("%B %d, %Y")
run_generator [File.join(destination_root, 'things-43')]
- assert_file "things-43/public/humans.txt", /Name: Things43/, /Software: Ruby on Rails/, /Date Created: #{date}/
+ assert_file "things-43/public/humans.txt", /Name: Things43/, /Software: Ruby on Rails/
end
protected
@@ -394,6 +387,10 @@ protected
def action(*args, &block)
silence(:stdout) { generator.send(*args, &block) }
end
+
+ def assert_gem(gem)
+ assert_file "Gemfile", /^gem\s+["']#{gem}["']$/
+ end
end
class CustomAppGeneratorTest < Rails::Generators::TestCase
diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb
index 6c31b80c7d..b0e1865b26 100644
--- a/railties/test/generators/plugin_new_generator_test.rb
+++ b/railties/test/generators/plugin_new_generator_test.rb
@@ -99,7 +99,13 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase
end
def test_generation_runs_bundle_install_with_full_and_mountable
- result = run_generator [destination_root, "--mountable", "--full"]
+ result = run_generator [destination_root, "--mountable", "--full", "--dev"]
+ assert_file "#{destination_root}/Gemfile.lock" do |contents|
+ assert_match(/bukkits/, contents)
+ end
+ assert_match(/run bundle install/, result)
+ assert_match(/Using bukkits \(0\.0\.1\)/, result)
+ assert_match(/Your bundle is complete/, result)
assert_equal 1, result.scan("Your bundle is complete").size
end
@@ -236,6 +242,13 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase
assert_no_file "test/dummy"
end
+ def test_creating_dummy_application_with_different_name
+ run_generator [destination_root, "--dummy_path", "spec/fake"]
+ assert_file "spec/fake"
+ assert_file "spec/fake/config/application.rb"
+ assert_no_file "test/dummy"
+ end
+
def test_creating_dummy_without_tests_but_with_dummy_path
run_generator [destination_root, "--dummy_path", "spec/dummy", "--skip-test-unit"]
assert_file "spec/dummy"
@@ -341,4 +354,3 @@ protected
silence(:stdout){ generator.send(*args, &block) }
end
end
-
diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb
index f2dc0c71b1..03be81e59f 100644
--- a/railties/test/isolation/abstract_unit.rb
+++ b/railties/test/isolation/abstract_unit.rb
@@ -17,8 +17,8 @@ RAILS_FRAMEWORK_ROOT = File.expand_path("#{File.dirname(__FILE__)}/../../..")
# These files do not require any others and are needed
# to run the tests
-require "#{RAILS_FRAMEWORK_ROOT}/activesupport/lib/active_support/testing/isolation"
-require "#{RAILS_FRAMEWORK_ROOT}/activesupport/lib/active_support/core_ext/kernel/reporting"
+require "active_support/testing/isolation"
+require "active_support/core_ext/kernel/reporting"
module TestHelpers
module Paths
@@ -248,7 +248,6 @@ module TestHelpers
def use_frameworks(arr)
to_remove = [:actionmailer,
- :activemodel,
:activerecord] - arr
if to_remove.include? :activerecord
remove_from_config "config.active_record.whitelist_attributes = true"
diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb
index 9a6b2b66ca..55f72f532f 100644
--- a/railties/test/railties/engine_test.rb
+++ b/railties/test/railties/engine_test.rb
@@ -537,10 +537,11 @@ YAML
assert_equal "foo", last_response.body
end
- test "it loads its environment file" do
+ test "it loads its environments file" do
@plugin.write "lib/bukkits.rb", <<-RUBY
module Bukkits
class Engine < ::Rails::Engine
+ config.paths["config/environments"].push "config/environments/additional.rb"
end
end
RUBY
@@ -551,9 +552,16 @@ YAML
end
RUBY
+ @plugin.write "config/environments/additional.rb", <<-RUBY
+ Bukkits::Engine.configure do
+ config.additional_environment_loaded = true
+ end
+ RUBY
+
boot_rails
assert Bukkits::Engine.config.environment_loaded
+ assert Bukkits::Engine.config.additional_environment_loaded
end
test "it passes router in env" do
diff --git a/tools/profile b/tools/profile
index 51cb7f33e8..6cc935bce5 100755
--- a/tools/profile
+++ b/tools/profile
@@ -7,7 +7,6 @@ ENV['NO_RELOAD'] ||= '1'
ENV['RAILS_ENV'] ||= 'development'
GC.enable_stats
-require 'rubygems'
Gem.source_index
require 'benchmark'