aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile10
-rw-r--r--actionmailer/lib/action_mailer/railtie.rb1
-rw-r--r--actionpack/CHANGELOG.md27
-rw-r--r--actionpack/lib/abstract_controller/asset_paths.rb2
-rw-r--r--actionpack/lib/abstract_controller/base.rb6
-rw-r--r--actionpack/lib/action_controller/base.rb18
-rw-r--r--actionpack/lib/action_controller/metal/hide_actions.rb10
-rw-r--r--actionpack/lib/action_controller/metal/strong_parameters.rb31
-rw-r--r--actionpack/lib/action_controller/railtie.rb1
-rw-r--r--actionpack/lib/action_controller/test_case.rb11
-rw-r--r--actionpack/lib/action_dispatch/http/filter_parameters.rb29
-rw-r--r--actionpack/lib/action_dispatch/http/headers.rb43
-rw-r--r--actionpack/lib/action_dispatch/http/parameter_filter.rb90
-rw-r--r--actionpack/lib/action_dispatch/http/request.rb8
-rw-r--r--actionpack/lib/action_view.rb1
-rw-r--r--actionpack/lib/action_view/asset_paths.rb143
-rw-r--r--actionpack/lib/action_view/digestor.rb40
-rw-r--r--actionpack/lib/action_view/helpers.rb6
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helper.rb358
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb93
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb70
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb71
-rw-r--r--actionpack/lib/action_view/helpers/asset_url_helper.rb355
-rw-r--r--actionpack/lib/action_view/helpers/date_helper.rb9
-rw-r--r--actionpack/lib/action_view/helpers/tags/check_box.rb8
-rw-r--r--actionpack/lib/action_view/railtie.rb8
-rw-r--r--actionpack/lib/action_view/test_case.rb37
-rw-r--r--actionpack/test/controller/parameters/multi_parameter_attributes_test.rb23
-rw-r--r--actionpack/test/controller/parameters/nested_parameters_test.rb6
-rw-r--r--actionpack/test/controller/parameters/parameters_permit_test.rb2
-rw-r--r--actionpack/test/dispatch/header_test.rb20
-rw-r--r--actionpack/test/fixtures/digestor/level/below/_header.html.erb0
-rw-r--r--actionpack/test/fixtures/digestor/level/below/index.html.erb1
-rw-r--r--actionpack/test/fixtures/test/render_two_partials.html.erb2
-rw-r--r--actionpack/test/template/asset_tag_helper_test.rb279
-rw-r--r--actionpack/test/template/date_helper_i18n_test.rb29
-rw-r--r--actionpack/test/template/date_helper_test.rb16
-rw-r--r--actionpack/test/template/digestor_test.rb20
-rw-r--r--actionpack/test/template/form_helper_test.rb6
-rw-r--r--actionpack/test/template/sanitize_helper_test.rb6
-rw-r--r--actionpack/test/template/test_case_test.rb8
-rw-r--r--activemodel/CHANGELOG.md2
-rw-r--r--activemodel/lib/active_model/attribute_methods.rb2
-rw-r--r--activemodel/lib/active_model/callbacks.rb2
-rw-r--r--activemodel/lib/active_model/conversion.rb2
-rw-r--r--activemodel/lib/active_model/dirty.rb2
-rw-r--r--activemodel/lib/active_model/errors.rb2
-rw-r--r--activemodel/lib/active_model/lint.rb8
-rw-r--r--activemodel/lib/active_model/model.rb2
-rw-r--r--activemodel/lib/active_model/naming.rb2
-rw-r--r--activemodel/lib/active_model/observing.rb6
-rw-r--r--activemodel/lib/active_model/railtie.rb4
-rw-r--r--activemodel/lib/active_model/serialization.rb2
-rw-r--r--activemodel/lib/active_model/translation.rb2
-rw-r--r--activemodel/lib/active_model/validations.rb13
-rw-r--r--activemodel/lib/active_model/validations/acceptance.rb2
-rw-r--r--activemodel/lib/active_model/validations/callbacks.rb2
-rw-r--r--activemodel/lib/active_model/validations/confirmation.rb2
-rw-r--r--activemodel/lib/active_model/validations/exclusion.rb2
-rw-r--r--activemodel/lib/active_model/validations/inclusion.rb2
-rw-r--r--activemodel/lib/active_model/validations/length.rb6
-rw-r--r--activemodel/lib/active_model/validations/numericality.rb4
-rw-r--r--activemodel/lib/active_model/validations/presence.rb4
-rw-r--r--activemodel/lib/active_model/validator.rb2
-rw-r--r--activemodel/test/cases/secure_password_test.rb2
-rw-r--r--activerecord/CHANGELOG.md75
-rw-r--r--activerecord/lib/active_record/associations/preloader.rb24
-rw-r--r--activerecord/lib/active_record/attribute_assignment.rb5
-rw-r--r--activerecord/lib/active_record/attribute_methods.rb155
-rw-r--r--activerecord/lib/active_record/attribute_methods/before_type_cast.rb43
-rw-r--r--activerecord/lib/active_record/attribute_methods/dirty.rb34
-rw-r--r--activerecord/lib/active_record/attribute_methods/read.rb51
-rw-r--r--activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb2
-rw-r--r--activerecord/lib/active_record/attribute_methods/write.rb24
-rw-r--r--activerecord/lib/active_record/callbacks.rb13
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb18
-rw-r--r--activerecord/lib/active_record/connection_adapters/column.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql_adapter.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb13
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb8
-rw-r--r--activerecord/lib/active_record/fixtures.rb3
-rw-r--r--activerecord/lib/active_record/locale/en.yml6
-rw-r--r--activerecord/lib/active_record/querying.rb1
-rw-r--r--activerecord/lib/active_record/railties/databases.rake2
-rw-r--r--activerecord/lib/active_record/relation.rb53
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb4
-rw-r--r--activerecord/lib/active_record/relation/merger.rb22
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb71
-rw-r--r--activerecord/lib/active_record/timestamp.rb3
-rw-r--r--activerecord/lib/active_record/validations/presence.rb6
-rw-r--r--activerecord/lib/active_record/validations/uniqueness.rb3
-rw-r--r--activerecord/lib/rails/generators/active_record.rb6
-rw-r--r--activerecord/lib/rails/generators/active_record/migration/migration_generator.rb6
-rw-r--r--activerecord/lib/rails/generators/active_record/model/model_generator.rb4
-rw-r--r--activerecord/lib/rails/generators/active_record/observer/observer_generator.rb4
-rw-r--r--activerecord/test/cases/adapters/postgresql/quoting_test.rb13
-rw-r--r--activerecord/test/cases/adapters/postgresql/schema_test.rb4
-rw-r--r--activerecord/test/cases/adapters/sqlite3/copy_table_test.rb2
-rw-r--r--activerecord/test/cases/associations/has_many_through_associations_test.rb1
-rw-r--r--activerecord/test/cases/attribute_methods_test.rb4
-rw-r--r--activerecord/test/cases/autosave_association_test.rb3
-rw-r--r--activerecord/test/cases/calculations_test.rb23
-rw-r--r--activerecord/test/cases/defaults_test.rb112
-rw-r--r--activerecord/test/cases/dirty_test.rb44
-rw-r--r--activerecord/test/cases/dup_test.rb14
-rw-r--r--activerecord/test/cases/migration/change_schema_test.rb2
-rw-r--r--activerecord/test/cases/migration_test.rb6
-rw-r--r--activerecord/test/cases/query_cache_test.rb2
-rw-r--r--activerecord/test/cases/reflection_test.rb1
-rw-r--r--activerecord/test/cases/relations_test.rb50
-rw-r--r--activerecord/test/cases/schema_dumper_test.rb6
-rw-r--r--activerecord/test/cases/validations/i18n_generate_message_validation_test.rb7
-rw-r--r--activerecord/test/cases/validations/presence_validation_test.rb7
-rw-r--r--activerecord/test/schema/postgresql_specific_schema.rb9
-rw-r--r--activerecord/test/support/connection.rb2
-rw-r--r--activesupport/CHANGELOG.md11
-rw-r--r--activesupport/lib/active_support/cache/mem_cache_store.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/array/extract_options.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/array/wrap.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/hash/conversions.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/hash/deep_merge.rb6
-rw-r--r--activesupport/lib/active_support/core_ext/hash/slice.rb8
-rw-r--r--activesupport/lib/active_support/core_ext/module/deprecation.rb8
-rw-r--r--activesupport/lib/active_support/core_ext/object.rb7
-rw-r--r--activesupport/lib/active_support/core_ext/object/conversions.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/time/calculations.rb2
-rw-r--r--activesupport/lib/active_support/descendants_tracker.rb53
-rw-r--r--activesupport/lib/active_support/queueing.rb30
-rw-r--r--activesupport/lib/active_support/testing/performance/ruby.rb2
-rw-r--r--activesupport/test/caching_test.rb14
-rw-r--r--activesupport/test/callbacks_test.rb2
-rw-r--r--activesupport/test/core_ext/array_ext_test.rb1
-rw-r--r--activesupport/test/core_ext/hash_ext_test.rb27
-rw-r--r--activesupport/test/descendants_tracker_test_cases.rb20
-rw-r--r--activesupport/test/descendants_tracker_with_autoloading_test.rb10
-rw-r--r--activesupport/test/queueing/container_test.rb28
-rw-r--r--activesupport/test/queueing/test_queue_test.rb44
-rw-r--r--activesupport/test/testing/performance_test.rb15
-rw-r--r--guides/source/4_0_release_notes.md8
-rw-r--r--guides/source/active_record_querying.md56
-rw-r--r--guides/source/active_support_core_extensions.md8
-rw-r--r--guides/source/ajax_on_rails.md316
-rw-r--r--guides/source/configuring.md16
-rw-r--r--guides/source/initialization.md2
-rw-r--r--guides/source/migrations.md21
-rw-r--r--guides/source/upgrading_ruby_on_rails.md2
-rw-r--r--guides/source/working_with_javascript.md394
-rw-r--r--rails.gemspec2
-rw-r--r--railties/CHANGELOG.md6
-rw-r--r--railties/lib/rails/all.rb2
-rw-r--r--railties/lib/rails/application.rb18
-rw-r--r--railties/lib/rails/application/bootstrap.rb14
-rw-r--r--railties/lib/rails/application/configuration.rb18
-rw-r--r--railties/lib/rails/application/finisher.rb9
-rw-r--r--railties/lib/rails/application/routes_reloader.rb2
-rw-r--r--railties/lib/rails/commands.rb55
-rw-r--r--railties/lib/rails/commands/destroy.rb2
-rw-r--r--railties/lib/rails/commands/generate.rb2
-rw-r--r--railties/lib/rails/commands/runner.rb2
-rw-r--r--railties/lib/rails/commands/server.rb14
-rw-r--r--railties/lib/rails/commands/update.rb2
-rw-r--r--railties/lib/rails/engine.rb16
-rw-r--r--railties/lib/rails/engine/configuration.rb30
-rw-r--r--railties/lib/rails/generators.rb58
-rw-r--r--railties/lib/rails/generators/actions.rb44
-rw-r--r--railties/lib/rails/generators/base.rb8
-rw-r--r--railties/lib/rails/generators/erb.rb4
-rw-r--r--railties/lib/rails/generators/erb/controller/controller_generator.rb8
-rw-r--r--railties/lib/rails/generators/erb/mailer/mailer_generator.rb6
-rw-r--r--railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb8
-rw-r--r--railties/lib/rails/generators/generated_attribute.rb8
-rw-r--r--railties/lib/rails/generators/js/assets/assets_generator.rb4
-rw-r--r--railties/lib/rails/generators/named_base.rb6
-rw-r--r--railties/lib/rails/generators/rails/app/app_generator.rb8
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/application.rb2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml4
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt3
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt7
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt4
-rw-r--r--railties/lib/rails/generators/rails/assets/assets_generator.rb8
-rw-r--r--railties/lib/rails/generators/rails/controller/controller_generator.rb4
-rw-r--r--railties/lib/rails/generators/rails/generator/generator_generator.rb6
-rw-r--r--railties/lib/rails/generators/rails/helper/helper_generator.rb4
-rw-r--r--railties/lib/rails/generators/rails/integration_test/integration_test_generator.rb2
-rw-r--r--railties/lib/rails/generators/rails/migration/migration_generator.rb4
-rw-r--r--railties/lib/rails/generators/rails/model/model_generator.rb4
-rw-r--r--railties/lib/rails/generators/rails/observer/observer_generator.rb2
-rw-r--r--railties/lib/rails/generators/rails/performance_test/performance_test_generator.rb2
-rw-r--r--railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb32
-rw-r--r--railties/lib/rails/generators/rails/plugin_new/templates/app/views/layouts/%name%/application.html.erb.tt2
-rw-r--r--railties/lib/rails/generators/rails/plugin_new/templates/rails/application.rb2
-rw-r--r--railties/lib/rails/generators/rails/resource/resource_generator.rb8
-rw-r--r--railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb6
-rw-r--r--railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb12
-rw-r--r--railties/lib/rails/generators/rails/task/task_generator.rb2
-rw-r--r--railties/lib/rails/generators/rails/task/templates/task.rb2
-rw-r--r--railties/lib/rails/generators/resource_helpers.rb2
-rw-r--r--railties/lib/rails/generators/test_case.rb4
-rw-r--r--railties/lib/rails/generators/test_unit/controller/controller_generator.rb4
-rw-r--r--railties/lib/rails/generators/test_unit/helper/helper_generator.rb2
-rw-r--r--railties/lib/rails/generators/test_unit/integration/integration_generator.rb2
-rw-r--r--railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb4
-rw-r--r--railties/lib/rails/generators/test_unit/model/model_generator.rb6
-rw-r--r--railties/lib/rails/generators/test_unit/observer/observer_generator.rb2
-rw-r--r--railties/lib/rails/generators/test_unit/performance/performance_generator.rb2
-rw-r--r--railties/lib/rails/generators/test_unit/plugin/plugin_generator.rb2
-rw-r--r--railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb4
-rw-r--r--railties/lib/rails/info_controller.rb2
-rw-r--r--railties/lib/rails/paths.rb2
-rw-r--r--railties/lib/rails/railtie.rb2
-rw-r--r--railties/lib/rails/railtie/configurable.rb2
-rw-r--r--railties/lib/rails/railtie/configuration.rb8
-rw-r--r--railties/lib/rails/source_annotation_extractor.rb14
-rw-r--r--railties/lib/rails/tasks/annotations.rake2
-rw-r--r--railties/lib/rails/tasks/framework.rake10
-rw-r--r--railties/lib/rails/tasks/middleware.rake2
-rw-r--r--railties/lib/rails/tasks/misc.rake4
-rw-r--r--railties/lib/rails/tasks/routes.rake2
-rw-r--r--railties/lib/rails/tasks/tmp.rake4
-rw-r--r--railties/lib/rails/test_unit/railtie.rb4
-rw-r--r--railties/lib/rails/test_unit/testing.rake28
-rw-r--r--railties/test/application/asset_debugging_test.rb9
-rw-r--r--railties/test/application/assets_test.rb186
-rw-r--r--railties/test/application/configuration_test.rb56
-rw-r--r--railties/test/application/generators_test.rb30
-rw-r--r--railties/test/application/initializers/frameworks_test.rb5
-rw-r--r--railties/test/application/initializers/i18n_test.rb14
-rw-r--r--railties/test/application/initializers/notifications_test.rb2
-rw-r--r--railties/test/application/loading_test.rb28
-rw-r--r--railties/test/application/middleware/cache_test.rb38
-rw-r--r--railties/test/application/middleware/session_test.rb2
-rw-r--r--railties/test/application/middleware_test.rb13
-rw-r--r--railties/test/application/queue_test.rb79
-rw-r--r--railties/test/application/rake/notes_test.rb4
-rw-r--r--railties/test/application/rake_test.rb10
-rw-r--r--railties/test/application/routing_test.rb28
-rw-r--r--railties/test/application/url_generation_test.rb7
-rw-r--r--railties/test/commands/console_test.rb8
-rw-r--r--railties/test/fixtures/lib/plugin_builders/spec_builder.rb2
-rw-r--r--railties/test/generators/actions_test.rb36
-rw-r--r--railties/test/generators/app_generator_test.rb16
-rw-r--r--railties/test/generators/model_generator_test.rb6
-rw-r--r--railties/test/generators/namespaced_generators_test.rb6
-rw-r--r--railties/test/generators/orm_test.rb4
-rw-r--r--railties/test/generators/plugin_new_generator_test.rb2
-rw-r--r--railties/test/generators/resource_generator_test.rb2
-rw-r--r--railties/test/generators/scaffold_generator_test.rb2
-rw-r--r--railties/test/generators/shared_generator_tests.rb14
-rw-r--r--railties/test/generators_test.rb8
-rw-r--r--railties/test/initializable_test.rb18
-rw-r--r--railties/test/isolation/abstract_unit.rb8
-rw-r--r--railties/test/paths_test.rb28
-rw-r--r--railties/test/rails_info_controller_test.rb6
-rw-r--r--railties/test/railties/engine_test.rb42
-rw-r--r--railties/test/railties/generators_test.rb2
-rw-r--r--railties/test/railties/mounted_engine_test.rb38
258 files changed, 3006 insertions, 2448 deletions
diff --git a/Gemfile b/Gemfile
index 3b77524077..6e0f43c526 100644
--- a/Gemfile
+++ b/Gemfile
@@ -6,9 +6,9 @@ gem 'arel', github: 'rails/arel', branch: 'master'
gem 'mocha', '>= 0.11.2', :require => false
gem 'rack-test', github: 'brynary/rack-test'
-gem 'rack-cache', "~> 1.2"
+gem 'rack-cache', '~> 1.2'
gem 'bcrypt-ruby', '~> 3.0.0'
-gem 'jquery-rails'
+gem 'jquery-rails', '~> 2.1.4', github: 'rails/jquery-rails'
gem 'turbolinks'
gem 'coffee-rails', github: 'rails/coffee-rails'
@@ -28,7 +28,7 @@ group :doc do
# for some weeks unapplied. As a temporary solution
# this is our own fork with the fix.
gem 'sdoc', github: 'fxn/sdoc'
- gem 'redcarpet', '~> 2.1.1'
+ gem 'redcarpet', '~> 2.1.1', :platforms => :ruby
gem 'w3c_validators'
end
@@ -41,8 +41,8 @@ instance_eval File.read local_gemfile if File.exists? local_gemfile
platforms :mri do
group :test do
- gem 'ruby-prof', '~> 0.11.2'
- gem 'debugger' if !ENV['TRAVIS'] && RUBY_VERSION < "2.0"
+ gem 'ruby-prof', '~> 0.11.2' if RUBY_VERSION < '2.0'
+ gem 'debugger' if !ENV['TRAVIS'] && RUBY_VERSION < '2.0' && RUBY_PATCHLEVEL < 286
end
end
diff --git a/actionmailer/lib/action_mailer/railtie.rb b/actionmailer/lib/action_mailer/railtie.rb
index abf6ad80cf..59dc26841f 100644
--- a/actionmailer/lib/action_mailer/railtie.rb
+++ b/actionmailer/lib/action_mailer/railtie.rb
@@ -22,7 +22,6 @@ module ActionMailer
options.queue ||= app.queue
# make sure readers methods get compiled
- options.asset_path ||= app.config.asset_path
options.asset_host ||= app.config.asset_host
options.relative_url_root ||= app.config.relative_url_root
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index fd02492834..48ba1518e0 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,6 +1,31 @@
## Rails 4.0.0 (unreleased) ##
-* Remove old asset tag concatenation (no longer needed now that we have the asset pipeline). *Josh Peek*
+* `date_select` helper accepts `with_css_classes: true` to add css classes similar with type
+ of generated select tags.
+
+ *Pavel Nikitin*
+
+* Only non-js/css under app/assets path will be included in default config.assets.precompile.
+
+ *Josh Peek*
+
+* Remove support for the RAILS_ASSET_ID environment configuration
+ (no longer needed now that we have the asset pipeline).
+
+ *Josh Peek*
+
+* Remove old asset_path configuration (no longer needed now that we have the asset pipeline).
+
+ *Josh Peek*
+
+* `assert_template` can be used to assert on the same template with different locals
+ Fix #3675
+
+ *Yves Senn*
+
+* Remove old asset tag concatenation (no longer needed now that we have the asset pipeline).
+
+ *Josh Peek*
* Accept :remote as symbolic option for `link_to` helper. *Riley Lynch*
diff --git a/actionpack/lib/abstract_controller/asset_paths.rb b/actionpack/lib/abstract_controller/asset_paths.rb
index 822254b1a4..e6170228d9 100644
--- a/actionpack/lib/abstract_controller/asset_paths.rb
+++ b/actionpack/lib/abstract_controller/asset_paths.rb
@@ -3,7 +3,7 @@ module AbstractController
extend ActiveSupport::Concern
included do
- config_accessor :asset_host, :asset_path, :assets_dir, :javascripts_dir,
+ config_accessor :asset_host, :assets_dir, :javascripts_dir,
:stylesheets_dir, :default_asset_host_protocol, :relative_url_root
end
end
diff --git a/actionpack/lib/abstract_controller/base.rb b/actionpack/lib/abstract_controller/base.rb
index 9c3960961b..388e043f0b 100644
--- a/actionpack/lib/abstract_controller/base.rb
+++ b/actionpack/lib/abstract_controller/base.rb
@@ -217,8 +217,10 @@ module AbstractController
# * <tt>string</tt> - The name of the method that handles the action
# * <tt>nil</tt> - No method name could be found. Raise ActionNotFound.
def method_for_action(action_name)
- if action_method?(action_name) then action_name
- elsif respond_to?(:action_missing, true) then "_handle_action_missing"
+ if action_method?(action_name)
+ action_name
+ elsif respond_to?(:action_missing, true)
+ "_handle_action_missing"
end
end
end
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index 6b8d9384d4..9b3bf99fc3 100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -43,7 +43,7 @@ module ActionController
#
# def server_ip
# location = request.env["SERVER_ADDR"]
- # render :text => "This server hosted at #{location}"
+ # render text: "This server hosted at #{location}"
# end
#
# == Parameters
@@ -113,9 +113,9 @@ module ActionController
# def search
# @results = Search.find(params[:query])
# case @results.count
- # when 0 then render :action => "no_results"
- # when 1 then render :action => "show"
- # when 2..10 then render :action => "show_many"
+ # when 0 then render action: "no_results"
+ # when 1 then render action: "show"
+ # when 2..10 then render action: "show_many"
# end
# end
#
@@ -131,7 +131,7 @@ module ActionController
# @entry = Entry.new(params[:entry])
# if @entry.save
# # The entry was saved correctly, redirect to show
- # redirect_to :action => 'show', :id => @entry.id
+ # redirect_to action: 'show', id: @entry.id
# else
# # things didn't go so well, do something else
# end
@@ -148,15 +148,15 @@ module ActionController
# An action may contain only a single render or a single redirect. Attempting to try to do either again will result in a DoubleRenderError:
#
# def do_something
- # redirect_to :action => "elsewhere"
- # render :action => "overthere" # raises DoubleRenderError
+ # redirect_to action: "elsewhere"
+ # render action: "overthere" # raises DoubleRenderError
# end
#
# If you need to redirect on the condition of something, then be sure to add "and return" to halt execution.
#
# def do_something
- # redirect_to(:action => "elsewhere") and return if monkeys.nil?
- # render :action => "overthere" # won't be called if monkeys is nil
+ # redirect_to(action: "elsewhere") and return if monkeys.nil?
+ # render action: "overthere" # won't be called if monkeys is nil
# end
#
class Base < Metal
diff --git a/actionpack/lib/action_controller/metal/hide_actions.rb b/actionpack/lib/action_controller/metal/hide_actions.rb
index 420b22cf56..2aa6b7adaf 100644
--- a/actionpack/lib/action_controller/metal/hide_actions.rb
+++ b/actionpack/lib/action_controller/metal/hide_actions.rb
@@ -26,20 +26,14 @@ module ActionController
self.hidden_actions = hidden_actions.dup.merge(args.map(&:to_s)).freeze
end
- def inherited(klass)
- klass.class_eval { @visible_actions = {} }
- super
- end
-
def visible_action?(action_name)
- return @visible_actions[action_name] if @visible_actions.key?(action_name)
- @visible_actions[action_name] = !hidden_actions.include?(action_name)
+ action_methods.include?(action_name)
end
# Overrides AbstractController::Base#action_methods to remove any methods
# that are listed as hidden methods.
def action_methods
- @action_methods ||= Set.new(super.reject { |name| hidden_actions.include?(name) })
+ @action_methods ||= Set.new(super.reject { |name| hidden_actions.include?(name) }).freeze
end
end
end
diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb
index e4d6b65d9a..73f2e94cd1 100644
--- a/actionpack/lib/action_controller/metal/strong_parameters.rb
+++ b/actionpack/lib/action_controller/metal/strong_parameters.rb
@@ -171,14 +171,39 @@ module ActionController
# permitted[:person][:age] # => nil
# permitted[:person][:pets][0][:name] # => "Purplish"
# permitted[:person][:pets][0][:category] # => nil
+ #
+ # Note that if you use +permit+ in a key that points to a hash,
+ # it won't allow all the hash. You also need to specify which
+ # attributes inside the hash should be whitelisted.
+ #
+ # params = ActionController::Parameters.new({
+ # person: {
+ # contact: {
+ # email: 'none@test.com'
+ # phone: '555-1234'
+ # }
+ # }
+ # })
+ #
+ # params.require(:person).permit(:contact)
+ # # => {}
+ #
+ # params.require(:person).permit(contact: :phone)
+ # # => {"contact"=>{"phone"=>"555-1234"}}
+ #
+ # params.require(:person).permit(contact: [ :email, :phone ])
+ # # => {"contact"=>{"email"=>"none@test.com", "phone"=>"555-1234"}}
def permit(*filters)
params = self.class.new
filters.each do |filter|
case filter
when Symbol, String then
- params[filter] = self[filter] if has_key?(filter)
- keys.grep(/\A#{Regexp.escape(filter)}\(\di\)\z/) { |key| params[key] = self[key] }
+ if has_key?(filter)
+ _value = self[filter]
+ params[filter] = _value unless Hash === _value
+ end
+ keys.grep(/\A#{Regexp.escape(filter)}\(\d+[if]?\)\z/) { |key| params[key] = self[key] }
when Hash then
self.slice(*filter.keys).each do |key, values|
return unless values
@@ -336,7 +361,7 @@ module ActionController
# # It's mandatory to specify the nested attributes that should be whitelisted.
# # If you use `permit` with just the key that points to the nested attributes hash,
# # it will return an empty hash.
- # params.require(:person).permit(:name, :age, pets_attributes: { :name, :category })
+ # params.require(:person).permit(:name, :age, pets_attributes: [ :name, :category ])
# end
# end
#
diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb
index ee0f053bad..3e44155f73 100644
--- a/actionpack/lib/action_controller/railtie.rb
+++ b/actionpack/lib/action_controller/railtie.rb
@@ -34,7 +34,6 @@ module ActionController
options.stylesheets_dir ||= paths["public/stylesheets"].first
# Ensure readers methods get compiled
- options.asset_path ||= app.config.asset_path
options.asset_host ||= app.config.asset_host
options.relative_url_root ||= app.config.relative_url_root
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index ace5a2c822..d911d47a1d 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -123,11 +123,12 @@ module ActionController
if expected_partial = options[:partial]
if expected_locals = options[:locals]
- if defined?(@locals)
- actual_locals = @locals[expected_partial.to_s.sub(/^_/,'')]
- expected_locals.each_pair do |k,v|
- assert_equal(v, actual_locals[k])
- end
+ if defined?(@_rendered_views)
+ view = expected_partial.to_s.sub(/^_/,'')
+ msg = 'expecting %s to be rendered with %s but was with %s' % [expected_partial,
+ expected_locals,
+ @_rendered_views.locals_for(view)]
+ assert(@_rendered_views.view_rendered?(view, options[:locals]), msg)
else
warn "the :locals option to #assert_template is only supported in a ActionView::TestCase"
end
diff --git a/actionpack/lib/action_dispatch/http/filter_parameters.rb b/actionpack/lib/action_dispatch/http/filter_parameters.rb
index 47cf41cfa3..4a7df6b657 100644
--- a/actionpack/lib/action_dispatch/http/filter_parameters.rb
+++ b/actionpack/lib/action_dispatch/http/filter_parameters.rb
@@ -1,3 +1,4 @@
+require 'mutex_m'
require 'active_support/core_ext/hash/keys'
require 'active_support/core_ext/object/duplicable'
@@ -20,9 +21,18 @@ module ActionDispatch
# end
# => reverses the value to all keys matching /secret/i
module FilterParameters
- extend ActiveSupport::Concern
+ @@parameter_filter_for = {}.extend(Mutex_m)
- @@parameter_filter_for = {}
+ ENV_MATCH = [/RAW_POST_DATA/, "rack.request.form_vars"] # :nodoc:
+ NULL_PARAM_FILTER = ParameterFilter.new # :nodoc:
+ NULL_ENV_FILTER = ParameterFilter.new ENV_MATCH # :nodoc:
+
+ def initialize(env)
+ super
+ @filtered_parameters = nil
+ @filtered_env = nil
+ @filtered_path = nil
+ end
# Return a hash of parameters with all sensitive data replaced.
def filtered_parameters
@@ -42,15 +52,24 @@ module ActionDispatch
protected
def parameter_filter
- parameter_filter_for(@env["action_dispatch.parameter_filter"])
+ parameter_filter_for @env.fetch("action_dispatch.parameter_filter") {
+ return NULL_PARAM_FILTER
+ }
end
def env_filter
- parameter_filter_for(Array(@env["action_dispatch.parameter_filter"]) + [/RAW_POST_DATA/, "rack.request.form_vars"])
+ user_key = @env.fetch("action_dispatch.parameter_filter") {
+ return NULL_ENV_FILTER
+ }
+ parameter_filter_for(Array(user_key) + ENV_MATCH)
end
def parameter_filter_for(filters)
- @@parameter_filter_for[filters] ||= ParameterFilter.new(filters)
+ @@parameter_filter_for.synchronize do
+ # Do we *actually* need this cache? Constructing ParameterFilters
+ # doesn't seem too expensive.
+ @@parameter_filter_for[filters] ||= ParameterFilter.new(filters)
+ end
end
KV_RE = '[^&;=]+'
diff --git a/actionpack/lib/action_dispatch/http/headers.rb b/actionpack/lib/action_dispatch/http/headers.rb
index a3bb25f75a..dc04d4577b 100644
--- a/actionpack/lib/action_dispatch/http/headers.rb
+++ b/actionpack/lib/action_dispatch/http/headers.rb
@@ -1,32 +1,39 @@
module ActionDispatch
module Http
- class Headers < ::Hash
- @@env_cache = Hash.new { |h,k| h[k] = "HTTP_#{k.upcase.gsub(/-/, '_')}" }
+ class Headers
+ include Enumerable
- def initialize(*args)
-
- if args.size == 1 && args[0].is_a?(Hash)
- super()
- update(args[0])
- else
- super
- end
+ def initialize(env = {})
+ @headers = env
end
def [](header_name)
- super env_name(header_name)
+ @headers[env_name(header_name)]
+ end
+
+ def []=(k,v); @headers[k] = v; end
+ def key?(k); @headers.key? k; end
+ alias :include? :key?
+
+ def fetch(header_name, *args, &block)
+ @headers.fetch env_name(header_name), *args, &block
end
- def fetch(header_name, default=nil, &block)
- super env_name(header_name), default, &block
+ def each(&block)
+ @headers.each(&block)
end
private
- # Converts a HTTP header name to an environment variable name if it is
- # not contained within the headers hash.
- def env_name(header_name)
- include?(header_name) ? header_name : @@env_cache[header_name]
- end
+
+ # Converts a HTTP header name to an environment variable name if it is
+ # not contained within the headers hash.
+ def env_name(header_name)
+ @headers.include?(header_name) ? header_name : cgi_name(header_name)
+ end
+
+ def cgi_name(k)
+ "HTTP_#{k.upcase.gsub(/-/, '_')}"
+ end
end
end
end
diff --git a/actionpack/lib/action_dispatch/http/parameter_filter.rb b/actionpack/lib/action_dispatch/http/parameter_filter.rb
index 490b46c990..b655a54865 100644
--- a/actionpack/lib/action_dispatch/http/parameter_filter.rb
+++ b/actionpack/lib/action_dispatch/http/parameter_filter.rb
@@ -1,74 +1,72 @@
module ActionDispatch
module Http
class ParameterFilter
+ FILTERED = '[FILTERED]'.freeze # :nodoc:
- def initialize(filters)
+ def initialize(filters = [])
@filters = filters
end
def filter(params)
- if enabled?
- compiled_filter.call(params)
- else
- params.dup
- end
+ compiled_filter.call(params)
end
private
- def enabled?
- @filters.present?
+ def compiled_filter
+ @compiled_filter ||= CompiledFilter.compile(@filters)
end
- FILTERED = '[FILTERED]'.freeze
+ class CompiledFilter # :nodoc:
+ def self.compile(filters)
+ return lambda { |params| params.dup } if filters.empty?
- def compiled_filter
- @compiled_filter ||= begin
- regexps, blocks = compile_filter
+ strings, regexps, blocks = [], [], []
- lambda do |original_params|
- filtered_params = {}
+ filters.each do |item|
+ case item
+ when Proc
+ blocks << item
+ when Regexp
+ regexps << item
+ else
+ strings << item.to_s
+ end
+ end
- original_params.each do |key, value|
- if regexps.find { |r| key =~ r }
- value = FILTERED
- elsif value.is_a?(Hash)
- value = filter(value)
- elsif value.is_a?(Array)
- value = value.map { |v| v.is_a?(Hash) ? filter(v) : v }
- elsif blocks.present?
- key = key.dup
- value = value.dup if value.duplicable?
- blocks.each { |b| b.call(key, value) }
- end
+ regexps << Regexp.new(strings.join('|'), true) unless strings.empty?
+ new regexps, blocks
+ end
- filtered_params[key] = value
- end
+ attr_reader :regexps, :blocks
- filtered_params
- end
+ def initialize(regexps, blocks)
+ @regexps = regexps
+ @blocks = blocks
end
- end
- def compile_filter
- strings, regexps, blocks = [], [], []
+ def call(original_params)
+ filtered_params = {}
+
+ original_params.each do |key, value|
+ if regexps.any? { |r| key =~ r }
+ value = FILTERED
+ elsif value.is_a?(Hash)
+ value = call(value)
+ elsif value.is_a?(Array)
+ value = value.map { |v| v.is_a?(Hash) ? call(v) : v }
+ elsif blocks.any?
+ key = key.dup
+ value = value.dup if value.duplicable?
+ blocks.each { |b| b.call(key, value) }
+ end
- @filters.each do |item|
- case item
- when NilClass
- when Proc
- blocks << item
- when Regexp
- regexps << item
- else
- strings << item.to_s
+ filtered_params[key] = value
end
- end
- regexps << Regexp.new(strings.join('|'), true) unless strings.empty?
- [regexps, blocks]
+ filtered_params
+ end
end
-
end
end
end
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index b8ebeb408f..fc8825d6d9 100644
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -70,7 +70,13 @@ module ActionDispatch
RFC5789 = %w(PATCH)
HTTP_METHODS = RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC5789
- HTTP_METHOD_LOOKUP = Hash.new { |h, m| h[m] = m.underscore.to_sym if HTTP_METHODS.include?(m) }
+
+ HTTP_METHOD_LOOKUP = {}
+
+ # Populate the HTTP method lookup cache
+ HTTP_METHODS.each { |method|
+ HTTP_METHOD_LOOKUP[method] = method.underscore.to_sym
+ }
# Returns the HTTP \method that the application should see.
# In the case where the \method was overridden by a middleware
diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb
index 091b0d8cd2..8bbf52382a 100644
--- a/actionpack/lib/action_view.rb
+++ b/actionpack/lib/action_view.rb
@@ -29,7 +29,6 @@ module ActionView
extend ActiveSupport::Autoload
eager_autoload do
- autoload :AssetPaths
autoload :Base
autoload :Context
autoload :CompiledTemplates, "action_view/context"
diff --git a/actionpack/lib/action_view/asset_paths.rb b/actionpack/lib/action_view/asset_paths.rb
deleted file mode 100644
index 4bbb31b3ee..0000000000
--- a/actionpack/lib/action_view/asset_paths.rb
+++ /dev/null
@@ -1,143 +0,0 @@
-require 'zlib'
-require 'active_support/core_ext/file'
-
-module ActionView
- class AssetPaths #:nodoc:
- URI_REGEXP = %r{^[-a-z]+://|^(?:cid|data):|^//}
-
- attr_reader :config, :controller
-
- def initialize(config, controller = nil)
- @config = config
- @controller = controller
- end
-
- # Add the extension +ext+ if not present. Return full or scheme-relative URLs otherwise untouched.
- # Prefix with <tt>/dir/</tt> if lacking a leading +/+. Account for relative URL
- # roots. Rewrite the asset path for cache-busting asset ids. Include
- # asset host, if configured, with the correct request protocol.
- #
- # When :relative (default), the protocol will be determined by the client using current protocol
- # When :request, the protocol will be the request protocol
- # Otherwise, the protocol is used (E.g. :http, :https, etc)
- def compute_public_path(source, dir, options = {})
- source = source.to_s
- return source if is_uri?(source)
-
- source = rewrite_extension(source, dir, options[:ext]) if options[:ext]
- source = rewrite_asset_path(source, dir, options)
- source = rewrite_relative_url_root(source, relative_url_root)
- source = rewrite_host_and_protocol(source, options[:protocol])
- source
- end
-
- # Return the filesystem path for the source
- def compute_source_path(source, dir, ext)
- source = rewrite_extension(source, dir, ext) if ext
-
- sources = []
- sources << config.assets_dir
- sources << dir unless source[0] == ?/
- sources << source
-
- File.join(sources)
- end
-
- def is_uri?(path)
- path =~ URI_REGEXP
- end
-
- private
-
- def rewrite_extension(source, dir, ext)
- raise NotImplementedError
- end
-
- def rewrite_asset_path(source, path = nil)
- raise NotImplementedError
- end
-
- def rewrite_relative_url_root(source, relative_url_root)
- relative_url_root && !source.starts_with?("#{relative_url_root}/") ? "#{relative_url_root}#{source}" : source
- end
-
- def has_request?
- controller.respond_to?(:request)
- end
-
- def rewrite_host_and_protocol(source, protocol = nil)
- host = compute_asset_host(source)
- if host && !is_uri?(host)
- if (protocol || default_protocol) == :request && !has_request?
- host = nil
- else
- host = "#{compute_protocol(protocol)}#{host}"
- end
- end
- host ? "#{host}#{source}" : source
- end
-
- def compute_protocol(protocol)
- protocol ||= default_protocol
- case protocol
- when :relative
- "//"
- when :request
- unless @controller
- invalid_asset_host!("The protocol requested was :request. Consider using :relative instead.")
- end
- @controller.request.protocol
- else
- "#{protocol}://"
- end
- end
-
- def default_protocol
- @config.default_asset_host_protocol || (has_request? ? :request : :relative)
- end
-
- def invalid_asset_host!(help_message)
- raise ActionView::MissingRequestError, "This asset host cannot be computed without a request in scope. #{help_message}"
- end
-
- # Pick an asset host for this source. Returns +nil+ if no host is set,
- # the host if no wildcard is set, the host interpolated with the
- # numbers 0-3 if it contains <tt>%d</tt> (the number is the source hash mod 4),
- # or the value returned from invoking call on an object responding to call
- # (proc or otherwise).
- def compute_asset_host(source)
- if host = asset_host_config
- if host.respond_to?(:call)
- args = [source]
- arity = arity_of(host)
- if (arity > 1 || arity < -2) && !has_request?
- invalid_asset_host!("Remove the second argument to your asset_host Proc if you do not need the request, or make it optional.")
- end
- args << current_request if (arity > 1 || arity < 0) && has_request?
- host.call(*args)
- else
- (host =~ /%d/) ? host % (Zlib.crc32(source) % 4) : host
- end
- end
- end
-
- def relative_url_root
- config.relative_url_root || current_request.try(:script_name)
- end
-
- def asset_host_config
- config.asset_host
- end
-
- # Returns the current request if one exists.
- def current_request
- controller.request if has_request?
- end
-
- # Returns the arity of a callable
- def arity_of(callable)
- callable.respond_to?(:arity) ? callable.arity : callable.method(:call).arity
- end
-
- end
-end
diff --git a/actionpack/lib/action_view/digestor.rb b/actionpack/lib/action_view/digestor.rb
index 5d3add4091..1c6eaf36f7 100644
--- a/actionpack/lib/action_view/digestor.rb
+++ b/actionpack/lib/action_view/digestor.rb
@@ -1,3 +1,5 @@
+require 'mutex_m'
+
module ActionView
class Digestor
EXPLICIT_DEPENDENCY = /# Template Dependency: ([^ ]+)/
@@ -19,16 +21,30 @@ module ActionView
/x
cattr_reader(:cache)
- @@cache = Hash.new
+ @@cache = Hash.new.extend Mutex_m
def self.digest(name, format, finder, options = {})
- cache["#{name}.#{format}"] ||= new(name, format, finder, options).digest
+ cache.synchronize do
+ unsafe_digest name, format, finder, options
+ end
end
- attr_reader :name, :format, :finder, :options
+ ###
+ # This method is NOT thread safe. DO NOT CALL IT DIRECTLY, instead call
+ # Digestor.digest
+ def self.unsafe_digest(name, format, finder, options = {}) # :nodoc:
+ key = "#{name}.#{format}"
- def initialize(name, format, finder, options = {})
- @name, @format, @finder, @options = name, format, finder, options
+ cache.fetch(key) do
+ klass = options[:partial] || name.include?("/_") ? PartialDigestor : Digestor
+ cache[key] = klass.new(name, format, finder).digest
+ end
+ end
+
+ attr_reader :name, :format, :finder
+
+ def initialize(name, format, finder)
+ @name, @format, @finder = name, format, finder
end
def digest
@@ -48,7 +64,7 @@ module ActionView
def nested_dependencies
dependencies.collect do |dependency|
- dependencies = Digestor.new(dependency, format, finder, partial: true).nested_dependencies
+ dependencies = PartialDigestor.new(dependency, format, finder).nested_dependencies
dependencies.any? ? { dependency => dependencies } : dependency
end
end
@@ -64,11 +80,11 @@ module ActionView
end
def directory
- name.split("/").first
+ name.split("/")[0..-2].join("/")
end
def partial?
- options[:partial] || name.include?("/_")
+ false
end
def source
@@ -77,7 +93,7 @@ module ActionView
def dependency_digest
dependencies.collect do |template_name|
- Digestor.digest(template_name, format, finder, partial: true)
+ Digestor.unsafe_digest(template_name, format, finder, partial: true)
end.join("-")
end
@@ -101,4 +117,10 @@ module ActionView
source.scan(EXPLICIT_DEPENDENCY).flatten.uniq
end
end
+
+ class PartialDigestor < Digestor # :nodoc:
+ def partial?
+ true
+ end
+ end
end
diff --git a/actionpack/lib/action_view/helpers.rb b/actionpack/lib/action_view/helpers.rb
index f2a3a494bc..269e78a021 100644
--- a/actionpack/lib/action_view/helpers.rb
+++ b/actionpack/lib/action_view/helpers.rb
@@ -4,6 +4,7 @@ module ActionView #:nodoc:
autoload :ActiveModelHelper
autoload :AssetTagHelper
+ autoload :AssetUrlHelper
autoload :AtomFeedHelper
autoload :BenchmarkHelper
autoload :CacheHelper
@@ -28,12 +29,9 @@ module ActionView #:nodoc:
extend ActiveSupport::Concern
- included do
- extend SanitizeHelper::ClassMethods
- end
-
include ActiveModelHelper
include AssetTagHelper
+ include AssetUrlHelper
include AtomFeedHelper
include BenchmarkHelper
include CacheHelper
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
index 5b5fc84e90..31316fcdd9 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
@@ -1,8 +1,6 @@
require 'active_support/core_ext/array/extract_options'
require 'active_support/core_ext/hash/keys'
-require 'action_view/helpers/asset_tag_helpers/javascript_tag_helpers'
-require 'action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers'
-require 'action_view/helpers/asset_tag_helpers/asset_paths'
+require 'action_view/helpers/asset_url_helper'
require 'action_view/helpers/tag_helper'
module ActionView
@@ -17,187 +15,87 @@ module ActionView
# stylesheet_link_tag("application")
# # => <link href="/assets/application.css?body=1" media="screen" rel="stylesheet" />
#
- #
- # === Using asset hosts
- #
- # By default, Rails links to these assets on the current host in the public
- # folder, but you can direct Rails to link to assets from a dedicated asset
- # server by setting <tt>ActionController::Base.asset_host</tt> in the application
- # configuration, typically in <tt>config/environments/production.rb</tt>.
- # For example, you'd define <tt>assets.example.com</tt> to be your asset
- # host this way, inside the <tt>configure</tt> block of your environment-specific
- # configuration files or <tt>config/application.rb</tt>:
- #
- # config.action_controller.asset_host = "assets.example.com"
- #
- # Helpers take that into account:
- #
- # image_tag("rails.png")
- # # => <img alt="Rails" src="http://assets.example.com/assets/rails.png" />
- # stylesheet_link_tag("application")
- # # => <link href="http://assets.example.com/assets/application.css" media="screen" rel="stylesheet" />
- #
- # Browsers typically open at most two simultaneous connections to a single
- # host, which means your assets often have to wait for other assets to finish
- # downloading. You can alleviate this by using a <tt>%d</tt> wildcard in the
- # +asset_host+. For example, "assets%d.example.com". If that wildcard is
- # present Rails distributes asset requests among the corresponding four hosts
- # "assets0.example.com", ..., "assets3.example.com". With this trick browsers
- # will open eight simultaneous connections rather than two.
- #
- # image_tag("rails.png")
- # # => <img alt="Rails" src="http://assets0.example.com/assets/rails.png" />
- # stylesheet_link_tag("application")
- # # => <link href="http://assets2.example.com/assets/application.css" media="screen" rel="stylesheet" />
- #
- # To do this, you can either setup four actual hosts, or you can use wildcard
- # DNS to CNAME the wildcard to a single asset host. You can read more about
- # setting up your DNS CNAME records from your ISP.
- #
- # Note: This is purely a browser performance optimization and is not meant
- # for server load balancing. See http://www.die.net/musings/page_load_time/
- # for background.
- #
- # Alternatively, you can exert more control over the asset host by setting
- # +asset_host+ to a proc like this:
- #
- # ActionController::Base.asset_host = Proc.new { |source|
- # "http://assets#{Digest::MD5.hexdigest(source).to_i(16) % 2 + 1}.example.com"
- # }
- # image_tag("rails.png")
- # # => <img alt="Rails" src="http://assets1.example.com/assets/rails.png" />
- # stylesheet_link_tag("application")
- # # => <link href="http://assets2.example.com/assets/application.css" media="screen" rel="stylesheet" />
- #
- # The example above generates "http://assets1.example.com" and
- # "http://assets2.example.com". This option is useful for example if
- # you need fewer/more than four hosts, custom host names, etc.
- #
- # As you see the proc takes a +source+ parameter. That's a string with the
- # absolute path of the asset, for example "/assets/rails.png".
- #
- # ActionController::Base.asset_host = Proc.new { |source|
- # if source.ends_with?('.css')
- # "http://stylesheets.example.com"
- # else
- # "http://assets.example.com"
- # end
- # }
- # image_tag("rails.png")
- # # => <img alt="Rails" src="http://assets.example.com/assets/rails.png" />
- # stylesheet_link_tag("application")
- # # => <link href="http://stylesheets.example.com/assets/application.css" media="screen" rel="stylesheet" />
- #
- # Alternatively you may ask for a second parameter +request+. That one is
- # particularly useful for serving assets from an SSL-protected page. The
- # example proc below disables asset hosting for HTTPS connections, while
- # still sending assets for plain HTTP requests from asset hosts. If you don't
- # have SSL certificates for each of the asset hosts this technique allows you
- # to avoid warnings in the client about mixed media.
- #
- # config.action_controller.asset_host = Proc.new { |source, request|
- # if request.ssl?
- # "#{request.protocol}#{request.host_with_port}"
- # else
- # "#{request.protocol}assets.example.com"
- # end
- # }
- #
- # You can also implement a custom asset host object that responds to +call+
- # and takes either one or two parameters just like the proc.
- #
- # config.action_controller.asset_host = AssetHostingWithMinimumSsl.new(
- # "http://asset%d.example.com", "https://asset1.example.com"
- # )
- #
- # === Customizing the asset path
- #
- # By default, Rails appends asset's timestamps to all asset paths. This allows
- # you to set a cache-expiration date for the asset far into the future, but
- # still be able to instantly invalidate it by simply updating the file (and
- # hence updating the timestamp, which then updates the URL as the timestamp
- # is part of that, which in turn busts the cache).
- #
- # It's the responsibility of the web server you use to set the far-future
- # expiration date on cache assets that you need to take advantage of this
- # feature. Here's an example for Apache:
- #
- # # Asset Expiration
- # ExpiresActive On
- # <FilesMatch "\.(ico|gif|jpe?g|png|js|css)$">
- # ExpiresDefault "access plus 1 year"
- # </FilesMatch>
- #
- # Also note that in order for this to work, all your application servers must
- # return the same timestamps. This means that they must have their clocks
- # synchronized. If one of them drifts out of sync, you'll see different
- # timestamps at random and the cache won't work. In that case the browser
- # will request the same assets over and over again even thought they didn't
- # change. You can use something like Live HTTP Headers for Firefox to verify
- # that the cache is indeed working.
- #
- # This strategy works well enough for most server setups and requires the
- # least configuration, but if you deploy several application servers at
- # different times - say to handle a temporary spike in load - then the
- # asset time stamps will be out of sync. In a setup like this you may want
- # to set the way that asset paths are generated yourself.
- #
- # Altering the asset paths that Rails generates can be done in two ways.
- # The easiest is to define the RAILS_ASSET_ID environment variable. The
- # contents of this variable will always be used in preference to
- # calculated timestamps. A more complex but flexible way is to set
- # <tt>ActionController::Base.config.asset_path</tt> to a proc
- # that takes the unmodified asset path and returns the path needed for
- # your asset caching to work. Typically you'd do something like this in
- # <tt>config/environments/production.rb</tt>:
- #
- # # Normally you'd calculate RELEASE_NUMBER at startup.
- # RELEASE_NUMBER = 12345
- # config.action_controller.asset_path = proc { |asset_path|
- # "/release-#{RELEASE_NUMBER}#{asset_path}"
- # }
- #
- # This example would cause the following behavior on all servers no
- # matter when they were deployed:
- #
- # image_tag("rails.png")
- # # => <img alt="Rails" src="/release-12345/images/rails.png" />
- # stylesheet_link_tag("application")
- # # => <link href="/release-12345/stylesheets/application.css?1232285206" media="screen" rel="stylesheet" />
- #
- # Changing the asset_path does require that your web servers have
- # knowledge of the asset template paths that you rewrite to so it's not
- # suitable for out-of-the-box use. To use the example given above you
- # could use something like this in your Apache VirtualHost configuration:
- #
- # <LocationMatch "^/release-\d+/(images|javascripts|stylesheets)/.*$">
- # # Some browsers still send conditional-GET requests if there's a
- # # Last-Modified header or an ETag header even if they haven't
- # # reached the expiry date sent in the Expires header.
- # Header unset Last-Modified
- # Header unset ETag
- # FileETag None
- #
- # # Assets requested using a cache-busting filename should be served
- # # only once and then cached for a really long time. The HTTP/1.1
- # # spec frowns on hugely-long expiration times though and suggests
- # # that assets which never expire be served with an expiration date
- # # 1 year from access.
- # ExpiresActive On
- # ExpiresDefault "access plus 1 year"
- # </LocationMatch>
- #
- # # We use cached-busting location names with the far-future expires
- # # headers to ensure that if a file does change it can force a new
- # # request. The actual asset filenames are still the same though so we
- # # need to rewrite the location from the cache-busting location to the
- # # real asset location so that we can serve it.
- # RewriteEngine On
- # RewriteRule ^/release-\d+/(images|javascripts|stylesheets)/(.*)$ /$1/$2 [L]
module AssetTagHelper
+ extend ActiveSupport::Concern
+
+ include AssetUrlHelper
include TagHelper
- include JavascriptTagHelpers
- include StylesheetTagHelpers
+
+ # Returns an HTML script tag for each of the +sources+ provided.
+ #
+ # Sources may be paths to JavaScript files. Relative paths are assumed to be relative
+ # to <tt>assets/javascripts</tt>, full paths are assumed to be relative to the document
+ # root. Relative paths are idiomatic, use absolute paths only when needed.
+ #
+ # When passing paths, the ".js" extension is optional.
+ #
+ # You can modify the HTML attributes of the script tag by passing a hash as the
+ # last argument.
+ #
+ # javascript_include_tag "xmlhr"
+ # # => <script src="/assets/xmlhr.js?1284139606"></script>
+ #
+ # javascript_include_tag "xmlhr.js"
+ # # => <script src="/assets/xmlhr.js?1284139606"></script>
+ #
+ # javascript_include_tag "common.javascript", "/elsewhere/cools"
+ # # => <script src="/assets/common.javascript?1284139606"></script>
+ # # <script src="/elsewhere/cools.js?1423139606"></script>
+ #
+ # javascript_include_tag "http://www.example.com/xmlhr"
+ # # => <script src="http://www.example.com/xmlhr"></script>
+ #
+ # javascript_include_tag "http://www.example.com/xmlhr.js"
+ # # => <script src="http://www.example.com/xmlhr.js"></script>
+ #
+ def javascript_include_tag(*sources)
+ options = sources.extract_options!.stringify_keys
+ sources.uniq.map { |source|
+ tag_options = {
+ "src" => path_to_javascript(source)
+ }.merge(options)
+ content_tag(:script, "", tag_options)
+ }.join("\n").html_safe
+ end
+
+ # Returns a stylesheet link tag for the sources specified as arguments. If
+ # you don't specify an extension, <tt>.css</tt> will be appended automatically.
+ # You can modify the link attributes by passing a hash as the last argument.
+ # For historical reasons, the 'media' attribute will always be present and defaults
+ # to "screen", so you must explicitely set it to "all" for the stylesheet(s) to
+ # apply to all media types.
+ #
+ # stylesheet_link_tag "style"
+ # # => <link href="/assets/style.css" media="screen" rel="stylesheet" />
+ #
+ # stylesheet_link_tag "style.css"
+ # # => <link href="/assets/style.css" media="screen" rel="stylesheet" />
+ #
+ # stylesheet_link_tag "http://www.example.com/style.css"
+ # # => <link href="http://www.example.com/style.css" media="screen" rel="stylesheet" />
+ #
+ # stylesheet_link_tag "style", :media => "all"
+ # # => <link href="/assets/style.css" media="all" rel="stylesheet" />
+ #
+ # stylesheet_link_tag "style", :media => "print"
+ # # => <link href="/assets/style.css" media="print" rel="stylesheet" />
+ #
+ # stylesheet_link_tag "random.styles", "/css/stylish"
+ # # => <link href="/assets/random.styles" media="screen" rel="stylesheet" />
+ # # <link href="/css/stylish.css" media="screen" rel="stylesheet" />
+ #
+ def stylesheet_link_tag(*sources)
+ options = sources.extract_options!.stringify_keys
+ sources.uniq.map { |source|
+ tag_options = {
+ "rel" => "stylesheet",
+ "media" => "screen",
+ "href" => path_to_stylesheet(source)
+ }.merge(options)
+ tag(:link, tag_options)
+ }.join("\n").html_safe
+ end
+
# Returns a link tag that browsers and news readers can use to auto-detect
# an RSS or Atom feed. The +type+ can either be <tt>:rss</tt> (default) or
# <tt>:atom</tt>. Control the link options in url_for format using the
@@ -268,93 +166,6 @@ module ActionView
}.merge(options.symbolize_keys))
end
- # 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") # => "/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"
- #
- # If you have images as application resources this method may conflict with their named routes.
- # The alias +path_to_image+ is provided to avoid that. Rails uses the alias internally, and
- # plugin authors are encouraged to do so.
- def image_path(source)
- source.present? ? asset_paths.compute_public_path(source, 'images') : ""
- 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.
- # 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
- end
- alias_method :url_to_image, :image_url # aliased to avoid conflicts with an image_url named route
-
- # Computes the path to a video asset in the public videos directory.
- # Full paths from the document root will be passed through.
- # Used internally by +video_tag+ to build the video path.
- #
- # video_path("hd") # => /videos/hd
- # video_path("hd.avi") # => /videos/hd.avi
- # video_path("trailers/hd.avi") # => /videos/trailers/hd.avi
- # video_path("/trailers/hd.avi") # => /trailers/hd.avi
- # video_path("http://www.example.com/vid/hd.avi") # => http://www.example.com/vid/hd.avi
- def video_path(source)
- asset_paths.compute_public_path(source, 'videos')
- end
- alias_method :path_to_video, :video_path # aliased to avoid conflicts with a video_path named route
-
- # Computes the full URL to a video asset in the public videos directory.
- # This will use +video_path+ internally, so most of their behaviors will be the same.
- def video_url(source)
- URI.join(current_host, path_to_video(source)).to_s
- end
- alias_method :url_to_video, :video_url # aliased to avoid conflicts with an video_url named route
-
- # Computes the path to an audio asset in the public audios directory.
- # Full paths from the document root will be passed through.
- # Used internally by +audio_tag+ to build the audio path.
- #
- # audio_path("horse") # => /audios/horse
- # audio_path("horse.wav") # => /audios/horse.wav
- # audio_path("sounds/horse.wav") # => /audios/sounds/horse.wav
- # audio_path("/sounds/horse.wav") # => /sounds/horse.wav
- # audio_path("http://www.example.com/sounds/horse.wav") # => http://www.example.com/sounds/horse.wav
- def audio_path(source)
- asset_paths.compute_public_path(source, 'audios')
- end
- alias_method :path_to_audio, :audio_path # aliased to avoid conflicts with an audio_path named route
-
- # 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.
- # Full paths from the document root will be passed through.
- #
- # 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)
- asset_paths.compute_public_path(source, 'fonts')
- 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.
- # 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
- end
- 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.
#
@@ -462,11 +273,6 @@ module ActionView
end
private
-
- def asset_paths
- @asset_paths ||= AssetTagHelper::AssetPaths.new(config, controller)
- end
-
def multiple_sources_tag(type, sources)
options = sources.extract_options!.symbolize_keys
sources.flatten!
@@ -482,10 +288,6 @@ module ActionView
content_tag(type, nil, options)
end
end
-
- def current_host
- url_for(:only_path => false)
- end
end
end
end
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb
deleted file mode 100644
index 35f91cec18..0000000000
--- a/actionpack/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb
+++ /dev/null
@@ -1,93 +0,0 @@
-require 'thread'
-require 'active_support/core_ext/file'
-require 'active_support/core_ext/module/attribute_accessors'
-
-module ActionView
- module Helpers
- module AssetTagHelper
-
- class AssetPaths < ::ActionView::AssetPaths #:nodoc:
- # You can enable or disable the asset tag ids cache.
- # With the cache enabled, the asset tag helper methods will make fewer
- # expensive file system calls (the default implementation checks the file
- # system timestamp). However this prevents you from modifying any asset
- # files while the server is running.
- #
- # ActionView::Helpers::AssetTagHelper::AssetPaths.cache_asset_ids = false
- mattr_accessor :cache_asset_ids
-
- # Add or change an asset id in the asset id cache. This can be used
- # for SASS on Heroku.
- # :api: public
- def add_to_asset_ids_cache(source, asset_id)
- self.asset_ids_cache_guard.synchronize do
- self.asset_ids_cache[source] = asset_id
- end
- end
-
- private
-
- def rewrite_extension(source, dir, ext)
- source_ext = File.extname(source)
-
- source_with_ext = if source_ext.empty?
- "#{source}.#{ext}"
- elsif ext != source_ext[1..-1]
- with_ext = "#{source}.#{ext}"
- with_ext if File.exist?(File.join(config.assets_dir, dir, with_ext))
- end
-
- source_with_ext || source
- end
-
- # Break out the asset path rewrite in case plugins wish to put the asset id
- # someplace other than the query string.
- def rewrite_asset_path(source, dir, options = nil)
- source = "/#{dir}/#{source}" unless source[0] == ?/
- path = config.asset_path
-
- if path && path.respond_to?(:call)
- return path.call(source)
- elsif path && path.is_a?(String)
- return path % [source]
- end
-
- asset_id = rails_asset_id(source)
- if asset_id.empty?
- source
- else
- "#{source}?#{asset_id}"
- end
- end
-
- mattr_accessor :asset_ids_cache
- self.asset_ids_cache = {}
-
- mattr_accessor :asset_ids_cache_guard
- self.asset_ids_cache_guard = Mutex.new
-
- # Use the RAILS_ASSET_ID environment variable or the source's
- # modification time as its cache-busting asset id.
- def rails_asset_id(source)
- if asset_id = ENV["RAILS_ASSET_ID"]
- asset_id
- else
- if self.cache_asset_ids && (asset_id = self.asset_ids_cache[source])
- asset_id
- else
- path = File.join(config.assets_dir, source)
- asset_id = File.exist?(path) ? File.mtime(path).to_i.to_s : ''
-
- if self.cache_asset_ids
- add_to_asset_ids_cache(source, asset_id)
- end
-
- asset_id
- end
- end
- end
- end
-
- end
- end
-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
deleted file mode 100644
index b6b9eadc88..0000000000
--- a/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb
+++ /dev/null
@@ -1,70 +0,0 @@
-require 'active_support/core_ext/file'
-
-module ActionView
- module Helpers
- module AssetTagHelper
- module JavascriptTagHelpers
- extend ActiveSupport::Concern
-
- # Computes the path to a javascript asset in the public javascripts directory.
- # If the +source+ filename has no extension, .js will be appended (except for explicit URIs)
- # Full paths from the document root will be passed through.
- # Used internally by javascript_include_tag to build the script path.
- #
- # javascript_path "xmlhr" # => /javascripts/xmlhr.js
- # javascript_path "dir/xmlhr.js" # => /javascripts/dir/xmlhr.js
- # javascript_path "/dir/xmlhr" # => /dir/xmlhr.js
- # javascript_path "http://www.example.com/js/xmlhr" # => http://www.example.com/js/xmlhr
- # javascript_path "http://www.example.com/js/xmlhr.js" # => http://www.example.com/js/xmlhr.js
- def javascript_path(source)
- asset_paths.compute_public_path(source, 'javascripts', :ext => 'js')
- end
- alias_method :path_to_javascript, :javascript_path # aliased to avoid conflicts with a javascript_path named route
-
- # Computes the full URL to a javascript asset in the public javascripts directory.
- # This will use +javascript_path+ internally, so most of their behaviors will be the same.
- def javascript_url(source)
- URI.join(current_host, path_to_javascript(source)).to_s
- end
- alias_method :url_to_javascript, :javascript_url # aliased to avoid conflicts with a javascript_url named route
-
- # Returns an HTML script tag for each of the +sources+ provided.
- #
- # Sources may be paths to JavaScript files. Relative paths are assumed to be relative
- # to <tt>public/javascripts</tt>, full paths are assumed to be relative to the document
- # root. Relative paths are idiomatic, use absolute paths only when needed.
- #
- # When passing paths, the ".js" extension is optional.
- #
- # You can modify the HTML attributes of the script tag by passing a hash as the
- # last argument.
- #
- # javascript_include_tag "xmlhr"
- # # => <script src="/javascripts/xmlhr.js?1284139606"></script>
- #
- # javascript_include_tag "xmlhr.js"
- # # => <script src="/javascripts/xmlhr.js?1284139606"></script>
- #
- # javascript_include_tag "common.javascript", "/elsewhere/cools"
- # # => <script src="/javascripts/common.javascript?1284139606"></script>
- # # <script src="/elsewhere/cools.js?1423139606"></script>
- #
- # javascript_include_tag "http://www.example.com/xmlhr"
- # # => <script src="http://www.example.com/xmlhr"></script>
- #
- # javascript_include_tag "http://www.example.com/xmlhr.js"
- # # => <script src="http://www.example.com/xmlhr.js"></script>
- #
- def javascript_include_tag(*sources)
- options = sources.extract_options!.stringify_keys
- sources.dup.map { |source|
- tag_options = {
- "src" => path_to_javascript(source)
- }.merge(options)
- content_tag(:script, "", tag_options)
- }.join("\n").html_safe
- end
- end
- end
- end
-end
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
deleted file mode 100644
index bf59f8e81a..0000000000
--- a/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb
+++ /dev/null
@@ -1,71 +0,0 @@
-require 'active_support/core_ext/file'
-
-module ActionView
- module Helpers
- module AssetTagHelper
- module StylesheetTagHelpers
- extend ActiveSupport::Concern
-
- # Computes the path to a stylesheet asset in the public stylesheets directory.
- # If the +source+ filename has no extension, <tt>.css</tt> will be appended (except for explicit URIs).
- # Full paths from the document root will be passed through.
- # Used internally by +stylesheet_link_tag+ to build the stylesheet path.
- #
- # stylesheet_path "style" # => /stylesheets/style.css
- # stylesheet_path "dir/style.css" # => /stylesheets/dir/style.css
- # stylesheet_path "/dir/style.css" # => /dir/style.css
- # stylesheet_path "http://www.example.com/css/style" # => http://www.example.com/css/style
- # stylesheet_path "http://www.example.com/css/style.css" # => http://www.example.com/css/style.css
- def stylesheet_path(source)
- asset_paths.compute_public_path(source, 'stylesheets', :ext => 'css', :protocol => :request)
- end
- alias_method :path_to_stylesheet, :stylesheet_path # aliased to avoid conflicts with a stylesheet_path named route
-
- # Computes the full URL to a stylesheet asset in the public stylesheets directory.
- # This will use +stylesheet_path+ internally, so most of their behaviors will be the same.
- def stylesheet_url(source)
- URI.join(current_host, path_to_stylesheet(source)).to_s
- end
- alias_method :url_to_stylesheet, :stylesheet_url # aliased to avoid conflicts with a stylesheet_url named route
-
- # Returns a stylesheet link tag for the sources specified as arguments. If
- # you don't specify an extension, <tt>.css</tt> will be appended automatically.
- # You can modify the link attributes by passing a hash as the last argument.
- # For historical reasons, the 'media' attribute will always be present and defaults
- # to "screen", so you must explicitely set it to "all" for the stylesheet(s) to
- # apply to all media types.
- #
- # stylesheet_link_tag "style" # =>
- # <link href="/stylesheets/style.css" media="screen" rel="stylesheet" />
- #
- # stylesheet_link_tag "style.css" # =>
- # <link href="/stylesheets/style.css" media="screen" rel="stylesheet" />
- #
- # stylesheet_link_tag "http://www.example.com/style.css" # =>
- # <link href="http://www.example.com/style.css" media="screen" rel="stylesheet" />
- #
- # stylesheet_link_tag "style", :media => "all" # =>
- # <link href="/stylesheets/style.css" media="all" rel="stylesheet" />
- #
- # stylesheet_link_tag "style", :media => "print" # =>
- # <link href="/stylesheets/style.css" media="print" rel="stylesheet" />
- #
- # stylesheet_link_tag "random.styles", "/css/stylish" # =>
- # <link href="/stylesheets/random.styles" media="screen" rel="stylesheet" />
- # <link href="/css/stylish.css" media="screen" rel="stylesheet" />
- #
- def stylesheet_link_tag(*sources)
- options = sources.extract_options!.stringify_keys
- sources.uniq.map { |source|
- tag_options = {
- "rel" => "stylesheet",
- "media" => "screen",
- "href" => path_to_stylesheet(source)
- }.merge(options)
- tag(:link, tag_options)
- }.join("\n").html_safe
- end
- end
- end
- end
-end
diff --git a/actionpack/lib/action_view/helpers/asset_url_helper.rb b/actionpack/lib/action_view/helpers/asset_url_helper.rb
new file mode 100644
index 0000000000..0bb5e739bb
--- /dev/null
+++ b/actionpack/lib/action_view/helpers/asset_url_helper.rb
@@ -0,0 +1,355 @@
+require 'zlib'
+
+module ActionView
+ # = Action View Asset URL Helpers
+ module Helpers #:nodoc:
+ # This module provides methods for generating asset paths and
+ # urls.
+ #
+ # image_path("rails.png")
+ # # => "/assets/rails.png"
+ #
+ # image_url("rails.png")
+ # # => "http://www.example.com/assets/rails.png"
+ #
+ # === Using asset hosts
+ #
+ # By default, Rails links to these assets on the current host in the public
+ # folder, but you can direct Rails to link to assets from a dedicated asset
+ # server by setting <tt>ActionController::Base.asset_host</tt> in the application
+ # configuration, typically in <tt>config/environments/production.rb</tt>.
+ # For example, you'd define <tt>assets.example.com</tt> to be your asset
+ # host this way, inside the <tt>configure</tt> block of your environment-specific
+ # configuration files or <tt>config/application.rb</tt>:
+ #
+ # config.action_controller.asset_host = "assets.example.com"
+ #
+ # Helpers take that into account:
+ #
+ # image_tag("rails.png")
+ # # => <img alt="Rails" src="http://assets.example.com/assets/rails.png" />
+ # stylesheet_link_tag("application")
+ # # => <link href="http://assets.example.com/assets/application.css" media="screen" rel="stylesheet" />
+ #
+ # Browsers typically open at most two simultaneous connections to a single
+ # host, which means your assets often have to wait for other assets to finish
+ # downloading. You can alleviate this by using a <tt>%d</tt> wildcard in the
+ # +asset_host+. For example, "assets%d.example.com". If that wildcard is
+ # present Rails distributes asset requests among the corresponding four hosts
+ # "assets0.example.com", ..., "assets3.example.com". With this trick browsers
+ # will open eight simultaneous connections rather than two.
+ #
+ # image_tag("rails.png")
+ # # => <img alt="Rails" src="http://assets0.example.com/assets/rails.png" />
+ # stylesheet_link_tag("application")
+ # # => <link href="http://assets2.example.com/assets/application.css" media="screen" rel="stylesheet" />
+ #
+ # To do this, you can either setup four actual hosts, or you can use wildcard
+ # DNS to CNAME the wildcard to a single asset host. You can read more about
+ # setting up your DNS CNAME records from your ISP.
+ #
+ # Note: This is purely a browser performance optimization and is not meant
+ # for server load balancing. See http://www.die.net/musings/page_load_time/
+ # for background.
+ #
+ # Alternatively, you can exert more control over the asset host by setting
+ # +asset_host+ to a proc like this:
+ #
+ # ActionController::Base.asset_host = Proc.new { |source|
+ # "http://assets#{Digest::MD5.hexdigest(source).to_i(16) % 2 + 1}.example.com"
+ # }
+ # image_tag("rails.png")
+ # # => <img alt="Rails" src="http://assets1.example.com/assets/rails.png" />
+ # stylesheet_link_tag("application")
+ # # => <link href="http://assets2.example.com/assets/application.css" media="screen" rel="stylesheet" />
+ #
+ # The example above generates "http://assets1.example.com" and
+ # "http://assets2.example.com". This option is useful for example if
+ # you need fewer/more than four hosts, custom host names, etc.
+ #
+ # As you see the proc takes a +source+ parameter. That's a string with the
+ # absolute path of the asset, for example "/assets/rails.png".
+ #
+ # ActionController::Base.asset_host = Proc.new { |source|
+ # if source.ends_with?('.css')
+ # "http://stylesheets.example.com"
+ # else
+ # "http://assets.example.com"
+ # end
+ # }
+ # image_tag("rails.png")
+ # # => <img alt="Rails" src="http://assets.example.com/assets/rails.png" />
+ # stylesheet_link_tag("application")
+ # # => <link href="http://stylesheets.example.com/assets/application.css" media="screen" rel="stylesheet" />
+ #
+ # Alternatively you may ask for a second parameter +request+. That one is
+ # particularly useful for serving assets from an SSL-protected page. The
+ # example proc below disables asset hosting for HTTPS connections, while
+ # still sending assets for plain HTTP requests from asset hosts. If you don't
+ # have SSL certificates for each of the asset hosts this technique allows you
+ # to avoid warnings in the client about mixed media.
+ #
+ # config.action_controller.asset_host = Proc.new { |source, request|
+ # if request.ssl?
+ # "#{request.protocol}#{request.host_with_port}"
+ # else
+ # "#{request.protocol}assets.example.com"
+ # end
+ # }
+ #
+ # You can also implement a custom asset host object that responds to +call+
+ # and takes either one or two parameters just like the proc.
+ #
+ # config.action_controller.asset_host = AssetHostingWithMinimumSsl.new(
+ # "http://asset%d.example.com", "https://asset1.example.com"
+ # )
+ #
+ module AssetUrlHelper
+ URI_REGEXP = %r{^[-a-z]+://|^(?:cid|data):|^//}
+
+ # Computes the path to asset in public directory. If :type
+ # options is set, a file extension will be appended and scoped
+ # to the corresponding public directory.
+ #
+ # All other asset *_path helpers delegate through this method.
+ #
+ # asset_path "application.js" # => /application.js
+ # asset_path "application", type: :javascript # => /javascripts/application.js
+ # asset_path "application", type: :stylesheet # => /stylesheets/application.css
+ # asset_path "http://www.example.com/js/xmlhr.js" # => http://www.example.com/js/xmlhr.js
+ def asset_path(source, options = {})
+ source = source.to_s
+ return "" unless source.present?
+ return source if source =~ URI_REGEXP
+
+ tail, source = source[/([\?#].+)$/], source.sub(/([\?#].+)$/, '')
+
+ if extname = compute_asset_extname(source, options)
+ source = "#{source}#{extname}"
+ end
+
+ if source[0] != ?/
+ source = compute_asset_path(source, options)
+ end
+
+ relative_url_root = (defined?(config.relative_url_root) && config.relative_url_root) ||
+ (respond_to?(:request) && request.try(:script_name))
+ if relative_url_root
+ source = "#{relative_url_root}#{source}" unless source.starts_with?("#{relative_url_root}/")
+ end
+
+ if host = compute_asset_host(source, options)
+ source = "#{host}#{source}"
+ end
+
+ "#{source}#{tail}"
+ end
+ alias_method :path_to_asset, :asset_path # aliased to avoid conflicts with a asset_path named route
+
+ # Computes the full URL to a asset in the public directory. This
+ # will use +asset_path+ internally, so most of their behaviors
+ # will be the same.
+ def asset_url(source, options = {})
+ path_to_asset(source, options.merge(:protocol => :request))
+ end
+ alias_method :url_to_asset, :asset_url # aliased to avoid conflicts with an asset_url named route
+
+ ASSET_EXTENSIONS = {
+ javascript: '.js',
+ stylesheet: '.css'
+ }
+
+ # Compute extname to append to asset path. Returns nil if
+ # nothing should be added.
+ def compute_asset_extname(source, options = {})
+ return if options[:extname] == false
+ extname = options[:extname] || ASSET_EXTENSIONS[options[:type]]
+ extname if extname && File.extname(source) != extname
+ end
+
+ # Maps asset types to public directory.
+ ASSET_PUBLIC_DIRECTORIES = {
+ audio: '/audios',
+ font: '/fonts',
+ image: '/images',
+ javascript: '/javascripts',
+ stylesheet: '/stylesheets',
+ video: '/videos'
+ }
+
+ # Computes asset path to public directory. Plugins and
+ # extensions can override this method to point to custom assets
+ # or generate digested paths or query strings.
+ def compute_asset_path(source, options = {})
+ dir = ASSET_PUBLIC_DIRECTORIES[options[:type]] || ""
+ File.join(dir, source)
+ end
+
+ # Pick an asset host for this source. Returns +nil+ if no host is set,
+ # the host if no wildcard is set, the host interpolated with the
+ # numbers 0-3 if it contains <tt>%d</tt> (the number is the source hash mod 4),
+ # or the value returned from invoking call on an object responding to call
+ # (proc or otherwise).
+ def compute_asset_host(source = "", options = {})
+ request = self.request if respond_to?(:request)
+ host = config.asset_host if defined? config.asset_host
+ host ||= request.base_url if request && options[:protocol] == :request
+ return unless host
+
+ if host.respond_to?(:call)
+ arity = host.respond_to?(:arity) ? host.arity : host.method(:call).arity
+ args = [source]
+ args << request if request && (arity > 1 || arity < 0)
+ host = host.call(*args)
+ elsif host =~ /%d/
+ host = host % (Zlib.crc32(source) % 4)
+ end
+
+ if host =~ URI_REGEXP
+ host
+ else
+ protocol = options[:protocol] || config.default_asset_host_protocol || (request ? :request : :relative)
+ case protocol
+ when :relative
+ "//#{host}"
+ when :request
+ "#{request.protocol}#{host}"
+ else
+ "#{protocol}://#{host}"
+ end
+ end
+ end
+
+ # Computes the path to a javascript asset in the public javascripts directory.
+ # If the +source+ filename has no extension, .js will be appended (except for explicit URIs)
+ # Full paths from the document root will be passed through.
+ # Used internally by javascript_include_tag to build the script path.
+ #
+ # javascript_path "xmlhr" # => /javascripts/xmlhr.js
+ # javascript_path "dir/xmlhr.js" # => /javascripts/dir/xmlhr.js
+ # javascript_path "/dir/xmlhr" # => /dir/xmlhr.js
+ # javascript_path "http://www.example.com/js/xmlhr" # => http://www.example.com/js/xmlhr
+ # javascript_path "http://www.example.com/js/xmlhr.js" # => http://www.example.com/js/xmlhr.js
+ def javascript_path(source, options = {})
+ path_to_asset(source, {type: :javascript}.merge!(options))
+ end
+ alias_method :path_to_javascript, :javascript_path # aliased to avoid conflicts with a javascript_path named route
+
+ # Computes the full URL to a javascript asset in the public javascripts directory.
+ # This will use +javascript_path+ internally, so most of their behaviors will be the same.
+ def javascript_url(source, options = {})
+ url_to_asset(source, {type: :javascript}.merge!(options))
+ end
+ alias_method :url_to_javascript, :javascript_url # aliased to avoid conflicts with a javascript_url named route
+
+ # Computes the path to a stylesheet asset in the public stylesheets directory.
+ # If the +source+ filename has no extension, <tt>.css</tt> will be appended (except for explicit URIs).
+ # Full paths from the document root will be passed through.
+ # Used internally by +stylesheet_link_tag+ to build the stylesheet path.
+ #
+ # stylesheet_path "style" # => /stylesheets/style.css
+ # stylesheet_path "dir/style.css" # => /stylesheets/dir/style.css
+ # stylesheet_path "/dir/style.css" # => /dir/style.css
+ # stylesheet_path "http://www.example.com/css/style" # => http://www.example.com/css/style
+ # stylesheet_path "http://www.example.com/css/style.css" # => http://www.example.com/css/style.css
+ def stylesheet_path(source, options = {})
+ path_to_asset(source, {type: :stylesheet}.merge!(options))
+ end
+ alias_method :path_to_stylesheet, :stylesheet_path # aliased to avoid conflicts with a stylesheet_path named route
+
+ # Computes the full URL to a stylesheet asset in the public stylesheets directory.
+ # This will use +stylesheet_path+ internally, so most of their behaviors will be the same.
+ def stylesheet_url(source, options = {})
+ url_to_asset(source, {type: :stylesheet}.merge!(options))
+ end
+ alias_method :url_to_stylesheet, :stylesheet_url # aliased to avoid conflicts with a stylesheet_url named route
+
+ # 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") # => "/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"
+ #
+ # If you have images as application resources this method may conflict with their named routes.
+ # The alias +path_to_image+ is provided to avoid that. Rails uses the alias internally, and
+ # plugin authors are encouraged to do so.
+ def image_path(source, options = {})
+ path_to_asset(source, {type: :image}.merge!(options))
+ 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.
+ # This will use +image_path+ internally, so most of their behaviors will be the same.
+ def image_url(source, options = {})
+ url_to_asset(source, {type: :image}.merge!(options))
+ end
+ alias_method :url_to_image, :image_url # aliased to avoid conflicts with an image_url named route
+
+ # Computes the path to a video asset in the public videos directory.
+ # Full paths from the document root will be passed through.
+ # Used internally by +video_tag+ to build the video path.
+ #
+ # video_path("hd") # => /videos/hd
+ # video_path("hd.avi") # => /videos/hd.avi
+ # video_path("trailers/hd.avi") # => /videos/trailers/hd.avi
+ # video_path("/trailers/hd.avi") # => /trailers/hd.avi
+ # video_path("http://www.example.com/vid/hd.avi") # => http://www.example.com/vid/hd.avi
+ def video_path(source, options = {})
+ path_to_asset(source, {type: :video}.merge!(options))
+ end
+ alias_method :path_to_video, :video_path # aliased to avoid conflicts with a video_path named route
+
+ # Computes the full URL to a video asset in the public videos directory.
+ # This will use +video_path+ internally, so most of their behaviors will be the same.
+ def video_url(source, options = {})
+ url_to_asset(source, {type: :video}.merge!(options))
+ end
+ alias_method :url_to_video, :video_url # aliased to avoid conflicts with an video_url named route
+
+ # Computes the path to an audio asset in the public audios directory.
+ # Full paths from the document root will be passed through.
+ # Used internally by +audio_tag+ to build the audio path.
+ #
+ # audio_path("horse") # => /audios/horse
+ # audio_path("horse.wav") # => /audios/horse.wav
+ # audio_path("sounds/horse.wav") # => /audios/sounds/horse.wav
+ # audio_path("/sounds/horse.wav") # => /sounds/horse.wav
+ # audio_path("http://www.example.com/sounds/horse.wav") # => http://www.example.com/sounds/horse.wav
+ def audio_path(source, options = {})
+ path_to_asset(source, {type: :audio}.merge!(options))
+ end
+ alias_method :path_to_audio, :audio_path # aliased to avoid conflicts with an audio_path named route
+
+ # 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, options = {})
+ url_to_asset(source, {type: :audio}.merge!(options))
+ 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.
+ # Full paths from the document root will be passed through.
+ #
+ # 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, options = {})
+ path_to_asset(source, {type: :font}.merge!(options))
+ 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.
+ # This will use +font_path+ internally, so most of their behaviors will be the same.
+ def font_url(source, options = {})
+ url_to_asset(source, {type: :font}.merge!(options))
+ end
+ alias_method :url_to_font, :font_url # aliased to avoid conflicts with an font_url named route
+ end
+ end
+end
diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb
index 387dfeab17..f43d20c6ed 100644
--- a/actionpack/lib/action_view/helpers/date_helper.rb
+++ b/actionpack/lib/action_view/helpers/date_helper.rb
@@ -73,13 +73,17 @@ module ActionView
options[:include_seconds] ||= !!include_seconds_or_options
end
+ options = {
+ scope: :'datetime.distance_in_words'
+ }.merge!(options)
+
from_time = from_time.to_time if from_time.respond_to?(:to_time)
to_time = to_time.to_time if to_time.respond_to?(:to_time)
from_time, to_time = to_time, from_time if from_time > to_time
distance_in_minutes = ((to_time - from_time)/60.0).round
distance_in_seconds = (to_time - from_time).round
- I18n.with_options :locale => options[:locale], :scope => :'datetime.distance_in_words' do |locale|
+ I18n.with_options :locale => options[:locale], :scope => options[:scope] do |locale|
case distance_in_minutes
when 0..1
return distance_in_minutes == 0 ?
@@ -196,6 +200,8 @@ module ActionView
# for <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>, <tt>:hour</tt>, <tt>:minute</tt> and <tt>:second</tt>.
# Setting this option prepends a select option with a generic prompt (Day, Month, Year, Hour, Minute, Seconds)
# or the given prompt string.
+ # * <tt>:with_css_classes</tt> - Set to true if you want assign different styles for 'select' tags. This option
+ # automatically set classes 'year', 'month', 'day', 'hour', 'minute' and 'second' for your 'select' tags.
#
# If anything is passed in the +html_options+ hash it will be applied to every select tag in the set.
#
@@ -937,6 +943,7 @@ module ActionView
:name => input_name_from_type(type)
}.merge!(@html_options)
select_options[:disabled] = 'disabled' if @options[:disabled]
+ select_options[:class] = type if @options[:with_css_classes]
select_html = "\n"
select_html << content_tag(:option, '', :value => '') + "\n" if @options[:include_blank]
diff --git a/actionpack/lib/action_view/helpers/tags/check_box.rb b/actionpack/lib/action_view/helpers/tags/check_box.rb
index 9d17a1dde3..e21cc07746 100644
--- a/actionpack/lib/action_view/helpers/tags/check_box.rb
+++ b/actionpack/lib/action_view/helpers/tags/check_box.rb
@@ -46,10 +46,12 @@ module ActionView
false
when String
value == @checked_value
- when Array
- value.include?(@checked_value)
else
- value.to_i == @checked_value.to_i
+ if value.respond_to?(:include?)
+ value.include?(@checked_value)
+ else
+ value.to_i == @checked_value.to_i
+ end
end
end
diff --git a/actionpack/lib/action_view/railtie.rb b/actionpack/lib/action_view/railtie.rb
index 55f6ea5522..3875d88a9f 100644
--- a/actionpack/lib/action_view/railtie.rb
+++ b/actionpack/lib/action_view/railtie.rb
@@ -20,14 +20,6 @@ module ActionView
ActiveSupport.on_load(:action_view) { self.logger ||= Rails.logger }
end
- initializer "action_view.cache_asset_ids" do |app|
- unless app.config.cache_classes
- ActiveSupport.on_load(:action_view) do
- ActionView::Helpers::AssetTagHelper::AssetPaths.cache_asset_ids = false
- end
- end
- end
-
initializer "action_view.set_configs" do |app|
ActiveSupport.on_load(:action_view) do
app.config.action_view.each do |k,v|
diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb
index 5434b3421e..a548b44780 100644
--- a/actionpack/lib/action_view/test_case.rb
+++ b/actionpack/lib/action_view/test_case.rb
@@ -119,8 +119,29 @@ module ActionView
output
end
- def locals
- @locals ||= {}
+ def rendered_views
+ @_rendered_views ||= RenderedViewsCollection.new
+ end
+
+ class RenderedViewsCollection
+ def initialize
+ @rendered_views ||= {}
+ end
+
+ def add(view, locals)
+ @rendered_views[view] ||= []
+ @rendered_views[view] << locals
+ end
+
+ def locals_for(view)
+ @rendered_views[view]
+ end
+
+ def view_rendered?(view, expected_locals)
+ locals_for(view).any? do |actual_locals|
+ expected_locals.all? {|key, value| value == actual_locals[key] }
+ end
+ end
end
included do
@@ -156,18 +177,18 @@ module ActionView
end
module Locals
- attr_accessor :locals
+ attr_accessor :rendered_views
def render(options = {}, local_assigns = {})
case options
when Hash
if block_given?
- locals[options[:layout]] = options[:locals]
+ rendered_views.add options[:layout], options[:locals]
elsif options.key?(:partial)
- locals[options[:partial]] = options[:locals]
+ rendered_views.add options[:partial], options[:locals]
end
else
- locals[options] = local_assigns
+ rendered_views.add options, local_assigns
end
super
@@ -180,7 +201,7 @@ module ActionView
view = @controller.view_context
view.singleton_class.send :include, _helpers
view.extend(Locals)
- view.locals = self.locals
+ view.rendered_views = self.rendered_views
view.output_buffer = self.output_buffer
view
end
@@ -197,7 +218,7 @@ module ActionView
:@_routes,
:@controller,
:@_layouts,
- :@locals,
+ :@_rendered_views,
:@method_name,
:@output_buffer,
:@_partials,
diff --git a/actionpack/test/controller/parameters/multi_parameter_attributes_test.rb b/actionpack/test/controller/parameters/multi_parameter_attributes_test.rb
index 2214ec769c..15338059bc 100644
--- a/actionpack/test/controller/parameters/multi_parameter_attributes_test.rb
+++ b/actionpack/test/controller/parameters/multi_parameter_attributes_test.rb
@@ -5,18 +5,20 @@ class MultiParameterAttributesTest < ActiveSupport::TestCase
test "permitted multi-parameter attribute keys" do
params = ActionController::Parameters.new({
book: {
- "shipped_at(1i)" => "2012",
- "shipped_at(2i)" => "3",
- "shipped_at(3i)" => "25",
- "shipped_at(4i)" => "10",
- "shipped_at(5i)" => "15",
- "published_at(1i)" => "1999",
- "published_at(2i)" => "2",
- "published_at(3i)" => "5"
+ "shipped_at(1i)" => "2012",
+ "shipped_at(2i)" => "3",
+ "shipped_at(3i)" => "25",
+ "shipped_at(4i)" => "10",
+ "shipped_at(5i)" => "15",
+ "published_at(1i)" => "1999",
+ "published_at(2i)" => "2",
+ "published_at(3i)" => "5",
+ "price(1)" => "R$",
+ "price(2f)" => "2.02"
}
})
- permitted = params.permit book: [ :shipped_at ]
+ permitted = params.permit book: [ :shipped_at, :price ]
assert permitted.permitted?
@@ -26,6 +28,9 @@ class MultiParameterAttributesTest < ActiveSupport::TestCase
assert_equal "10", permitted[:book]["shipped_at(4i)"]
assert_equal "15", permitted[:book]["shipped_at(5i)"]
+ assert_equal "R$", permitted[:book]["price(1)"]
+ assert_equal "2.02", permitted[:book]["price(2f)"]
+
assert_nil permitted[:book]["published_at(1i)"]
assert_nil permitted[:book]["published_at(2i)"]
assert_nil permitted[:book]["published_at(3i)"]
diff --git a/actionpack/test/controller/parameters/nested_parameters_test.rb b/actionpack/test/controller/parameters/nested_parameters_test.rb
index 41f5b6e127..d287e79cba 100644
--- a/actionpack/test/controller/parameters/nested_parameters_test.rb
+++ b/actionpack/test/controller/parameters/nested_parameters_test.rb
@@ -15,18 +15,22 @@ class NestedParametersTest < ActiveSupport::TestCase
details: {
pages: 200,
genre: "Tragedy"
+ },
+ id: {
+ isbn: 'x'
}
},
magazine: "Mjallo!"
})
- permitted = params.permit book: [ :title, { authors: [ :name ] }, { details: :pages } ]
+ permitted = params.permit book: [ :title, { authors: [ :name ] }, { details: :pages }, :id ]
assert permitted.permitted?
assert_equal "Romeo and Juliet", permitted[:book][:title]
assert_equal "William Shakespeare", permitted[:book][:authors][0][:name]
assert_equal "Christopher Marlowe", permitted[:book][:authors][1][:name]
assert_equal 200, permitted[:book][:details][:pages]
+ assert_nil permitted[:book][:id]
assert_nil permitted[:book][:details][:genre]
assert_nil permitted[:book][:authors][0][:born]
assert_nil permitted[:magazine]
diff --git a/actionpack/test/controller/parameters/parameters_permit_test.rb b/actionpack/test/controller/parameters/parameters_permit_test.rb
index 18bb51c5a3..ad970f0a9a 100644
--- a/actionpack/test/controller/parameters/parameters_permit_test.rb
+++ b/actionpack/test/controller/parameters/parameters_permit_test.rb
@@ -3,7 +3,7 @@ require 'action_controller/metal/strong_parameters'
class ParametersPermitTest < ActiveSupport::TestCase
setup do
- @params = ActionController::Parameters.new({ person: {
+ @params = ActionController::Parameters.new({ person: {
age: "32", name: { first: "David", last: "Heinemeier Hansson" }
}})
end
diff --git a/actionpack/test/dispatch/header_test.rb b/actionpack/test/dispatch/header_test.rb
index bc7cad8db5..42432510c3 100644
--- a/actionpack/test/dispatch/header_test.rb
+++ b/actionpack/test/dispatch/header_test.rb
@@ -7,6 +7,26 @@ class HeaderTest < ActiveSupport::TestCase
)
end
+ def test_each
+ headers = []
+ @headers.each { |pair| headers << pair }
+ assert_equal [["HTTP_CONTENT_TYPE", "text/plain"]], headers
+ end
+
+ def test_setter
+ @headers['foo'] = "bar"
+ assert_equal "bar", @headers['foo']
+ end
+
+ def test_key?
+ assert @headers.key?('HTTP_CONTENT_TYPE')
+ assert @headers.include?('HTTP_CONTENT_TYPE')
+ end
+
+ def test_fetch_with_block
+ assert_equal 'omg', @headers.fetch('notthere') { 'omg' }
+ end
+
test "content type" do
assert_equal "text/plain", @headers["Content-Type"]
assert_equal "text/plain", @headers["content-type"]
diff --git a/actionpack/test/fixtures/digestor/level/below/_header.html.erb b/actionpack/test/fixtures/digestor/level/below/_header.html.erb
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/actionpack/test/fixtures/digestor/level/below/_header.html.erb
diff --git a/actionpack/test/fixtures/digestor/level/below/index.html.erb b/actionpack/test/fixtures/digestor/level/below/index.html.erb
new file mode 100644
index 0000000000..b92f49a8f8
--- /dev/null
+++ b/actionpack/test/fixtures/digestor/level/below/index.html.erb
@@ -0,0 +1 @@
+<%= render partial: "header" %>
diff --git a/actionpack/test/fixtures/test/render_two_partials.html.erb b/actionpack/test/fixtures/test/render_two_partials.html.erb
new file mode 100644
index 0000000000..3db6025860
--- /dev/null
+++ b/actionpack/test/fixtures/test/render_two_partials.html.erb
@@ -0,0 +1,2 @@
+<%= render :partial => 'partial', :locals => {'first' => '1'} %>
+<%= render :partial => 'partial', :locals => {'second' => '2'} %>
diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb
index 754622c883..eb1a54a81f 100644
--- a/actionpack/test/template/asset_tag_helper_test.rb
+++ b/actionpack/test/template/asset_tag_helper_test.rb
@@ -13,27 +13,10 @@ end
class AssetTagHelperTest < ActionView::TestCase
tests ActionView::Helpers::AssetTagHelper
+ attr_reader :request
+
def setup
super
- silence_warnings do
- ActionView::Helpers::AssetTagHelper.send(
- :const_set,
- :JAVASCRIPTS_DIR,
- File.dirname(__FILE__) + "/../fixtures/public/javascripts"
- )
-
- ActionView::Helpers::AssetTagHelper.send(
- :const_set,
- :STYLESHEETS_DIR,
- File.dirname(__FILE__) + "/../fixtures/public/stylesheets"
- )
-
- ActionView::Helpers::AssetTagHelper.send(
- :const_set,
- :ASSETS_DIR,
- File.dirname(__FILE__) + "/../fixtures/public"
- )
- end
@controller = BasicController.new
@@ -42,6 +25,7 @@ class AssetTagHelperTest < ActionView::TestCase
def protocol() 'http://' end
def ssl?() false end
def host_with_port() 'localhost' end
+ def base_url() 'http://www.example.com' end
end.new
@controller.request = @request
@@ -51,9 +35,23 @@ class AssetTagHelperTest < ActionView::TestCase
"http://www.example.com"
end
- def teardown
- ENV.delete('RAILS_ASSET_ID')
- end
+ AssetPathToTag = {
+ %(asset_path("foo")) => %(/foo),
+ %(asset_path("style.css")) => %(/style.css),
+ %(asset_path("xmlhr.js")) => %(/xmlhr.js),
+ %(asset_path("xml.png")) => %(/xml.png),
+ %(asset_path("dir/xml.png")) => %(/dir/xml.png),
+ %(asset_path("/dir/xml.png")) => %(/dir/xml.png),
+
+ %(asset_path("script.min")) => %(/script.min),
+ %(asset_path("script.min.js")) => %(/script.min.js),
+ %(asset_path("style.min")) => %(/style.min),
+ %(asset_path("style.min.css")) => %(/style.min.css),
+
+ %(asset_path("style", type: :stylesheet)) => %(/stylesheets/style.css),
+ %(asset_path("xmlhr", type: :javascript)) => %(/javascripts/xmlhr.js),
+ %(asset_path("xml.png", type: :image)) => %(/images/xml.png)
+ }
AutoDiscoveryToTag = {
%(auto_discovery_link_tag) => %(<link href="http://www.example.com" rel="alternate" title="RSS" type="application/rss+xml" />),
@@ -73,7 +71,14 @@ class AssetTagHelperTest < ActionView::TestCase
JavascriptPathToTag = {
%(javascript_path("xmlhr")) => %(/javascripts/xmlhr.js),
%(javascript_path("super/xmlhr")) => %(/javascripts/super/xmlhr.js),
- %(javascript_path("/super/xmlhr.js")) => %(/super/xmlhr.js)
+ %(javascript_path("/super/xmlhr.js")) => %(/super/xmlhr.js),
+ %(javascript_path("xmlhr.min")) => %(/javascripts/xmlhr.min.js),
+ %(javascript_path("xmlhr.min.js")) => %(/javascripts/xmlhr.min.js),
+
+ %(javascript_path("xmlhr.js?123")) => %(/javascripts/xmlhr.js?123),
+ %(javascript_path("xmlhr.js?body=1")) => %(/javascripts/xmlhr.js?body=1),
+ %(javascript_path("xmlhr.js#hash")) => %(/javascripts/xmlhr.js#hash),
+ %(javascript_path("xmlhr.js?123#hash")) => %(/javascripts/xmlhr.js?123#hash)
}
PathToJavascriptToTag = {
@@ -98,7 +103,6 @@ class AssetTagHelperTest < ActionView::TestCase
%(javascript_include_tag("bank")) => %(<script src="/javascripts/bank.js" ></script>),
%(javascript_include_tag("bank.js")) => %(<script src="/javascripts/bank.js" ></script>),
%(javascript_include_tag("bank", :lang => "vbscript")) => %(<script lang="vbscript" src="/javascripts/bank.js" ></script>),
- %(javascript_include_tag("common.javascript", "/elsewhere/cools")) => %(<script src="/javascripts/common.javascript" ></script>\n<script src="/elsewhere/cools.js" ></script>),
%(javascript_include_tag("http://example.com/all")) => %(<script src="http://example.com/all"></script>),
%(javascript_include_tag("http://example.com/all.js")) => %(<script src="http://example.com/all.js"></script>),
@@ -109,14 +113,17 @@ class AssetTagHelperTest < ActionView::TestCase
%(stylesheet_path("bank")) => %(/stylesheets/bank.css),
%(stylesheet_path("bank.css")) => %(/stylesheets/bank.css),
%(stylesheet_path('subdir/subdir')) => %(/stylesheets/subdir/subdir.css),
- %(stylesheet_path('/subdir/subdir.css')) => %(/subdir/subdir.css)
+ %(stylesheet_path('/subdir/subdir.css')) => %(/subdir/subdir.css),
+ %(stylesheet_path("style.min")) => %(/stylesheets/style.min.css),
+ %(stylesheet_path("style.min.css")) => %(/stylesheets/style.min.css)
}
PathToStyleToTag = {
%(path_to_stylesheet("style")) => %(/stylesheets/style.css),
%(path_to_stylesheet("style.css")) => %(/stylesheets/style.css),
%(path_to_stylesheet('dir/file')) => %(/stylesheets/dir/file.css),
- %(path_to_stylesheet('/dir/file.rcss')) => %(/dir/file.rcss)
+ %(path_to_stylesheet('/dir/file.rcss', :extname => false)) => %(/dir/file.rcss),
+ %(path_to_stylesheet('/dir/file', :extname => '.rcss')) => %(/dir/file.rcss)
}
StyleUrlToTag = {
@@ -130,7 +137,8 @@ class AssetTagHelperTest < ActionView::TestCase
%(url_to_stylesheet("style")) => %(http://www.example.com/stylesheets/style.css),
%(url_to_stylesheet("style.css")) => %(http://www.example.com/stylesheets/style.css),
%(url_to_stylesheet('dir/file')) => %(http://www.example.com/stylesheets/dir/file.css),
- %(url_to_stylesheet('/dir/file.rcss')) => %(http://www.example.com/dir/file.rcss)
+ %(url_to_stylesheet('/dir/file.rcss', :extname => false)) => %(http://www.example.com/dir/file.rcss),
+ %(url_to_stylesheet('/dir/file', :extname => '.rcss')) => %(http://www.example.com/dir/file.rcss)
}
StyleLinkToTag = {
@@ -139,7 +147,6 @@ class AssetTagHelperTest < ActionView::TestCase
%(stylesheet_link_tag("/elsewhere/file")) => %(<link href="/elsewhere/file.css" media="screen" rel="stylesheet" />),
%(stylesheet_link_tag("subdir/subdir")) => %(<link href="/stylesheets/subdir/subdir.css" media="screen" rel="stylesheet" />),
%(stylesheet_link_tag("bank", :media => "all")) => %(<link href="/stylesheets/bank.css" media="all" rel="stylesheet" />),
- %(stylesheet_link_tag("random.styles", "/elsewhere/file")) => %(<link href="/stylesheets/random.styles" media="screen" rel="stylesheet" />\n<link href="/elsewhere/file.css" media="screen" rel="stylesheet" />),
%(stylesheet_link_tag("http://www.example.com/styles/style")) => %(<link href="http://www.example.com/styles/style" media="screen" rel="stylesheet" />),
%(stylesheet_link_tag("http://www.example.com/styles/style.css")) => %(<link href="http://www.example.com/styles/style.css" media="screen" rel="stylesheet" />),
@@ -283,6 +290,14 @@ class AssetTagHelperTest < ActionView::TestCase
%(audio_tag(["audio.mp3", "audio.ogg"], :autobuffer => true, :controls => true)) => %(<audio autobuffer="autobuffer" controls="controls"><source src="/audios/audio.mp3" /><source src="/audios/audio.ogg" /></audio>)
}
+ FontPathToTag = {
+ %(font_path("font.eot")) => %(/fonts/font.eot),
+ %(font_path("font.eot#iefix")) => %(/fonts/font.eot#iefix),
+ %(font_path("font.woff")) => %(/fonts/font.woff),
+ %(font_path("font.ttf")) => %(/fonts/font.ttf),
+ %(font_path("font.ttf?123")) => %(/fonts/font.ttf?123)
+ }
+
def test_autodiscovery_link_tag_deprecated_types
result = nil
assert_deprecated do
@@ -293,6 +308,18 @@ class AssetTagHelperTest < ActionView::TestCase
assert_equal expected, result
end
+ def test_asset_path_tag
+ AssetPathToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) }
+ end
+
+ def test_compute_asset_public_path
+ assert_equal "/robots.txt", compute_asset_path("robots.txt")
+ assert_equal "/robots.txt", compute_asset_path("/robots.txt")
+ assert_equal "/javascripts/foo.js", compute_asset_path("foo.js", :type => :javascript)
+ assert_equal "/javascripts/foo.js", compute_asset_path("/foo.js", :type => :javascript)
+ assert_equal "/stylesheets/foo.css", compute_asset_path("foo.css", :type => :stylesheet)
+ end
+
def test_auto_discovery_link_tag
AutoDiscoveryToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) }
end
@@ -313,8 +340,7 @@ class AssetTagHelperTest < ActionView::TestCase
UrlToJavascriptToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) }
end
- def test_javascript_include_tag_with_blank_asset_id
- ENV["RAILS_ASSET_ID"] = ""
+ def test_javascript_include_tag
JavascriptIncludeToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) }
end
@@ -332,17 +358,7 @@ class AssetTagHelperTest < ActionView::TestCase
assert javascript_include_tag("prototype").html_safe?
end
- def test_all_javascript_expansion_not_include_application_js_if_not_exists
- FileUtils.mv(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'application.js'),
- File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'application.bak'))
- assert_no_match(/application\.js/, javascript_include_tag(:all))
- ensure
- FileUtils.mv(File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'application.bak'),
- File.join(ActionView::Helpers::AssetTagHelper::JAVASCRIPTS_DIR, 'application.js'))
- end
-
def test_stylesheet_path
- ENV["RAILS_ASSET_ID"] = ""
StylePathToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) }
end
@@ -351,7 +367,6 @@ class AssetTagHelperTest < ActionView::TestCase
end
def test_stylesheet_url
- ENV["RAILS_ASSET_ID"] = ""
StyleUrlToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) }
end
@@ -360,7 +375,6 @@ class AssetTagHelperTest < ActionView::TestCase
end
def test_stylesheet_link_tag
- ENV["RAILS_ASSET_ID"] = ""
StyleLinkToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) }
end
@@ -375,7 +389,6 @@ class AssetTagHelperTest < ActionView::TestCase
end
def test_stylesheet_link_tag_is_html_safe
- ENV["RAILS_ASSET_ID"] = ""
assert stylesheet_link_tag('dir/file').html_safe?
assert stylesheet_link_tag('dir/other/file', 'dir/file2').html_safe?
end
@@ -385,7 +398,6 @@ class AssetTagHelperTest < ActionView::TestCase
end
def test_stylesheet_link_tag_should_not_output_the_same_asset_twice
- ENV["RAILS_ASSET_ID"] = ""
assert_dom_equal %(<link href="/stylesheets/wellington.css" media="screen" rel="stylesheet" />\n<link href="/stylesheets/amsterdam.css" media="screen" rel="stylesheet" />), stylesheet_link_tag('wellington', 'wellington', 'amsterdam')
end
@@ -427,21 +439,6 @@ class AssetTagHelperTest < ActionView::TestCase
FaviconLinkToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) }
end
- def test_image_tag_windows_behaviour
- old_asset_id, ENV["RAILS_ASSET_ID"] = ENV["RAILS_ASSET_ID"], "1"
- # This simulates the behavior of File#exist? on windows when testing a file ending in "."
- # If the file "rails.png" exists, windows will return true when asked if "rails.png." exists (notice trailing ".")
- # OS X, linux etc will return false in this case.
- File.stubs(:exist?).with('template/../fixtures/public/images/rails.png.').returns(true)
- assert_equal '<img alt="Rails" src="/images/rails.png?1" />', image_tag('rails.png')
- ensure
- if old_asset_id
- ENV["RAILS_ASSET_ID"] = old_asset_id
- else
- ENV.delete("RAILS_ASSET_ID")
- end
- end
-
def test_video_path
VideoPathToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) }
end
@@ -482,6 +479,10 @@ class AssetTagHelperTest < ActionView::TestCase
AudioLinkToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) }
end
+ def test_font_path
+ FontPathToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) }
+ end
+
def test_video_audio_tag_does_not_modify_options
options = {:autoplay => true}
video_tag('video', options)
@@ -490,27 +491,6 @@ class AssetTagHelperTest < ActionView::TestCase
assert_equal({:autoplay => true}, options)
end
- def test_timebased_asset_id
- expected_time = File.mtime(File.expand_path(File.dirname(__FILE__) + "/../fixtures/public/images/rails.png")).to_i.to_s
- assert_equal %(<img alt="Rails" src="/images/rails.png?#{expected_time}" />), image_tag("rails.png")
- end
-
- def test_string_asset_id
- @controller.config.asset_path = "/assets.v12345%s"
-
- expected_path = "/assets.v12345/images/rails.png"
- assert_equal %(<img alt="Rails" src="#{expected_path}" />), image_tag("rails.png")
- end
-
- def test_proc_asset_id
- @controller.config.asset_path = Proc.new do |asset_path|
- "/assets.v12345#{asset_path}"
- end
-
- expected_path = "/assets.v12345/images/rails.png"
- assert_equal %(<img alt="Rails" src="#{expected_path}" />), image_tag("rails.png")
- end
-
def test_image_tag_interpreting_email_cid_correctly
# An inline image has no need for an alt tag to be automatically generated from the cid:
assert_equal '<img src="cid:thi%25%25sis@acontentid" />', image_tag("cid:thi%25%25sis@acontentid")
@@ -520,37 +500,6 @@ class AssetTagHelperTest < ActionView::TestCase
assert_equal '<img alt="Image" src="cid:thi%25%25sis@acontentid" />', image_tag("cid:thi%25%25sis@acontentid", :alt => "Image")
end
- def test_timebased_asset_id_with_relative_url_root
- @controller.config.relative_url_root = "/collaboration/hieraki"
- expected_time = File.mtime(File.expand_path(File.dirname(__FILE__) + "/../fixtures/public/images/rails.png")).to_i.to_s
- assert_equal %(<img alt="Rails" src="#{@controller.config.relative_url_root}/images/rails.png?#{expected_time}" />), image_tag("rails.png")
- end
-
- # Same as above, but with script_name
- def test_timebased_asset_id_with_script_name
- @request.script_name = "/collaboration/hieraki"
- expected_time = File.mtime(File.expand_path(File.dirname(__FILE__) + "/../fixtures/public/images/rails.png")).to_i.to_s
- assert_equal %(<img alt="Rails" src="#{@request.script_name}/images/rails.png?#{expected_time}" />), image_tag("rails.png")
- end
-
- def test_should_skip_asset_id_on_complete_url
- assert_equal %(<img alt="Rails" src="http://www.example.com/rails.png" />), image_tag("http://www.example.com/rails.png")
- end
-
- def test_should_skip_asset_id_on_scheme_relative_url
- assert_equal %(<img alt="Rails" src="//www.example.com/rails.png" />), image_tag("//www.example.com/rails.png")
- end
-
- def test_should_use_preset_asset_id
- ENV["RAILS_ASSET_ID"] = "4500"
- assert_equal %(<img alt="Rails" src="/images/rails.png?4500" />), image_tag("rails.png")
- end
-
- def test_preset_empty_asset_id
- ENV["RAILS_ASSET_ID"] = ""
- assert_equal %(<img alt="Rails" src="/images/rails.png" />), image_tag("rails.png")
- end
-
def test_should_not_modify_source_string
source = '/images/rails.png'
copy = source.dup
@@ -559,7 +508,6 @@ class AssetTagHelperTest < ActionView::TestCase
end
def test_caching_image_path_with_caching_and_proc_asset_host_using_request
- ENV['RAILS_ASSET_ID'] = ''
@controller.config.asset_host = Proc.new do |source, request|
if request.ssl?
"#{request.protocol}#{request.host_with_port}"
@@ -579,12 +527,14 @@ end
class AssetTagHelperNonVhostTest < ActionView::TestCase
tests ActionView::Helpers::AssetTagHelper
+ attr_reader :request
+
def setup
super
@controller = BasicController.new
@controller.config.relative_url_root = "/collaboration/hieraki"
- @request = Struct.new(:protocol).new("gopher://")
+ @request = Struct.new(:protocol, :base_url).new("gopher://", "gopher://www.example.com")
@controller.request = @request
end
@@ -599,10 +549,33 @@ class AssetTagHelperNonVhostTest < ActionView::TestCase
assert_dom_equal(%(/collaboration/hieraki/images/xml.png), image_path("xml.png"))
end
+ def test_should_return_nothing_if_asset_host_isnt_configured
+ assert_equal nil, compute_asset_host("foo")
+ end
+
+ def test_should_current_request_host_is_always_returned_for_request
+ assert_equal "gopher://www.example.com", compute_asset_host("foo", :protocol => :request)
+ end
+
def test_should_ignore_relative_root_path_on_complete_url
assert_dom_equal(%(http://www.example.com/images/xml.png), image_path("http://www.example.com/images/xml.png"))
end
+ def test_should_return_simple_string_asset_host
+ @controller.config.asset_host = "assets.example.com"
+ assert_equal "gopher://assets.example.com", compute_asset_host("foo")
+ end
+
+ def test_should_return_relative_asset_host
+ @controller.config.asset_host = "assets.example.com"
+ assert_equal "//assets.example.com", compute_asset_host("foo", :protocol => :relative)
+ end
+
+ def test_should_return_custom_protocol_asset_host
+ @controller.config.asset_host = "assets.example.com"
+ assert_equal "ftp://assets.example.com", compute_asset_host("foo", :protocol => "ftp")
+ end
+
def test_should_compute_proper_path_with_asset_host
@controller.config.asset_host = "assets.example.com"
assert_dom_equal(%(<link href="http://www.example.com/collaboration/hieraki" rel="alternate" title="RSS" type="application/rss+xml" />), auto_discovery_link_tag)
@@ -635,6 +608,11 @@ class AssetTagHelperNonVhostTest < ActionView::TestCase
assert_dom_equal(%(gopher://assets.example.com/collaboration/hieraki/images/xml.png), image_url("xml.png"))
end
+ def test_should_return_asset_host_with_protocol
+ @controller.config.asset_host = "http://assets.example.com"
+ assert_equal "http://assets.example.com", compute_asset_host("foo")
+ end
+
def test_should_ignore_asset_host_on_complete_url
@controller.config.asset_host = "http://assets.example.com"
assert_dom_equal(%(<link href="http://bar.example.com/stylesheets/style.css" media="screen" rel="stylesheet" />), stylesheet_link_tag("http://bar.example.com/stylesheets/style.css"))
@@ -645,6 +623,11 @@ class AssetTagHelperNonVhostTest < ActionView::TestCase
assert_dom_equal(%(<link href="//bar.example.com/stylesheets/style.css" media="screen" rel="stylesheet" />), stylesheet_link_tag("//bar.example.com/stylesheets/style.css"))
end
+ def test_should_wildcard_asset_host
+ @controller.config.asset_host = 'http://a%d.example.com'
+ assert_match(%r(http://a[0123].example.com), compute_asset_host("foo"))
+ end
+
def test_should_wildcard_asset_host_between_zero_and_four
@controller.config.asset_host = 'http://a%d.example.com'
assert_match(%r(http://a[0123].example.com/collaboration/hieraki/images/xml.png), image_path('xml.png'))
@@ -668,3 +651,73 @@ class AssetTagHelperNonVhostTest < ActionView::TestCase
assert_dom_equal(%(/collaboration/hieraki/stylesheets/foo.css), stylesheet_path("foo"))
end
end
+
+class AssetUrlHelperControllerTest < ActionView::TestCase
+ tests ActionView::Helpers::AssetUrlHelper
+
+ def setup
+ super
+
+ @controller = BasicController.new
+ @controller.extend ActionView::Helpers::AssetUrlHelper
+
+ @request = Class.new do
+ attr_accessor :script_name
+ def protocol() 'http://' end
+ def ssl?() false end
+ def host_with_port() 'www.example.com' end
+ def base_url() 'http://www.example.com' end
+ end.new
+
+ @controller.request = @request
+ end
+
+ def test_asset_path
+ assert_equal "/foo", @controller.asset_path("foo")
+ end
+
+ def test_asset_url
+ assert_equal "http://www.example.com/foo", @controller.asset_url("foo")
+ end
+end
+
+class AssetUrlHelperEmptyModuleTest < ActionView::TestCase
+ tests ActionView::Helpers::AssetUrlHelper
+
+ def setup
+ super
+
+ @module = Module.new
+ @module.extend ActionView::Helpers::AssetUrlHelper
+ end
+
+ def test_asset_path
+ assert_equal "/foo", @module.asset_path("foo")
+ end
+
+ def test_asset_url
+ assert_equal "/foo", @module.asset_url("foo")
+ end
+
+ def test_asset_url_with_request
+ @module.instance_eval do
+ def request
+ Struct.new(:base_url, :script_name).new("http://www.example.com", nil)
+ end
+ end
+
+ assert @module.request
+ assert_equal "http://www.example.com/foo", @module.asset_url("foo")
+ end
+
+ def test_asset_url_with_config_asset_host
+ @module.instance_eval do
+ def config
+ Struct.new(:asset_host).new("http://www.example.com")
+ end
+ end
+
+ assert @module.config.asset_host
+ assert_equal "http://www.example.com/foo", @module.asset_url("foo")
+ end
+end
diff --git a/actionpack/test/template/date_helper_i18n_test.rb b/actionpack/test/template/date_helper_i18n_test.rb
index 63066d40cd..495a9d3f9d 100644
--- a/actionpack/test/template/date_helper_i18n_test.rb
+++ b/actionpack/test/template/date_helper_i18n_test.rb
@@ -36,16 +36,13 @@ class DateHelperDistanceOfTimeInWordsI18nTests < ActiveSupport::TestCase
end
end
- def assert_distance_of_time_in_words_translates_key(passed, expected)
- diff, passed_options = *passed
- key, count = *expected
- to = @from + diff
-
- options = {:locale => 'en', :scope => :'datetime.distance_in_words'}
- options[:count] = count if count
-
- I18n.expects(:t).with(key, options)
- distance_of_time_in_words(@from, to, passed_options.merge(:locale => 'en'))
+ def test_distance_of_time_in_words_calls_i18n_with_custom_scope
+ {
+ [30.days, { scope: :'datetime.distance_in_words_ago' }] => [:'about_x_months', 1],
+ [60.days, { scope: :'datetime.distance_in_words_ago' }] => [:'x_months', 2],
+ }.each do |passed, expected|
+ assert_distance_of_time_in_words_translates_key(passed, expected, scope: :'datetime.distance_in_words_ago')
+ end
end
def test_time_ago_in_words_passes_locale
@@ -74,6 +71,18 @@ class DateHelperDistanceOfTimeInWordsI18nTests < ActiveSupport::TestCase
assert_equal expected, I18n.t(key, :count => count, :scope => 'datetime.distance_in_words')
end
end
+
+ def assert_distance_of_time_in_words_translates_key(passed, expected, expected_options = {})
+ diff, passed_options = *passed
+ key, count = *expected
+ to = @from + diff
+
+ options = { locale: 'en', scope: :'datetime.distance_in_words' }.merge!(expected_options)
+ options[:count] = count if count
+
+ I18n.expects(:t).with(key, options)
+ distance_of_time_in_words(@from, to, passed_options.merge(locale: 'en'))
+ end
end
class DateHelperSelectTagsI18nTests < ActiveSupport::TestCase
diff --git a/actionpack/test/template/date_helper_test.rb b/actionpack/test/template/date_helper_test.rb
index a4da7cd4b0..8bd8eff3c0 100644
--- a/actionpack/test/template/date_helper_test.rb
+++ b/actionpack/test/template/date_helper_test.rb
@@ -1007,6 +1007,22 @@ class DateHelperTest < ActionView::TestCase
assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), { :date_separator => " / ", :prefix => "date[first]", :use_hidden => true })
end
+ def test_select_date_with_css_classes_option
+ expected = %(<select id="date_first_year" name="date[first][year]" class="year">\n)
+ expected << %(<option value="2003" selected="selected">2003</option>\n<option value="2004">2004</option>\n<option value="2005">2005</option>\n)
+ expected << "</select>\n"
+
+ expected << %(<select id="date_first_month" name="date[first][month]" class="month">\n)
+ expected << %(<option value="1">January</option>\n<option value="2">February</option>\n<option value="3">March</option>\n<option value="4">April</option>\n<option value="5">May</option>\n<option value="6">June</option>\n<option value="7">July</option>\n<option value="8" selected="selected">August</option>\n<option value="9">September</option>\n<option value="10">October</option>\n<option value="11">November</option>\n<option value="12">December</option>\n)
+ expected << "</select>\n"
+
+ expected << %(<select id="date_first_day" name="date[first][day]" class="day">\n)
+ expected << %(<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="4">4</option>\n<option value="5">5</option>\n<option value="6">6</option>\n<option value="7">7</option>\n<option value="8">8</option>\n<option value="9">9</option>\n<option value="10">10</option>\n<option value="11">11</option>\n<option value="12">12</option>\n<option value="13">13</option>\n<option value="14">14</option>\n<option value="15">15</option>\n<option value="16" selected="selected">16</option>\n<option value="17">17</option>\n<option value="18">18</option>\n<option value="19">19</option>\n<option value="20">20</option>\n<option value="21">21</option>\n<option value="22">22</option>\n<option value="23">23</option>\n<option value="24">24</option>\n<option value="25">25</option>\n<option value="26">26</option>\n<option value="27">27</option>\n<option value="28">28</option>\n<option value="29">29</option>\n<option value="30">30</option>\n<option value="31">31</option>\n)
+ expected << "</select>\n"
+
+ assert_dom_equal expected, select_date(Time.mktime(2003, 8, 16), {:start_year => 2003, :end_year => 2005, :prefix => "date[first]", :with_css_classes => true})
+ end
+
def test_select_datetime
expected = %(<select id="date_first_year" name="date[first][year]">\n)
expected << %(<option value="2003" selected="selected">2003</option>\n<option value="2004">2004</option>\n<option value="2005">2005</option>\n)
diff --git a/actionpack/test/template/digestor_test.rb b/actionpack/test/template/digestor_test.rb
index 01b101cb49..b9d26da3af 100644
--- a/actionpack/test/template/digestor_test.rb
+++ b/actionpack/test/template/digestor_test.rb
@@ -13,20 +13,24 @@ end
class FixtureFinder
FIXTURES_DIR = "#{File.dirname(__FILE__)}/../fixtures/digestor"
- TMP_DIR = "#{File.dirname(__FILE__)}/../tmp"
def find(logical_name, keys, partial, options)
- FixtureTemplate.new("#{TMP_DIR}/digestor/#{partial ? logical_name.gsub(%r|/([^/]+)$|, '/_\1') : logical_name}.#{options[:formats].first}.erb")
+ FixtureTemplate.new("digestor/#{partial ? logical_name.gsub(%r|/([^/]+)$|, '/_\1') : logical_name}.#{options[:formats].first}.erb")
end
end
class TemplateDigestorTest < ActionView::TestCase
def setup
- FileUtils.cp_r FixtureFinder::FIXTURES_DIR, FixtureFinder::TMP_DIR
+ @cwd = Dir.pwd
+ @tmp_dir = Dir.mktmpdir
+
+ FileUtils.cp_r FixtureFinder::FIXTURES_DIR, @tmp_dir
+ Dir.chdir @tmp_dir
end
def teardown
- FileUtils.rm_r File.join(FixtureFinder::TMP_DIR, "digestor")
+ Dir.chdir @cwd
+ FileUtils.rm_r @tmp_dir
ActionView::Digestor.cache.clear
end
@@ -59,6 +63,12 @@ class TemplateDigestorTest < ActionView::TestCase
change_template("comments/_comment")
end
end
+
+ def test_directory_depth_dependency
+ assert_digest_difference("level/below/index") do
+ change_template("level/below/_header")
+ end
+ end
def test_logging_of_missing_template
assert_logged "Couldn't find template for digesting: messages/something_missing.html" do
@@ -153,7 +163,7 @@ class TemplateDigestorTest < ActionView::TestCase
end
def change_template(template_name)
- File.open("#{FixtureFinder::TMP_DIR}/digestor/#{template_name}.html.erb", "w") do |f|
+ File.open("digestor/#{template_name}.html.erb", "w") do |f|
f.write "\nTHIS WAS CHANGED!"
end
end
diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb
index 246c4bfada..fbfc73deda 100644
--- a/actionpack/test/template/form_helper_test.rb
+++ b/actionpack/test/template/form_helper_test.rb
@@ -400,6 +400,12 @@ class FormHelperTest < ActionView::TestCase
'<input name="post[secret]" type="hidden" value="0" /><input checked="checked" id="post_secret" name="post[secret]" type="checkbox" value="1" />',
check_box("post", "secret")
)
+
+ @post.secret = Set.new(['1'])
+ assert_dom_equal(
+ '<input name="post[secret]" type="hidden" value="0" /><input checked="checked" id="post_secret" name="post[secret]" type="checkbox" value="1" />',
+ check_box("post", "secret")
+ )
end
def test_check_box_with_include_hidden_false
diff --git a/actionpack/test/template/sanitize_helper_test.rb b/actionpack/test/template/sanitize_helper_test.rb
index 7626cdf386..12d5260a9d 100644
--- a/actionpack/test/template/sanitize_helper_test.rb
+++ b/actionpack/test/template/sanitize_helper_test.rb
@@ -17,7 +17,7 @@ class SanitizeHelperTest < ActionView::TestCase
end
def test_sanitize_form
- assert_sanitized "<form action=\"/foo/bar\" method=\"post\"><input></form>", ''
+ assert_equal '', sanitize("<form action=\"/foo/bar\" method=\"post\"><input></form>")
end
def test_should_sanitize_illegal_style_properties
@@ -48,8 +48,4 @@ class SanitizeHelperTest < ActionView::TestCase
def test_sanitize_is_marked_safe
assert sanitize("<html><script></script></html>").html_safe?
end
-
- def assert_sanitized(text, expected = nil)
- assert_equal((expected || text), sanitize(text))
- end
end
diff --git a/actionpack/test/template/test_case_test.rb b/actionpack/test/template/test_case_test.rb
index 5265ae6b3a..c7231d9cd5 100644
--- a/actionpack/test/template/test_case_test.rb
+++ b/actionpack/test/template/test_case_test.rb
@@ -321,6 +321,14 @@ module ActionView
assert_template :partial => "_partial_for_use_in_layout", :locals => { :name => "Somebody Else" }
end
end
+
+ test 'supports different locals on the same partial' do
+ controller.controller_path = "test"
+ render(:template => "test/render_two_partials")
+ assert_template partial: '_partial', locals: { 'first' => '1' }
+ assert_template partial: '_partial', locals: { 'second' => '2' }
+ end
+
end
module AHelperWithInitialize
diff --git a/activemodel/CHANGELOG.md b/activemodel/CHANGELOG.md
index 2c966943ee..aa42bf762f 100644
--- a/activemodel/CHANGELOG.md
+++ b/activemodel/CHANGELOG.md
@@ -76,6 +76,6 @@
* Trim down Active Model API by removing `valid?` and `errors.full_messages` *José Valim*
-* When `^` or `$` are used in the regular expression provided to `validates_format_of` and the :multiline option is not set to true, an exception will be raised. This is to prevent security vulnerabilities when using `validates_format_of`. The problem is described in detail in the Rails security guide.
+* When `^` or `$` are used in the regular expression provided to `validates_format_of` and the :multiline option is not set to true, an exception will be raised. This is to prevent security vulnerabilities when using `validates_format_of`. The problem is described in detail in the Rails security guide *Jan Berdajs + Egor Homakov*
Please check [3-2-stable](https://github.com/rails/rails/blob/3-2-stable/activemodel/CHANGELOG.md) for previous changes.
diff --git a/activemodel/lib/active_model/attribute_methods.rb b/activemodel/lib/active_model/attribute_methods.rb
index ef04f1fa49..a1d01b2c89 100644
--- a/activemodel/lib/active_model/attribute_methods.rb
+++ b/activemodel/lib/active_model/attribute_methods.rb
@@ -11,7 +11,7 @@ module ActiveModel
# # => ActiveModel::MissingAttributeError: missing attribute: user_id
class MissingAttributeError < NoMethodError
end
- # == Active Model Attribute Methods
+ # == Active \Model Attribute Methods
#
# <tt>ActiveModel::AttributeMethods</tt> provides a way to add prefixes and
# suffixes to your methods as well as handling the creation of Active Record
diff --git a/activemodel/lib/active_model/callbacks.rb b/activemodel/lib/active_model/callbacks.rb
index e442455a53..eab94554cc 100644
--- a/activemodel/lib/active_model/callbacks.rb
+++ b/activemodel/lib/active_model/callbacks.rb
@@ -1,7 +1,7 @@
require 'active_support/callbacks'
module ActiveModel
- # == Active Model Callbacks
+ # == Active \Model \Callbacks
#
# Provides an interface for any class to have Active Record like callbacks.
#
diff --git a/activemodel/lib/active_model/conversion.rb b/activemodel/lib/active_model/conversion.rb
index 48c53f0789..42de32e63e 100644
--- a/activemodel/lib/active_model/conversion.rb
+++ b/activemodel/lib/active_model/conversion.rb
@@ -1,7 +1,7 @@
require 'active_support/inflector'
module ActiveModel
- # == Active Model Conversions
+ # == Active \Model Conversions
#
# Handles default conversions: to_model, to_key, to_param, and to_partial_path.
#
diff --git a/activemodel/lib/active_model/dirty.rb b/activemodel/lib/active_model/dirty.rb
index c0b268fa4d..9d09353ef2 100644
--- a/activemodel/lib/active_model/dirty.rb
+++ b/activemodel/lib/active_model/dirty.rb
@@ -3,7 +3,7 @@ require 'active_support/hash_with_indifferent_access'
require 'active_support/core_ext/object/duplicable'
module ActiveModel
- # == Active Model Dirty
+ # == Active \Model \Dirty
#
# Provides a way to track changes in your object in the same way as
# Active Record does.
diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb
index b3b9ba8e56..6510629248 100644
--- a/activemodel/lib/active_model/errors.rb
+++ b/activemodel/lib/active_model/errors.rb
@@ -4,7 +4,7 @@ require 'active_support/core_ext/array/conversions'
require 'active_support/core_ext/string/inflections'
module ActiveModel
- # == Active Model Errors
+ # == Active \Model \Errors
#
# Provides a modified +Hash+ that you can include in your object
# for handling error messages and interacting with Action Pack helpers.
diff --git a/activemodel/lib/active_model/lint.rb b/activemodel/lib/active_model/lint.rb
index 550fa474ea..1be2913f0b 100644
--- a/activemodel/lib/active_model/lint.rb
+++ b/activemodel/lib/active_model/lint.rb
@@ -1,8 +1,8 @@
module ActiveModel
module Lint
- # == Active Model Lint Tests
+ # == Active \Model \Lint \Tests
#
- # You can test whether an object is compliant with the Active Model API by
+ # You can test whether an object is compliant with the Active \Model API by
# including <tt>ActiveModel::Lint::Tests</tt> in your TestCase. It will
# include tests that tell you whether your object is fully compliant,
# or if not, which aspects of the API are not implemented.
@@ -71,7 +71,7 @@ module ActiveModel
assert_boolean model.persisted?, "persisted?"
end
- # == Naming
+ # == \Naming
#
# Model.model_name must return a string with some convenience methods:
# <tt>:human</tt>, <tt>:singular</tt> and <tt>:plural</tt>. Check
@@ -85,7 +85,7 @@ module ActiveModel
assert model_name.plural.respond_to?(:to_str)
end
- # == Errors Testing
+ # == \Errors Testing
#
# Returns an object that implements [](attribute) defined which returns an
# Array of Strings that are the errors for the attribute in question.
diff --git a/activemodel/lib/active_model/model.rb b/activemodel/lib/active_model/model.rb
index 33a530e6bd..62383a03e8 100644
--- a/activemodel/lib/active_model/model.rb
+++ b/activemodel/lib/active_model/model.rb
@@ -1,6 +1,6 @@
module ActiveModel
- # == Active Model Basic Model
+ # == Active \Model Basic \Model
#
# Includes the required interface for an object to interact with
# <tt>ActionPack</tt>, using different <tt>ActiveModel</tt> modules.
diff --git a/activemodel/lib/active_model/naming.rb b/activemodel/lib/active_model/naming.rb
index c0d93e5d53..eb8265d8c6 100644
--- a/activemodel/lib/active_model/naming.rb
+++ b/activemodel/lib/active_model/naming.rb
@@ -195,7 +195,7 @@ module ActiveModel
end
end
- # == Active Model Naming
+ # == Active \Model \Naming
#
# Creates a +model_name+ method on your object.
#
diff --git a/activemodel/lib/active_model/observing.rb b/activemodel/lib/active_model/observing.rb
index 9db7639ea3..9419645e7b 100644
--- a/activemodel/lib/active_model/observing.rb
+++ b/activemodel/lib/active_model/observing.rb
@@ -8,7 +8,7 @@ require 'active_support/core_ext/object/try'
require 'active_support/descendants_tracker'
module ActiveModel
- # == Active Model Observers Activation
+ # == Active \Model Observers Activation
module Observing
extend ActiveSupport::Concern
@@ -229,7 +229,7 @@ module ActiveModel
end
end
- # == Active Model Observers
+ # == Active \Model Observers
#
# Observer classes respond to life cycle callbacks to implement trigger-like
# behavior outside the original class. This is a great way to reduce the
@@ -257,7 +257,7 @@ module ActiveModel
#
# This Observer uses logger to log when specific callbacks are triggered.
#
- # == Observing a class that can't be inferred
+ # == \Observing a class that can't be inferred
#
# Observers will by default be mapped to the class with which they share a
# name. So <tt>CommentObserver</tt> will be tied to observing <tt>Comment</tt>,
diff --git a/activemodel/lib/active_model/railtie.rb b/activemodel/lib/active_model/railtie.rb
index f239758b35..75cde900e3 100644
--- a/activemodel/lib/active_model/railtie.rb
+++ b/activemodel/lib/active_model/railtie.rb
@@ -2,7 +2,7 @@ require "active_model"
require "rails"
module ActiveModel
- class Railtie < Rails::Railtie
+ class Railtie < Rails::Railtie # :nodoc:
config.eager_load_namespaces << ActiveModel
end
-end \ No newline at end of file
+end
diff --git a/activemodel/lib/active_model/serialization.rb b/activemodel/lib/active_model/serialization.rb
index 8a63014ffb..dfd68a90fd 100644
--- a/activemodel/lib/active_model/serialization.rb
+++ b/activemodel/lib/active_model/serialization.rb
@@ -2,7 +2,7 @@ require 'active_support/core_ext/hash/except'
require 'active_support/core_ext/hash/slice'
module ActiveModel
- # == Active Model Serialization
+ # == Active \Model \Serialization
#
# Provides a basic serialization to a serializable_hash for your object.
#
diff --git a/activemodel/lib/active_model/translation.rb b/activemodel/lib/active_model/translation.rb
index 7a86701f73..0d098ba93d 100644
--- a/activemodel/lib/active_model/translation.rb
+++ b/activemodel/lib/active_model/translation.rb
@@ -1,6 +1,6 @@
module ActiveModel
- # == Active Model Translation
+ # == Active \Model \Translation
#
# Provides integration between your object and the Rails internationalization
# (i18n) framework.
diff --git a/activemodel/lib/active_model/validations.rb b/activemodel/lib/active_model/validations.rb
index 243d911f71..81b44f97e0 100644
--- a/activemodel/lib/active_model/validations.rb
+++ b/activemodel/lib/active_model/validations.rb
@@ -3,10 +3,11 @@ require 'active_support/core_ext/hash/keys'
require 'active_support/core_ext/hash/except'
require 'active_model/errors'
require 'active_model/validations/callbacks'
+require 'active_model/validator'
module ActiveModel
- # == Active Model Validations
+ # == Active \Model Validations
#
# Provides a full validation framework to your objects.
#
@@ -233,7 +234,7 @@ module ActiveModel
#
# person = Person.new
# person.valid? # => false
- # person.errors # => #<ActiveModel::Errors:0x007fe603816640 @messages={:name=>["can't be blank"]}>
+ # person.errors # => #<ActiveModel::Errors:0x007fe603816640 @messages={:name=>["can't be blank"]}>
def errors
@errors ||= Errors.new(self)
end
@@ -250,7 +251,7 @@ module ActiveModel
#
# person = Person.new
# person.name = ''
- # person.valid? # => false
+ # person.valid? # => false
# person.name = 'david'
# person.valid? # => true
#
@@ -265,7 +266,7 @@ module ActiveModel
# end
#
# person = Person.new
- # person.valid? # => true
+ # person.valid? # => true
# person.valid?(:new) # => false
def valid?(context = nil)
current_context, self.validation_context = validation_context, context
@@ -287,7 +288,7 @@ module ActiveModel
#
# person = Person.new
# person.name = ''
- # person.invalid? # => true
+ # person.invalid? # => true
# person.name = 'david'
# person.invalid? # => false
#
@@ -302,7 +303,7 @@ module ActiveModel
# end
#
# person = Person.new
- # person.invalid? # => false
+ # person.invalid? # => false
# person.invalid?(:new) # => true
def invalid?(context = nil)
!valid?(context)
diff --git a/activemodel/lib/active_model/validations/acceptance.rb b/activemodel/lib/active_model/validations/acceptance.rb
index 8d5ebf527f..ec7ad4b048 100644
--- a/activemodel/lib/active_model/validations/acceptance.rb
+++ b/activemodel/lib/active_model/validations/acceptance.rb
@@ -1,6 +1,6 @@
module ActiveModel
- # == Active Model Acceptance Validator
+ # == Active \Model Acceptance \Validator
module Validations
class AcceptanceValidator < EachValidator #:nodoc:
def initialize(options)
diff --git a/activemodel/lib/active_model/validations/callbacks.rb b/activemodel/lib/active_model/validations/callbacks.rb
index c153ef4309..a8fb4fdfc2 100644
--- a/activemodel/lib/active_model/validations/callbacks.rb
+++ b/activemodel/lib/active_model/validations/callbacks.rb
@@ -2,7 +2,7 @@ require 'active_support/callbacks'
module ActiveModel
module Validations
- # == Active Model Validation callbacks
+ # == Active \Model Validation Callbacks
#
# Provides an interface for any class to have +before_validation+ and
# +after_validation+ callbacks.
diff --git a/activemodel/lib/active_model/validations/confirmation.rb b/activemodel/lib/active_model/validations/confirmation.rb
index baa034eca6..4071589747 100644
--- a/activemodel/lib/active_model/validations/confirmation.rb
+++ b/activemodel/lib/active_model/validations/confirmation.rb
@@ -1,6 +1,6 @@
module ActiveModel
- # == Active Model Confirmation Validator
+ # == Active \Model Confirmation \Validator
module Validations
class ConfirmationValidator < EachValidator #:nodoc:
def validate_each(record, attribute, value)
diff --git a/activemodel/lib/active_model/validations/exclusion.rb b/activemodel/lib/active_model/validations/exclusion.rb
index 3ec552c372..7a90750c49 100644
--- a/activemodel/lib/active_model/validations/exclusion.rb
+++ b/activemodel/lib/active_model/validations/exclusion.rb
@@ -2,7 +2,7 @@ require "active_model/validations/clusivity"
module ActiveModel
- # == Active Model Exclusion Validator
+ # == Active \Model Exclusion \Validator
module Validations
class ExclusionValidator < EachValidator #:nodoc:
include Clusivity
diff --git a/activemodel/lib/active_model/validations/inclusion.rb b/activemodel/lib/active_model/validations/inclusion.rb
index babc8982da..a333a09976 100644
--- a/activemodel/lib/active_model/validations/inclusion.rb
+++ b/activemodel/lib/active_model/validations/inclusion.rb
@@ -2,7 +2,7 @@ require "active_model/validations/clusivity"
module ActiveModel
- # == Active Model Inclusion Validator
+ # == Active \Model Inclusion \Validator
module Validations
class InclusionValidator < EachValidator #:nodoc:
include Clusivity
diff --git a/activemodel/lib/active_model/validations/length.rb b/activemodel/lib/active_model/validations/length.rb
index e4a1f9e80a..70ef589cd7 100644
--- a/activemodel/lib/active_model/validations/length.rb
+++ b/activemodel/lib/active_model/validations/length.rb
@@ -1,8 +1,8 @@
module ActiveModel
- # == Active Model Length Validator
+ # == Active \Model Length \Validator
module Validations
- class LengthValidator < EachValidator #:nodoc:
+ class LengthValidator < EachValidator # :nodoc:
MESSAGES = { :is => :wrong_length, :minimum => :too_short, :maximum => :too_long }.freeze
CHECKS = { :is => :==, :minimum => :>=, :maximum => :<= }.freeze
@@ -37,7 +37,7 @@ module ActiveModel
value = tokenize(value)
value_length = value.respond_to?(:length) ? value.length : value.to_s.length
errors_options = options.except(*RESERVED_OPTIONS)
-
+
CHECKS.each do |key, validity_check|
next unless check_value = options[key]
next if value_length.send(validity_check, check_value)
diff --git a/activemodel/lib/active_model/validations/numericality.rb b/activemodel/lib/active_model/validations/numericality.rb
index edebca94a8..ffd045a8fb 100644
--- a/activemodel/lib/active_model/validations/numericality.rb
+++ b/activemodel/lib/active_model/validations/numericality.rb
@@ -1,8 +1,8 @@
module ActiveModel
- # == Active Model Numericality Validator
+ # == Active \Model Numericality \Validator
module Validations
- class NumericalityValidator < EachValidator #:nodoc:
+ class NumericalityValidator < EachValidator # :nodoc:
CHECKS = { :greater_than => :>, :greater_than_or_equal_to => :>=,
:equal_to => :==, :less_than => :<, :less_than_or_equal_to => :<=,
:odd => :odd?, :even => :even?, :other_than => :!= }.freeze
diff --git a/activemodel/lib/active_model/validations/presence.rb b/activemodel/lib/active_model/validations/presence.rb
index f159e40858..70247ee4c8 100644
--- a/activemodel/lib/active_model/validations/presence.rb
+++ b/activemodel/lib/active_model/validations/presence.rb
@@ -1,9 +1,9 @@
module ActiveModel
- # == Active Model Presence Validator
+ # == Active \Model Presence \Validator
module Validations
- class PresenceValidator < EachValidator #:nodoc:
+ class PresenceValidator < EachValidator # :nodoc:
def validate(record)
record.errors.add_on_blank(attributes, options)
end
diff --git a/activemodel/lib/active_model/validator.rb b/activemodel/lib/active_model/validator.rb
index 85aec00f25..09da4cc93d 100644
--- a/activemodel/lib/active_model/validator.rb
+++ b/activemodel/lib/active_model/validator.rb
@@ -2,7 +2,7 @@ require "active_support/core_ext/module/anonymous"
module ActiveModel
- # == Active Model Validator
+ # == Active \Model \Validator
#
# A simple base class that can be used along with
# ActiveModel::Validations::ClassMethods.validates_with
diff --git a/activemodel/test/cases/secure_password_test.rb b/activemodel/test/cases/secure_password_test.rb
index 19e74d3cc9..509e2fdbb5 100644
--- a/activemodel/test/cases/secure_password_test.rb
+++ b/activemodel/test/cases/secure_password_test.rb
@@ -55,7 +55,7 @@ class SecurePasswordTest < ActiveModel::TestCase
end
test "User should not be created with blank digest" do
- assert_raise RuntimeError do
+ assert_raise RuntimeError do
@user.run_callbacks :create
end
@user.password = "supersecretpassword"
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 9abfe2e6fd..ffd19a5334 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,5 +1,67 @@
## Rails 4.0.0 (unreleased) ##
+* Add `find_or_create_by`, `find_or_create_by!` and
+ `find_or_initialize_by` methods to `Relation`.
+
+ These are similar to the `first_or_create` family of methods, but
+ the behaviour when a record is created is slightly different:
+
+ User.where(first_name: 'Penélope').first_or_create
+
+ will execute:
+
+ User.where(first_name: 'Penélope').create
+
+ Causing all the `create` callbacks to execute within the context of
+ the scope. This could affect queries that occur within callbacks.
+
+ User.find_or_create_by(first_name: 'Penélope')
+
+ will execute:
+
+ User.create(first_name: 'Penélope')
+
+ Which obviously does not affect the scoping of queries within
+ callbacks.
+
+ The `find_or_create_by` version also reads better, frankly.
+
+ If you need to add extra attributes during create, you can do one of:
+
+ User.create_with(active: true).find_or_create_by(first_name: 'Jon')
+ User.find_or_create_by(first_name: 'Jon') { |u| u.active = true }
+
+ The `first_or_create` family of methods have been nodoc'ed in favour
+ of this API. They may be deprecated in the future but their
+ implementation is very small and it's probably not worth putting users
+ through lots of annoying deprecation warnings.
+
+ *Jon Leighton*
+
+* Fix bug with presence validation of associations. Would incorrectly add duplicated errors
+ when the association was blank. Bug introduced in 1fab518c6a75dac5773654646eb724a59741bc13.
+
+ *Scott Willson*
+
+* Fix bug where sum(expression) returns string '0' for no matching records
+ Fixes #7439
+
+ *Tim Macfarlane*
+
+* PostgreSQL adapter correctly fetches default values when using multiple schemas and domains in a db. Fixes #7914
+
+ *Arturo Pie*
+
+* Learn ActiveRecord::QueryMethods#order work with hash arguments
+
+ When symbol or hash passed we convert it to Arel::Nodes::Ordering.
+ If we pass invalid direction(like name: :DeSc) ActiveRecord::QueryMethods#order will raise an exception
+
+ User.order(:name, email: :desc)
+ # SELECT "users".* FROM "users" ORDER BY "users"."name" ASC, "users"."email" DESC
+
+ *Tima Maslyuchenko*
+
* Rename `ActiveRecord::Fixtures` class to `ActiveRecord::FixtureSet`.
Instances of this class normally hold a collection of fixtures (records)
loaded either from a single YAML file, or from a file and a folder
@@ -50,6 +112,10 @@
app processes (so long as the code in those processes doesn't
contain any references to the removed column).
+ The `partial_updates` configuration option is now renamed to
+ `partial_writes` to reflect the fact that it now impacts both inserts
+ and updates.
+
*Jon Leighton*
* Allow before and after validations to take an array of lifecycle events
@@ -269,6 +335,11 @@
*Ari Pollak*
+* Fix AR#dup to nullify the validation errors in the dup'ed object. Previously the original
+ and the dup'ed object shared the same errors.
+
+ * Christian Seiler*
+
* Raise `ArgumentError` if list of attributes to change is empty in `update_all`.
*Roman Shatsov*
@@ -578,9 +649,9 @@
* `find_or_initialize_by_...` can be rewritten using
`where(...).first_or_initialize`
* `find_or_create_by_...` can be rewritten using
- `where(...).first_or_create`
+ `find_or_create_by(...)` or where(...).first_or_create`
* `find_or_create_by_...!` can be rewritten using
- `where(...).first_or_create!`
+ `find_or_create_by!(...) or `where(...).first_or_create!`
The implementation of the deprecated dynamic finders has been moved
to the `activerecord-deprecated_finders` gem. See below for details.
diff --git a/activerecord/lib/active_record/associations/preloader.rb b/activerecord/lib/active_record/associations/preloader.rb
index ce5bf15f10..c1cd3a4ae3 100644
--- a/activerecord/lib/active_record/associations/preloader.rb
+++ b/activerecord/lib/active_record/associations/preloader.rb
@@ -30,17 +30,21 @@ module ActiveRecord
# option references an association's column), it will fallback to the table
# join strategy.
class Preloader #:nodoc:
- autoload :Association, 'active_record/associations/preloader/association'
- autoload :SingularAssociation, 'active_record/associations/preloader/singular_association'
- autoload :CollectionAssociation, 'active_record/associations/preloader/collection_association'
- autoload :ThroughAssociation, 'active_record/associations/preloader/through_association'
+ extend ActiveSupport::Autoload
- autoload :HasMany, 'active_record/associations/preloader/has_many'
- autoload :HasManyThrough, 'active_record/associations/preloader/has_many_through'
- autoload :HasOne, 'active_record/associations/preloader/has_one'
- autoload :HasOneThrough, 'active_record/associations/preloader/has_one_through'
- autoload :HasAndBelongsToMany, 'active_record/associations/preloader/has_and_belongs_to_many'
- autoload :BelongsTo, 'active_record/associations/preloader/belongs_to'
+ eager_autoload do
+ autoload :Association, 'active_record/associations/preloader/association'
+ autoload :SingularAssociation, 'active_record/associations/preloader/singular_association'
+ autoload :CollectionAssociation, 'active_record/associations/preloader/collection_association'
+ autoload :ThroughAssociation, 'active_record/associations/preloader/through_association'
+
+ autoload :HasMany, 'active_record/associations/preloader/has_many'
+ autoload :HasManyThrough, 'active_record/associations/preloader/has_many_through'
+ autoload :HasOne, 'active_record/associations/preloader/has_one'
+ autoload :HasOneThrough, 'active_record/associations/preloader/has_one_through'
+ autoload :HasAndBelongsToMany, 'active_record/associations/preloader/has_and_belongs_to_many'
+ autoload :BelongsTo, 'active_record/associations/preloader/belongs_to'
+ end
attr_reader :records, :associations, :preload_scope, :model
diff --git a/activerecord/lib/active_record/attribute_assignment.rb b/activerecord/lib/active_record/attribute_assignment.rb
index af13b75a9d..6c5e2ac05d 100644
--- a/activerecord/lib/active_record/attribute_assignment.rb
+++ b/activerecord/lib/active_record/attribute_assignment.rb
@@ -57,9 +57,8 @@ module ActiveRecord
# by calling new on the column type or aggregation type (through composed_of) object with these parameters.
# So having the pairs written_on(1) = "2004", written_on(2) = "6", written_on(3) = "24", will instantiate
# written_on (a date type) with Date.new("2004", "6", "24"). You can also specify a typecast character in the
- # parentheses to have the parameters typecasted before they're used in the constructor. Use i for Fixnum,
- # f for Float, s for String, and a for Array. If all the values for a given attribute are empty, the
- # attribute will be set to +nil+.
+ # parentheses to have the parameters typecasted before they're used in the constructor. Use i for Fixnum and
+ # f for Float. If all the values for a given attribute are empty, the attribute will be set to +nil+.
def assign_multiparameter_attributes(pairs)
execute_callstack_for_multiparameter_attributes(
extract_callstack_for_multiparameter_attributes(pairs)
diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb
index 0aff2562b8..1dd9a3d45d 100644
--- a/activerecord/lib/active_record/attribute_methods.rb
+++ b/activerecord/lib/active_record/attribute_methods.rb
@@ -2,7 +2,7 @@ require 'active_support/core_ext/enumerable'
module ActiveRecord
# = Active Record Attribute Methods
- module AttributeMethods #:nodoc:
+ module AttributeMethods
extend ActiveSupport::Concern
include ActiveModel::AttributeMethods
@@ -20,7 +20,7 @@ module ActiveRecord
module ClassMethods
# Generates all the attribute related methods for columns in the database
# accessors, mutators and query methods.
- def define_attribute_methods
+ def define_attribute_methods # :nodoc:
# Use a mutex; we don't want two thread simaltaneously trying to define
# attribute methods.
@attribute_methods_mutex.synchronize do
@@ -31,15 +31,29 @@ module ActiveRecord
end
end
- def attribute_methods_generated?
+ def attribute_methods_generated? # :nodoc:
@attribute_methods_generated ||= false
end
- def undefine_attribute_methods
+ def undefine_attribute_methods # :nodoc:
super if attribute_methods_generated?
@attribute_methods_generated = false
end
+ # Raises a <tt>ActiveRecord::DangerousAttributeError</tt> exception when an
+ # \Active \Record method is defined in the model, otherwise +false+.
+ #
+ # class Person < ActiveRecord::Base
+ # def save
+ # 'already defined by Active Record'
+ # end
+ # end
+ #
+ # Person.instance_method_already_implemented?(:save)
+ # # => ActiveRecord::DangerousAttributeError: save is defined by ActiveRecord
+ #
+ # Person.instance_method_already_implemented?(:name)
+ # # => false
def instance_method_already_implemented?(method_name)
if dangerous_attribute_method?(method_name)
raise DangerousAttributeError, "#{method_name} is defined by ActiveRecord"
@@ -56,11 +70,11 @@ module ActiveRecord
# A method name is 'dangerous' if it is already defined by Active Record, but
# not by any ancestors. (So 'puts' is not dangerous but 'save' is.)
- def dangerous_attribute_method?(name)
+ def dangerous_attribute_method?(name) # :nodoc:
method_defined_within?(name, Base)
end
- def method_defined_within?(name, klass, sup = klass.superclass)
+ def method_defined_within?(name, klass, sup = klass.superclass) # :nodoc:
if klass.method_defined?(name) || klass.private_method_defined?(name)
if sup.method_defined?(name) || sup.private_method_defined?(name)
klass.instance_method(name).owner != sup.instance_method(name).owner
@@ -72,13 +86,27 @@ module ActiveRecord
end
end
+ # Returns +true+ if +attribute+ is an attribute method and table exists,
+ # +false+ otherwise.
+ #
+ # class Person < ActiveRecord::Base
+ # end
+ #
+ # Person.attribute_method?('name') # => true
+ # Person.attribute_method?(:age=) # => true
+ # Person.attribute_method?(:nothing) # => false
def attribute_method?(attribute)
super || (table_exists? && column_names.include?(attribute.to_s.sub(/=$/, '')))
end
- # Returns an array of column names as strings if it's not
- # an abstract class and table exists.
- # Otherwise it returns an empty array.
+ # Returns an array of column names as strings if it's not an abstract class and
+ # table exists. Otherwise it returns an empty array.
+ #
+ # class Person < ActiveRecord::Base
+ # end
+ #
+ # Person.attribute_names
+ # # => ["id", "created_at", "updated_at", "name", "age"]
def attribute_names
@attribute_names ||= if !abstract_class? && table_exists?
column_names
@@ -90,7 +118,7 @@ module ActiveRecord
# If we haven't generated any methods yet, generate them, then
# see if we've created the method we're looking for.
- def method_missing(method, *args, &block)
+ def method_missing(method, *args, &block) # :nodoc:
unless self.class.attribute_methods_generated?
self.class.define_attribute_methods
@@ -104,7 +132,7 @@ module ActiveRecord
end
end
- def attribute_missing(match, *args, &block)
+ def attribute_missing(match, *args, &block) # :nodoc:
if self.class.columns_hash[match.attr_name]
ActiveSupport::Deprecation.warn(
"The method `#{match.method_name}', matching the attribute `#{match.attr_name}' has " \
@@ -118,22 +146,60 @@ module ActiveRecord
super
end
+ # A Person object with a name attribute can ask <tt>person.respond_to?(:name)</tt>,
+ # <tt>person.respond_to?(:name=)</tt>, and <tt>person.respond_to?(:name?)</tt>
+ # which will all return +true+. It also define the attribute methods if they have
+ # not been generated.
+ #
+ # class Person < ActiveRecord::Base
+ # end
+ #
+ # person = Person.new
+ # person.respond_to(:name) # => true
+ # person.respond_to(:name=) # => true
+ # person.respond_to(:name?) # => true
+ # person.respond_to('age') # => true
+ # person.respond_to('age=') # => true
+ # person.respond_to('age?') # => true
+ # person.respond_to(:nothing) # => false
def respond_to?(name, include_private = false)
self.class.define_attribute_methods unless self.class.attribute_methods_generated?
super
end
- # Returns true if the given attribute is in the attributes hash
+ # Returns +true+ if the given attribute is in the attributes hash, otherwise +false+.
+ #
+ # class Person < ActiveRecord::Base
+ # end
+ #
+ # person = Person.new
+ # person.has_attribute?(:name) # => true
+ # person.has_attribute?('age') # => true
+ # person.has_attribute?(:nothing) # => false
def has_attribute?(attr_name)
@attributes.has_key?(attr_name.to_s)
end
# Returns an array of names for the attributes available on this object.
+ #
+ # class Person < ActiveRecord::Base
+ # end
+ #
+ # person = Person.new
+ # person.attribute_names
+ # # => ["id", "created_at", "updated_at", "name", "age"]
def attribute_names
@attributes.keys
end
# Returns a hash of all the attributes with their names as keys and the values of the attributes as values.
+ #
+ # class Person < ActiveRecord::Base
+ # end
+ #
+ # person = Person.create(name: 'Francesco', age: 22)
+ # person.attributes
+ # # => {"id"=>3, "created_at"=>Sun, 21 Oct 2012 04:53:04, "updated_at"=>Sun, 21 Oct 2012 04:53:04, "name"=>"Francesco", "age"=>22}
def attributes
attribute_names.each_with_object({}) { |name, attrs|
attrs[name] = read_attribute(name)
@@ -146,13 +212,13 @@ module ActiveRecord
# <tt>:db</tt> format. Other attributes return the value of
# <tt>#inspect</tt> without modification.
#
- # person = Person.create!(:name => "David Heinemeier Hansson " * 3)
+ # person = Person.create!(name: 'David Heinemeier Hansson ' * 3)
#
# person.attribute_for_inspect(:name)
- # # => '"David Heinemeier Hansson David Heinemeier Hansson D..."'
+ # # => "\"David Heinemeier Hansson David Heinemeier Hansson D...\""
#
# person.attribute_for_inspect(:created_at)
- # # => '"2009-01-12 04:48:57"'
+ # # => "\"2012-10-22 00:15:07\""
def attribute_for_inspect(attr_name)
value = read_attribute(attr_name)
@@ -165,14 +231,38 @@ module ActiveRecord
end
end
- # Returns true if the specified +attribute+ has been set by the user or by a database load and is neither
- # nil nor empty? (the latter only applies to objects that respond to empty?, most notably Strings).
+ # Returns +true+ if the specified +attribute+ has been set by the user or by a
+ # database load and is neither +nil+ nor <tt>empty?</tt> (the latter only applies
+ # to objects that respond to <tt>empty?</tt>, most notably Strings). Otherwise, +false+.
+ # Note that it always returns +true+ with boolean attributes.
+ #
+ # class Task < ActiveRecord::Base
+ # end
+ #
+ # person = Task.new(title: '', is_done: false)
+ # person.attribute_present?(:title) # => false
+ # person.attribute_present?(:is_done) # => true
+ # person.name = 'Francesco'
+ # person.is_done = true
+ # person.attribute_present?(:title) # => true
+ # person.attribute_present?(:is_done) # => true
def attribute_present?(attribute)
value = read_attribute(attribute)
!value.nil? && !(value.respond_to?(:empty?) && value.empty?)
end
- # Returns the column object for the named attribute.
+ # Returns the column object for the named attribute. Returns +nil+ if the
+ # named attribute not exists.
+ #
+ # class Person < ActiveRecord::Base
+ # end
+ #
+ # person = Person.new
+ # person.column_for_attribute(:name) # the result depends on the ConnectionAdapter
+ # # => #<ActiveRecord::ConnectionAdapters::SQLite3Column:0x007ff4ab083980 @name="name", @sql_type="varchar(255)", @null=true, ...>
+ #
+ # person.column_for_attribute(:nothing)
+ # # => nil
def column_for_attribute(name)
# FIXME: should this return a null object for columns that don't exist?
self.class.columns_hash[name.to_s]
@@ -180,42 +270,57 @@ module ActiveRecord
# Returns the value of the attribute identified by <tt>attr_name</tt> after it has been typecast (for example,
# "2004-12-12" in a data column is cast to a date object, like Date.new(2004, 12, 12)).
- # (Alias for the protected read_attribute method).
+ # (Alias for <tt>read_attribute</tt>).
+ #
+ # class Person < ActiveRecord::Base
+ # end
+ #
+ # person = Person.new(name: 'Francesco', age: '22')
+ # person[:name] # => "Francesco"
+ # person[:age] # => 22
def [](attr_name)
read_attribute(attr_name)
end
# Updates the attribute identified by <tt>attr_name</tt> with the specified +value+.
- # (Alias for the protected write_attribute method).
+ # (Alias for the protected <tt>write_attribute</tt> method).
+ #
+ # class Person < ActiveRecord::Base
+ # end
+ #
+ # person = Person.new
+ # person[:age] = '22'
+ # person[:age] # => 22
+ # person[:age] # => Fixnum
def []=(attr_name, value)
write_attribute(attr_name, value)
end
protected
- def clone_attributes(reader_method = :read_attribute, attributes = {})
+ def clone_attributes(reader_method = :read_attribute, attributes = {}) # :nodoc:
attribute_names.each do |name|
attributes[name] = clone_attribute_value(reader_method, name)
end
attributes
end
- def clone_attribute_value(reader_method, attribute_name)
+ def clone_attribute_value(reader_method, attribute_name) # :nodoc:
value = send(reader_method, attribute_name)
value.duplicable? ? value.clone : value
rescue TypeError, NoMethodError
value
end
- def arel_attributes_with_values_for_create(attribute_names)
+ def arel_attributes_with_values_for_create(attribute_names) # :nodoc:
arel_attributes_with_values(attributes_for_create(attribute_names))
end
- def arel_attributes_with_values_for_update(attribute_names)
+ def arel_attributes_with_values_for_update(attribute_names) # :nodoc:
arel_attributes_with_values(attributes_for_update(attribute_names))
end
- def attribute_method?(attr_name)
+ def attribute_method?(attr_name) # :nodoc:
defined?(@attributes) && @attributes.include?(attr_name)
end
diff --git a/activerecord/lib/active_record/attribute_methods/before_type_cast.rb b/activerecord/lib/active_record/attribute_methods/before_type_cast.rb
index d4f529acbf..faee99ccd1 100644
--- a/activerecord/lib/active_record/attribute_methods/before_type_cast.rb
+++ b/activerecord/lib/active_record/attribute_methods/before_type_cast.rb
@@ -1,5 +1,28 @@
module ActiveRecord
module AttributeMethods
+ # = Active Record Attribute Methods Before Type Cast
+ #
+ # <tt>ActiveRecord::AttributeMethods::BeforeTypeCast</tt> provides a way to
+ # read the value of the attributes before typecasting and deserialization.
+ #
+ # class Task < ActiveRecord::Base
+ # end
+ #
+ # task = Task.new(id: '1', completed_on: '2012-10-21')
+ # task.id # => 1
+ # task.completed_on # => Sun, 21 Oct 2012
+ #
+ # task.attributes_before_type_cast
+ # # => {"id"=>"1", "completed_on"=>"2012-10-21", ... }
+ # task.read_attribute_before_type_cast('id') # => 1
+ # task.read_attribute_before_type_cast('completed_on') # => "2012-10-21"
+ #
+ # In addition to #read_attribute_before_type_cast and #attributes_before_type_cast,
+ # it declares a method for all attributes with the <tt>*_before_type_cast</tt>
+ # suffix.
+ #
+ # task.id_before_type_cast # => "1"
+ # task.completed_on_before_type_cast # => "2012-10-21"
module BeforeTypeCast
extend ActiveSupport::Concern
@@ -7,11 +30,31 @@ module ActiveRecord
attribute_method_suffix "_before_type_cast"
end
+ # Returns the value of the attribute identified by +attr_name+ before
+ # typecasting and deserialization.
+ #
+ # class Task < ActiveRecord::Base
+ # end
+ #
+ # task = Task.new(id: '1', completed_on: '2012-10-21')
+ # task.read_attribute('id') # => 1
+ # task.read_attribute_before_type_cast('id') # => '1'
+ # task.read_attribute('completed_on') # => Sun, 21 Oct 2012
+ # task.read_attribute_before_type_cast('completed_on') # => "2012-10-21"
def read_attribute_before_type_cast(attr_name)
@attributes[attr_name]
end
# Returns a hash of attributes before typecasting and deserialization.
+ #
+ # class Task < ActiveRecord::Base
+ # end
+ #
+ # task = Task.new(title: nil, is_done: true, completed_on: '2012-10-21')
+ # task.attributes
+ # # => {"id"=>nil, "title"=>nil, "is_done"=>true, "completed_on"=>Sun, 21 Oct 2012, "created_at"=>nil, "updated_at"=>nil}
+ # task.attributes_before_type_cast
+ # # => {"id"=>nil, "title"=>nil, "is_done"=>true, "completed_on"=>"2012-10-21", "created_at"=>nil, "updated_at"=>nil}
def attributes_before_type_cast
@attributes
end
diff --git a/activerecord/lib/active_record/attribute_methods/dirty.rb b/activerecord/lib/active_record/attribute_methods/dirty.rb
index 7a5bb9e863..59f209cec8 100644
--- a/activerecord/lib/active_record/attribute_methods/dirty.rb
+++ b/activerecord/lib/active_record/attribute_methods/dirty.rb
@@ -1,9 +1,10 @@
require 'active_support/core_ext/module/attribute_accessors'
+require 'active_support/deprecation'
module ActiveRecord
ActiveSupport.on_load(:active_record_config) do
- mattr_accessor :partial_updates, instance_accessor: false
- self.partial_updates = true
+ mattr_accessor :partial_writes, instance_accessor: false
+ self.partial_writes = true
end
module AttributeMethods
@@ -17,7 +18,18 @@ module ActiveRecord
raise "You cannot include Dirty after Timestamp"
end
- config_attribute :partial_updates
+ config_attribute :partial_writes
+
+ def self.partial_updates=(v); self.partial_writes = v; end
+ def self.partial_updates?; partial_writes?; end
+ def self.partial_updates; partial_writes; end
+
+ ActiveSupport::Deprecation.deprecate_methods(
+ singleton_class,
+ :partial_updates= => :partial_writes=,
+ :partial_updates? => :partial_writes?,
+ :partial_updates => :partial_writes
+ )
end
# Attempts to +save+ the record and clears changed attributes if successful.
@@ -64,26 +76,16 @@ module ActiveRecord
end
def update(*)
- partial_updates? ? super(keys_for_partial_update) : super
+ partial_writes? ? super(keys_for_partial_write) : super
end
def create(*)
- if partial_updates?
- keys = keys_for_partial_update
-
- # This is an extremely bloody annoying necessity to work around mysql being crap.
- # See test_mysql_text_not_null_defaults
- keys.concat self.class.columns.select(&:explicit_default?).map(&:name)
-
- super keys
- else
- super
- end
+ partial_writes? ? super(keys_for_partial_write) : super
end
# Serialized attributes should always be written in case they've been
# changed in place.
- def keys_for_partial_update
+ def keys_for_partial_write
changed | (attributes.keys & self.class.serialized_attributes.keys)
end
diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb
index 6213b5dcd5..46fd6ebfb3 100644
--- a/activerecord/lib/active_record/attribute_methods/read.rb
+++ b/activerecord/lib/active_record/attribute_methods/read.rb
@@ -35,21 +35,36 @@ module ActiveRecord
protected
- # We want to generate the methods via module_eval rather than define_method,
- # because define_method is slower on dispatch and uses more memory (because it
- # creates a closure).
+ # We want to generate the methods via module_eval rather than
+ # define_method, because define_method is slower on dispatch and
+ # uses more memory (because it creates a closure).
#
- # But sometimes the database might return columns with characters that are not
- # allowed in normal method names (like 'my_column(omg)'. So to work around this
- # we first define with the __temp__ identifier, and then use alias method to
- # rename it to what we want.
- def define_method_attribute(attr_name)
+ # But sometimes the database might return columns with
+ # characters that are not allowed in normal method names (like
+ # 'my_column(omg)'. So to work around this we first define with
+ # the __temp__ identifier, and then use alias method to rename
+ # it to what we want.
+ #
+ # We are also defining a constant to hold the frozen string of
+ # the attribute name. Using a constant means that we do not have
+ # to allocate an object on each call to the attribute method.
+ # Making it frozen means that it doesn't get duped when used to
+ # key the @attributes_cache in read_attribute.
+ def define_method_attribute(name)
+ safe_name = name.unpack('h*').first
generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
- def __temp__
- read_attribute(:'#{attr_name}') { |n| missing_attribute(n, caller) }
+ module AttrNames
+ unless defined? ATTR_#{safe_name}
+ ATTR_#{safe_name} = #{name.inspect}.freeze
+ end
+ end
+
+ def __temp__#{safe_name}
+ read_attribute(AttrNames::ATTR_#{safe_name}) { |n| missing_attribute(n, caller) }
end
- alias_method '#{attr_name}', :__temp__
- undef_method :__temp__
+
+ alias_method #{name.inspect}, :__temp__#{safe_name}
+ undef_method :__temp__#{safe_name}
STR
end
@@ -70,17 +85,13 @@ module ActiveRecord
# it has been typecast (for example, "2004-12-12" in a data column is cast
# to a date object, like Date.new(2004, 12, 12)).
def read_attribute(attr_name)
- return unless attr_name
- name_sym = attr_name.to_sym
-
# If it's cached, just return it
# We use #[] first as a perf optimization for non-nil values. See https://gist.github.com/3552829.
- @attributes_cache[name_sym] || @attributes_cache.fetch(name_sym) {
- name = attr_name.to_s
-
+ name = attr_name.to_s
+ @attributes_cache[name] || @attributes_cache.fetch(name) {
column = @columns_hash.fetch(name) {
return @attributes.fetch(name) {
- if name_sym == :id && self.class.primary_key != name
+ if name == 'id' && self.class.primary_key != name
read_attribute(self.class.primary_key)
end
}
@@ -91,7 +102,7 @@ module ActiveRecord
}
if self.class.cache_attribute?(name)
- @attributes_cache[name_sym] = column.type_cast(value)
+ @attributes_cache[name] = column.type_cast(value)
else
column.type_cast value
end
diff --git a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
index b9a69cdb0a..f36a5806a9 100644
--- a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
+++ b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
@@ -50,7 +50,7 @@ module ActiveRecord
if (rounded_value != rounded_time) || (!rounded_value && original_time)
write_attribute("#{attr_name}", original_time)
#{attr_name}_will_change!
- @attributes_cache[:"#{attr_name}"] = zoned_time
+ @attributes_cache["#{attr_name}"] = zoned_time
end
end
EOV
diff --git a/activerecord/lib/active_record/attribute_methods/write.rb b/activerecord/lib/active_record/attribute_methods/write.rb
index 6eb9e25fd9..cd33494cc3 100644
--- a/activerecord/lib/active_record/attribute_methods/write.rb
+++ b/activerecord/lib/active_record/attribute_methods/write.rb
@@ -9,15 +9,19 @@ module ActiveRecord
module ClassMethods
protected
- def define_method_attribute=(attr_name)
- if attr_name =~ ActiveModel::AttributeMethods::NAME_COMPILABLE_REGEXP
- generated_attribute_methods.module_eval("def #{attr_name}=(new_value); write_attribute('#{attr_name}', new_value); end", __FILE__, __LINE__)
- else
- generated_attribute_methods.send(:define_method, "#{attr_name}=") do |new_value|
- write_attribute(attr_name, new_value)
- end
+
+ # See define_method_attribute in read.rb for an explanation of
+ # this code.
+ def define_method_attribute=(name)
+ safe_name = name.unpack('h*').first
+ generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
+ def __temp__#{safe_name}=(value)
+ write_attribute(AttrNames::ATTR_#{safe_name}, value)
end
- end
+ alias_method #{(name + '=').inspect}, :__temp__#{safe_name}=
+ undef_method :__temp__#{safe_name}=
+ STR
+ end
end
# Updates the attribute identified by <tt>attr_name</tt> with the
@@ -26,13 +30,13 @@ module ActiveRecord
def write_attribute(attr_name, value)
attr_name = attr_name.to_s
attr_name = self.class.primary_key if attr_name == 'id' && self.class.primary_key
- @attributes_cache.delete(attr_name.to_sym)
+ @attributes_cache.delete(attr_name)
column = column_for_attribute(attr_name)
# If we're dealing with a binary column, write the data to the cache
# so we don't attempt to typecast multiple times.
if column && column.binary?
- @attributes_cache[attr_name.to_sym] = value
+ @attributes_cache[attr_name] = value
end
if column || @attributes.has_key?(attr_name)
diff --git a/activerecord/lib/active_record/callbacks.rb b/activerecord/lib/active_record/callbacks.rb
index 188a06e448..725bfffef2 100644
--- a/activerecord/lib/active_record/callbacks.rb
+++ b/activerecord/lib/active_record/callbacks.rb
@@ -203,10 +203,9 @@ module ActiveRecord
# == Ordering callbacks
#
# Sometimes the code needs that the callbacks execute in a specific order. For example, a +before_destroy+
- # callback (log_children in this case) should be executed before the children get destroyed by the
- # dependent destroy option.
+ # callback (+log_children+ in this case) should be executed before the children get destroyed by the +dependent: destroy+ option.
#
- # Let's take at the code below:
+ # Let's look at the code below:
#
# class Topic < ActiveRecord::Base
# has_many :children, dependent: destroy
@@ -219,9 +218,8 @@ module ActiveRecord
# end
# end
#
- # In this case the problem is that when the +before_destroy+ is executed, the children are not available
- # because the dependent destroy gets executed first. To solve this issue it is possible to use the
- # +prepend+ option on the +before_destroy+ callback.
+ # In this case, the problem is that when the +before_destroy+ callback is executed, the children are not available
+ # because the +destroy+ callback gets executed first. You can use the +prepend+ option on the +before_destroy+ callback to avoid this.
#
# class Topic < ActiveRecord::Base
# has_many :children, dependent: destroy
@@ -234,8 +232,7 @@ module ActiveRecord
# end
# end
#
- # This way, the +before_destroy+ gets executed before the <tt>dependent: destroy</tt> is called, and
- # the data is still available.
+ # This way, the +before_destroy+ gets executed before the <tt>dependent: destroy</tt> is called, and the data is still available.
#
# == Transactions
#
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 8c83c4f5db..b0e7bd7e82 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -4,17 +4,19 @@ module ActiveRecord
module ConnectionAdapters
class AbstractMysqlAdapter < AbstractAdapter
class Column < ConnectionAdapters::Column # :nodoc:
- attr_reader :collation
+ attr_reader :collation, :strict
- def initialize(name, default, sql_type = nil, null = true, collation = nil)
- super(name, default, sql_type, null)
+ def initialize(name, default, sql_type = nil, null = true, collation = nil, strict = false)
+ @strict = strict
@collation = collation
+
+ super(name, default, sql_type, null)
end
def extract_default(default)
if sql_type =~ /blob/i || type == :text
if default.blank?
- return null ? nil : ''
+ null || strict ? nil : ''
else
raise ArgumentError, "#{type} columns cannot have a default value: #{default.inspect}"
end
@@ -30,10 +32,6 @@ module ActiveRecord
super
end
- def explicit_default?
- !null && (sql_type =~ /blob/i || type == :text)
- end
-
# Must return the relevant concrete adapter
def adapter
raise NotImplementedError
@@ -571,6 +569,10 @@ module ActiveRecord
where_sql
end
+ def strict_mode?
+ @config.fetch(:strict, true)
+ end
+
protected
# MySQL is too stupid to create a temporary table for use subquery, so we have
diff --git a/activerecord/lib/active_record/connection_adapters/column.rb b/activerecord/lib/active_record/connection_adapters/column.rb
index 2028abf6f0..816b5e17c1 100644
--- a/activerecord/lib/active_record/connection_adapters/column.rb
+++ b/activerecord/lib/active_record/connection_adapters/column.rb
@@ -53,10 +53,6 @@ module ActiveRecord
!default.nil?
end
- def explicit_default?
- false
- end
-
# Returns the Ruby class that corresponds to the abstract data type.
def klass
case type
diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
index 328d080687..879eec7fcf 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
@@ -53,7 +53,7 @@ module ActiveRecord
end
def new_column(field, default, type, null, collation) # :nodoc:
- Column.new(field, default, type, null, collation)
+ Column.new(field, default, type, null, collation, strict_mode?)
end
def error_number(exception)
@@ -259,9 +259,7 @@ module ActiveRecord
# Make MySQL reject illegal values rather than truncating or
# blanking them. See
# http://dev.mysql.com/doc/refman/5.5/en/server-sql-mode.html#sqlmode_strict_all_tables
- if @config.fetch(:strict, true)
- variable_assignments << "SQL_MODE='STRICT_ALL_TABLES'"
- end
+ variable_assignments << "SQL_MODE='STRICT_ALL_TABLES'" if strict_mode?
encoding = @config[:encoding]
diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
index 0b936bbf39..76667616a1 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -150,7 +150,7 @@ module ActiveRecord
end
def new_column(field, default, type, null, collation) # :nodoc:
- Column.new(field, default, type, null, collation)
+ Column.new(field, default, type, null, collation, strict_mode?)
end
def error_number(exception) # :nodoc:
@@ -546,9 +546,7 @@ module ActiveRecord
# Make MySQL reject illegal values rather than truncating or
# blanking them. See
# http://dev.mysql.com/doc/refman/5.5/en/server-sql-mode.html#sqlmode_strict_all_tables
- if @config.fetch(:strict, true)
- execute("SET SQL_MODE='STRICT_ALL_TABLES'", :skip_logging)
- end
+ execute("SET SQL_MODE='STRICT_ALL_TABLES'", :skip_logging) if strict_mode?
end
def select(sql, name = nil, binds = [])
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
index 37d43d891d..9d3fa18e3a 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
@@ -90,7 +90,7 @@ module ActiveRecord
else super(value, column)
end
when IPAddr
- return super(value, column) unless ['inet','cidr'].includes? column.sql_type
+ return super(value, column) unless ['inet','cidr'].include? column.sql_type
PostgreSQLColumn.cidr_to_string(value)
else
super(value, column)
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
index 2264595751..7cad8f94cf 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
@@ -280,16 +280,13 @@ module ActiveRecord
end_sql
if result.nil? or result.empty?
- # If that fails, try parsing the primary key's default value.
- # Support the 7.x and 8.0 nextval('foo'::text) as well as
- # the 8.1+ nextval('foo'::regclass).
result = query(<<-end_sql, 'SCHEMA')[0]
SELECT attr.attname,
CASE
- WHEN split_part(def.adsrc, '''', 2) ~ '.' THEN
- substr(split_part(def.adsrc, '''', 2),
- strpos(split_part(def.adsrc, '''', 2), '.')+1)
- ELSE split_part(def.adsrc, '''', 2)
+ WHEN split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2) ~ '.' THEN
+ substr(split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2),
+ strpos(split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2), '.')+1)
+ ELSE split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2)
END
FROM pg_class t
JOIN pg_attribute attr ON (t.oid = attrelid)
@@ -297,7 +294,7 @@ module ActiveRecord
JOIN pg_constraint cons ON (conrelid = adrelid AND adnum = conkey[1])
WHERE t.oid = '#{quote_table_name(table)}'::regclass
AND cons.contype = 'p'
- AND def.adsrc ~* 'nextval'
+ AND pg_get_expr(def.adbin, def.adrelid) ~* 'nextval'
end_sql
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index bd375ad15a..e18464fa35 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -78,11 +78,8 @@ module ActiveRecord
when /\A\(?(-?\d+(\.\d*)?\)?)\z/
$1
# Character types
- when /\A'(.*)'::(?:character varying|bpchar|text)\z/m
+ when /\A\(?'(.*)'::.*\b(?:character varying|bpchar|text)\z/m
$1
- # Character types (8.1 formatting)
- when /\AE'(.*)'::(?:character varying|bpchar|text)\z/m
- $1.gsub(/\\(\d\d\d)/) { $1.oct.chr }
# Binary data types
when /\A'(.*)'::bytea\z/m
$1
@@ -763,7 +760,8 @@ module ActiveRecord
# - ::regclass is a function that gives the id for a table name
def column_definitions(table_name) #:nodoc:
exec_query(<<-end_sql, 'SCHEMA').rows
- SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull, a.atttypid, a.atttypmod
+ SELECT a.attname, format_type(a.atttypid, a.atttypmod),
+ pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod
FROM pg_attribute a LEFT JOIN pg_attrdef d
ON a.attrelid = d.adrelid AND a.attnum = d.adnum
WHERE a.attrelid = '#{quote_table_name(table_name)}'::regclass
diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb
index 899e89a6f5..7f1d62af39 100644
--- a/activerecord/lib/active_record/fixtures.rb
+++ b/activerecord/lib/active_record/fixtures.rb
@@ -657,7 +657,8 @@ module ActiveRecord
#--
# Deprecate 'Fixtures' in favor of 'FixtureSet'.
#++
- Fixtures = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('ActiveRecord::Fixtures', '::ActiveRecord::FixtureSet')
+ # :nodoc:
+ Fixtures = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('ActiveRecord::Fixtures', 'ActiveRecord::FixtureSet')
class Fixture #:nodoc:
include Enumerable
diff --git a/activerecord/lib/active_record/locale/en.yml b/activerecord/lib/active_record/locale/en.yml
index 896132d566..b1fbd38622 100644
--- a/activerecord/lib/active_record/locale/en.yml
+++ b/activerecord/lib/active_record/locale/en.yml
@@ -4,11 +4,15 @@ en:
#created_at: "Created at"
#updated_at: "Updated at"
+ # Default error messages
+ errors:
+ messages:
+ taken: "has already been taken"
+
# Active Record models configuration
activerecord:
errors:
messages:
- taken: "has already been taken"
record_invalid: "Validation failed: %{errors}"
restrict_dependent_destroy:
one: "Cannot delete record because a dependent %{record} exists"
diff --git a/activerecord/lib/active_record/querying.rb b/activerecord/lib/active_record/querying.rb
index 13e09eda53..45f6a78428 100644
--- a/activerecord/lib/active_record/querying.rb
+++ b/activerecord/lib/active_record/querying.rb
@@ -3,6 +3,7 @@ module ActiveRecord
module Querying
delegate :find, :take, :take!, :first, :first!, :last, :last!, :exists?, :any?, :many?, :to => :all
delegate :first_or_create, :first_or_create!, :first_or_initialize, :to => :all
+ delegate :find_or_create_by, :find_or_create_by!, :find_or_initialize_by, :to => :all
delegate :find_by, :find_by!, :to => :all
delegate :destroy, :destroy_all, :delete, :delete_all, :update, :update_all, :to => :all
delegate :find_each, :find_in_batches, :to => :all
diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake
index 69a9526fcc..0a9caa25b2 100644
--- a/activerecord/lib/active_record/railties/databases.rake
+++ b/activerecord/lib/active_record/railties/databases.rake
@@ -307,7 +307,7 @@ db_namespace = namespace :db do
# desc "Recreate the databases from the structure.sql file"
task :load => [:environment, :load_config] do
- current_config = ActiveRecord::Tasks::DatabaseTasks.current_config(:env => (ENV['RAILS_ENV'] || 'test'))
+ current_config = ActiveRecord::Tasks::DatabaseTasks.current_config
filename = ENV['DB_STRUCTURE'] || File.join(Rails.root, "db", "structure.sql")
case current_config['adapter']
when /mysql/, /postgresql/, /sqlite/
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index ed80422336..2e2286e4fd 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -91,8 +91,10 @@ module ActiveRecord
end
def initialize_copy(other)
- @values = @values.dup
- @values[:bind] = @values[:bind].dup if @values[:bind]
+ # This method is a hot spot, so for now, use Hash[] to dup the hash.
+ # https://bugs.ruby-lang.org/issues/7166
+ @values = Hash[@values]
+ @values[:bind] = @values[:bind].dup if @values.key? :bind
reset
end
@@ -127,46 +129,53 @@ module ActiveRecord
scoping { @klass.create!(*args, &block) }
end
- # Tries to load the first record; if it fails, then <tt>create</tt> is called with the same arguments as this method.
- #
- # Expects arguments in the same format as +Base.create+.
+ def first_or_create(attributes = nil, &block) # :nodoc:
+ first || create(attributes, &block)
+ end
+
+ def first_or_create!(attributes = nil, &block) # :nodoc:
+ first || create!(attributes, &block)
+ end
+
+ def first_or_initialize(attributes = nil, &block) # :nodoc:
+ first || new(attributes, &block)
+ end
+
+ # Finds the first record with the given attributes, or creates a record with the attributes
+ # if one is not found.
#
# ==== Examples
# # Find the first user named Penélope or create a new one.
- # User.where(:first_name => 'Penélope').first_or_create
+ # User.find_or_create_by(first_name: 'Penélope')
# # => <User id: 1, first_name: 'Penélope', last_name: nil>
#
# # Find the first user named Penélope or create a new one.
# # We already have one so the existing record will be returned.
- # User.where(:first_name => 'Penélope').first_or_create
+ # User.find_or_create_by(first_name: 'Penélope')
# # => <User id: 1, first_name: 'Penélope', last_name: nil>
#
# # Find the first user named Scarlett or create a new one with a particular last name.
- # User.where(:first_name => 'Scarlett').first_or_create(:last_name => 'Johansson')
+ # User.create_with(last_name: 'Johansson').find_or_create_by(first_name: 'Scarlett')
# # => <User id: 2, first_name: 'Scarlett', last_name: 'Johansson'>
#
# # Find the first user named Scarlett or create a new one with a different last name.
# # We already have one so the existing record will be returned.
- # User.where(:first_name => 'Scarlett').first_or_create do |user|
+ # User.find_or_create_by(first_name: 'Scarlett') do |user|
# user.last_name = "O'Hara"
# end
# # => <User id: 2, first_name: 'Scarlett', last_name: 'Johansson'>
- def first_or_create(attributes = nil, &block)
- first || create(attributes, &block)
+ def find_or_create_by(attributes, &block)
+ find_by(attributes) || create(attributes, &block)
end
- # Like <tt>first_or_create</tt> but calls <tt>create!</tt> so an exception is raised if the created record is invalid.
- #
- # Expects arguments in the same format as <tt>Base.create!</tt>.
- def first_or_create!(attributes = nil, &block)
- first || create!(attributes, &block)
+ # Like <tt>find_or_create_by</tt>, but calls <tt>create!</tt> so an exception is raised if the created record is invalid.
+ def find_or_create_by!(attributes, &block)
+ find_by(attributes) || create!(attributes, &block)
end
- # Like <tt>first_or_create</tt> but calls <tt>new</tt> instead of <tt>create</tt>.
- #
- # Expects arguments in the same format as <tt>Base.new</tt>.
- def first_or_initialize(attributes = nil, &block)
- first || new(attributes, &block)
+ # Like <tt>find_or_create_by</tt>, but calls <tt>new</tt> instead of <tt>create</tt>.
+ def find_or_initialize_by(attributes, &block)
+ find_by(attributes) || new(attributes, &block)
end
# Runs EXPLAIN on the query or queries triggered by this relation and
@@ -540,7 +549,7 @@ module ActiveRecord
end
def values
- @values.dup
+ Hash[@values]
end
def inspect
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index 7c43d844d0..a7d2f4bd24 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -343,13 +343,13 @@ module ActiveRecord
def column_for(field)
field_name = field.respond_to?(:name) ? field.name.to_s : field.to_s.split('.').last
- @klass.columns.detect { |c| c.name.to_s == field_name }
+ @klass.columns_hash[field_name]
end
def type_cast_calculated_value(value, column, operation = nil)
case operation
when 'count' then value.to_i
- when 'sum' then type_cast_using_column(value || '0', column)
+ when 'sum' then type_cast_using_column(value || 0, column)
when 'average' then value.respond_to?(:to_d) ? value.to_d : value
else type_cast_using_column(value, column)
end
diff --git a/activerecord/lib/active_record/relation/merger.rb b/activerecord/lib/active_record/relation/merger.rb
index e5b50673da..59226d316e 100644
--- a/activerecord/lib/active_record/relation/merger.rb
+++ b/activerecord/lib/active_record/relation/merger.rb
@@ -22,7 +22,17 @@ module ActiveRecord
# the values.
def other
other = Relation.new(relation.klass, relation.table)
- hash.each { |k, v| other.send("#{k}!", v) }
+ hash.each { |k, v|
+ if k == :joins
+ if Hash === v
+ other.joins!(v)
+ else
+ other.joins!(*v)
+ end
+ else
+ other.send("#{k}!", v)
+ end
+ }
other
end
end
@@ -39,16 +49,18 @@ module ActiveRecord
@values = other.values
end
+ NORMAL_VALUES = Relation::SINGLE_VALUE_METHODS +
+ Relation::MULTI_VALUE_METHODS -
+ [:where, :order, :bind, :reverse_order, :lock, :create_with, :reordering, :from] # :nodoc:
+
def normal_values
- Relation::SINGLE_VALUE_METHODS +
- Relation::MULTI_VALUE_METHODS -
- [:where, :order, :bind, :reverse_order, :lock, :create_with, :reordering, :from]
+ NORMAL_VALUES
end
def merge
normal_values.each do |name|
value = values[name]
- relation.send("#{name}!", value) unless value.blank?
+ relation.send("#{name}!", *value) unless value.blank?
end
merge_multi_values
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index 3c59bd8a68..14bcb337e9 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -202,6 +202,15 @@ module ActiveRecord
#
# User.order('name DESC, email')
# => SELECT "users".* FROM "users" ORDER BY name DESC, email
+ #
+ # User.order(:name)
+ # => SELECT "users".* FROM "users" ORDER BY "users"."name" ASC
+ #
+ # User.order(email: :desc)
+ # => SELECT "users".* FROM "users" ORDER BY "users"."email" DESC
+ #
+ # User.order(:name, email: :desc)
+ # => SELECT "users".* FROM "users" ORDER BY "users"."name" ASC, "users"."email" DESC
def order(*args)
args.blank? ? self : spawn.order!(*args)
end
@@ -210,6 +219,8 @@ module ActiveRecord
def order!(*args)
args.flatten!
+ validate_order_args args
+
references = args.reject { |arg| Arel::Node === arg }
references.map! { |arg| arg =~ /^([a-zA-Z]\w*)\.(\w+)/ && $1 }.compact!
references!(references) if references.any?
@@ -235,6 +246,8 @@ module ActiveRecord
def reorder!(*args)
args.flatten!
+ validate_order_args args
+
self.reordering_value = true
self.order_values = args
self
@@ -245,13 +258,11 @@ module ActiveRecord
# User.joins(:posts)
# => SELECT "users".* FROM "users" INNER JOIN "posts" ON "posts"."user_id" = "users"."id"
def joins(*args)
- args.compact.blank? ? self : spawn.joins!(*args)
+ args.compact.blank? ? self : spawn.joins!(*args.flatten)
end
# Like #joins, but modifies relation in place.
def joins!(*args)
- args.flatten!
-
self.joins_values += args
self
end
@@ -658,9 +669,7 @@ module ActiveRecord
arel.group(*group_values.uniq.reject{|g| g.blank?}) unless group_values.empty?
- order = order_values
- order = reverse_sql_order(order) if reverse_order_value
- arel.order(*order.uniq.reject{|o| o.blank?}) unless order.empty?
+ build_order(arel)
build_select(arel, select_values.uniq)
@@ -729,22 +738,22 @@ module ActiveRecord
buckets = joins.group_by do |join|
case join
when String
- 'string_join'
+ :string_join
when Hash, Symbol, Array
- 'association_join'
+ :association_join
when ActiveRecord::Associations::JoinDependency::JoinAssociation
- 'stashed_join'
+ :stashed_join
when Arel::Nodes::Join
- 'join_node'
+ :join_node
else
raise 'unknown class: %s' % join.class.name
end
end
- association_joins = buckets['association_join'] || []
- stashed_association_joins = buckets['stashed_join'] || []
- join_nodes = (buckets['join_node'] || []).uniq
- string_joins = (buckets['string_join'] || []).map { |x|
+ association_joins = buckets[:association_join] || []
+ stashed_association_joins = buckets[:stashed_join] || []
+ join_nodes = (buckets[:join_node] || []).uniq
+ string_joins = (buckets[:string_join] || []).map { |x|
x.strip
}.uniq
@@ -786,11 +795,17 @@ module ActiveRecord
case o
when Arel::Nodes::Ordering
o.reverse
- when String, Symbol
+ when String
o.to_s.split(',').collect do |s|
s.strip!
s.gsub!(/\sasc\Z/i, ' DESC') || s.gsub!(/\sdesc\Z/i, ' ASC') || s.concat(' DESC')
end
+ when Symbol
+ { o => :desc }
+ when Hash
+ o.each_with_object({}) do |(field, dir), memo|
+ memo[field] = (dir == :asc ? :desc : :asc )
+ end
else
o
end
@@ -801,5 +816,31 @@ module ActiveRecord
o.is_a?(Array) && o.all?{|obj| obj.is_a?(String)}
end
+ def build_order(arel)
+ orders = order_values
+ orders = reverse_sql_order(orders) if reverse_order_value
+
+ orders = orders.uniq.reject(&:blank?).map do |order|
+ case order
+ when Symbol
+ table[order].asc
+ when Hash
+ order.map { |field, dir| table[field].send(dir) }
+ else
+ order
+ end
+ end.flatten
+
+ arel.order(*orders) unless orders.empty?
+ end
+
+ def validate_order_args(args)
+ args.select { |a| Hash === a }.each do |h|
+ unless (h.values - [:asc, :desc]).empty?
+ raise ArgumentError, 'Direction should be :asc or :desc'
+ end
+ end
+ end
+
end
end
diff --git a/activerecord/lib/active_record/timestamp.rb b/activerecord/lib/active_record/timestamp.rb
index bf95ccb298..ec4588f601 100644
--- a/activerecord/lib/active_record/timestamp.rb
+++ b/activerecord/lib/active_record/timestamp.rb
@@ -42,6 +42,7 @@ module ActiveRecord
def initialize_dup(other) # :nodoc:
clear_timestamp_attributes
+ super
end
private
@@ -74,7 +75,7 @@ module ActiveRecord
end
def should_record_timestamps?
- self.record_timestamps && (!partial_updates? || changed? || (attributes.keys & self.class.serialized_attributes.keys).present?)
+ self.record_timestamps && (!partial_writes? || changed? || (attributes.keys & self.class.serialized_attributes.keys).present?)
end
def timestamp_attributes_for_create_in_model
diff --git a/activerecord/lib/active_record/validations/presence.rb b/activerecord/lib/active_record/validations/presence.rb
index 81a3521d24..6b14c39686 100644
--- a/activerecord/lib/active_record/validations/presence.rb
+++ b/activerecord/lib/active_record/validations/presence.rb
@@ -5,8 +5,10 @@ module ActiveRecord
super
attributes.each do |attribute|
next unless record.class.reflect_on_association(attribute)
- value = record.send(attribute)
- if Array(value).all? { |r| r.marked_for_destruction? }
+ associated_records = Array(record.send(attribute))
+
+ # Superclass validates presence. Ensure present records aren't about to be destroyed.
+ if associated_records.present? && associated_records.all? { |r| r.marked_for_destruction? }
record.errors.add(attribute, :blank, options)
end
end
diff --git a/activerecord/lib/active_record/validations/uniqueness.rb b/activerecord/lib/active_record/validations/uniqueness.rb
index 5dece1cb36..5fa6a0b892 100644
--- a/activerecord/lib/active_record/validations/uniqueness.rb
+++ b/activerecord/lib/active_record/validations/uniqueness.rb
@@ -26,11 +26,12 @@ module ActiveRecord
relation = relation.and(table[finder_class.primary_key.to_sym].not_eq(record.send(:id))) if record.persisted?
Array(options[:scope]).each do |scope_item|
- scope_value = record.read_attribute(scope_item)
reflection = record.class.reflect_on_association(scope_item)
if reflection
scope_value = record.send(reflection.foreign_key)
scope_item = reflection.foreign_key
+ else
+ scope_value = record.read_attribute(scope_item)
end
relation = relation.and(table[scope_item].eq(scope_value))
end
diff --git a/activerecord/lib/rails/generators/active_record.rb b/activerecord/lib/rails/generators/active_record.rb
index 297cd094c2..c8aa37f275 100644
--- a/activerecord/lib/rails/generators/active_record.rb
+++ b/activerecord/lib/rails/generators/active_record.rb
@@ -4,8 +4,8 @@ require 'rails/generators/active_model'
require 'active_record'
module ActiveRecord
- module Generators
- class Base < Rails::Generators::NamedBase #:nodoc:
+ module Generators # :nodoc:
+ class Base < Rails::Generators::NamedBase # :nodoc:
include Rails::Generators::Migration
# Set the current directory as base for the inherited generators.
@@ -14,7 +14,7 @@ module ActiveRecord
end
# Implement the required interface for Rails::Generators::Migration.
- def self.next_migration_number(dirname) #:nodoc:
+ def self.next_migration_number(dirname)
next_migration_number = current_migration_number(dirname) + 1
ActiveRecord::Migration.next_migration_number(next_migration_number)
end
diff --git a/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb b/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb
index a3c274d9b9..5f1dbe36d6 100644
--- a/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb
+++ b/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb
@@ -1,8 +1,8 @@
require 'rails/generators/active_record'
module ActiveRecord
- module Generators
- class MigrationGenerator < Base
+ module Generators # :nodoc:
+ class MigrationGenerator < Base # :nodoc:
argument :attributes, :type => :array, :default => [], :banner => "field[:type][:index] field[:type][:index]"
def create_migration_file
@@ -42,7 +42,7 @@ module ActiveRecord
attribute.name.singularize.foreign_key
end.to_sym
end
-
+
private
def validate_file_name!
diff --git a/activerecord/lib/rails/generators/active_record/model/model_generator.rb b/activerecord/lib/rails/generators/active_record/model/model_generator.rb
index 8e6ef20285..5f36181694 100644
--- a/activerecord/lib/rails/generators/active_record/model/model_generator.rb
+++ b/activerecord/lib/rails/generators/active_record/model/model_generator.rb
@@ -1,8 +1,8 @@
require 'rails/generators/active_record'
module ActiveRecord
- module Generators
- class ModelGenerator < Base
+ module Generators # :nodoc:
+ class ModelGenerator < Base # :nodoc:
argument :attributes, :type => :array, :default => [], :banner => "field[:type][:index] field[:type][:index]"
check_class_collision
diff --git a/activerecord/lib/rails/generators/active_record/observer/observer_generator.rb b/activerecord/lib/rails/generators/active_record/observer/observer_generator.rb
index c1c0e3f25b..e7445d03a2 100644
--- a/activerecord/lib/rails/generators/active_record/observer/observer_generator.rb
+++ b/activerecord/lib/rails/generators/active_record/observer/observer_generator.rb
@@ -1,8 +1,8 @@
require 'rails/generators/active_record'
module ActiveRecord
- module Generators
- class ObserverGenerator < Base
+ module Generators # :nodoc:
+ class ObserverGenerator < Base # :nodoc:
check_class_collision :suffix => "Observer"
def create_observer_file
diff --git a/activerecord/test/cases/adapters/postgresql/quoting_test.rb b/activerecord/test/cases/adapters/postgresql/quoting_test.rb
index f8a605b67c..685f0ea74f 100644
--- a/activerecord/test/cases/adapters/postgresql/quoting_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/quoting_test.rb
@@ -1,4 +1,5 @@
require "cases/helper"
+require 'ipaddr'
module ActiveRecord
module ConnectionAdapters
@@ -20,6 +21,18 @@ module ActiveRecord
assert_equal 'f', @conn.type_cast(false, c)
end
+ def test_type_cast_cidr
+ ip = IPAddr.new('255.0.0.0/8')
+ c = Column.new(nil, ip, 'cidr')
+ assert_equal ip, @conn.type_cast(ip, c)
+ end
+
+ def test_type_cast_inet
+ ip = IPAddr.new('255.1.0.0/8')
+ c = Column.new(nil, ip, 'inet')
+ assert_equal ip, @conn.type_cast(ip, c)
+ end
+
def test_quote_float_nan
nan = 0.0/0
c = Column.new(nil, 1, 'float')
diff --git a/activerecord/test/cases/adapters/postgresql/schema_test.rb b/activerecord/test/cases/adapters/postgresql/schema_test.rb
index 9208f53997..cd31900d4e 100644
--- a/activerecord/test/cases/adapters/postgresql/schema_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/schema_test.rb
@@ -72,7 +72,7 @@ class SchemaTest < ActiveRecord::TestCase
end
def test_schema_names
- assert_equal ["public", "test_schema", "test_schema2"], @connection.schema_names
+ assert_equal ["public", "schema_1", "test_schema", "test_schema2"], @connection.schema_names
end
def test_create_schema
@@ -97,7 +97,7 @@ class SchemaTest < ActiveRecord::TestCase
def test_drop_schema
begin
- @connection.create_schema "test_schema3"
+ @connection.create_schema "test_schema3"
ensure
@connection.drop_schema "test_schema3"
end
diff --git a/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb b/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb
index 7eef4ace81..74288a98d1 100644
--- a/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb
+++ b/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb
@@ -59,7 +59,7 @@ class CopyTableTest < ActiveRecord::TestCase
def test_copy_table_with_unconventional_primary_key
test_copy_table('owners', 'owners_unconventional') do |from, to, options|
- original_pk = @connection.primary_key('owners')
+ original_pk = @connection.primary_key('owners')
copied_pk = @connection.primary_key('owners_unconventional')
assert_equal original_pk, copied_pk
end
diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb
index f0582a3090..b2a5d9d6f7 100644
--- a/activerecord/test/cases/associations/has_many_through_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb
@@ -19,7 +19,6 @@ require 'models/book'
require 'models/subscription'
require 'models/essay'
require 'models/category'
-require 'models/owner'
require 'models/categorization'
require 'models/member'
require 'models/membership'
diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb
index d08b157011..c2b58fd7d1 100644
--- a/activerecord/test/cases/attribute_methods_test.rb
+++ b/activerecord/test/cases/attribute_methods_test.rb
@@ -542,10 +542,10 @@ class AttributeMethodsTest < ActiveRecord::TestCase
val = t.send attr_name unless attr_name == "type"
if attribute_gets_cached
assert cached_columns.include?(attr_name)
- assert_equal val, cache[attr_name.to_sym]
+ assert_equal val, cache[attr_name]
else
assert uncached_columns.include?(attr_name)
- assert !cache.include?(attr_name.to_sym)
+ assert !cache.include?(attr_name)
end
end
end
diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb
index fd4f09ab36..16ce150396 100644
--- a/activerecord/test/cases/autosave_association_test.rb
+++ b/activerecord/test/cases/autosave_association_test.rb
@@ -16,7 +16,6 @@ require 'models/ship_part'
require 'models/tag'
require 'models/tagging'
require 'models/treasure'
-require 'models/company'
require 'models/eye'
class TestAutosaveAssociationsInGeneral < ActiveRecord::TestCase
@@ -145,7 +144,7 @@ class TestDefaultAutosaveAssociationOnAHasOneAssociation < ActiveRecord::TestCas
firm = Firm.first
firm.account = Account.first
- assert_queries(Firm.partial_updates? ? 0 : 1) { firm.save! }
+ assert_queries(Firm.partial_writes? ? 0 : 1) { firm.save! }
firm = Firm.first.dup
firm.account = Account.first
diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb
index 6cb6c469d2..abbf2a765e 100644
--- a/activerecord/test/cases/calculations_test.rb
+++ b/activerecord/test/cases/calculations_test.rb
@@ -6,6 +6,8 @@ require 'models/edge'
require 'models/organization'
require 'models/possession'
require 'models/topic'
+require 'models/minivan'
+require 'models/speedometer'
Company.has_many :accounts
@@ -239,21 +241,12 @@ class CalculationsTest < ActiveRecord::TestCase
end
def test_should_group_by_association_with_non_numeric_foreign_key
- ActiveRecord::Base.connection.expects(:select_all).returns([{"count_all" => 1, "firm_id" => "ABC"}])
+ Speedometer.create! id: 'ABC'
+ Minivan.create! id: 'OMG', speedometer_id: 'ABC'
- firm = mock()
- firm.expects(:id).returns("ABC")
- firm.expects(:class).returns(Firm)
- Company.expects(:find).with(["ABC"]).returns([firm])
-
- column = mock()
- column.expects(:name).at_least_once.returns(:firm_id)
- column.expects(:type_cast).with("ABC").returns("ABC")
- Account.expects(:columns).at_least_once.returns([column])
-
- c = Account.group(:firm).count(:all)
+ c = Minivan.group(:speedometer).count(:all)
first_key = c.keys.first
- assert_equal Firm, first_key.class
+ assert_equal Speedometer, first_key.class
assert_equal 1, c[first_key]
end
@@ -378,6 +371,10 @@ class CalculationsTest < ActiveRecord::TestCase
end
end
+ def test_sum_expression_returns_zero_when_no_records_to_sum
+ assert_equal 0, Account.where('1 = 2').sum("2 * credit_limit")
+ end
+
def test_count_with_from_option
assert_equal Company.count(:all), Company.from('companies').count(:all)
assert_equal Account.where("credit_limit = 50").count(:all),
diff --git a/activerecord/test/cases/defaults_test.rb b/activerecord/test/cases/defaults_test.rb
index deaf5252db..0df872ff10 100644
--- a/activerecord/test/cases/defaults_test.rb
+++ b/activerecord/test/cases/defaults_test.rb
@@ -51,11 +51,60 @@ if current_adapter?(:MysqlAdapter) or current_adapter?(:Mysql2Adapter)
# We don't want that to happen, so we disable transactional fixtures here.
self.use_transactional_fixtures = false
- # MySQL 5 and higher is quirky with not null text/blob columns.
- # With MySQL Text/blob columns cannot have defaults. If the column is not
- # null MySQL will report that the column has a null default
- # but it behaves as though the column had a default of ''
- def test_mysql_text_not_null_defaults
+ def using_strict(strict)
+ connection = ActiveRecord::Model.remove_connection
+ ActiveRecord::Model.establish_connection connection.merge(strict: strict)
+ yield
+ ensure
+ ActiveRecord::Model.remove_connection
+ ActiveRecord::Model.establish_connection connection
+ end
+
+ # MySQL cannot have defaults on text/blob columns. It reports the
+ # default value as null.
+ #
+ # Despite this, in non-strict mode, MySQL will use an empty string
+ # as the default value of the field, if no other value is
+ # specified.
+ #
+ # Therefore, in non-strict mode, we want column.default to report
+ # an empty string as its default, to be consistent with that.
+ #
+ # In strict mode, column.default should be nil.
+ def test_mysql_text_not_null_defaults_non_strict
+ using_strict(false) do
+ with_text_blob_not_null_table do |klass|
+ assert_equal '', klass.columns_hash['non_null_blob'].default
+ assert_equal '', klass.columns_hash['non_null_text'].default
+
+ assert_nil klass.columns_hash['null_blob'].default
+ assert_nil klass.columns_hash['null_text'].default
+
+ instance = klass.create!
+
+ assert_equal '', instance.non_null_text
+ assert_equal '', instance.non_null_blob
+
+ assert_nil instance.null_text
+ assert_nil instance.null_blob
+ end
+ end
+ end
+
+ def test_mysql_text_not_null_defaults_strict
+ using_strict(true) do
+ with_text_blob_not_null_table do |klass|
+ assert_nil klass.columns_hash['non_null_blob'].default
+ assert_nil klass.columns_hash['non_null_text'].default
+ assert_nil klass.columns_hash['null_blob'].default
+ assert_nil klass.columns_hash['null_text'].default
+
+ assert_raises(ActiveRecord::StatementInvalid) { klass.create }
+ end
+ end
+ end
+
+ def with_text_blob_not_null_table
klass = Class.new(ActiveRecord::Base)
klass.table_name = 'test_mysql_text_not_null_defaults'
klass.connection.create_table klass.table_name do |t|
@@ -64,19 +113,8 @@ if current_adapter?(:MysqlAdapter) or current_adapter?(:Mysql2Adapter)
t.column :null_text, :text, :null => true
t.column :null_blob, :blob, :null => true
end
- assert_equal '', klass.columns_hash['non_null_blob'].default
- assert_equal '', klass.columns_hash['non_null_text'].default
-
- assert_nil klass.columns_hash['null_blob'].default
- assert_nil klass.columns_hash['null_text'].default
- assert_nothing_raised do
- instance = klass.create!
- assert_equal '', instance.non_null_text
- assert_equal '', instance.non_null_blob
- assert_nil instance.null_text
- assert_nil instance.null_blob
- end
+ yield klass
ensure
klass.connection.drop_table(klass.table_name) rescue nil
end
@@ -109,3 +147,43 @@ if current_adapter?(:MysqlAdapter) or current_adapter?(:Mysql2Adapter)
end
end
end
+
+if current_adapter?(:PostgreSQLAdapter)
+ class DefaultsUsingMultipleSchemasAndDomainTest < ActiveSupport::TestCase
+ def setup
+ @connection = ActiveRecord::Base.connection
+
+ @old_search_path = @connection.schema_search_path
+ @connection.schema_search_path = "schema_1, pg_catalog"
+ @connection.create_table "defaults" do |t|
+ t.text "text_col", :default => "some value"
+ t.string "string_col", :default => "some value"
+ end
+ Default.reset_column_information
+ end
+
+ def test_text_defaults_in_new_schema_when_overriding_domain
+ assert_equal "some value", Default.new.text_col, "Default of text column was not correctly parse"
+ end
+
+ def test_string_defaults_in_new_schema_when_overriding_domain
+ assert_equal "some value", Default.new.string_col, "Default of string column was not correctly parse"
+ end
+
+ def test_bpchar_defaults_in_new_schema_when_overriding_domain
+ @connection.execute "ALTER TABLE defaults ADD bpchar_col bpchar DEFAULT 'some value'"
+ Default.reset_column_information
+ assert_equal "some value", Default.new.bpchar_col, "Default of bpchar column was not correctly parse"
+ end
+
+ def test_text_defaults_after_updating_column_default
+ @connection.execute "ALTER TABLE defaults ALTER COLUMN text_col SET DEFAULT 'some text'::schema_1.text"
+ assert_equal "some text", Default.new.text_col, "Default of text column was not correctly parse after updating default using '::text' since postgreSQL will add parens to the default in db"
+ end
+
+ def teardown
+ @connection.schema_search_path = @old_search_path
+ Default.reset_column_information
+ end
+ end
+end
diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb
index 7334514f9a..40f1dbccde 100644
--- a/activerecord/test/cases/dirty_test.rb
+++ b/activerecord/test/cases/dirty_test.rb
@@ -311,12 +311,12 @@ class DirtyTest < ActiveRecord::TestCase
pirate = Pirate.new(:catchphrase => 'foo')
old_updated_on = 1.hour.ago.beginning_of_day
- with_partial_updates Pirate, false do
+ with_partial_writes Pirate, false do
assert_queries(2) { 2.times { pirate.save! } }
Pirate.where(id: pirate.id).update_all(:updated_on => old_updated_on)
end
- with_partial_updates Pirate, true do
+ with_partial_writes Pirate, true do
assert_queries(0) { 2.times { pirate.save! } }
assert_equal old_updated_on, pirate.reload.updated_on
@@ -329,12 +329,12 @@ class DirtyTest < ActiveRecord::TestCase
person = Person.new(:first_name => 'foo')
old_lock_version = 1
- with_partial_updates Person, false do
+ with_partial_writes Person, false do
assert_queries(2) { 2.times { person.save! } }
Person.where(id: person.id).update_all(:first_name => 'baz')
end
- with_partial_updates Person, true do
+ with_partial_writes Person, true do
assert_queries(0) { 2.times { person.save! } }
assert_equal old_lock_version, person.reload.lock_version
@@ -408,8 +408,8 @@ class DirtyTest < ActiveRecord::TestCase
assert !pirate.catchphrase_changed?
end
- def test_save_should_store_serialized_attributes_even_with_partial_updates
- with_partial_updates(Topic) do
+ def test_save_should_store_serialized_attributes_even_with_partial_writes
+ with_partial_writes(Topic) do
topic = Topic.create!(:content => {:a => "a"})
topic.content[:b] = "b"
#assert topic.changed? # Known bug, will fail
@@ -421,7 +421,7 @@ class DirtyTest < ActiveRecord::TestCase
end
def test_save_always_should_update_timestamps_when_serialized_attributes_are_present
- with_partial_updates(Topic) do
+ with_partial_writes(Topic) do
topic = Topic.create!(:content => {:a => "a"})
topic.save!
@@ -434,8 +434,8 @@ class DirtyTest < ActiveRecord::TestCase
end
end
- def test_save_should_not_save_serialized_attribute_with_partial_updates_if_not_present
- with_partial_updates(Topic) do
+ def test_save_should_not_save_serialized_attribute_with_partial_writes_if_not_present
+ with_partial_writes(Topic) do
Topic.create!(:author_name => 'Bill', :content => {:a => "a"})
topic = Topic.select('id, author_name').first
topic.update_columns author_name: 'John'
@@ -552,7 +552,7 @@ class DirtyTest < ActiveRecord::TestCase
end
test "partial insert" do
- with_partial_updates Person do
+ with_partial_writes Person do
jon = nil
assert_sql(/first_name/i) do
jon = Person.create! first_name: 'Jon'
@@ -568,20 +568,34 @@ class DirtyTest < ActiveRecord::TestCase
end
test "partial insert with empty values" do
- with_partial_updates Aircraft do
+ with_partial_writes Aircraft do
a = Aircraft.create!
a.reload
assert_not_nil a.id
end
end
+ test "partial_updates config attribute is deprecated" do
+ klass = Class.new(ActiveRecord::Base)
+
+ assert klass.partial_writes?
+ assert_deprecated { assert klass.partial_updates? }
+ assert_deprecated { assert klass.partial_updates }
+
+ assert_deprecated { klass.partial_updates = false }
+
+ assert !klass.partial_writes?
+ assert_deprecated { assert !klass.partial_updates? }
+ assert_deprecated { assert !klass.partial_updates }
+ end
+
private
- def with_partial_updates(klass, on = true)
- old = klass.partial_updates?
- klass.partial_updates = on
+ def with_partial_writes(klass, on = true)
+ old = klass.partial_writes?
+ klass.partial_writes = on
yield
ensure
- klass.partial_updates = old
+ klass.partial_writes = old
end
def check_pirate_after_save_failure(pirate)
diff --git a/activerecord/test/cases/dup_test.rb b/activerecord/test/cases/dup_test.rb
index 71b2b16608..4e2adff344 100644
--- a/activerecord/test/cases/dup_test.rb
+++ b/activerecord/test/cases/dup_test.rb
@@ -107,5 +107,19 @@ module ActiveRecord
assert Topic.after_initialize_called
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
end
diff --git a/activerecord/test/cases/migration/change_schema_test.rb b/activerecord/test/cases/migration/change_schema_test.rb
index ec4c554abb..17c1634444 100644
--- a/activerecord/test/cases/migration/change_schema_test.rb
+++ b/activerecord/test/cases/migration/change_schema_test.rb
@@ -293,7 +293,7 @@ module ActiveRecord
connection.create_table :testings do |t|
t.column :foo, :string, limit: 100
t.column :bar, :decimal, precision: 8, scale: 2
- t.column :taggable_id, :integer, null: false
+ t.column :taggable_id, :integer, null: false
t.column :taggable_type, :string, default: 'Photo'
end
diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb
index 3c0d2b18d9..c155f29973 100644
--- a/activerecord/test/cases/migration_test.rb
+++ b/activerecord/test/cases/migration_test.rb
@@ -344,11 +344,7 @@ class MigrationTest < ActiveRecord::TestCase
columns = Person.connection.columns(:binary_testings)
data_column = columns.detect { |c| c.name == "data" }
- if current_adapter?(:MysqlAdapter) or current_adapter?(:Mysql2Adapter)
- assert_equal '', data_column.default
- else
- assert_nil data_column.default
- end
+ assert_nil data_column.default
Person.connection.drop_table :binary_testings rescue nil
end
diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb
index 2d778e9e90..51a285a2b4 100644
--- a/activerecord/test/cases/query_cache_test.rb
+++ b/activerecord/test/cases/query_cache_test.rb
@@ -48,7 +48,7 @@ class QueryCacheTest < ActiveRecord::TestCase
}
assert_raises(RuntimeError) { mw.call({}) }
- assert_equal connection_id, ActiveRecord::Base.connection_id
+ assert_equal connection_id, ActiveRecord::Base.connection_id
end
def test_middleware_delegates
diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb
index 588da68ec1..a9d46f4fba 100644
--- a/activerecord/test/cases/reflection_test.rb
+++ b/activerecord/test/cases/reflection_test.rb
@@ -3,7 +3,6 @@ require 'models/topic'
require 'models/customer'
require 'models/company'
require 'models/company_in_module'
-require 'models/subscriber'
require 'models/ship'
require 'models/pirate'
require 'models/price_estimate'
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index b91423351e..5f96145b47 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -5,7 +5,6 @@ require 'models/post'
require 'models/topic'
require 'models/comment'
require 'models/author'
-require 'models/comment'
require 'models/entrant'
require 'models/developer'
require 'models/reply'
@@ -158,6 +157,22 @@ class RelationTest < ActiveRecord::TestCase
assert_equal 4, topics.to_a.size
assert_equal topics(:first).title, topics.first.title
end
+
+ def test_finding_with_assoc_order
+ topics = Topic.order(:id => :desc)
+ assert_equal 4, topics.to_a.size
+ assert_equal topics(:fourth).title, topics.first.title
+ end
+
+ def test_finding_with_reverted_assoc_order
+ topics = Topic.order(:id => :asc).reverse_order
+ assert_equal 4, topics.to_a.size
+ assert_equal topics(:fourth).title, topics.first.title
+ end
+
+ def test_raising_exception_on_invalid_hash_params
+ assert_raise(ArgumentError) { Topic.order(:name, "id DESC", :id => :DeSc) }
+ end
def test_finding_last_with_arel_order
topics = Topic.order(Topic.arel_table[:id].asc)
@@ -1043,6 +1058,39 @@ class RelationTest < ActiveRecord::TestCase
assert_equal 'parrot', parrot.name
end
+ def test_find_or_create_by
+ assert_nil Bird.find_by(name: 'bob')
+
+ bird = Bird.find_or_create_by(name: 'bob')
+ assert bird.persisted?
+
+ assert_equal bird, Bird.find_or_create_by(name: 'bob')
+ end
+
+ def test_find_or_create_by_with_create_with
+ assert_nil Bird.find_by(name: 'bob')
+
+ bird = Bird.create_with(color: 'green').find_or_create_by(name: 'bob')
+ assert bird.persisted?
+ assert_equal 'green', bird.color
+
+ assert_equal bird, Bird.create_with(color: 'blue').find_or_create_by(name: 'bob')
+ end
+
+ def test_find_or_create_by!
+ assert_raises(ActiveRecord::RecordInvalid) { Bird.find_or_create_by!(color: 'green') }
+ end
+
+ def test_find_or_initialize_by
+ assert_nil Bird.find_by(name: 'bob')
+
+ bird = Bird.find_or_initialize_by(name: 'bob')
+ assert bird.new_record?
+ bird.save!
+
+ assert_equal bird, Bird.find_or_initialize_by(name: 'bob')
+ end
+
def test_explicit_create_scope
hens = Bird.where(:name => 'hen')
assert_equal 'hen', hens.new.name
diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb
index 80f46c6b08..5f13124e5b 100644
--- a/activerecord/test/cases/schema_dumper_test.rb
+++ b/activerecord/test/cases/schema_dumper_test.rb
@@ -2,13 +2,9 @@ require "cases/helper"
class SchemaDumperTest < ActiveRecord::TestCase
- def initialize(*)
- super
- ActiveRecord::SchemaMigration.create_table
- end
-
def setup
super
+ ActiveRecord::SchemaMigration.create_table
@stream = StringIO.new
end
diff --git a/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb b/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb
index a8e513d81f..174d96aa4e 100644
--- a/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb
+++ b/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb
@@ -13,7 +13,7 @@ class I18nGenerateMessageValidationTest < ActiveRecord::TestCase
I18n.load_path.clear
I18n.backend = I18n::Backend::Simple.new
yield
- ensure
+ ensure
I18n.load_path.replace @old_load_path
I18n.backend = @old_backend
end
@@ -54,4 +54,9 @@ class I18nGenerateMessageValidationTest < ActiveRecord::TestCase
end
end
+ test "translation for 'taken' can be overridden" do
+ I18n.backend.store_translations "en", {errors: {attributes: {title: {taken: "Custom taken message" }}}}
+ assert_equal "Custom taken message", @topic.errors.generate_message(:title, :taken, :value => 'title')
+ end
+
end
diff --git a/activerecord/test/cases/validations/presence_validation_test.rb b/activerecord/test/cases/validations/presence_validation_test.rb
index cd9175f454..1de8934406 100644
--- a/activerecord/test/cases/validations/presence_validation_test.rb
+++ b/activerecord/test/cases/validations/presence_validation_test.rb
@@ -18,6 +18,13 @@ class PresenceValidationTest < ActiveRecord::TestCase
assert b.valid?
end
+ def test_validates_presence_of_has_one
+ Boy.validates_presence_of(:face)
+ b = Boy.new
+ assert b.invalid?, "should not be valid if has_one association missing"
+ assert_equal 1, b.errors[:face].size, "validates_presence_of should only add one error"
+ end
+
def test_validates_presence_of_has_one_marked_for_destruction
Boy.validates_presence_of(:face)
b = Boy.new
diff --git a/activerecord/test/schema/postgresql_specific_schema.rb b/activerecord/test/schema/postgresql_specific_schema.rb
index 2cd9f30b59..d0e7338f15 100644
--- a/activerecord/test/schema/postgresql_specific_schema.rb
+++ b/activerecord/test/schema/postgresql_specific_schema.rb
@@ -12,6 +12,8 @@ ActiveRecord::Schema.define do
execute 'DROP FUNCTION IF EXISTS partitioned_insert_trigger()'
+ execute "DROP SCHEMA IF EXISTS schema_1 CASCADE"
+
%w(accounts_id_seq developers_id_seq projects_id_seq topics_id_seq customers_id_seq orders_id_seq).each do |seq_name|
execute "SELECT setval('#{seq_name}', 100)"
end
@@ -37,7 +39,12 @@ ActiveRecord::Schema.define do
);
_SQL
- execute <<_SQL
+ execute "CREATE SCHEMA schema_1"
+ execute "CREATE DOMAIN schema_1.text AS text"
+ execute "CREATE DOMAIN schema_1.varchar AS varchar"
+ execute "CREATE DOMAIN schema_1.bpchar AS bpchar"
+
+ execute <<_SQL
CREATE TABLE geometrics (
id serial primary key,
a_point point,
diff --git a/activerecord/test/support/connection.rb b/activerecord/test/support/connection.rb
index 92736e0ca9..bea894a583 100644
--- a/activerecord/test/support/connection.rb
+++ b/activerecord/test/support/connection.rb
@@ -13,7 +13,7 @@ module ARTest
def self.connect
puts "Using #{connection_name}"
- ActiveRecord::Model.logger = ActiveSupport::Logger.new("debug.log")
+ ActiveRecord::Model.logger = ActiveSupport::Logger.new("debug.log", 0, 100 * 1024 * 1024)
ActiveRecord::Model.configurations = connection_config
ActiveRecord::Model.establish_connection 'arunit'
ARUnit2Model.establish_connection 'arunit2'
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index 0a12ba6cdd..23e2ce0b03 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,5 +1,16 @@
## Rails 4.0.0 (unreleased) ##
+* Hash#extract! returns only those keys that present in the receiver.
+
+ {:a => 1, :b => 2}.extract!(:a, :x) # => {:a => 1}
+
+ *Mikhail Dieterle*
+
+* Hash#extract! returns the same subclass, that the receiver is. I.e.
+ HashWithIndifferentAccess#extract! returns HashWithIndifferentAccess instance.
+
+ *Mikhail Dieterle*
+
* Optimize ActiveSupport::Cache::Entry to reduce memory and processing overhead. *Brian Durand*
* Tests tag the Rails log with the current test class and test case:
diff --git a/activesupport/lib/active_support/cache/mem_cache_store.rb b/activesupport/lib/active_support/cache/mem_cache_store.rb
index 5aa78cc9f3..17450fe4d0 100644
--- a/activesupport/lib/active_support/cache/mem_cache_store.rb
+++ b/activesupport/lib/active_support/cache/mem_cache_store.rb
@@ -132,6 +132,10 @@ module ActiveSupport
method = options && options[:unless_exist] ? :add : :set
value = options[:raw] ? entry.value.to_s : entry
expires_in = options[:expires_in].to_i
+ if expires_in > 0 && !options[:raw]
+ # Set the memcache expire a few minutes in the future to support race condition ttls on read
+ expires_in += 5.minutes
+ end
@data.send(method, escape_key(key), value, expires_in, options)
rescue Dalli::DalliError => e
logger.error("DalliError (#{e}): #{e.message}") if logger
diff --git a/activesupport/lib/active_support/core_ext/array/extract_options.rb b/activesupport/lib/active_support/core_ext/array/extract_options.rb
index 9008a0df2a..5f153a2cc3 100644
--- a/activesupport/lib/active_support/core_ext/array/extract_options.rb
+++ b/activesupport/lib/active_support/core_ext/array/extract_options.rb
@@ -18,7 +18,7 @@ class Array
# end
#
# options(1, 2) # => {}
- # options(1, 2, a: :b) # => {:a=>:b}
+ # options(1, 2, a: :b) # => {a: :b}
def extract_options!
if last.is_a?(Hash) && last.extractable_options?
pop
diff --git a/activesupport/lib/active_support/core_ext/array/wrap.rb b/activesupport/lib/active_support/core_ext/array/wrap.rb
index 7bf28b2f27..ffaf6ef024 100644
--- a/activesupport/lib/active_support/core_ext/array/wrap.rb
+++ b/activesupport/lib/active_support/core_ext/array/wrap.rb
@@ -23,7 +23,7 @@ class Array
# The last point is particularly worth comparing for some enumerables:
#
# Array(foo: :bar) # => [[:foo, :bar]]
- # Array.wrap(foo: :bar) # => [{:foo => :bar}]
+ # Array.wrap(foo: :bar) # => [{foo: :bar}]
#
# There's also a related idiom that uses the splat operator:
#
diff --git a/activesupport/lib/active_support/core_ext/hash/conversions.rb b/activesupport/lib/active_support/core_ext/hash/conversions.rb
index 828f03ad62..f5e3a9b842 100644
--- a/activesupport/lib/active_support/core_ext/hash/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/hash/conversions.rb
@@ -131,7 +131,7 @@ class Hash
else
xml_value = Hash[value.map { |k,v| [k, typecast_xml_value(v)] }]
- # Turn { :files => { :file => #<StringIO> } } into { :files => #<StringIO> } so it is compatible with
+ # Turn { files: { file: #<StringIO> } } into { files: #<StringIO> } so it is compatible with
# how multipart uploaded files from HTML appear
xml_value['file'].is_a?(StringIO) ? xml_value['file'] : xml_value
end
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 83f0c87b04..6ce2847ab5 100644
--- a/activesupport/lib/active_support/core_ext/hash/deep_merge.rb
+++ b/activesupport/lib/active_support/core_ext/hash/deep_merge.rb
@@ -4,10 +4,10 @@ class Hash
# 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]}
+ # h1.deep_merge(h2) #=> {x: {y: [7, 8, 9]}, z: "xyz"}
+ # h2.deep_merge(h1) #=> {x: {y: [4, 5, 6]}, z: [7, 8, 9]}
# h1.deep_merge(h2) { |key, old, new| Array.wrap(old) + Array.wrap(new) }
- # #=> {:x => {:y => [4, 5, 6, 7, 8, 9]}, :z => [7, 8, 9, "xyz"]}
+ # #=> {x: {y: [4, 5, 6, 7, 8, 9]}, z: [7, 8, 9, "xyz"]}
def deep_merge(other_hash, &block)
dup.deep_merge!(other_hash, &block)
end
diff --git a/activesupport/lib/active_support/core_ext/hash/slice.rb b/activesupport/lib/active_support/core_ext/hash/slice.rb
index 45fec57009..a92c5968ed 100644
--- a/activesupport/lib/active_support/core_ext/hash/slice.rb
+++ b/activesupport/lib/active_support/core_ext/hash/slice.rb
@@ -21,7 +21,7 @@ class Hash
# Returns a hash containing the removed key/value pairs.
#
# { a: 1, b: 2, c: 3, d: 4 }.slice!(:a, :b)
- # # => {:c => 3, :d => 4}
+ # # => {c: 3, d: 4}
def slice!(*keys)
keys.map! { |key| convert_key(key) } if respond_to?(:convert_key, true)
omit = slice(*self.keys - keys)
@@ -32,9 +32,9 @@ class Hash
# Removes and returns the key/value pairs matching the given keys.
#
- # { a: 1, b: 2, c: 3, d: 4 }.extract!(:a, :b)
- # # => {:a => 1, :b => 2}
+ # { a: 1, b: 2, c: 3, d: 4 }.extract!(:a, :b) # => { a: 1, b: 2 }
+ # { a: 1, b: 2 }.extract!(:a, :x) # => { a: 1 }
def extract!(*keys)
- keys.each_with_object({}) { |key, result| result[key] = delete(key) }
+ keys.each_with_object(self.class.new) { |key, result| result[key] = delete(key) if has_key?(key) }
end
end
diff --git a/activesupport/lib/active_support/core_ext/module/deprecation.rb b/activesupport/lib/active_support/core_ext/module/deprecation.rb
index 34ec6a3d8f..cc45cee5b8 100644
--- a/activesupport/lib/active_support/core_ext/module/deprecation.rb
+++ b/activesupport/lib/active_support/core_ext/module/deprecation.rb
@@ -2,13 +2,13 @@ require 'active_support/deprecation/method_wrappers'
class Module
# deprecate :foo
- # deprecate :bar => 'message'
- # deprecate :foo, :bar, :baz => 'warning!', :qux => 'gone!'
+ # deprecate bar: 'message'
+ # deprecate :foo, :bar, baz: 'warning!', qux: 'gone!'
#
# You can also use custom deprecator instance:
#
- # deprecate :foo, :deprecator => MyLib::Deprecator.new
- # deprecate :foo, :bar => "warning!", :deprecator => MyLib::Deprecator.new
+ # deprecate :foo, deprecator: MyLib::Deprecator.new
+ # deprecate :foo, bar: "warning!", deprecator: MyLib::Deprecator.new
#
# \Custom deprecators must respond to <tt>deprecation_warning(deprecated_method_name, message, caller_backtrace)</tt>
# method where you can implement your custom warning behavior.
diff --git a/activesupport/lib/active_support/core_ext/object.rb b/activesupport/lib/active_support/core_ext/object.rb
index ab01d7787a..ec2157221f 100644
--- a/activesupport/lib/active_support/core_ext/object.rb
+++ b/activesupport/lib/active_support/core_ext/object.rb
@@ -1,11 +1,14 @@
require 'active_support/core_ext/object/acts_like'
require 'active_support/core_ext/object/blank'
-require 'active_support/core_ext/object/deep_dup'
require 'active_support/core_ext/object/duplicable'
+require 'active_support/core_ext/object/deep_dup'
+require 'active_support/core_ext/object/try'
require 'active_support/core_ext/object/inclusion'
+
+require 'active_support/core_ext/object/conversions'
require 'active_support/core_ext/object/instance_variables'
+
require 'active_support/core_ext/object/to_json'
require 'active_support/core_ext/object/to_param'
require 'active_support/core_ext/object/to_query'
-require 'active_support/core_ext/object/try'
require 'active_support/core_ext/object/with_options'
diff --git a/activesupport/lib/active_support/core_ext/object/conversions.rb b/activesupport/lib/active_support/core_ext/object/conversions.rb
new file mode 100644
index 0000000000..540f7aadb0
--- /dev/null
+++ b/activesupport/lib/active_support/core_ext/object/conversions.rb
@@ -0,0 +1,4 @@
+require 'active_support/core_ext/object/to_param'
+require 'active_support/core_ext/object/to_query'
+require 'active_support/core_ext/array/conversions'
+require 'active_support/core_ext/hash/conversions'
diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb
index e3665cd896..931851d40e 100644
--- a/activesupport/lib/active_support/core_ext/time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/time/calculations.rb
@@ -135,7 +135,7 @@ class Time
# Returns a new Time representing the start of the day (0:00)
def beginning_of_day
- #(self - seconds_since_midnight).change(:usec => 0)
+ #(self - seconds_since_midnight).change(usec: 0)
change(:hour => 0)
end
alias :midnight :beginning_of_day
diff --git a/activesupport/lib/active_support/descendants_tracker.rb b/activesupport/lib/active_support/descendants_tracker.rb
index e2a8b4d4e3..27861e01d0 100644
--- a/activesupport/lib/active_support/descendants_tracker.rb
+++ b/activesupport/lib/active_support/descendants_tracker.rb
@@ -2,35 +2,50 @@ module ActiveSupport
# This module provides an internal implementation to track descendants
# which is faster than iterating through ObjectSpace.
module DescendantsTracker
- @@direct_descendants = Hash.new { |h, k| h[k] = [] }
+ @@direct_descendants = {}
- def self.direct_descendants(klass)
- @@direct_descendants[klass]
- end
+ class << self
+ def direct_descendants(klass)
+ @@direct_descendants[klass] || []
+ end
- def self.descendants(klass)
- @@direct_descendants[klass].inject([]) do |descendants, _klass|
- descendants << _klass
- descendants.concat _klass.descendants
+ def descendants(klass)
+ arr = []
+ accumulate_descendants(klass, arr)
+ arr
end
- end
- def self.clear
- if defined? ActiveSupport::Dependencies
- @@direct_descendants.each do |klass, descendants|
- if ActiveSupport::Dependencies.autoloaded?(klass)
- @@direct_descendants.delete(klass)
- else
- descendants.reject! { |v| ActiveSupport::Dependencies.autoloaded?(v) }
+ def clear
+ if defined? ActiveSupport::Dependencies
+ @@direct_descendants.each do |klass, descendants|
+ if ActiveSupport::Dependencies.autoloaded?(klass)
+ @@direct_descendants.delete(klass)
+ else
+ descendants.reject! { |v| ActiveSupport::Dependencies.autoloaded?(v) }
+ end
end
+ else
+ @@direct_descendants.clear
+ end
+ end
+
+ # This is the only method that is not thread safe, but is only ever called
+ # during the eager loading phase.
+ def store_inherited(klass, descendant)
+ (@@direct_descendants[klass] ||= []) << descendant
+ end
+
+ private
+ def accumulate_descendants(klass, acc)
+ if direct_descendants = @@direct_descendants[klass]
+ acc.concat(direct_descendants)
+ direct_descendants.each { |direct_descendant| accumulate_descendants(direct_descendant, acc) }
end
- else
- @@direct_descendants.clear
end
end
def inherited(base)
- self.direct_descendants << base
+ DescendantsTracker.store_inherited(self, base)
super
end
diff --git a/activesupport/lib/active_support/queueing.rb b/activesupport/lib/active_support/queueing.rb
index 7c352886f3..c8ba28021d 100644
--- a/activesupport/lib/active_support/queueing.rb
+++ b/activesupport/lib/active_support/queueing.rb
@@ -56,32 +56,6 @@ module ActiveSupport
end
end
- # A container for multiple queues. This class delegates to a default Queue
- # so that <tt>Rails.queue.push</tt> and friends will Just Work. To use this class
- # with multiple queues:
- #
- # # In your configuration:
- # Rails.queue[:image_queue] = SomeQueue.new
- # Rails.queue[:mail_queue] = SomeQueue.new
- #
- # # In your app code:
- # Rails.queue[:mail_queue].push SomeJob.new
- #
- class QueueContainer < DelegateClass(::Queue)
- def initialize(default_queue)
- @queues = { :default => default_queue }
- super(default_queue)
- end
-
- def [](queue_name)
- @queues[queue_name]
- end
-
- def []=(queue_name, queue)
- @queues[queue_name] = queue
- end
- end
-
# The threaded consumer will run jobs in a background thread in
# development mode or in a VM where running jobs on a thread in
# production mode makes sense.
@@ -90,10 +64,6 @@ module ActiveSupport
# queue and joins the thread, which will ensure that all jobs
# are executed before the process finally dies.
class ThreadedQueueConsumer
- def self.start(*args)
- new(*args).start
- end
-
def initialize(queue, options = {})
@queue = queue
@logger = options[:logger]
diff --git a/activesupport/lib/active_support/testing/performance/ruby.rb b/activesupport/lib/active_support/testing/performance/ruby.rb
index 12aef0d7fe..7c149df1e4 100644
--- a/activesupport/lib/active_support/testing/performance/ruby.rb
+++ b/activesupport/lib/active_support/testing/performance/ruby.rb
@@ -2,7 +2,7 @@ begin
require 'ruby-prof'
rescue LoadError
$stderr.puts 'Specify ruby-prof as application\'s dependency in Gemfile to run benchmarks.'
- exit
+ raise
end
module ActiveSupport
diff --git a/activesupport/test/caching_test.rb b/activesupport/test/caching_test.rb
index febf0eeeff..9f76f4c90b 100644
--- a/activesupport/test/caching_test.rb
+++ b/activesupport/test/caching_test.rb
@@ -3,6 +3,20 @@ require 'abstract_unit'
require 'active_support/cache'
class CacheKeyTest < ActiveSupport::TestCase
+ def test_entry_legacy_optional_ivars
+ legacy = Class.new(ActiveSupport::Cache::Entry) do
+ def initialize(value, options = {})
+ @value = value
+ @expires_in = nil
+ @created_at = nil
+ super
+ end
+ end
+
+ entry = legacy.new 'foo'
+ assert_equal 'foo', entry.value
+ end
+
def test_expand_cache_key
assert_equal '1/2/true', ActiveSupport::Cache.expand_cache_key([1, '2', true])
assert_equal 'name/1/2/true', ActiveSupport::Cache.expand_cache_key([1, '2', true], :name)
diff --git a/activesupport/test/callbacks_test.rb b/activesupport/test/callbacks_test.rb
index b7c3b130c3..8810302f40 100644
--- a/activesupport/test/callbacks_test.rb
+++ b/activesupport/test/callbacks_test.rb
@@ -120,7 +120,7 @@ module CallbacksTest
end
class Child < ParentController
- skip_callback :dispatch, :before, :log, :if => proc {|c| c.action_name == :update}
+ skip_callback :dispatch, :before, :log, :if => proc {|c| c.action_name == :update}
skip_callback :dispatch, :after, :log2
end
diff --git a/activesupport/test/core_ext/array_ext_test.rb b/activesupport/test/core_ext/array_ext_test.rb
index 0b33a63460..9dfa2cbf11 100644
--- a/activesupport/test/core_ext/array_ext_test.rb
+++ b/activesupport/test/core_ext/array_ext_test.rb
@@ -1,6 +1,7 @@
require 'abstract_unit'
require 'active_support/core_ext/array'
require 'active_support/core_ext/big_decimal'
+require 'active_support/core_ext/object/conversions'
require 'active_support/core_ext' # FIXME: pulling in all to_xml extensions
require 'active_support/hash_with_indifferent_access'
diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb
index 53ea2aad16..7cfe7b0ea7 100644
--- a/activesupport/test/core_ext/hash_ext_test.rb
+++ b/activesupport/test/core_ext/hash_ext_test.rb
@@ -3,6 +3,7 @@ require 'active_support/core_ext/hash'
require 'bigdecimal'
require 'active_support/core_ext/string/access'
require 'active_support/ordered_hash'
+require 'active_support/core_ext/object/conversions'
require 'active_support/core_ext/object/deep_dup'
require 'active_support/inflections'
@@ -723,8 +724,32 @@ class HashExtTest < ActiveSupport::TestCase
def test_extract
original = {:a => 1, :b => 2, :c => 3, :d => 4}
expected = {:a => 1, :b => 2}
+ remaining = {:c => 3, :d => 4}
- assert_equal expected, original.extract!(:a, :b)
+ assert_equal expected, original.extract!(:a, :b, :x)
+ assert_equal remaining, original
+ end
+
+ def test_extract_nils
+ original = {:a => nil, :b => nil}
+ expected = {:a => nil}
+ extracted = original.extract!(:a, :x)
+
+ assert_equal expected, extracted
+ assert_equal nil, extracted[:a]
+ assert_equal nil, extracted[:x]
+ end
+
+ def test_indifferent_extract
+ original = {:a => 1, 'b' => 2, :c => 3, 'd' => 4}.with_indifferent_access
+ expected = {:a => 1, :b => 2}.with_indifferent_access
+ remaining = {:c => 3, :d => 4}.with_indifferent_access
+
+ [['a', 'b'], [:a, :b]].each do |keys|
+ copy = original.dup
+ assert_equal expected, copy.extract!(*keys)
+ assert_equal remaining, copy
+ end
end
def test_except
diff --git a/activesupport/test/descendants_tracker_test_cases.rb b/activesupport/test/descendants_tracker_test_cases.rb
index 066ec8549b..69e046998e 100644
--- a/activesupport/test/descendants_tracker_test_cases.rb
+++ b/activesupport/test/descendants_tracker_test_cases.rb
@@ -1,3 +1,5 @@
+require 'set'
+
module DescendantsTrackerTestCases
class Parent
extend ActiveSupport::DescendantsTracker
@@ -18,15 +20,15 @@ module DescendantsTrackerTestCases
ALL = [Parent, Child1, Child2, Grandchild1, Grandchild2]
def test_descendants
- assert_equal [Child1, Grandchild1, Grandchild2, Child2], Parent.descendants
- assert_equal [Grandchild1, Grandchild2], Child1.descendants
- assert_equal [], Child2.descendants
+ assert_equal_sets [Child1, Grandchild1, Grandchild2, Child2], Parent.descendants
+ assert_equal_sets [Grandchild1, Grandchild2], Child1.descendants
+ assert_equal_sets [], Child2.descendants
end
def test_direct_descendants
- assert_equal [Child1, Child2], Parent.direct_descendants
- assert_equal [Grandchild1, Grandchild2], Child1.direct_descendants
- assert_equal [], Child2.direct_descendants
+ assert_equal_sets [Child1, Child2], Parent.direct_descendants
+ assert_equal_sets [Grandchild1, Grandchild2], Child1.direct_descendants
+ assert_equal_sets [], Child2.direct_descendants
end
def test_clear
@@ -40,6 +42,10 @@ module DescendantsTrackerTestCases
protected
+ def assert_equal_sets(expected, actual)
+ assert_equal Set.new(expected), Set.new(actual)
+ end
+
def mark_as_autoloaded(*klasses)
# If ActiveSupport::Dependencies is not loaded, forget about autoloading.
# This allows using AS::DescendantsTracker without AS::Dependencies.
@@ -56,4 +62,4 @@ module DescendantsTrackerTestCases
ActiveSupport::Dependencies.autoloaded_constants = old_autoloaded if defined? ActiveSupport::Dependencies
ActiveSupport::DescendantsTracker.class_eval("@@direct_descendants").replace(old_descendants)
end
-end \ No newline at end of file
+end
diff --git a/activesupport/test/descendants_tracker_with_autoloading_test.rb b/activesupport/test/descendants_tracker_with_autoloading_test.rb
index 9180f1f977..ab1be296f8 100644
--- a/activesupport/test/descendants_tracker_with_autoloading_test.rb
+++ b/activesupport/test/descendants_tracker_with_autoloading_test.rb
@@ -18,17 +18,17 @@ class DescendantsTrackerWithAutoloadingTest < ActiveSupport::TestCase
def test_clear_with_autoloaded_children_and_granchildren
mark_as_autoloaded Child1, Grandchild1, Grandchild2 do
ActiveSupport::DescendantsTracker.clear
- assert_equal [Child2], Parent.descendants
- assert_equal [], Child2.descendants
+ assert_equal_sets [Child2], Parent.descendants
+ assert_equal_sets [], Child2.descendants
end
end
def test_clear_with_autoloaded_granchildren
mark_as_autoloaded Grandchild1, Grandchild2 do
ActiveSupport::DescendantsTracker.clear
- assert_equal [Child1, Child2], Parent.descendants
- assert_equal [], Child1.descendants
- assert_equal [], Child2.descendants
+ assert_equal_sets [Child1, Child2], Parent.descendants
+ assert_equal_sets [], Child1.descendants
+ assert_equal_sets [], Child2.descendants
end
end
end
diff --git a/activesupport/test/queueing/container_test.rb b/activesupport/test/queueing/container_test.rb
deleted file mode 100644
index 7afc11e7a9..0000000000
--- a/activesupport/test/queueing/container_test.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-require 'abstract_unit'
-require 'active_support/queueing'
-
-module ActiveSupport
- class ContainerTest < ActiveSupport::TestCase
- def test_delegates_to_default
- q = Queue.new
- container = QueueContainer.new q
- job = Object.new
-
- container.push job
- assert_equal job, q.pop
- end
-
- def test_access_default
- q = Queue.new
- container = QueueContainer.new q
- assert_equal q, container[:default]
- end
-
- def test_assign_queue
- container = QueueContainer.new Object.new
- q = Object.new
- container[:foo] = q
- assert_equal q, container[:foo]
- end
- end
-end
diff --git a/activesupport/test/queueing/test_queue_test.rb b/activesupport/test/queueing/test_queue_test.rb
index e398a48bea..451fb68d3e 100644
--- a/activesupport/test/queueing/test_queue_test.rb
+++ b/activesupport/test/queueing/test_queue_test.rb
@@ -99,4 +99,48 @@ class TestQueueTest < ActiveSupport::TestCase
assert job.ran?, "The job runs synchronously when the queue is drained"
assert_equal job.thread_id, Thread.current.object_id
end
+
+ class IdentifiableJob
+ def initialize(id)
+ @id = id
+ end
+
+ def ==(other)
+ other.same_id?(@id)
+ end
+
+ def same_id?(other_id)
+ other_id == @id
+ end
+
+ def run
+ end
+ end
+
+ def test_queue_can_be_observed
+ jobs = (1..10).map do |id|
+ IdentifiableJob.new(id)
+ end
+
+ jobs.each do |job|
+ @queue.push job
+ end
+
+ assert_equal jobs, @queue.jobs
+ end
+
+ def test_adding_an_unmarshallable_job
+ anonymous_class_instance = Struct.new(:run).new
+
+ assert_raises TypeError do
+ @queue.push anonymous_class_instance
+ end
+ end
+
+ def test_attempting_to_add_a_reference_to_itself
+ job = {reference: @queue}
+ assert_raises TypeError do
+ @queue.push job
+ end
+ end
end
diff --git a/activesupport/test/testing/performance_test.rb b/activesupport/test/testing/performance_test.rb
index 53073cb8db..6918110cce 100644
--- a/activesupport/test/testing/performance_test.rb
+++ b/activesupport/test/testing/performance_test.rb
@@ -1,10 +1,19 @@
require 'abstract_unit'
-require 'active_support/testing/performance'
-
module ActiveSupport
module Testing
class PerformanceTest < ActiveSupport::TestCase
+ begin
+ require 'active_support/testing/performance'
+ HAVE_RUBYPROF = true
+ rescue LoadError
+ HAVE_RUBYPROF = false
+ end
+
+ def setup
+ skip "no rubyprof" unless HAVE_RUBYPROF
+ end
+
def test_amount_format
amount_metric = ActiveSupport::Testing::Performance::Metrics[:amount].new
assert_equal "0", amount_metric.format(0)
@@ -56,4 +65,4 @@ module ActiveSupport
end
end
end
-end \ No newline at end of file
+end
diff --git a/guides/source/4_0_release_notes.md b/guides/source/4_0_release_notes.md
index 54fe49252f..6b3680aa2d 100644
--- a/guides/source/4_0_release_notes.md
+++ b/guides/source/4_0_release_notes.md
@@ -95,9 +95,9 @@ Railties
* Load all environments available in `config.paths["config/environments"]`.
-* Add `config.queue_consumer` to allow the default consumer to be configurable.
+* Add `config.queue_consumer` to change the job queue consumer from the default `ActiveSupport::ThreadedQueueConsumer`.
-* Add `Rails.queue` as an interface with a default implementation that consumes jobs in a separate thread.
+* Add `Rails.queue` for processing jobs in the background.
* Remove `Rack::SSL` in favour of `ActionDispatch::SSL`.
@@ -810,6 +810,10 @@ Active Support
* Add `Time#prev_quarter` and `Time#next_quarter` short-hands for `months_ago(3)` and `months_since(3)`.
+* Add `Time#last_week`, `Time#last_month`, `Time#last_year` as aliases for `Time#prev_week`, `Time#prev_month`, and `Time#prev_year`.
+
+* Add `Date#last_week`, `Date#last_month`, `Date#last_year` as aliases for `Date#prev_week`, `Date#prev_month`, and `Date#prev_year`.
+
* Remove obsolete and unused `require_association` method from dependencies.
* Add `:instance_accessor` option for `config_accessor`.
diff --git a/guides/source/active_record_querying.md b/guides/source/active_record_querying.md
index 66e6390f67..76548a3397 100644
--- a/guides/source/active_record_querying.md
+++ b/guides/source/active_record_querying.md
@@ -1225,17 +1225,17 @@ WARNING: Up to and including Rails 3.1, when the number of arguments passed to a
Find or build a new object
--------------------------
-It's common that you need to find a record or create it if it doesn't exist. You can do that with the `first_or_create` and `first_or_create!` methods.
+It's common that you need to find a record or create it if it doesn't exist. You can do that with the `find_or_create_by` and `find_or_create_by!` methods.
-### `first_or_create`
+### `find_or_create_by`
-The `first_or_create` method checks whether `first` returns `nil` or not. If it does return `nil`, then `create` is called. This is very powerful when coupled with the `where` method. Let's see an example.
+The `find_or_create_by` method checks whether a record with the attributes exists. If it doesn't, then `create` is called. Let's see an example.
-Suppose you want to find a client named 'Andy', and if there's none, create one and additionally set his `locked` attribute to false. You can do so by running:
+Suppose you want to find a client named 'Andy', and if there's none, create one. You can do so by running:
```ruby
-Client.where(:first_name => 'Andy').first_or_create(:locked => false)
-# => #<Client id: 1, first_name: "Andy", orders_count: 0, locked: false, created_at: "2011-08-30 06:09:27", updated_at: "2011-08-30 06:09:27">
+Client.find_or_create_by(first_name: 'Andy')
+# => #<Client id: 1, first_name: "Andy", orders_count: 0, locked: true, created_at: "2011-08-30 06:09:27", updated_at: "2011-08-30 06:09:27">
```
The SQL generated by this method looks like this:
@@ -1243,27 +1243,39 @@ The SQL generated by this method looks like this:
```sql
SELECT * FROM clients WHERE (clients.first_name = 'Andy') LIMIT 1
BEGIN
-INSERT INTO clients (created_at, first_name, locked, orders_count, updated_at) VALUES ('2011-08-30 05:22:57', 'Andy', 0, NULL, '2011-08-30 05:22:57')
+INSERT INTO clients (created_at, first_name, locked, orders_count, updated_at) VALUES ('2011-08-30 05:22:57', 'Andy', 1, NULL, '2011-08-30 05:22:57')
COMMIT
```
-`first_or_create` returns either the record that already exists or the new record. In our case, we didn't already have a client named Andy so the record is created and returned.
+`find_or_create_by` returns either the record that already exists or the new record. In our case, we didn't already have a client named Andy so the record is created and returned.
The new record might not be saved to the database; that depends on whether validations passed or not (just like `create`).
-It's also worth noting that `first_or_create` takes into account the arguments of the `where` method. In the example above we didn't explicitly pass a `:first_name => 'Andy'` argument to `first_or_create`. However, that was used when creating the new record because it was already passed before to the `where` method.
+Suppose we want to set the 'locked' attribute to true if we're
+creating a new record, but we don't want to include it in the query. So
+we want to find the client named "Andy", or if that client doesn't
+exist, create a client named "Andy" which is not locked.
-You can do the same with the `find_or_create_by` method:
+We can achive this in two ways. The first is to use `create_with`:
```ruby
-Client.find_or_create_by_first_name(:first_name => "Andy", :locked => false)
+Client.create_with(locked: false).find_or_create_by(first_name: 'Andy')
```
-This method still works, but it's encouraged to use `first_or_create` because it's more explicit on which arguments are used to _find_ the record and which are used to _create_, resulting in less confusion overall.
+The second way is using a block:
-### `first_or_create!`
+```ruby
+Client.find_or_create_by(first_name: 'Andy') do |c|
+ c.locked = false
+end
+```
-You can also use `first_or_create!` to raise an exception if the new record is invalid. Validations are not covered on this guide, but let's assume for a moment that you temporarily add
+The block will only be executed if the client is being created. The
+second time we run this code, the block will be ignored.
+
+### `find_or_create_by!`
+
+You can also use `find_or_create_by!` to raise an exception if the new record is invalid. Validations are not covered on this guide, but let's assume for a moment that you temporarily add
```ruby
validates :orders_count, :presence => true
@@ -1272,19 +1284,21 @@ validates :orders_count, :presence => true
to your `Client` model. If you try to create a new `Client` without passing an `orders_count`, the record will be invalid and an exception will be raised:
```ruby
-Client.where(:first_name => 'Andy').first_or_create!(:locked => false)
+Client.find_or_create_by!(first_name: 'Andy')
# => ActiveRecord::RecordInvalid: Validation failed: Orders count can't be blank
```
-As with `first_or_create` there is a `find_or_create_by!` method but the `first_or_create!` method is preferred for clarity.
-
-### `first_or_initialize`
+### `find_or_initialize_by`
-The `first_or_initialize` method will work just like `first_or_create` but it will not call `create` but `new`. This means that a new model instance will be created in memory but won't be saved to the database. Continuing with the `first_or_create` example, we now want the client named 'Nick':
+The `find_or_initialize_by` method will work just like
+`find_or_create_by` but it will call `new` instead of `create`. This
+means that a new model instance will be created in memory but won't be
+saved to the database. Continuing with the `find_or_create_by` example, we
+now want the client named 'Nick':
```ruby
-nick = Client.where(:first_name => 'Nick').first_or_initialize(:locked => false)
-# => <Client id: nil, first_name: "Nick", orders_count: 0, locked: false, created_at: "2011-08-30 06:09:27", updated_at: "2011-08-30 06:09:27">
+nick = Client.find_or_initialize_by(first_name: 'Nick')
+# => <Client id: nil, first_name: "Nick", orders_count: 0, locked: true, created_at: "2011-08-30 06:09:27", updated_at: "2011-08-30 06:09:27">
nick.persisted?
# => false
diff --git a/guides/source/active_support_core_extensions.md b/guides/source/active_support_core_extensions.md
index 193cc41d79..c08ad1ee90 100644
--- a/guides/source/active_support_core_extensions.md
+++ b/guides/source/active_support_core_extensions.md
@@ -2871,6 +2871,14 @@ rest = hash.extract!(:a) # => {a: 1}
hash # => {b: 2}
```
+The method `extract!` returns the same subclass of Hash, that the receiver is.
+
+```ruby
+hash = {a: 1, b: 2}.with_indifferent_access
+rest = hash.extract!(:a).class
+# => ActiveSupport::HashWithIndifferentAccess
+```
+
NOTE: Defined in `active_support/core_ext/hash/slice.rb`.
### Indifferent Access
diff --git a/guides/source/ajax_on_rails.md b/guides/source/ajax_on_rails.md
deleted file mode 100644
index 97c56036e8..0000000000
--- a/guides/source/ajax_on_rails.md
+++ /dev/null
@@ -1,316 +0,0 @@
-AJAX on Rails
-=============
-
-This guide covers the built-in Ajax/JavaScript functionality of Rails (and more);
-it will enable you to create rich and dynamic AJAX applications with ease! We will
-cover the following topics:
-
-* Quick introduction to AJAX and related technologies
-* Unobtrusive JavaScript helpers with drivers for Prototype, jQuery etc
-* Testing JavaScript functionality
-
---------------------------------------------------------------------------------
-
-Hello AJAX - a Quick Intro
---------------------------
-
-AJAX is about updating parts of a web page without reloading the page. An AJAX
-call happens as a response to an event, like when the page finished loading or
-when a user clicks on an element. For example, let say you click on a link, which
-would usually take you to a new page, but instead of doing that, an asynchronous
-HTTP request is made and the response is evaluated with JavaScript. That way the
-page is not reloaded and new information can be dynamically included in the page.
-The way that happens is by inserting, removing or changing parts of the DOM. The
-DOM, or Document Object Model, is a convention to represent the HTML document as
-a set of nodes that contain other nodes. For example, a list of names is represented
-as a `ul` element node containing several `li` element nodes. An AJAX call can
-be made to obtain a new list item to include, and append it inside a `li` node to
-the `ul` node.
-
-### Asynchronous JavaScript + XML
-
-AJAX means Asynchronous JavaScript + XML. Asynchronous means that the page is not
-reloaded, the request made is separate from the regular page request. JavaScript
-is used to evaluate the response and the XML part is a bit misleading as XML is
-not required, you respond to the HTTP request with JSON or regular HTML as well.
-
-### The DOM
-
-The DOM (Document Object Model) is a convention to represent HTML (or XML)
-documents, as a set of nodes that act as objects and contain other nodes. You can
-have a `div` element that contains other `div` elements as well as `p` elements
-that contain text.
-
-### Standard HTML communication vs AJAX
-
-In regular HTML comunications, when you click on a link, the browser makes an HTTP
-`GET` request, the server responds with a new HTML document that the browsers renders
-and then replaces the previous one. The same thing happens when you click a button to
-submit a form, except that you make and HTTP `POST` request, but you also get a new
-HTML document that the browser renders and replaces the current one. In AJAX
-communications, the request is separate, and the response is evaluated in JavaScript
-instead of rendered by the browser. That way you can have more control over the content
-that gets returned, and the page is not reloaded.
-
-Built-in Rails Helpers
-----------------------
-
-Rails 4.0 ships with [jQuery](http://jquery.com) as the default JavaScript library.
-The Gemfile contains `gem 'jquery-rails'` which provides the `jquery.js` and
-`jquery_ujs.js` files via the asset pipeline.
-
-You will have to use the `require` directive to tell Sprockets to load `jquery.js`
-and `jquery.js`. For example, a new Rails application includes a default
-`app/assets/javascripts/application.js` file which contains the following lines:
-
-```
-// ...
-//= require jquery
-//= require jquery_ujs
-// ...
-```
-
-The `application.js` file acts like a manifest and is used to tell Sprockets the
-files that you wish to require. In this case, you are requiring the files `jquery.js`
-and `jquery_ujs.js` provided by the `jquery-rails` gem.
-
-If the application is not using the asset pipeline, this can be accessed as:
-
-```ruby
-javascript_include_tag :defaults
-```
-
-By default, `:defaults` loads jQuery.
-
-You can also choose to use Prototype instead of jQuery and specify the option
-using `-j` switch while generating the application.
-
-```bash
-rails new app_name -j prototype
-```
-
-This will add the `prototype-rails` gem to the Gemfile and modify the
-`app/assets/javascripts/application.js` file:
-
-```
-// ...
-//= require prototype
-//= require prototype_ujs
-// ...
-```
-
-You are ready to add some AJAX love to your Rails app!
-
-### Examples
-
-To make them working with AJAX, simply pass the `remote: true` option to
-the original non-remote method.
-
-```ruby
-button_to 'New', action: 'new', form_class: 'new-thing'
-```
-
-will produce
-
-```html
-<form method="post" action="/controller/new" class="new-thing">
- <div><input value="New" type="submit" /></div>
-</form>
-```
-
-```ruby
-button_to 'Create', action: 'create', remote: true, form: { 'data-type' => 'json' }
-```
-
-will produce
-
-```html
-<form method="post" action="/images/create" class="button_to" data-remote="true" data-type="json">
- <div><input value="Create" type="submit" /></div>
-</form>
-```
-
-```ruby
-button_to 'Delete Image', { action: 'delete', id: @image.id },
- method: :delete, data: { confirm: 'Are you sure?' }
-```
-
-will produce
-
-```html
-<form method="post" action="/images/delete/1" class="button_to">
- <div>
- <input type="hidden" name="_method" value="delete" />
- <input data-confirm='Are you sure?' value="Delete" type="submit" />
- </div>
-</form>
-```
-
-```ruby
-button_to 'Destroy', 'http://www.example.com',
- method: 'delete', remote: true, data: { disable_with: 'loading...', confirm: 'Are you sure?' }
-```
-
-will produce
-
-```html
-<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' data-disable-with='loading...' data-confirm='Are you sure?' />
- </div>
-</form>
-```
-
-### The Quintessential AJAX Rails Helper: link_to_remote
-
-Let's start with what is probably the most often used helper: `link_to_remote`. It has an interesting feature from the documentation point of view: the options supplied to `link_to_remote` are shared by all other AJAX helpers, so learning the mechanics and options of `link_to_remote` is a great help when using other helpers.
-
-The signature of `link_to_remote` function is the same as that of the standard `link_to` helper:
-
-```ruby
-def link_to_remote(name, options = {}, html_options = nil)
-```
-
-And here is a simple example of link_to_remote in action:
-
-```ruby
-link_to_remote "Add to cart",
- :url => add_to_cart_url(product.id),
- :update => "cart"
-```
-
-* The very first parameter, a string, is the text of the link which appears on the page.
-* The second parameter, the `options` hash is the most interesting part as it has the AJAX specific stuff:
- * **:url** This is the only parameter that is always required to generate the simplest remote link (technically speaking, it is not required, you can pass an empty `options` hash to `link_to_remote` - but in this case the URL used for the POST request will be equal to your current URL which is probably not your intention). This URL points to your AJAX action handler. The URL is typically specified by Rails REST view helpers, but you can use the `url_for` format too.
- * **:update** Specifying a DOM id of the element we would like to update. The above example demonstrates the simplest way of accomplishing this - however, we are in trouble if the server responds with an error message because that will be injected into the page too! However, Rails has a solution for this situation:
-
- ```ruby
- link_to_remote "Add to cart",
- :url => add_to_cart_url(product),
- :update => { :success => "cart", :failure => "error" }
- ```
-
- If the server returns 200, the output of the above example is equivalent to our first, simple one. However, in case of error, the element with the DOM id `error` is updated rather than the `cart` element.
-
- * **position** By default (i.e. when not specifying this option, like in the examples before) the response is injected into the element with the specified DOM id, replacing the original content of the element (if there was any). You might want to alter this behavior by keeping the original content - the only question is where to place the new content? This can specified by the `position` parameter, with four possibilities:
- * `:before` Inserts the response text just before the target element. More precisely, it creates a text node from the response and inserts it as the left sibling of the target element.
- * `:after` Similar behavior to `:before`, but in this case the response is inserted after the target element.
- * `:top` Inserts the text into the target element, before its original content. If the target element was empty, this is equivalent with not specifying `:position` at all.
- * `:bottom` The counterpart of `:top`: the response is inserted after the target element's original content.
-
- A typical example of using `:bottom` is inserting a new \<li> element into an existing list:
-
- ```ruby
- link_to_remote "Add new item",
- :url => items_url,
- :update => 'item_list',
- :position => :bottom
- ```
-
- * **:method** Most typically you want to use a POST request when adding a remote
-link to your view so this is the default behavior. However, sometimes you'll want to update (PATCH/PUT) or delete/destroy (DELETE) something and you can specify this with the `:method` option. Let's see an example for a typical AJAX link for deleting an item from a list:
-
- ```ruby
- link_to_remote "Delete the item",
- :url => item_url(item),
- :method => :delete
- ```
-
- Note that if we wouldn't override the default behavior (POST), the above snippet would route to the create action rather than destroy.
-
- * **JavaScript filters** You can customize the remote call further by wrapping it with some JavaScript code. Let's say in the previous example, when deleting a link, you'd like to ask for a confirmation by showing a simple modal text box to the user. This is a typical example what you can accomplish with these options - let's see them one by one:
- * `:condition` =&gt; `code` Evaluates `code` (which should evaluate to a boolean) and proceeds if it's true, cancels the request otherwise.
- * `:before` =&gt; `code` Evaluates the `code` just before launching the request. The output of the code has no influence on the execution. Typically used show a progress indicator (see this in action in the next example).
- * `:after` =&gt; `code` Evaluates the `code` after launching the request. Note that this is different from the `:success` or `:complete` callback (covered in the next section) since those are triggered after the request is completed, while the code snippet passed to `:after` is evaluated after the remote call is made. A common example is to disable elements on the page or otherwise prevent further action while the request is completed.
- * `:submit` =&gt; `dom_id` This option does not make sense for `link_to_remote`, but we'll cover it for the sake of completeness. By default, the parent element of the form elements the user is going to submit is the current form - use this option if you want to change the default behavior. By specifying this option you can change the parent element to the element specified by the DOM id `dom_id`.
- * `:with` &gt; `code` The JavaScript code snippet in `code` is evaluated and added to the request URL as a parameter (or set of parameters). Therefore, `code` should return a valid URL query string (like "item_type=8" or "item_type=8&sort=true"). Usually you want to obtain some value(s) from the page - let's see an example:
-
- ```ruby
- link_to_remote "Update record",
- :url => record_url(record),
- :method => :patch,
- :with => "'status=' + 'encodeURIComponent($('status').value) + '&completed=' + $('completed')"
- ```
-
- This generates a remote link which adds 2 parameters to the standard URL generated by Rails, taken from the page (contained in the elements matched by the 'status' and 'completed' DOM id).
-
- * **Callbacks** Since an AJAX call is typically asynchronous, as its name suggests (this is not a rule, and you can fire a synchronous request - see the last option, `:type`) your only way of communicating with a request once it is fired is via specifying callbacks. There are six options at your disposal (in fact 508, counting all possible response types, but these six are the most frequent and therefore specified by a constant):
- * `:loading:` =&gt; `code` The request is in the process of receiving the data, but the transfer is not completed yet.
- * `:loaded:` =&gt; `code` The transfer is completed, but the data is not processed and returned yet
- * `:interactive:` =&gt; `code` One step after `:loaded`: The data is fully received and being processed
- * `:success:` =&gt; `code` The data is fully received, parsed and the server responded with "200 OK"
- * `:failure:` =&gt; `code` The data is fully received, parsed and the server responded with **anything** but "200 OK" (typically 404 or 500, but in general with any status code ranging from 100 to 509)
- * `:complete:` =&gt; `code` The combination of the previous two: The request has finished receiving and parsing the data, and returned a status code (which can be anything).
- * Any other status code ranging from 100 to 509: Additionally you might want to check for other HTTP status codes, such as 404. In this case simply use the status code as a number:
-
- ```ruby
- link_to_remote "Add new item",
- :url => items_url,
- :update => "item_list",
- 404 => "alert('Item not found!')"
- ```
-
- Let's see a typical example for the most frequent callbacks, `:success`, `:failure` and `:complete` in action:
-
- ```ruby
- link_to_remote "Add new item",
- :url => items_url,
- :update => "item_list",
- :before => "$('progress').show()",
- :complete => "$('progress').hide()",
- :success => "display_item_added(request)",
- :failure => "display_error(request)"
- ```
-
- * **:type** If you want to fire a synchronous request for some obscure reason (blocking the browser while the request is processed and doesn't return a status code), you can use the `:type` option with the value of `:synchronous`.
-
-* Finally, using the `html_options` parameter you can add HTML attributes to the generated tag. It works like the same parameter of the `link_to` helper. There are interesting side effects for the `href` and `onclick` parameters though:
- * If you specify the `href` parameter, the AJAX link will degrade gracefully, i.e. the link will point to the URL even if JavaScript is disabled in the client browser
- * `link_to_remote` gains its AJAX behavior by specifying the remote call in the onclick handler of the link. If you supply `html_options[:onclick]` you override the default behavior, so use this with care!
-
-We are finished with `link_to_remote`. I know this is quite a lot to digest for one helper function, but remember, these options are common for all the rest of the Rails view helpers, so we will take a look at the differences / additional parameters in the next sections.
-
-### AJAX Forms
-
-There are three different ways of adding AJAX forms to your view using Rails Prototype helpers. They are slightly different, but striving for the same goal: instead of submitting the form using the standard HTTP request/response cycle, it is submitted asynchronously, thus not reloading the page. These methods are the following:
-
-* `remote_form_for` (and its alias `form_remote_for`) is tied to Rails most tightly of the three since it takes a resource, model or array of resources (in case of a nested resource) as a parameter.
-* `form_remote_tag` AJAXifies the form by serializing and sending its data in the background
-* `submit_to_remote` and `button_to_remote` is more rarely used than the previous two. Rather than creating an AJAX form, you add a button/input
-
-Let's see them in action one by one!
-
-#### `remote_form_for`
-
-#### `form_remote_tag`
-
-#### `submit_to_remote`
-
-### Serving JavaScript
-
-First we'll check out how to send JavaScript to the server manually. You are practically never going to need this, but it's interesting to understand what's going on under the hood.
-
-```ruby
-def javascript_test
- render :text => "alert('Hello, world!')",
- :content_type => "text/javascript"
-end
-```
-
-(Note: if you want to test the above method, create a `link_to_remote` with a single parameter - `:url`, pointing to the `javascript_test` action)
-
-What happens here is that by specifying the Content-Type header variable, we instruct the browser to evaluate the text we are sending over (rather than displaying it as plain text, which is the default behavior).
-
-Testing JavaScript
-------------------
-
-JavaScript testing reminds me the definition of the world 'classic' by Mark Twain: "A classic is something that everybody wants to have read and nobody wants to read." It's similar with JavaScript testing: everyone would like to have it, yet it's not done by too much developers as it is tedious, complicated, there is a proliferation of tools and no consensus/accepted best practices, but we will nevertheless take a stab at it:
-
-* (Fire)Watir
-* Selenium
-* Celerity/Culerity
-* Cucumber+Webrat
-* Mention stuff like screw.unit/jsSpec
-
-Note to self: check out the RailsConf JS testing video
diff --git a/guides/source/configuring.md b/guides/source/configuring.md
index 2131a6c6a8..ab2766054b 100644
--- a/guides/source/configuring.md
+++ b/guides/source/configuring.md
@@ -56,14 +56,6 @@ These configuration methods are to be called on a `Rails::Railtie` object, such
* `config.asset_host` sets the host for the assets. Useful when CDNs are used for hosting assets, or when you want to work around the concurrency constraints builtin in browsers using different domain aliases. Shorter version of `config.action_controller.asset_host`.
-* `config.asset_path` lets you decorate asset paths. This can be a callable, a string, or be `nil` which is the default. For example, the normal path for `blog.js` would be `/javascripts/blog.js`, let that absolute path be `path`. If `config.asset_path` is a callable, Rails calls it when generating asset paths passing `path` as argument. If `config.asset_path` is a string, it is expected to be a `sprintf` format string with a `%s` where `path` will get inserted. In either case, Rails outputs the decorated path. Shorter version of `config.action_controller.asset_path`.
-
- ```ruby
- config.asset_path = proc { |path| "/blog/public#{path}" }
- ```
-
-NOTE. The `config.asset_path` configuration is ignored if the asset pipeline is enabled, which is the default.
-
* `config.autoload_once_paths` accepts an array of paths from which Rails will autoload constants that won't be wiped per request. Relevant if `config.cache_classes` is false, which is the case in development mode by default. Otherwise, all autoloading happens only once. All elements of this array must also be in `autoload_paths`. Default is an empty array.
* `config.autoload_paths` accepts an array of paths from which Rails will autoload constants. Default is all directories under `app`.
@@ -115,9 +107,9 @@ NOTE. The `config.asset_path` configuration is ignored if the asset pipeline is
* `config.middleware` allows you to configure the application's middleware. This is covered in depth in the [Configuring Middleware](#configuring-middleware) section below.
-* `config.queue` configures a different queue implementation for the application. Defaults to `ActiveSupport::SynchronousQueue`. Note that, if the default queue is changed, the default `queue_consumer` is not going to be initialized, it is up to the new queue implementation to handle starting and shutting down its own consumer(s).
+* `config.queue` configures the default job queue for the application. Defaults to `ActiveSupport::Queue.new` which processes jobs in a background thread. If you change the queue, you're responsible for running the jobs as well.
-* `config.queue_consumer` configures a different consumer implementation for the default queue. Defaults to `ActiveSupport::ThreadedQueueConsumer`.
+* `config.queue_consumer` configures a different job consumer for the default queue. Defaults to `ActiveSupport::ThreadedQueueConsumer`. The job consumer must respond to `start`.
* `config.reload_classes_only_on_change` enables or disables reloading of classes only when tracked files change. By default tracks everything on autoload paths and is set to true. If `config.cache_classes` is true, this option is ignored.
@@ -298,8 +290,6 @@ The schema dumper adds one additional configuration option:
* `config.action_controller.asset_host` sets the host for the assets. Useful when CDNs are used for hosting assets rather than the application server itself.
-* `config.action_controller.asset_path` takes a block which configures where assets can be found. Shorter version of `config.action_controller.asset_path`.
-
* `config.action_controller.perform_caching` configures whether the application should perform caching or not. Set to false in development mode, true in production.
* `config.action_controller.default_static_extension` configures the extension used for cached pages. Defaults to `.html`.
@@ -577,8 +567,6 @@ Some parts of Rails can also be configured externally by supplying environment v
* `ENV["RAILS_RELATIVE_URL_ROOT"]` is used by the routing code to recognize URLs when you deploy your application to a subdirectory.
-* `ENV["RAILS_ASSET_ID"]` will override the default cache-busting timestamps that Rails generates for downloadable assets.
-
* `ENV["RAILS_CACHE_ID"]` and `ENV["RAILS_APP_VERSION"]` are used to generate expanded cache keys in Rails' caching code. This allows you to have multiple separate caches from the same application.
diff --git a/guides/source/initialization.md b/guides/source/initialization.md
index c582acd3a3..393bf51863 100644
--- a/guides/source/initialization.md
+++ b/guides/source/initialization.md
@@ -534,7 +534,7 @@ require "rails"
action_controller
action_mailer
rails/test_unit
- sprockets/rails
+ sprockets
).each do |framework|
begin
require "#{framework}/railtie"
diff --git a/guides/source/migrations.md b/guides/source/migrations.md
index 657e872cd0..3eeb45f8c6 100644
--- a/guides/source/migrations.md
+++ b/guides/source/migrations.md
@@ -889,6 +889,27 @@ class AddFuzzToProduct < ActiveRecord::Migration
end
```
+There are other ways in which the above example could have gone badly.
+
+For example, imagine that Alice creates a migration that selectively
+updates the +description+ field on certain products. She runs the
+migration, commits the code, and then begins working on the next feature,
+which is to add a new column +fuzz+ to the products table.
+
+She creates two migrations for this new feature, one which adds the new
+column, and a second which selectively updates the +fuzz+ column based on
+other product attributes.
+
+These migrations run just fine, but when Bob comes back from his vacation
+and calls `rake db:migrate` to run all the outstanding migrations, he gets a
+subtle bug: The descriptions have defaults, and the +fuzz+ column is present,
+but +fuzz+ is nil on all products.
+
+The solution is again to use +Product.reset_column_information+ before
+referencing the Product model in a migration, ensuring the Active Record's
+knowledge of the table structure is current before manipulating data in those
+records.
+
Schema Dumping and You
----------------------
diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md
index 148316d170..d57bb1f8bc 100644
--- a/guides/source/upgrading_ruby_on_rails.md
+++ b/guides/source/upgrading_ruby_on_rails.md
@@ -69,6 +69,8 @@ in the `config/initializers/wrap_parameters.rb` file:
### Action Pack
+Rails 4.0 removed the `ActionController::Base.asset_path` option. Use the assets pipeline feature.
+
Rails 4.0 has deprecated `ActionController::Base.page_cache_extension` option. Use
`ActionController::Base.default_static_extension` instead.
diff --git a/guides/source/working_with_javascript.md b/guides/source/working_with_javascript.md
new file mode 100644
index 0000000000..c33fa8864c
--- /dev/null
+++ b/guides/source/working_with_javascript.md
@@ -0,0 +1,394 @@
+Working With JavaScript
+=======================
+
+This guide covers the built-in Ajax/JavaScript functionality of Rails (and
+more); it will enable you to create rich and dynamic AJAX applications with
+ease! We will cover the following topics:
+
+* An introduction to AJAX
+* Unobtrusive JavaScript
+* Built-in Helpers
+* Server-side concerns
+* Turbolinks
+
+-------------------------------------------------------------------------------
+
+An introduction to AJAX
+------------------------
+
+In order to understand AJAX, you must first understand what a web browser does
+normally.
+
+When you type `http://localhost:3000` into your browser's address bar and hit
+'Go', the browser (your 'client') makes a request to the server. It parses the
+response, then fetches all associated assets, like JavaScript files,
+stylesheets and images. It then assembles the page. If you click a link, it
+does the same process: fetch the page, fetch the assets, put it all together,
+show you the results. This is called the 'Request-Response cycle'.
+
+JavaScript can also make requests to the server, and parse the response. It
+also has the ability to update information on the page. Combining these two
+powers, a JavaScript developer can make a web page that can update just parts of
+itself, without needing to get the full page data from the server. This is a
+powerful technique that we call AJAX, which stands for Asynchronous JavaScript and XML.
+
+Rails ships with CoffeeScript by default, and so the rest of the examples
+in this guide will be in CoffeeScript. All of these lessons, of course, apply
+to vanilla JavaScript as well.
+
+As an example, here's some CoffeeScript code that makes an AJAX request using
+the jQuery library:
+
+```
+$.ajax(url: "/test").done (html) ->
+ $("#results").append html
+```
+
+This code fetches data from "/test", and then appends the result to the `div`
+with an id of `results`.
+
+Rails provides quite a bit of built-in support for building web pages with this
+technique. You rarely have to write this code yourself. The rest of this guide
+will show you how Rails can help you write web sites in this manner, but it's
+all built on top of this fairly simple technique.
+
+Unobtrusive JavaScript
+-------------------------------------
+
+Rails uses a technique called "Unobtrusive JavaScript" to handle attaching
+JavaScript to the DOM. This is generally considered to be a best-practice
+within the frontend community, but you may occasionally read tutorials that
+demonstrate other ways.
+
+Here's the simplest way to write JavaScript. You may see it referred to as
+'inline JavaScript':
+
+```
+<a href="#" onclick="alert('Hello, world.')">Here</a>
+```
+
+When clicked, the alert will trigger. Here's the problem: what happens when
+we have lots of JavaScript we want to execute on a click?
+
+```
+<a href="#" onclick="function fib(n){return n<2?n:fib(n-1)+fib(n-2);};alert('fib of 15 is: ' + fib(15) + '.');">Calculate</a>
+```
+
+Awkward, right? We could pull the function definition out of the click handler,
+and turn it into CoffeeScript:
+
+```
+fib = (n) ->
+ (if n < 2 then n else fib(n - 1) + fib(n - 2))
+```
+
+And then on our page:
+
+```
+<a href="#" onclick="alert('fib of 15 is: ' + fib(15) + '.');">Calculate</a>
+```
+
+That's a little bit better, but what about multiple links that have the same
+effect?
+
+```
+<a href="#" onclick="alert('fib of 16 is: ' + fib(16) + '.');">Calculate</a>
+<a href="#" onclick="alert('fib of 17 is: ' + fib(17) + '.');">Calculate</a>
+<a href="#" onclick="alert('fib of 18 is: ' + fib(18) + '.');">Calculate</a>
+```
+
+Not very DRY, eh? We can fix this by using events instead. We'll add a `data-*`
+attribute to our link, and then bind a handler to the click event of every link
+that has that attribute:
+
+```
+fib = (n) ->
+ (if n < 2 then n else fib(n - 1) + fib(n - 2))
+
+$(document).ready ->
+ $("a[data-fib]").click (e) ->
+ count = $(this).data("fib")
+ alert "fib of #{count} is: #{fib(count)}."
+
+... later ...
+
+<a href="#" data-fib="15">Calculate</a>
+<a href="#" data-fib="16">Calculate</a>
+<a href="#" data-fib="17">Calculate</a>
+```
+
+We call this 'unobtrusive' JavaScript because we're no longer mixing our
+JavaScript into our HTML. We've properly separated our concerns, making future
+changes easier. We can easily add behavior to any link by adding the data
+attribute. We can run all of our JavaScript through a minimizer and
+concatenator. We can serve our entire JavaScript bundle on every page, which
+means that it'll get downloaded on the first page load and then be cached on
+every page after that. Lots of little benefits really add up.
+
+The Rails team strongly encourages you to write your CoffeeScript (and
+JavaScript) in this style, and you can expect that many libraries will also
+follow this pattern.
+
+Built-in Helpers
+----------------------
+
+Rails provides a bunch of view helper methods written in Ruby to assist you
+in generating HTML. Sometimes, you want to add a little AJAX to those elements,
+and Rails has got your back in those cases.
+
+Because of Unobtrusive JavaScript, the Rails AJAX helpers actually consist of two
+parts: the JavaScript part and the Ruby part.
+[rails.js](https://github.com/rails/jquery-ujs/blob/master/src/rails.js)
+provides the JavaScript half, and the regular Ruby view helpers add appropriate
+tags to your DOM. The CoffeeScript in rails.js then listens for these
+attributes, and attaches appropriate handlers.
+
+### form_for
+
+[`form_for`](http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-form_for)
+is a helper that assists with writing forms. `form_for` takes a `:remote`
+option. It works like this:
+
+```
+<%= form_for(@post, remote: true) do |f| %>
+ ...
+<% end %>
+```
+
+This will generate the following HTML:
+
+```
+<form accept-charset="UTF-8" action="/posts" class="new_post" data-remote="true" id="new_post" method="post">
+ ...
+</form>
+```
+
+Note the `data-remote='true'`. Now, the form will be submitted by AJAX rather
+than by the browser's normal submit mechanism.
+
+You probably don't want to just sit there with a filled out `<form>`, though.
+You probably want to do something upon a successful submission. To do that,
+bind to the `ajax:success` event. On failure, use `ajax:error`. Check it out:
+
+```
+<script>
+$(document).ready ->
+ $("#new_post").on("ajax:success", (e, data, status, xhr) ->
+ $("#new_post").append xhr.responseText
+ ).bind "ajax:error", (e, xhr, status, error) ->
+ $("#new_post").append "<p>ERROR</p>"
+</script>
+```
+
+Obviously, you'll want to be a bit more sophisticated than that, but it's a
+start.
+
+### form_tag
+
+[`form_tag`](http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html#method-i-form_tag)
+is very similar to `form_for`. It has a `:remote` option that you can use like
+this:
+
+```
+<%= form_tag('/posts', remote: true) %>
+```
+
+Everything else is the same as `form_for`. See its documentation for full
+details.
+
+### link_to
+
+[`link_to`](http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to)
+is a helper that assits with generating links. It has a `:remote` option you
+can use like this:
+
+```
+<%= link_to "first post", @post, remote: true %>
+```
+
+which generates
+
+```
+<a href="/posts/1" data-remote="true">a post</a>
+```
+
+You can bind to the same AJAX events as `form_for`. Here's an example. Let's
+assume that we have a resource `/fib/:n` that calculates the `n`th Fibonacci
+number. We would generate some HTML like this:
+
+```
+<%= link_to "Calculate", "/fib/15", remote: true, data: { fib: 15 } %>
+```
+
+and write some CoffeeScript like this:
+
+```
+$(document).ready ->
+ $("a[data-fib]").on "ajax:success", (e, data, status, xhr) ->
+ count = $(this).data("fib")
+ alert "fib of #{count} is: #{data}."
+```
+
+Easy!
+
+### button_to
+
+[`button_to`](http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-button_to) is a helper that helps you create buttons. It has a `:remote` option that you can call like this:
+
+```
+<%= button_to "A post", @post, remote: true %>
+```
+
+this generates
+
+```
+<form action="/posts/1" class="button_to" data-remote="true" method="post">
+</form>
+```
+
+Since it's just a `<form>`, all of the information on `form_for` also applies.
+
+Server-side concerns
+--------------------
+
+AJAX isn't just client-side, you also need to do some work on the server
+side to support it. Often, people like their AJAX requests to return JSON
+rather than HTML. Let's discuss what it takes to make that happen.
+
+### A Simple Example
+
+Imagine you have a series of users that you would like to display and provide a
+form on that same page to create a new user. The index action of your
+controller looks like this:
+
+```
+class UsersController < ApplicationController
+ def index
+ @users = User.all
+ @user = User.new
+ end
+ # ...
+```
+
+The index view (`app/views/users/index.html.erb`) contains:
+
+```
+<b>Users</b>
+
+<ul id="users">
+<% @users.each do |user| %>
+ <%= render user %>
+<% end %>
+</ul>
+
+<br>
+
+<%= form_for(@user, remote: true) do |f| %>
+ <%= f.label :name %><br>
+ <%= f.text_field :name %>
+ <%= f.submit %>
+<% end %>
+```
+
+The `app/views/users/_user.html.erb` partial contains the following:
+
+```
+<li><%= user.name %></li>
+```
+
+The top portion of the index page displays the users. The bottom portion
+provides a form to create a new user.
+
+The bottom form will call the create action on the Users controller. Because
+the form's remote option is set to true, the request will be posted to the
+users controller as an AJAX request, looking for JavaScript. In order to
+service that request, the create action of your controller would look like
+this:
+
+```
+ # app/controllers/users_controller.rb
+ # ......
+ def create
+ @user = User.new(params[:user])
+
+ respond_to do |format|
+ if @user.save
+ format.html { redirect_to @user, notice: 'User was successfully created.' }
+ format.js {}
+ format.json { render json: @user, status: :created, location: @user }
+ else
+ format.html { render action: "new" }
+ format.json { render json: @user.errors, status: :unprocessable_entity }
+ end
+ end
+ end
+```
+
+Notice the format.js in the respond_to block; that allows the controller to
+respond to your AJAX request. You then have a corresponding
+`app/views/users/create.js.erb` view file that generates the actual JavaScript
+code that will be sent and executed on the client side.
+
+```
+$("<%= escape_javascript(render @user) %>").appendTo("#users");
+```
+
+Turbolinks
+----------
+
+Rails 4 ships with the [Turbolinks gem](https://github.com/rails/turbolinks).
+This gem uses AJAX to speed up page rendering in most applications.
+
+### How Turbolinks works
+
+Turbolinks attaches a click handler to all `<a>` on the page. If your browser
+supports
+[PushState](https://developer.mozilla.org/en-US/docs/DOM/Manipulating_the_browser_history#The_pushState(\).C2.A0method),
+Turbolinks will make an AJAX request for the page, parse the response, and
+replace the entire `<body>` of the page with the `<body>` of the response. It
+will then use PushState to change the URL to the correct one, preserving
+refresh semantics and giving you pretty URLs.
+
+The only thing you have to do to enable Turbolinks is have it in your Gemfile,
+and put `//= require turbolinks` in your CoffeeScript manifest, which is usually
+`app/assets/javascripts/application.js`.
+
+If you want to disable Turbolinks for certain links, add a `data-no-turbolink`
+attribute to the tag:
+
+```
+<a href="..." data-no-turbolink>No turbolinks here</a>.
+```
+
+### Page Change events
+
+When writing CoffeeScript, you'll often want to do some sort of processing upon
+page load. With jQuery, you'd write something like this:
+
+```
+$(document).ready ->
+ alert "page has loaded!"
+```
+
+However, because Turbolinks overrides the normal page loading process, the
+event that this relies on will not be fired. If you have code that looks like
+this, you must change your code to do this instead:
+
+```
+$(document).on "page:change", ->
+ alert "page has loaded!"
+```
+
+For more details, including other events you can bind to, check out [the
+Turbolinks
+README](https://github.com/rails/turbolinks/blob/ec9ca4d6cf9626e03a672f3b9e7968c816aff94e/README.md).
+
+Other resources
+---------------
+
+Here are some helpful links to help you learn even more:
+
+* [jquery-ujs wiki](https://github.com/rails/jquery-ujs/wiki)
+* [jquery-ujs list of external articles](https://github.com/rails/jquery-ujs/wiki/External-articles)
+* [Rails 3 Remote Links and Forms: A Definitive Guide](http://www.alfajango.com/blog/rails-3-remote-links-and-forms/)
+* [Railscasts: Unobtrusive JavaScript](http://railscasts.com/episodes/205-unobtrusive-javascript)
diff --git a/rails.gemspec b/rails.gemspec
index 3600882c5c..97f6dfeac8 100644
--- a/rails.gemspec
+++ b/rails.gemspec
@@ -25,5 +25,5 @@ Gem::Specification.new do |s|
s.add_dependency('actionmailer', version)
s.add_dependency('railties', version)
s.add_dependency('bundler', '~> 1.2')
- s.add_dependency('sprockets-rails', '~> 1.0')
+ s.add_dependency('sprockets-rails', '~> 2.0.0.rc1')
end
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index c9fa541db8..ba9b24c6c6 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -1,5 +1,7 @@
## Rails 4.0.0 (unreleased) ##
+* Add `.rake` to list of file extensions included by `rake notes` and `rake notes:custom`. *Brent J. Nordquist*
+
* New test locations `test/models`, `test/helpers`, `test/controllers`, and
`test/mailers`. Corresponding rake tasks added as well. *Mike Moore*
@@ -79,9 +81,9 @@
* Load all environments available in `config.paths["config/environments"]`. *Piotr Sarnacki*
-* Add `config.queue_consumer` to allow the default consumer to be configurable. *Carlos Antonio da Silva*
+* Add `config.queue_consumer` to change the job queue consumer from the default `ActiveSupport::ThreadedQueueConsumer`. *Carlos Antonio da Silva*
-* Add Rails.queue as an interface with a default implementation that consumes jobs in a separate thread. *Yehuda Katz*
+* Add `Rails.queue` for processing jobs in the background. *Yehuda Katz*
* Remove Rack::SSL in favour of ActionDispatch::SSL. *Rafael Mendonça França*
diff --git a/railties/lib/rails/all.rb b/railties/lib/rails/all.rb
index eabe566829..6c9c53fc69 100644
--- a/railties/lib/rails/all.rb
+++ b/railties/lib/rails/all.rb
@@ -5,7 +5,7 @@ require "rails"
action_controller
action_mailer
rails/test_unit
- sprockets/rails
+ sprockets
).each do |framework|
begin
require "#{framework}/railtie"
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index b30e6ff615..9ef001c7d0 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -71,7 +71,7 @@ module Rails
attr_reader :reloaders
attr_writer :queue
- delegate :default_url_options, :default_url_options=, :to => :routes
+ delegate :default_url_options, :default_url_options=, to: :routes
def initialize
super
@@ -106,7 +106,7 @@ module Rails
def key_generator
# number of iterations selected based on consultation with the google security
# team. Details at https://github.com/rails/rails/pull/6952#issuecomment-7661220
- @key_generator ||= ActiveSupport::KeyGenerator.new(config.secret_token, :iterations=>1000)
+ @key_generator ||= ActiveSupport::KeyGenerator.new(config.secret_token, iterations: 1000)
end
# Stores some of the Rails initial environment parameters which
@@ -198,11 +198,7 @@ module Rails
end
def queue #:nodoc:
- @queue ||= ActiveSupport::QueueContainer.new(build_queue)
- end
-
- def build_queue #:nodoc:
- config.queue.new
+ @queue ||= config.queue || ActiveSupport::Queue.new
end
def to_app #:nodoc:
@@ -290,7 +286,7 @@ module Rails
def default_middleware_stack #:nodoc:
ActionDispatch::MiddlewareStack.new.tap do |middleware|
app = self
- if rack_cache = config.action_controller.perform_caching && config.action_dispatch.rack_cache
+ if rack_cache = config.action_dispatch.rack_cache
begin
require 'rack/cache'
rescue LoadError => error
@@ -300,9 +296,9 @@ module Rails
if rack_cache == true
rack_cache = {
- :metastore => "rails:/",
- :entitystore => "rails:/",
- :verbose => false
+ metastore: "rails:/",
+ entitystore: "rails:/",
+ verbose: false
}
end
diff --git a/railties/lib/rails/application/bootstrap.rb b/railties/lib/rails/application/bootstrap.rb
index a1bc95550b..62d57c0cc6 100644
--- a/railties/lib/rails/application/bootstrap.rb
+++ b/railties/lib/rails/application/bootstrap.rb
@@ -7,13 +7,13 @@ module Rails
module Bootstrap
include Initializable
- initializer :load_environment_hook, :group => :all do end
+ initializer :load_environment_hook, group: :all do end
- initializer :load_active_support, :group => :all do
+ initializer :load_active_support, group: :all do
require "active_support/all" unless config.active_support.bare
end
- initializer :set_eager_load, :group => :all do
+ initializer :set_eager_load, group: :all do
if config.eager_load.nil?
warn <<-INFO
config.eager_load is set to nil. Please update your config/environments/*.rb files accordingly:
@@ -28,7 +28,7 @@ INFO
end
# Initialize the logger early in the stack in case we need to log some deprecation.
- initializer :initialize_logger, :group => :all do
+ initializer :initialize_logger, group: :all do
Rails.logger ||= config.logger || begin
path = config.paths["log"].first
unless File.exist? File.dirname path
@@ -56,7 +56,7 @@ INFO
end
# Initialize cache early in the stack so railties can make use of it.
- initializer :initialize_cache, :group => :all do
+ initializer :initialize_cache, group: :all do
unless Rails.cache
Rails.cache = ActiveSupport::Cache.lookup_store(config.cache_store)
@@ -67,11 +67,11 @@ INFO
end
# Sets the dependency loading mechanism.
- initializer :initialize_dependency_mechanism, :group => :all do
+ initializer :initialize_dependency_mechanism, group: :all do
ActiveSupport::Dependencies.mechanism = config.cache_classes ? :require : :load
end
- initializer :bootstrap_hook, :group => :all do |app|
+ initializer :bootstrap_hook, group: :all do |app|
ActiveSupport.run_load_hooks(:before_initialize, app)
end
end
diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb
index a7a35c2685..7df517de71 100644
--- a/railties/lib/rails/application/configuration.rb
+++ b/railties/lib/rails/application/configuration.rb
@@ -6,7 +6,7 @@ require 'rails/engine/configuration'
module Rails
class Application
class Configuration < ::Rails::Engine::Configuration
- attr_accessor :asset_host, :asset_path, :assets, :autoflush_log,
+ attr_accessor :asset_host, :assets, :autoflush_log,
:cache_classes, :cache_store, :consider_all_requests_local, :console,
:eager_load, :exceptions_app, :file_watcher, :filter_parameters,
:force_ssl, :helpers_paths, :logger, :log_formatter, :log_tags,
@@ -43,14 +43,14 @@ module Rails
@exceptions_app = nil
@autoflush_log = true
@log_formatter = ActiveSupport::Logger::SimpleFormatter.new
- @queue = ActiveSupport::SynchronousQueue
- @queue_consumer = ActiveSupport::ThreadedQueueConsumer
+ @queue = ActiveSupport::SynchronousQueue.new
+ @queue_consumer = nil
@eager_load = nil
@assets = ActiveSupport::OrderedOptions.new
@assets.enabled = false
@assets.paths = []
- @assets.precompile = [ Proc.new { |path| !%w(.js .css).include?(File.extname(path)) },
+ @assets.precompile = [ Proc.new { |path, fn| fn =~ /app\/assets/ && !%w(.js .css).include?(File.extname(path)) },
/(?:\/|\\|\A)application\.(css|js)$/ ]
@assets.prefix = "/assets"
@assets.version = ''
@@ -64,10 +64,6 @@ module Rails
@assets.logger = nil
end
- def compiled_asset_path
- "/"
- end
-
def encoding=(value)
@encoding = value
silence_warnings do
@@ -79,10 +75,10 @@ module Rails
def paths
@paths ||= begin
paths = super
- paths.add "config/database", :with => "config/database.yml"
- paths.add "config/environment", :with => "config/environment.rb"
+ paths.add "config/database", with: "config/database.yml"
+ paths.add "config/environment", with: "config/environment.rb"
paths.add "lib/templates"
- paths.add "log", :with => "log/#{Rails.env}.log"
+ paths.add "log", with: "log/#{Rails.env}.log"
paths.add "public"
paths.add "public/javascripts"
paths.add "public/stylesheets"
diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb
index d2a402aa51..c520f7af9d 100644
--- a/railties/lib/rails/application/finisher.rb
+++ b/railties/lib/rails/application/finisher.rb
@@ -72,7 +72,7 @@ module Rails
# Set app reload just after the finisher hook to ensure
# paths added in the hook are still loaded.
- initializer :set_clear_dependencies_hook, :group => :all do
+ initializer :set_clear_dependencies_hook, group: :all do
callback = lambda do
ActiveSupport::DescendantsTracker.clear
ActiveSupport::Dependencies.clear
@@ -83,7 +83,7 @@ module Rails
self.reloaders << reloader
# We need to set a to_prepare callback regardless of the reloader result, i.e.
# models should be reloaded if any of the reloaders (i18n, routes) were updated.
- ActionDispatch::Reloader.to_prepare(:prepend => true){ reloader.execute }
+ ActionDispatch::Reloader.to_prepare(prepend: true){ reloader.execute }
else
ActionDispatch::Reloader.to_cleanup(&callback)
end
@@ -97,8 +97,9 @@ module Rails
end
initializer :activate_queue_consumer do |app|
- if config.queue == ActiveSupport::Queue
- app.queue_consumer = config.queue_consumer.start(app.queue, {logger: Rails.logger})
+ if config.queue.class == ActiveSupport::Queue
+ app.queue_consumer = config.queue_consumer || config.queue.consumer
+ app.queue_consumer.start
at_exit { app.queue_consumer.shutdown }
end
end
diff --git a/railties/lib/rails/application/routes_reloader.rb b/railties/lib/rails/application/routes_reloader.rb
index 6f9a200aa9..737977adf9 100644
--- a/railties/lib/rails/application/routes_reloader.rb
+++ b/railties/lib/rails/application/routes_reloader.rb
@@ -4,7 +4,7 @@ module Rails
class Application
class RoutesReloader
attr_reader :route_sets, :paths
- delegate :execute_if_updated, :execute, :updated?, :to => :updater
+ delegate :execute_if_updated, :execute, :updated?, to: :updater
def initialize
@paths = []
diff --git a/railties/lib/rails/commands.rb b/railties/lib/rails/commands.rb
index 9c5dc8f188..b0fae13192 100644
--- a/railties/lib/rails/commands.rb
+++ b/railties/lib/rails/commands.rb
@@ -9,6 +9,30 @@ aliases = {
"r" => "runner"
}
+help_message = <<-EOT
+Usage: rails COMMAND [ARGS]
+
+The most common rails commands are:
+ generate Generate new code (short-cut alias: "g")
+ console Start the Rails console (short-cut alias: "c")
+ server Start the Rails server (short-cut alias: "s")
+ dbconsole Start a console for the database specified in config/database.yml
+ (short-cut alias: "db")
+ new Create a new Rails application. "rails new my_app" creates a
+ new application called MyApp in "./my_app"
+
+In addition to those, there are:
+ application Generate the Rails application code
+ destroy Undo code generated with "generate" (short-cut alias: "d")
+ benchmarker See how fast a piece of code runs
+ profiler Get profile information from a piece of code
+ plugin new Generates skeleton for developing a Rails plugin
+ runner Run a piece of code in the application environment (short-cut alias: "r")
+
+All commands can be run with -h (or --help) for more information.
+EOT
+
+
command = ARGV.shift
command = aliases[command] || command
@@ -81,29 +105,14 @@ when '--version', '-v'
ARGV.unshift '--version'
require 'rails/commands/application'
-else
- puts "Error: Command not recognized" unless %w(-h --help).include?(command)
- puts <<-EOT
-Usage: rails COMMAND [ARGS]
-
-The most common rails commands are:
- generate Generate new code (short-cut alias: "g")
- console Start the Rails console (short-cut alias: "c")
- server Start the Rails server (short-cut alias: "s")
- dbconsole Start a console for the database specified in config/database.yml
- (short-cut alias: "db")
- new Create a new Rails application. "rails new my_app" creates a
- new application called MyApp in "./my_app"
+when '-h', '--help'
+ puts help_message
-In addition to those, there are:
- application Generate the Rails application code
- destroy Undo code generated with "generate" (short-cut alias: "d")
- benchmarker See how fast a piece of code runs
- profiler Get profile information from a piece of code
- plugin new Generates skeleton for developing a Rails plugin
- runner Run a piece of code in the application environment (short-cut alias: "r")
-
-All commands can be run with -h (or --help) for more information.
- EOT
+else
+ puts "Error: Command '#{command}' not recognized"
+ if %x{rake #{command} --dry-run 2>&1 } && $?.success?
+ puts "Did you mean: `$ rake #{command}` ?\n\n"
+ end
+ puts help_message
exit(1)
end
diff --git a/railties/lib/rails/commands/destroy.rb b/railties/lib/rails/commands/destroy.rb
index 9023c61bf2..5479da86a0 100644
--- a/railties/lib/rails/commands/destroy.rb
+++ b/railties/lib/rails/commands/destroy.rb
@@ -6,4 +6,4 @@ if [nil, "-h", "--help"].include?(ARGV.first)
end
name = ARGV.shift
-Rails::Generators.invoke name, ARGV, :behavior => :revoke, :destination_root => Rails.root
+Rails::Generators.invoke name, ARGV, behavior: :revoke, destination_root: Rails.root
diff --git a/railties/lib/rails/commands/generate.rb b/railties/lib/rails/commands/generate.rb
index 9f13cb0513..351c59c645 100644
--- a/railties/lib/rails/commands/generate.rb
+++ b/railties/lib/rails/commands/generate.rb
@@ -8,4 +8,4 @@ end
name = ARGV.shift
root = defined?(ENGINE_ROOT) ? ENGINE_ROOT : Rails.root
-Rails::Generators.invoke name, ARGV, :behavior => :invoke, :destination_root => root
+Rails::Generators.invoke name, ARGV, behavior: :invoke, destination_root: root
diff --git a/railties/lib/rails/commands/runner.rb b/railties/lib/rails/commands/runner.rb
index a672258aa6..0cc672e01c 100644
--- a/railties/lib/rails/commands/runner.rb
+++ b/railties/lib/rails/commands/runner.rb
@@ -1,7 +1,7 @@
require 'optparse'
require 'rbconfig'
-options = { :environment => (ENV['RAILS_ENV'] || "development").dup }
+options = { environment: (ENV['RAILS_ENV'] || "development").dup }
code_or_file = nil
if ARGV.first.nil?
diff --git a/railties/lib/rails/commands/server.rb b/railties/lib/rails/commands/server.rb
index a684129353..80fdc06cd2 100644
--- a/railties/lib/rails/commands/server.rb
+++ b/railties/lib/rails/commands/server.rb
@@ -105,13 +105,13 @@ module Rails
def default_options
super.merge({
- :Port => 3000,
- :DoNotReverseLookup => true,
- :environment => (ENV['RAILS_ENV'] || "development").dup,
- :daemonize => false,
- :debugger => false,
- :pid => File.expand_path("tmp/pids/server.pid"),
- :config => File.expand_path("config.ru")
+ Port: 3000,
+ DoNotReverseLookup: true,
+ environment: (ENV['RAILS_ENV'] || "development").dup,
+ daemonize: false,
+ debugger: false,
+ pid: File.expand_path("tmp/pids/server.pid"),
+ config: File.expand_path("config.ru")
})
end
end
diff --git a/railties/lib/rails/commands/update.rb b/railties/lib/rails/commands/update.rb
index 85a81cddf0..59fae5c337 100644
--- a/railties/lib/rails/commands/update.rb
+++ b/railties/lib/rails/commands/update.rb
@@ -6,4 +6,4 @@ if ARGV.size == 0
end
name = ARGV.shift
-Rails::Generators.invoke name, ARGV, :behavior => :skip
+Rails::Generators.invoke name, ARGV, behavior: :skip
diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb
index 7afb599910..2c2bb1c714 100644
--- a/railties/lib/rails/engine.rb
+++ b/railties/lib/rails/engine.rb
@@ -251,7 +251,7 @@ module Rails
#
# # config/routes.rb
# MyApplication::Application.routes.draw do
- # mount MyEngine::Engine => "/my_engine", :as => "my_engine"
+ # mount MyEngine::Engine => "/my_engine", as: "my_engine"
# get "/foo" => "foo#index"
# end
#
@@ -368,7 +368,7 @@ module Rails
def isolate_namespace(mod)
engine_name(generate_railtie_name(mod))
- self.routes.default_scope = { :module => ActiveSupport::Inflector.underscore(mod.name) }
+ self.routes.default_scope = { module: ActiveSupport::Inflector.underscore(mod.name) }
self.isolated = true
unless mod.respond_to?(:railtie_namespace)
@@ -407,8 +407,8 @@ module Rails
end
end
- delegate :middleware, :root, :paths, :to => :config
- delegate :engine_name, :isolated?, :to => "self.class"
+ delegate :middleware, :root, :paths, to: :config
+ delegate :engine_name, :isolated?, to: "self.class"
def initialize
@_all_autoload_paths = nil
@@ -536,7 +536,7 @@ module Rails
end
# Add configured load paths to ruby load paths and remove duplicates.
- initializer :set_load_path, :before => :bootstrap_hook do
+ initializer :set_load_path, before: :bootstrap_hook do
_all_load_paths.reverse_each do |path|
$LOAD_PATH.unshift(path) if File.directory?(path)
end
@@ -548,7 +548,7 @@ module Rails
#
# This needs to be an initializer, since it needs to run once
# per engine and get the engine as a block parameter
- initializer :set_autoload_paths, :before => :bootstrap_hook do |app|
+ initializer :set_autoload_paths, before: :bootstrap_hook do |app|
ActiveSupport::Dependencies.autoload_paths.unshift(*_all_autoload_paths)
ActiveSupport::Dependencies.autoload_once_paths.unshift(*_all_autoload_once_paths)
@@ -581,13 +581,13 @@ module Rails
end
end
- initializer :load_environment_config, :before => :load_environment_hook, :group => :all do
+ initializer :load_environment_config, before: :load_environment_hook, group: :all do
paths["config/environments"].existent.each do |environment|
require environment
end
end
- initializer :append_assets_path, :group => :all do |app|
+ initializer :append_assets_path, group: :all do |app|
app.config.assets.paths.unshift(*paths["vendor/assets"].existent_directories)
app.config.assets.paths.unshift(*paths["lib/assets"].existent_directories)
app.config.assets.paths.unshift(*paths["app/assets"].existent_directories)
diff --git a/railties/lib/rails/engine/configuration.rb b/railties/lib/rails/engine/configuration.rb
index 6b18b1e249..22e885a3a6 100644
--- a/railties/lib/rails/engine/configuration.rb
+++ b/railties/lib/rails/engine/configuration.rb
@@ -20,7 +20,7 @@ module Rails
# Holds generators configuration:
#
# config.generators do |g|
- # g.orm :data_mapper, :migration => true
+ # g.orm :data_mapper, migration: true
# g.template_engine :haml
# g.test_framework :rspec
# end
@@ -38,26 +38,26 @@ module Rails
def paths
@paths ||= begin
paths = Rails::Paths::Root.new(@root)
- paths.add "app", :eager_load => true, :glob => "*"
- paths.add "app/assets", :glob => "*"
- paths.add "app/controllers", :eager_load => true
- paths.add "app/helpers", :eager_load => true
- paths.add "app/models", :eager_load => true
- paths.add "app/mailers", :eager_load => true
+ paths.add "app", eager_load: true, glob: "*"
+ paths.add "app/assets", glob: "*"
+ paths.add "app/controllers", eager_load: true
+ paths.add "app/helpers", eager_load: true
+ paths.add "app/models", eager_load: true
+ paths.add "app/mailers", eager_load: true
paths.add "app/views"
- paths.add "lib", :load_path => true
- paths.add "lib/assets", :glob => "*"
- paths.add "lib/tasks", :glob => "**/*.rake"
+ paths.add "lib", load_path: true
+ paths.add "lib/assets", glob: "*"
+ paths.add "lib/tasks", glob: "**/*.rake"
paths.add "config"
- paths.add "config/environments", :glob => "#{Rails.env}.rb"
- paths.add "config/initializers", :glob => "**/*.rb"
- paths.add "config/locales", :glob => "*.{rb,yml}"
+ paths.add "config/environments", glob: "#{Rails.env}.rb"
+ paths.add "config/initializers", glob: "**/*.rb"
+ paths.add "config/locales", glob: "*.{rb,yml}"
paths.add "config/routes.rb"
paths.add "db"
paths.add "db/migrate"
paths.add "db/seeds.rb"
- paths.add "vendor", :load_path => true
- paths.add "vendor/assets", :glob => "*"
+ paths.add "vendor", load_path: true
+ paths.add "vendor/assets", glob: "*"
paths
end
end
diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb
index a8c0626a41..367f9288b8 100644
--- a/railties/lib/rails/generators.rb
+++ b/railties/lib/rails/generators.rb
@@ -23,41 +23,41 @@ module Rails
mattr_accessor :namespace
DEFAULT_ALIASES = {
- :rails => {
- :actions => '-a',
- :orm => '-o',
- :javascripts => '-j',
- :javascript_engine => '-je',
- :resource_controller => '-c',
- :scaffold_controller => '-c',
- :stylesheets => '-y',
- :stylesheet_engine => '-se',
- :template_engine => '-e',
- :test_framework => '-t'
+ rails: {
+ actions: '-a',
+ orm: '-o',
+ javascripts: '-j',
+ javascript_engine: '-je',
+ resource_controller: '-c',
+ scaffold_controller: '-c',
+ stylesheets: '-y',
+ stylesheet_engine: '-se',
+ template_engine: '-e',
+ test_framework: '-t'
},
- :test_unit => {
- :fixture_replacement => '-r',
+ test_unit: {
+ fixture_replacement: '-r',
}
}
DEFAULT_OPTIONS = {
- :rails => {
- :assets => true,
- :force_plural => false,
- :helper => true,
- :integration_tool => nil,
- :javascripts => true,
- :javascript_engine => :js,
- :orm => false,
- :performance_tool => nil,
- :resource_controller => :controller,
- :resource_route => true,
- :scaffold_controller => :scaffold_controller,
- :stylesheets => true,
- :stylesheet_engine => :css,
- :test_framework => false,
- :template_engine => :erb
+ rails: {
+ assets: true,
+ force_plural: false,
+ helper: true,
+ integration_tool: nil,
+ javascripts: true,
+ javascript_engine: :js,
+ orm: false,
+ performance_tool: nil,
+ resource_controller: :controller,
+ resource_route: true,
+ scaffold_controller: :scaffold_controller,
+ stylesheets: true,
+ stylesheet_engine: :css,
+ test_framework: false,
+ template_engine: :erb
}
}
diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb
index c41acc7841..5c4e81431c 100644
--- a/railties/lib/rails/generators/actions.rb
+++ b/railties/lib/rails/generators/actions.rb
@@ -7,9 +7,9 @@ module Rails
# Adds an entry into Gemfile for the supplied gem.
#
- # gem "rspec", :group => :test
- # gem "technoweenie-restful-authentication", :lib => "restful-authentication", :source => "http://gems.github.com/"
- # gem "rails", "3.0", :git => "git://github.com/rails/rails"
+ # 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
@@ -33,7 +33,7 @@ module Rails
str = "gem #{parts.join(", ")}"
str = " " + str if @in_group
str = "\n" + str
- append_file "Gemfile", str, :verbose => false
+ append_file "Gemfile", str, verbose: false
end
end
@@ -47,13 +47,13 @@ module Rails
log :gemfile, "group #{name}"
in_root do
- append_file "Gemfile", "\ngroup #{name} do", :force => true
+ append_file "Gemfile", "\ngroup #{name} do", force: true
@in_group = true
instance_eval(&block)
@in_group = false
- append_file "Gemfile", "\nend\n", :force => true
+ append_file "Gemfile", "\nend\n", force: true
end
end
@@ -64,7 +64,7 @@ module Rails
log :source, source
in_root do
- prepend_file "Gemfile", "source #{source.inspect}\n", :verbose => false
+ prepend_file "Gemfile", "source #{source.inspect}\n", verbose: false
end
end
@@ -77,7 +77,7 @@ module Rails
# "config.autoload_paths += %W(#{config.root}/extras)"
# end
#
- # environment(nil, :env => "development") do
+ # environment(nil, env: "development") do
# "config.active_record.observers = :cacher"
# end
def environment(data=nil, options={}, &block)
@@ -87,10 +87,10 @@ module Rails
in_root do
if options[:env].nil?
- inject_into_file 'config/application.rb', "\n #{data}", :after => sentinel, :verbose => false
+ inject_into_file 'config/application.rb', "\n #{data}", after: sentinel, verbose: false
else
Array(options[:env]).each do |env|
- inject_into_file "config/environments/#{env}.rb", "\n #{data}", :after => env_file_sentinel, :verbose => false
+ inject_into_file "config/environments/#{env}.rb", "\n #{data}", after: env_file_sentinel, verbose: false
end
end
end
@@ -100,8 +100,8 @@ module Rails
# Run a command in git.
#
# git :init
- # git :add => "this.file that.rb"
- # git :add => "onefile.rb", :rm => "badfile.cxx"
+ # git add: "this.file that.rb"
+ # git add: "onefile.rb", rm: "badfile.cxx"
def git(commands={})
if commands.is_a?(Symbol)
run "git #{commands}"
@@ -123,7 +123,7 @@ module Rails
# vendor("foreign.rb", "# Foreign code is fun")
def vendor(filename, data=nil, &block)
log :vendor, filename
- create_file("vendor/#{filename}", data, :verbose => false, &block)
+ create_file("vendor/#{filename}", data, verbose: false, &block)
end
# Create a new file in the lib/ directory. Code can be specified
@@ -136,7 +136,7 @@ module Rails
# lib("foreign.rb", "# Foreign code is fun")
def lib(filename, data=nil, &block)
log :lib, filename
- create_file("lib/#{filename}", data, :verbose => false, &block)
+ create_file("lib/#{filename}", data, verbose: false, &block)
end
# Create a new Rakefile with the provided code (either in a block or a string).
@@ -156,7 +156,7 @@ module Rails
# rakefile('seed.rake', 'puts "Planting seeds"')
def rakefile(filename, data=nil, &block)
log :rakefile, filename
- create_file("lib/tasks/#{filename}", data, :verbose => false, &block)
+ create_file("lib/tasks/#{filename}", data, verbose: false, &block)
end
# Create a new initializer with the provided code (either in a block or a string).
@@ -174,7 +174,7 @@ module Rails
# initializer("api.rb", "API_KEY = '123456'")
def initializer(filename, data=nil, &block)
log :initializer, filename
- create_file("config/initializers/#{filename}", data, :verbose => false, &block)
+ create_file("config/initializers/#{filename}", data, verbose: false, &block)
end
# Generate something using a generator from Rails or a plugin.
@@ -186,19 +186,19 @@ module Rails
log :generate, what
argument = args.map {|arg| arg.to_s }.flatten.join(" ")
- in_root { run_ruby_script("script/rails generate #{what} #{argument}", :verbose => false) }
+ in_root { run_ruby_script("script/rails generate #{what} #{argument}", verbose: false) }
end
# Runs the supplied rake task
#
# rake("db:migrate")
- # rake("db:migrate", :env => "production")
- # rake("gems:install", :sudo => true)
+ # rake("db:migrate", env: "production")
+ # rake("gems:install", sudo: true)
def rake(command, options={})
log :rake, command
env = options[:env] || ENV["RAILS_ENV"] || 'development'
sudo = options[:sudo] && RbConfig::CONFIG['host_os'] !~ /mswin|mingw/ ? 'sudo ' : ''
- in_root { run("#{sudo}#{extify(:rake)} #{command} RAILS_ENV=#{env}", :verbose => false) }
+ in_root { run("#{sudo}#{extify(:rake)} #{command} RAILS_ENV=#{env}", verbose: false) }
end
# Just run the capify command in root
@@ -206,7 +206,7 @@ module Rails
# capify!
def capify!
log :capify, ""
- in_root { run("#{extify(:capify)} .", :verbose => false) }
+ in_root { run("#{extify(:capify)} .", verbose: false) }
end
# Make an entry in Rails routing file config/routes.rb
@@ -217,7 +217,7 @@ module Rails
sentinel = /\.routes\.draw do\s*$/
in_root do
- inject_into_file 'config/routes.rb', "\n #{routing_code}", { :after => sentinel, :verbose => false }
+ inject_into_file 'config/routes.rb', "\n #{routing_code}", { after: sentinel, verbose: false }
end
end
diff --git a/railties/lib/rails/generators/base.rb b/railties/lib/rails/generators/base.rb
index cf6daada20..7e938fab47 100644
--- a/railties/lib/rails/generators/base.rb
+++ b/railties/lib/rails/generators/base.rb
@@ -171,9 +171,9 @@ module Rails
defaults = if options[:type] == :boolean
{ }
elsif [true, false].include?(default_value_for_option(name, options))
- { :banner => "" }
+ { banner: "" }
else
- { :desc => "#{name.to_s.humanize} to be invoked", :banner => "NAME" }
+ { desc: "#{name.to_s.humanize} to be invoked", banner: "NAME" }
end
unless class_options.key?(name)
@@ -343,8 +343,8 @@ module Rails
# Small macro to add ruby as an option to the generator with proper
# default value plus an instance helper method called shebang.
def self.add_shebang_option!
- class_option :ruby, :type => :string, :aliases => "-r", :default => Thor::Util.ruby_command,
- :desc => "Path to the Ruby binary of your choice", :banner => "PATH"
+ class_option :ruby, type: :string, aliases: "-r", default: Thor::Util.ruby_command,
+ desc: "Path to the Ruby binary of your choice", banner: "PATH"
no_tasks {
define_method :shebang do
diff --git a/railties/lib/rails/generators/erb.rb b/railties/lib/rails/generators/erb.rb
index aa824499ac..73e986ee7f 100644
--- a/railties/lib/rails/generators/erb.rb
+++ b/railties/lib/rails/generators/erb.rb
@@ -1,7 +1,7 @@
require 'rails/generators/named_base'
-module Erb # :nodoc:
- module Generators # :nodoc:
+module Erb # :nodoc:
+ module Generators # :nodoc:
class Base < Rails::Generators::NamedBase #:nodoc:
protected
diff --git a/railties/lib/rails/generators/erb/controller/controller_generator.rb b/railties/lib/rails/generators/erb/controller/controller_generator.rb
index e14cb09ff7..5f06734ab8 100644
--- a/railties/lib/rails/generators/erb/controller/controller_generator.rb
+++ b/railties/lib/rails/generators/erb/controller/controller_generator.rb
@@ -1,9 +1,9 @@
require 'rails/generators/erb'
-module Erb # :nodoc:
- module Generators # :nodoc:
- class ControllerGenerator < Base # :nodoc:
- argument :actions, :type => :array, :default => [], :banner => "action action"
+module Erb # :nodoc:
+ module Generators # :nodoc:
+ class ControllerGenerator < Base # :nodoc:
+ argument :actions, type: :array, default: [], banner: "action action"
def copy_view_files
base_path = File.join("app/views", class_path, file_name)
diff --git a/railties/lib/rails/generators/erb/mailer/mailer_generator.rb b/railties/lib/rails/generators/erb/mailer/mailer_generator.rb
index 89de2a4be5..7bcac30dde 100644
--- a/railties/lib/rails/generators/erb/mailer/mailer_generator.rb
+++ b/railties/lib/rails/generators/erb/mailer/mailer_generator.rb
@@ -1,8 +1,8 @@
require 'rails/generators/erb/controller/controller_generator'
-module Erb # :nodoc:
- module Generators # :nodoc:
- class MailerGenerator < ControllerGenerator # :nodoc:
+module Erb # :nodoc:
+ module Generators # :nodoc:
+ class MailerGenerator < ControllerGenerator # :nodoc:
protected
def format
diff --git a/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb
index 19fc53aeee..bacbc2d280 100644
--- a/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb
+++ b/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb
@@ -1,12 +1,12 @@
require 'rails/generators/erb'
require 'rails/generators/resource_helpers'
-module Erb # :nodoc:
- module Generators # :nodoc:
- class ScaffoldGenerator < Base # :nodoc:
+module Erb # :nodoc:
+ module Generators # :nodoc:
+ class ScaffoldGenerator < Base # :nodoc:
include Rails::Generators::ResourceHelpers
- argument :attributes, :type => :array, :default => [], :banner => "field:type field:type"
+ argument :attributes, type: :array, default: [], banner: "field:type field:type"
def create_root_folder
empty_directory File.join("app/views", controller_file_path)
diff --git a/railties/lib/rails/generators/generated_attribute.rb b/railties/lib/rails/generators/generated_attribute.rb
index 231813f774..d8a4f15b4b 100644
--- a/railties/lib/rails/generators/generated_attribute.rb
+++ b/railties/lib/rails/generators/generated_attribute.rb
@@ -23,7 +23,7 @@ module Rails
type = type.to_sym if type
if type && reference?(type)
- references_index = UNIQ_INDEX_OPTIONS.include?(has_index) ? { :unique => true } : true
+ references_index = UNIQ_INDEX_OPTIONS.include?(has_index) ? { unique: true } : true
attr_options[:index] = references_index
end
@@ -41,11 +41,11 @@ module Rails
def parse_type_and_options(type)
case type
when /(string|text|binary|integer)\{(\d+)\}/
- return $1, :limit => $2.to_i
+ return $1, limit: $2.to_i
when /decimal\{(\d+)[,.-](\d+)\}/
- return :decimal, :precision => $1.to_i, :scale => $2.to_i
+ return :decimal, precision: $1.to_i, scale: $2.to_i
when /(references|belongs_to)\{polymorphic\}/
- return $1, :polymorphic => true
+ return $1, polymorphic: true
else
return type, {}
end
diff --git a/railties/lib/rails/generators/js/assets/assets_generator.rb b/railties/lib/rails/generators/js/assets/assets_generator.rb
index 82f40de009..1e925b2cd2 100644
--- a/railties/lib/rails/generators/js/assets/assets_generator.rb
+++ b/railties/lib/rails/generators/js/assets/assets_generator.rb
@@ -1,8 +1,8 @@
require "rails/generators/named_base"
module Js # :nodoc:
- module Generators # :nodoc:
- class AssetsGenerator < Rails::Generators::NamedBase # :nodoc:
+ module Generators # :nodoc:
+ class AssetsGenerator < Rails::Generators::NamedBase # :nodoc:
source_root File.expand_path("../templates", __FILE__)
def copy_javascript
diff --git a/railties/lib/rails/generators/named_base.rb b/railties/lib/rails/generators/named_base.rb
index 2791bd9906..84f8f76838 100644
--- a/railties/lib/rails/generators/named_base.rb
+++ b/railties/lib/rails/generators/named_base.rb
@@ -5,9 +5,9 @@ require 'rails/generators/generated_attribute'
module Rails
module Generators
class NamedBase < Base
- argument :name, :type => :string
- class_option :skip_namespace, :type => :boolean, :default => false,
- :desc => "Skip namespace (affects only isolated applications)"
+ argument :name, type: :string
+ class_option :skip_namespace, type: :boolean, default: false,
+ desc: "Skip namespace (affects only isolated applications)"
def initialize(args, *options) #:nodoc:
@inside_template = nil
diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb
index 67e7c4d54f..18637451ac 100644
--- a/railties/lib/rails/generators/rails/app/app_generator.rb
+++ b/railties/lib/rails/generators/rails/app/app_generator.rb
@@ -96,7 +96,7 @@ module Rails
end
def public_directory
- directory "public", "public", :recursive => false
+ directory "public", "public", recursive: false
if options[:skip_index_html]
remove_file "public/index.html"
remove_file 'app/assets/images/rails.png'
@@ -108,7 +108,7 @@ module Rails
directory "script" do |content|
"#{shebang}\n" + content
end
- chmod "script", 0755, :verbose => false
+ chmod "script", 0755, verbose: false
end
def test
@@ -152,8 +152,8 @@ module Rails
add_shared_options_for "application"
# Add bin/rails options
- class_option :version, :type => :boolean, :aliases => "-v", :group => :rails,
- :desc => "Show Rails version number and quit"
+ class_option :version, type: :boolean, aliases: "-v", group: :rails,
+ desc: "Show Rails version number and quit"
def initialize(*args)
raise Error, "Options should be given after the application name. For details run: rails --help" if args[0].blank?
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 fb43c90e21..5f15c973c6 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/application.rb
+++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb
@@ -7,7 +7,7 @@ require 'rails/all'
<%= comment_if :skip_active_record %>require "active_record/railtie"
require "action_controller/railtie"
require "action_mailer/railtie"
-<%= comment_if :skip_sprockets %>require "sprockets/rails/railtie"
+<%= comment_if :skip_sprockets %>require "sprockets/railtie"
<%= comment_if :skip_test_unit %>require "rails/test_unit/railtie"
<% end -%>
diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml
index 07223a71c9..22c9194fad 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml
+++ b/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml
@@ -2,7 +2,9 @@
#
# Install the pg driver:
# gem install pg
-# On Mac OS X with macports:
+# On OS X with Homebrew:
+# gem install pg -- --with-pg-config=/usr/local/bin/pg_config
+# On OS X with MacPorts:
# gem install pg -- --with-pg-config=/opt/local/lib/postgresql84/bin/pg_config
# On Windows:
# gem install pg
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt
index 6b5b3a0b1f..bd0a0d44b8 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt
@@ -32,9 +32,6 @@
<%- end -%>
<%- unless options.skip_sprockets? -%>
- # Do not compress assets.
- config.assets.compress = false
-
# Debug mode disables concatenation and preprocessing of assets.
config.assets.debug = true
<%- end -%>
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
index d86207ae85..9df53bd6c9 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
@@ -24,7 +24,8 @@
<%- unless options.skip_sprockets? -%>
# Compress JavaScripts and CSS.
- config.assets.compress = true
+ config.assets.js_compressor = :uglifier
+ # config.assets.css_compressor = :sass
# Whether to fallback to assets pipeline if a precompiled asset is missed.
config.assets.compile = false
@@ -61,7 +62,7 @@
<%- end -%>
# Ignore bad email addresses and do not raise email delivery errors.
- # Set this to true and configure the email server for immediate delivery to raise delivery errors.
+ # Set this to true and configure the email server for immediate delivery to raise delivery errors.
# config.action_mailer.raise_delivery_errors = false
# Enable threaded mode.
@@ -88,5 +89,5 @@
# Default the production mode queue to an synchronous queue. You will probably
# want to replace this with an out-of-process queueing solution.
- # config.queue = ActiveSupport::SynchronousQueue
+ # config.queue = ActiveSupport::SynchronousQueue.new
end
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt
index 202fc98adf..a5ef0cd9cd 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt
@@ -34,6 +34,6 @@
# Print deprecation notices to the stderr.
config.active_support.deprecation = :stderr
- # Use the testing queue.
- config.queue = ActiveSupport::TestQueue
+ # Use the synchronous queue to run jobs immediately.
+ config.queue = ActiveSupport::SynchronousQueue.new
end
diff --git a/railties/lib/rails/generators/rails/assets/assets_generator.rb b/railties/lib/rails/generators/rails/assets/assets_generator.rb
index e4f07bba2e..6f4b86e708 100644
--- a/railties/lib/rails/generators/rails/assets/assets_generator.rb
+++ b/railties/lib/rails/generators/rails/assets/assets_generator.rb
@@ -1,11 +1,11 @@
module Rails
module Generators
class AssetsGenerator < NamedBase # :nodoc:
- class_option :javascripts, :type => :boolean, :desc => "Generate JavaScripts"
- class_option :stylesheets, :type => :boolean, :desc => "Generate Stylesheets"
+ class_option :javascripts, type: :boolean, desc: "Generate JavaScripts"
+ class_option :stylesheets, type: :boolean, desc: "Generate Stylesheets"
- class_option :javascript_engine, :desc => "Engine for JavaScripts"
- class_option :stylesheet_engine, :desc => "Engine for Stylesheets"
+ class_option :javascript_engine, desc: "Engine for JavaScripts"
+ class_option :stylesheet_engine, desc: "Engine for Stylesheets"
protected
diff --git a/railties/lib/rails/generators/rails/controller/controller_generator.rb b/railties/lib/rails/generators/rails/controller/controller_generator.rb
index 1482fc28d4..bae54623c6 100644
--- a/railties/lib/rails/generators/rails/controller/controller_generator.rb
+++ b/railties/lib/rails/generators/rails/controller/controller_generator.rb
@@ -1,8 +1,8 @@
module Rails
module Generators
class ControllerGenerator < NamedBase # :nodoc:
- argument :actions, :type => :array, :default => [], :banner => "action action"
- check_class_collision :suffix => "Controller"
+ argument :actions, type: :array, default: [], banner: "action action"
+ check_class_collision suffix: "Controller"
def create_controller_files
template 'controller.rb', File.join('app/controllers', class_path, "#{file_name}_controller.rb")
diff --git a/railties/lib/rails/generators/rails/generator/generator_generator.rb b/railties/lib/rails/generators/rails/generator/generator_generator.rb
index 8a0fdbf2fb..9a7a516b5b 100644
--- a/railties/lib/rails/generators/rails/generator/generator_generator.rb
+++ b/railties/lib/rails/generators/rails/generator/generator_generator.rb
@@ -1,10 +1,10 @@
module Rails
module Generators
class GeneratorGenerator < NamedBase # :nodoc:
- check_class_collision :suffix => "Generator"
+ check_class_collision suffix: "Generator"
- class_option :namespace, :type => :boolean, :default => true,
- :desc => "Namespace generator under lib/generators/name"
+ class_option :namespace, type: :boolean, default: true,
+ desc: "Namespace generator under lib/generators/name"
def create_generator_files
directory '.', generator_dir
diff --git a/railties/lib/rails/generators/rails/helper/helper_generator.rb b/railties/lib/rails/generators/rails/helper/helper_generator.rb
index 0975ab3903..5ff38e4111 100644
--- a/railties/lib/rails/generators/rails/helper/helper_generator.rb
+++ b/railties/lib/rails/generators/rails/helper/helper_generator.rb
@@ -1,7 +1,7 @@
module Rails
module Generators
- class HelperGenerator < NamedBase # :nodoc:
- check_class_collision :suffix => "Helper"
+ class HelperGenerator < NamedBase # :nodoc:
+ check_class_collision suffix: "Helper"
def create_helper_files
template 'helper.rb', File.join('app/helpers', class_path, "#{file_name}_helper.rb")
diff --git a/railties/lib/rails/generators/rails/integration_test/integration_test_generator.rb b/railties/lib/rails/generators/rails/integration_test/integration_test_generator.rb
index 9258ae1ee8..70770ddcb8 100644
--- a/railties/lib/rails/generators/rails/integration_test/integration_test_generator.rb
+++ b/railties/lib/rails/generators/rails/integration_test/integration_test_generator.rb
@@ -1,7 +1,7 @@
module Rails
module Generators
class IntegrationTestGenerator < NamedBase # :nodoc:
- hook_for :integration_tool, :as => :integration
+ hook_for :integration_tool, as: :integration
end
end
end
diff --git a/railties/lib/rails/generators/rails/migration/migration_generator.rb b/railties/lib/rails/generators/rails/migration/migration_generator.rb
index 2e1b6a27d8..965c42db36 100644
--- a/railties/lib/rails/generators/rails/migration/migration_generator.rb
+++ b/railties/lib/rails/generators/rails/migration/migration_generator.rb
@@ -1,8 +1,8 @@
module Rails
module Generators
class MigrationGenerator < NamedBase # :nodoc:
- argument :attributes, :type => :array, :default => [], :banner => "field[:type][:index] field[:type][:index]"
- hook_for :orm, :required => true
+ argument :attributes, type: :array, default: [], banner: "field[:type][:index] field[:type][:index]"
+ hook_for :orm, required: true
end
end
end
diff --git a/railties/lib/rails/generators/rails/model/model_generator.rb b/railties/lib/rails/generators/rails/model/model_generator.rb
index af1617fadf..ea3d69d7c9 100644
--- a/railties/lib/rails/generators/rails/model/model_generator.rb
+++ b/railties/lib/rails/generators/rails/model/model_generator.rb
@@ -1,8 +1,8 @@
module Rails
module Generators
class ModelGenerator < NamedBase # :nodoc:
- argument :attributes, :type => :array, :default => [], :banner => "field[:type][:index] field[:type][:index]"
- hook_for :orm, :required => true
+ argument :attributes, type: :array, default: [], banner: "field[:type][:index] field[:type][:index]"
+ hook_for :orm, required: true
end
end
end
diff --git a/railties/lib/rails/generators/rails/observer/observer_generator.rb b/railties/lib/rails/generators/rails/observer/observer_generator.rb
index a11085eb0f..7a4d701ac6 100644
--- a/railties/lib/rails/generators/rails/observer/observer_generator.rb
+++ b/railties/lib/rails/generators/rails/observer/observer_generator.rb
@@ -1,7 +1,7 @@
module Rails
module Generators
class ObserverGenerator < NamedBase # :nodoc:
- hook_for :orm, :required => true
+ hook_for :orm, required: true
end
end
end
diff --git a/railties/lib/rails/generators/rails/performance_test/performance_test_generator.rb b/railties/lib/rails/generators/rails/performance_test/performance_test_generator.rb
index 83771c3dd7..56cd562f3d 100644
--- a/railties/lib/rails/generators/rails/performance_test/performance_test_generator.rb
+++ b/railties/lib/rails/generators/rails/performance_test/performance_test_generator.rb
@@ -1,7 +1,7 @@
module Rails
module Generators
class PerformanceTestGenerator < NamedBase # :nodoc:
- hook_for :performance_tool, :as => :performance
+ hook_for :performance_tool, as: :performance
end
end
end
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 42e0246f76..4a0bcc35a4 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
@@ -68,7 +68,7 @@ module Rails
append_file "Rakefile", <<-EOF
#{rakefile_test_tasks}
-task :default => :test
+task default: :test
EOF
if full?
template "test/integration/navigation_test.rb"
@@ -89,10 +89,10 @@ task :default => :test
end
def test_dummy_config
- template "rails/boot.rb", "#{dummy_path}/config/boot.rb", :force => true
- template "rails/application.rb", "#{dummy_path}/config/application.rb", :force => true
+ template "rails/boot.rb", "#{dummy_path}/config/boot.rb", force: true
+ template "rails/application.rb", "#{dummy_path}/config/application.rb", force: true
if mountable?
- template "rails/routes.rb", "#{dummy_path}/config/routes.rb", :force => true
+ template "rails/routes.rb", "#{dummy_path}/config/routes.rb", force: true
end
end
@@ -135,10 +135,10 @@ task :default => :test
def script(force = false)
return unless full?
- directory "script", :force => force do |content|
+ directory "script", force: force do |content|
"#{shebang}\n" + content
end
- chmod "script", 0755, :verbose => false
+ chmod "script", 0755, verbose: false
end
def gemfile_entry
@@ -158,20 +158,20 @@ task :default => :test
alias_method :plugin_path, :app_path
- class_option :dummy_path, :type => :string, :default => "test/dummy",
- :desc => "Create dummy application at given path"
+ class_option :dummy_path, type: :string, default: "test/dummy",
+ desc: "Create dummy application at given path"
- class_option :full, :type => :boolean, :default => false,
- :desc => "Generate a rails engine with bundled Rails application for testing"
+ class_option :full, type: :boolean, default: false,
+ desc: "Generate a rails engine with bundled Rails application for testing"
- class_option :mountable, :type => :boolean, :default => false,
- :desc => "Generate mountable isolated application"
+ class_option :mountable, type: :boolean, default: false,
+ desc: "Generate mountable isolated application"
- class_option :skip_gemspec, :type => :boolean, :default => false,
- :desc => "Skip gemspec file"
+ class_option :skip_gemspec, type: :boolean, default: false,
+ desc: "Skip gemspec file"
- class_option :skip_gemfile_entry, :type => :boolean, :default => false,
- :desc => "If creating plugin in application's directory " +
+ class_option :skip_gemfile_entry, type: :boolean, default: false,
+ desc: "If creating plugin in application's directory " +
"skip adding entry to Gemfile"
def initialize(*args)
diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/app/views/layouts/%name%/application.html.erb.tt b/railties/lib/rails/generators/rails/plugin_new/templates/app/views/layouts/%name%/application.html.erb.tt
index bd983fb90f..1d380420b4 100644
--- a/railties/lib/rails/generators/rails/plugin_new/templates/app/views/layouts/%name%/application.html.erb.tt
+++ b/railties/lib/rails/generators/rails/plugin_new/templates/app/views/layouts/%name%/application.html.erb.tt
@@ -2,7 +2,7 @@
<html>
<head>
<title><%= camelized %></title>
- <%%= stylesheet_link_tag "<%= name %>/application", :media => "all" %>
+ <%%= stylesheet_link_tag "<%= name %>/application", media: "all" %>
<%%= javascript_include_tag "<%= name %>/application" %>
<%%= csrf_meta_tags %>
</head>
diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/rails/application.rb b/railties/lib/rails/generators/rails/plugin_new/templates/rails/application.rb
index 2f9b7fc962..8a8ba04a70 100644
--- a/railties/lib/rails/generators/rails/plugin_new/templates/rails/application.rb
+++ b/railties/lib/rails/generators/rails/plugin_new/templates/rails/application.rb
@@ -7,7 +7,7 @@ require 'rails/all'
<%= comment_if :skip_active_record %>require "active_record/railtie"
require "action_controller/railtie"
require "action_mailer/railtie"
-<%= comment_if :skip_sprockets %>require "sprockets/rails/railtie"
+<%= comment_if :skip_sprockets %>require "sprockets/railtie"
<%= comment_if :skip_test_unit %>require "rails/test_unit/railtie"
<% end -%>
diff --git a/railties/lib/rails/generators/rails/resource/resource_generator.rb b/railties/lib/rails/generators/rails/resource/resource_generator.rb
index d3ba597dbd..8014feb75f 100644
--- a/railties/lib/rails/generators/rails/resource/resource_generator.rb
+++ b/railties/lib/rails/generators/rails/resource/resource_generator.rb
@@ -7,14 +7,14 @@ module Rails
class ResourceGenerator < ModelGenerator # :nodoc:
include ResourceHelpers
- hook_for :resource_controller, :required => true do |controller|
+ hook_for :resource_controller, required: true do |controller|
invoke controller, [ controller_name, options[:actions] ]
end
- class_option :actions, :type => :array, :banner => "ACTION ACTION", :default => [],
- :desc => "Actions for the resource controller"
+ class_option :actions, type: :array, banner: "ACTION ACTION", default: [],
+ desc: "Actions for the resource controller"
- hook_for :resource_route, :required => true
+ hook_for :resource_route, required: true
end
end
end
diff --git a/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb
index c33c99e989..b4f466fbd8 100644
--- a/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb
+++ b/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb
@@ -6,10 +6,10 @@ module Rails
remove_hook_for :resource_controller
remove_class_option :actions
- class_option :stylesheets, :type => :boolean, :desc => "Generate Stylesheets"
- class_option :stylesheet_engine, :desc => "Engine for Stylesheets"
+ class_option :stylesheets, type: :boolean, desc: "Generate Stylesheets"
+ class_option :stylesheet_engine, desc: "Engine for Stylesheets"
- hook_for :scaffold_controller, :required => true
+ hook_for :scaffold_controller, required: true
hook_for :assets do |assets|
invoke assets, [controller_name]
diff --git a/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb b/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb
index df069ca937..4f36b612ae 100644
--- a/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb
+++ b/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb
@@ -5,21 +5,21 @@ module Rails
class ScaffoldControllerGenerator < NamedBase # :nodoc:
include ResourceHelpers
- check_class_collision :suffix => "Controller"
+ check_class_collision suffix: "Controller"
- class_option :orm, :banner => "NAME", :type => :string, :required => true,
- :desc => "ORM to generate the controller for"
+ class_option :orm, banner: "NAME", type: :string, required: true,
+ desc: "ORM to generate the controller for"
- argument :attributes, :type => :array, :default => [], :banner => "field:type field:type"
+ argument :attributes, type: :array, default: [], banner: "field:type field:type"
def create_controller_files
template "controller.rb", File.join('app/controllers', class_path, "#{controller_file_name}_controller.rb")
end
- hook_for :template_engine, :test_framework, :as => :scaffold
+ hook_for :template_engine, :test_framework, as: :scaffold
# Invoke the helper using the controller name (pluralized)
- hook_for :helper, :as => :scaffold do |invoked|
+ hook_for :helper, as: :scaffold do |invoked|
invoke invoked, [ controller_name ]
end
end
diff --git a/railties/lib/rails/generators/rails/task/task_generator.rb b/railties/lib/rails/generators/rails/task/task_generator.rb
index cf3d1182ea..754824ca0c 100644
--- a/railties/lib/rails/generators/rails/task/task_generator.rb
+++ b/railties/lib/rails/generators/rails/task/task_generator.rb
@@ -1,7 +1,7 @@
module Rails
module Generators
class TaskGenerator < NamedBase # :nodoc:
- argument :actions, :type => :array, :default => [], :banner => "action action"
+ argument :actions, type: :array, default: [], banner: "action action"
def create_task_files
template 'task.rb', File.join('lib/tasks', "#{file_name}.rake")
diff --git a/railties/lib/rails/generators/rails/task/templates/task.rb b/railties/lib/rails/generators/rails/task/templates/task.rb
index b7407bd6dc..1e3ed5f158 100644
--- a/railties/lib/rails/generators/rails/task/templates/task.rb
+++ b/railties/lib/rails/generators/rails/task/templates/task.rb
@@ -1,7 +1,7 @@
namespace :<%= file_name %> do
<% actions.each do |action| -%>
desc "TODO"
- task :<%= action %> => :environment do
+ task <%= action %>: :environment do
end
<% end -%>
diff --git a/railties/lib/rails/generators/resource_helpers.rb b/railties/lib/rails/generators/resource_helpers.rb
index 3df25219ab..7fd5c00768 100644
--- a/railties/lib/rails/generators/resource_helpers.rb
+++ b/railties/lib/rails/generators/resource_helpers.rb
@@ -8,7 +8,7 @@ module Rails
mattr_accessor :skip_warn
def self.included(base) #:nodoc:
- base.class_option :force_plural, :type => :boolean, :desc => "Forces the use of a plural ModelName"
+ base.class_option :force_plural, type: :boolean, desc: "Forces the use of a plural ModelName"
end
# Set controller variables on initialization.
diff --git a/railties/lib/rails/generators/test_case.rb b/railties/lib/rails/generators/test_case.rb
index 30ae805348..24308dcf6c 100644
--- a/railties/lib/rails/generators/test_case.rb
+++ b/railties/lib/rails/generators/test_case.rb
@@ -200,12 +200,12 @@ module Rails
# You can provide a configuration hash as second argument. This method returns the output
# printed by the generator.
def run_generator(args=self.default_arguments, config={})
- capture(:stdout) { self.generator_class.start(args, config.reverse_merge(:destination_root => destination_root)) }
+ capture(:stdout) { self.generator_class.start(args, config.reverse_merge(destination_root: destination_root)) }
end
# Instantiate the generator.
def generator(args=self.default_arguments, options={}, config={})
- @generator ||= self.generator_class.new(args, options, config.reverse_merge(:destination_root => destination_root))
+ @generator ||= self.generator_class.new(args, options, config.reverse_merge(destination_root: destination_root))
end
# Create a Rails::Generators::GeneratedAttribute by supplying the
diff --git a/railties/lib/rails/generators/test_unit/controller/controller_generator.rb b/railties/lib/rails/generators/test_unit/controller/controller_generator.rb
index c53930f994..b5aa581769 100644
--- a/railties/lib/rails/generators/test_unit/controller/controller_generator.rb
+++ b/railties/lib/rails/generators/test_unit/controller/controller_generator.rb
@@ -3,8 +3,8 @@ require 'rails/generators/test_unit'
module TestUnit # :nodoc:
module Generators # :nodoc:
class ControllerGenerator < Base # :nodoc:
- argument :actions, :type => :array, :default => [], :banner => "action action"
- check_class_collision :suffix => "ControllerTest"
+ argument :actions, type: :array, default: [], banner: "action action"
+ check_class_collision suffix: "ControllerTest"
def create_test_files
template 'functional_test.rb',
diff --git a/railties/lib/rails/generators/test_unit/helper/helper_generator.rb b/railties/lib/rails/generators/test_unit/helper/helper_generator.rb
index bcd370098e..0db76f9eaf 100644
--- a/railties/lib/rails/generators/test_unit/helper/helper_generator.rb
+++ b/railties/lib/rails/generators/test_unit/helper/helper_generator.rb
@@ -3,7 +3,7 @@ require 'rails/generators/test_unit'
module TestUnit # :nodoc:
module Generators # :nodoc:
class HelperGenerator < Base # :nodoc:
- check_class_collision :suffix => "HelperTest"
+ check_class_collision suffix: "HelperTest"
def create_helper_files
template 'helper_test.rb', File.join('test/helpers', class_path, "#{file_name}_helper_test.rb")
diff --git a/railties/lib/rails/generators/test_unit/integration/integration_generator.rb b/railties/lib/rails/generators/test_unit/integration/integration_generator.rb
index 427d128275..e004835bd5 100644
--- a/railties/lib/rails/generators/test_unit/integration/integration_generator.rb
+++ b/railties/lib/rails/generators/test_unit/integration/integration_generator.rb
@@ -3,7 +3,7 @@ require 'rails/generators/test_unit'
module TestUnit # :nodoc:
module Generators # :nodoc:
class IntegrationGenerator < Base # :nodoc:
- check_class_collision :suffix => "Test"
+ check_class_collision suffix: "Test"
def create_test_files
template 'integration_test.rb', File.join('test/integration', class_path, "#{file_name}_test.rb")
diff --git a/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb b/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb
index 570a733227..3334b189bf 100644
--- a/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb
+++ b/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb
@@ -3,8 +3,8 @@ require 'rails/generators/test_unit'
module TestUnit # :nodoc:
module Generators # :nodoc:
class MailerGenerator < Base # :nodoc:
- argument :actions, :type => :array, :default => [], :banner => "method method"
- check_class_collision :suffix => "Test"
+ argument :actions, type: :array, default: [], banner: "method method"
+ check_class_collision suffix: "Test"
def create_test_files
template "functional_test.rb", File.join('test/mailers', class_path, "#{file_name}_test.rb")
diff --git a/railties/lib/rails/generators/test_unit/model/model_generator.rb b/railties/lib/rails/generators/test_unit/model/model_generator.rb
index 9b73f3561f..2801749ffe 100644
--- a/railties/lib/rails/generators/test_unit/model/model_generator.rb
+++ b/railties/lib/rails/generators/test_unit/model/model_generator.rb
@@ -3,10 +3,10 @@ require 'rails/generators/test_unit'
module TestUnit # :nodoc:
module Generators # :nodoc:
class ModelGenerator < Base # :nodoc:
- argument :attributes, :type => :array, :default => [], :banner => "field:type field:type"
- class_option :fixture, :type => :boolean
+ argument :attributes, type: :array, default: [], banner: "field:type field:type"
+ class_option :fixture, type: :boolean
- check_class_collision :suffix => "Test"
+ check_class_collision suffix: "Test"
def create_test_file
template 'unit_test.rb', File.join('test/models', class_path, "#{file_name}_test.rb")
diff --git a/railties/lib/rails/generators/test_unit/observer/observer_generator.rb b/railties/lib/rails/generators/test_unit/observer/observer_generator.rb
index 8bfb749743..64fe694a8b 100644
--- a/railties/lib/rails/generators/test_unit/observer/observer_generator.rb
+++ b/railties/lib/rails/generators/test_unit/observer/observer_generator.rb
@@ -3,7 +3,7 @@ require 'rails/generators/test_unit'
module TestUnit # :nodoc:
module Generators # :nodoc:
class ObserverGenerator < Base # :nodoc:
- check_class_collision :suffix => "ObserverTest"
+ check_class_collision suffix: "ObserverTest"
def create_test_files
template 'unit_test.rb', File.join('test/models', class_path, "#{file_name}_observer_test.rb")
diff --git a/railties/lib/rails/generators/test_unit/performance/performance_generator.rb b/railties/lib/rails/generators/test_unit/performance/performance_generator.rb
index 9a80d1ea54..5552edeee4 100644
--- a/railties/lib/rails/generators/test_unit/performance/performance_generator.rb
+++ b/railties/lib/rails/generators/test_unit/performance/performance_generator.rb
@@ -3,7 +3,7 @@ require 'rails/generators/test_unit'
module TestUnit # :nodoc:
module Generators # :nodoc:
class PerformanceGenerator < Base # :nodoc:
- check_class_collision :suffix => "Test"
+ check_class_collision suffix: "Test"
def create_test_files
template 'performance_test.rb', File.join('test/performance', class_path, "#{file_name}_test.rb")
diff --git a/railties/lib/rails/generators/test_unit/plugin/plugin_generator.rb b/railties/lib/rails/generators/test_unit/plugin/plugin_generator.rb
index 41e8873783..b5d4f38444 100644
--- a/railties/lib/rails/generators/test_unit/plugin/plugin_generator.rb
+++ b/railties/lib/rails/generators/test_unit/plugin/plugin_generator.rb
@@ -3,7 +3,7 @@ require 'rails/generators/test_unit'
module TestUnit # :nodoc:
module Generators # :nodoc:
class PluginGenerator < Base # :nodoc:
- check_class_collision :suffix => "Test"
+ check_class_collision suffix: "Test"
def create_test_files
directory '.', 'test'
diff --git a/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb
index 0462c15224..3b4fec2e83 100644
--- a/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb
+++ b/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb
@@ -6,9 +6,9 @@ module TestUnit # :nodoc:
class ScaffoldGenerator < Base # :nodoc:
include Rails::Generators::ResourceHelpers
- check_class_collision :suffix => "ControllerTest"
+ check_class_collision suffix: "ControllerTest"
- argument :attributes, :type => :array, :default => [], :banner => "field:type field:type"
+ argument :attributes, type: :array, default: [], banner: "field:type field:type"
def create_test_files
template "functional_test.rb",
diff --git a/railties/lib/rails/info_controller.rb b/railties/lib/rails/info_controller.rb
index 512803aeac..e94c6a2030 100644
--- a/railties/lib/rails/info_controller.rb
+++ b/railties/lib/rails/info_controller.rb
@@ -23,7 +23,7 @@ class Rails::InfoController < ActionController::Base
def require_local!
unless local_request?
- render :text => '<p>For security purposes, this information is only available to local requests.</p>', :status => :forbidden
+ render text: '<p>For security purposes, this information is only available to local requests.</p>', status: :forbidden
end
end
diff --git a/railties/lib/rails/paths.rb b/railties/lib/rails/paths.rb
index acd9b71b55..8af4130e87 100644
--- a/railties/lib/rails/paths.rb
+++ b/railties/lib/rails/paths.rb
@@ -52,7 +52,7 @@ module Rails
def []=(path, value)
glob = self[path] ? self[path].glob : nil
- add(path, :with => value, :glob => glob)
+ add(path, with: value, glob: glob)
end
def add(path, options={})
diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb
index fba685c769..5b454e7f20 100644
--- a/railties/lib/rails/railtie.rb
+++ b/railties/lib/rails/railtie.rb
@@ -172,7 +172,7 @@ module Rails
end
end
- delegate :railtie_name, :to => "self.class"
+ delegate :railtie_name, to: "self.class"
def config
@config ||= Railtie::Configuration.new
diff --git a/railties/lib/rails/railtie/configurable.rb b/railties/lib/rails/railtie/configurable.rb
index 53796c74cf..1572af0b2a 100644
--- a/railties/lib/rails/railtie/configurable.rb
+++ b/railties/lib/rails/railtie/configurable.rb
@@ -6,7 +6,7 @@ module Rails
extend ActiveSupport::Concern
module ClassMethods
- delegate :config, :to => :instance
+ delegate :config, to: :instance
def inherited(base)
raise "You cannot inherit from a #{self.superclass.name} child"
diff --git a/railties/lib/rails/railtie/configuration.rb b/railties/lib/rails/railtie/configuration.rb
index 9dc8843887..0cbbf04da2 100644
--- a/railties/lib/rails/railtie/configuration.rb
+++ b/railties/lib/rails/railtie/configuration.rb
@@ -50,23 +50,23 @@ module Rails
# First configurable block to run. Called before any initializers are run.
def before_configuration(&block)
- ActiveSupport.on_load(:before_configuration, :yield => true, &block)
+ ActiveSupport.on_load(:before_configuration, yield: true, &block)
end
# Third configurable block to run. Does not run if +config.cache_classes+
# set to false.
def before_eager_load(&block)
- ActiveSupport.on_load(:before_eager_load, :yield => true, &block)
+ ActiveSupport.on_load(:before_eager_load, yield: true, &block)
end
# Second configurable block to run. Called before frameworks initialize.
def before_initialize(&block)
- ActiveSupport.on_load(:before_initialize, :yield => true, &block)
+ ActiveSupport.on_load(:before_initialize, yield: true, &block)
end
# Last configurable block to run. Called after frameworks initialize.
def after_initialize(&block)
- ActiveSupport.on_load(:after_initialize, :yield => true, &block)
+ ActiveSupport.on_load(:after_initialize, yield: true, &block)
end
# Array of callbacks defined by #to_prepare.
diff --git a/railties/lib/rails/source_annotation_extractor.rb b/railties/lib/rails/source_annotation_extractor.rb
index 31e34023c0..3474b02af4 100644
--- a/railties/lib/rails/source_annotation_extractor.rb
+++ b/railties/lib/rails/source_annotation_extractor.rb
@@ -32,9 +32,9 @@ class SourceAnnotationExtractor
end
# Prints all annotations with tag +tag+ under the root directories +app+, +config+, +lib+,
- # +script+, and +test+ (recursively). Only filenames with extension
- # +.builder+, +.rb+, +.erb+, +.haml+, +.slim+, +.css+, +.scss+, +.js+, and
- # +.coffee+ are taken into account. The +options+ hash is passed to each
+ # +script+, and +test+ (recursively). Filenames with extension
+ # +.builder+, +.rb+, +.erb+, +.haml+, +.slim+, +.css+, +.scss+, +.js+,
+ # +.coffee+, and +.rake+ are taken into account. The +options+ hash is passed to each
# annotation's +to_s+.
#
# This class method is the single entry point for the rake tasks.
@@ -56,9 +56,9 @@ class SourceAnnotationExtractor
end
# Returns a hash that maps filenames under +dir+ (recursively) to arrays
- # with their annotations. Only files with annotations are included, and only
- # those with extension +.builder+, +.rb+, +.erb+, +.haml+, +.slim+, +.css+,
- # +.scss+, +.js+, and +.coffee+
+ # with their annotations. Only files with annotations are included. Files
+ # with extension +.builder+, +.rb+, +.erb+, +.haml+, +.slim+, +.css+,
+ # +.scss+, +.js+, +.coffee+, and +.rake+
# are taken into account.
def find_in(dir)
results = {}
@@ -68,7 +68,7 @@ class SourceAnnotationExtractor
if File.directory?(item)
results.update(find_in(item))
- elsif item =~ /\.(builder|rb|coffee)$/
+ elsif item =~ /\.(builder|rb|coffee|rake)$/
results.update(extract_annotations_from(item, /#\s*(#{tag}):?\s*(.*)$/))
elsif item =~ /\.(css|scss|js)$/
results.update(extract_annotations_from(item, /\/\/\s*(#{tag}):?\s*(.*)$/))
diff --git a/railties/lib/rails/tasks/annotations.rake b/railties/lib/rails/tasks/annotations.rake
index 9067b03d00..386ecf44be 100644
--- a/railties/lib/rails/tasks/annotations.rake
+++ b/railties/lib/rails/tasks/annotations.rake
@@ -2,7 +2,7 @@ require 'rails/source_annotation_extractor'
desc "Enumerate all annotations (use notes:optimize, :fixme, :todo for focus)"
task :notes do
- SourceAnnotationExtractor.enumerate "OPTIMIZE|FIXME|TODO", :tag => true
+ SourceAnnotationExtractor.enumerate "OPTIMIZE|FIXME|TODO", tag: true
end
namespace :notes do
diff --git a/railties/lib/rails/tasks/framework.rake b/railties/lib/rails/tasks/framework.rake
index f9cff5b627..50499304cb 100644
--- a/railties/lib/rails/tasks/framework.rake
+++ b/railties/lib/rails/tasks/framework.rake
@@ -1,6 +1,6 @@
namespace :rails do
desc "Update configs and some other initially generated files (or use just update:configs, update:scripts, or update:application_controller)"
- task :update => [ "update:configs", "update:scripts", "update:application_controller" ]
+ task update: [ "update:configs", "update:scripts", "update:application_controller" ]
desc "Applies the template supplied by LOCATION=(/path/to/template) or URL"
task :template do
@@ -9,8 +9,8 @@ namespace :rails do
template = File.expand_path(template) if template !~ %r{\A[A-Za-z][A-Za-z0-9+\-\.]*://}
require 'rails/generators'
require 'rails/generators/rails/app/app_generator'
- generator = Rails::Generators::AppGenerator.new [Rails.root], {}, :destination_root => Rails.root
- generator.apply template, :verbose => false
+ generator = Rails::Generators::AppGenerator.new [Rails.root], {}, destination_root: Rails.root
+ generator.apply template, verbose: false
end
namespace :templates do
@@ -44,8 +44,8 @@ namespace :rails do
@app_generator ||= begin
require 'rails/generators'
require 'rails/generators/rails/app/app_generator'
- gen = Rails::Generators::AppGenerator.new ["rails"], { :with_dispatchers => true },
- :destination_root => Rails.root
+ gen = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true },
+ destination_root: Rails.root
File.exists?(Rails.root.join("config", "application.rb")) ?
gen.send(:app_const) : gen.send(:valid_app_const?)
gen
diff --git a/railties/lib/rails/tasks/middleware.rake b/railties/lib/rails/tasks/middleware.rake
index cd35ffb19a..31e961b483 100644
--- a/railties/lib/rails/tasks/middleware.rake
+++ b/railties/lib/rails/tasks/middleware.rake
@@ -1,5 +1,5 @@
desc 'Prints out your Rack middleware stack'
-task :middleware => :environment do
+task middleware: :environment do
Rails.configuration.middleware.each do |middleware|
puts "use #{middleware.inspect}"
end
diff --git a/railties/lib/rails/tasks/misc.rake b/railties/lib/rails/tasks/misc.rake
index 0a9b9ff4ff..4195106961 100644
--- a/railties/lib/rails/tasks/misc.rake
+++ b/railties/lib/rails/tasks/misc.rake
@@ -5,7 +5,7 @@ task :secret do
end
desc 'List versions of all Rails frameworks and the environment'
-task :about => :environment do
+task about: :environment do
puts Rails::Info
end
@@ -26,7 +26,7 @@ namespace :time do
require 'active_support'
require 'active_support/time'
jan_offset = Time.now.beginning_of_year.utc_offset
- jul_offset = Time.now.beginning_of_year.change(:month => 7).utc_offset
+ jul_offset = Time.now.beginning_of_year.change(month: 7).utc_offset
offset = jan_offset < jul_offset ? jan_offset : jul_offset
build_time_zone_list(:all, offset)
end
diff --git a/railties/lib/rails/tasks/routes.rake b/railties/lib/rails/tasks/routes.rake
index 95f47566ef..676b475640 100644
--- a/railties/lib/rails/tasks/routes.rake
+++ b/railties/lib/rails/tasks/routes.rake
@@ -1,5 +1,5 @@
desc 'Print out all defined routes in match order, with names. Target specific controller with CONTROLLER=x.'
-task :routes => :environment do
+task routes: :environment do
all_routes = Rails.application.routes.routes
require 'action_dispatch/routing/inspector'
inspector = ActionDispatch::Routing::RoutesInspector.new
diff --git a/railties/lib/rails/tasks/tmp.rake b/railties/lib/rails/tasks/tmp.rake
index 0bb64ced95..116988665f 100644
--- a/railties/lib/rails/tasks/tmp.rake
+++ b/railties/lib/rails/tasks/tmp.rake
@@ -1,6 +1,6 @@
namespace :tmp do
desc "Clear session, cache, and socket files from tmp/ (narrow w/ tmp:sessions:clear, tmp:cache:clear, tmp:sockets:clear)"
- task :clear => [ "tmp:sessions:clear", "tmp:cache:clear", "tmp:sockets:clear"]
+ task clear: [ "tmp:sessions:clear", "tmp:cache:clear", "tmp:sockets:clear"]
tmp_dirs = [ 'tmp/sessions',
'tmp/cache',
@@ -13,7 +13,7 @@ namespace :tmp do
tmp_dirs.each { |d| directory d }
desc "Creates tmp directories for sessions, cache, sockets, and pids"
- task :create => tmp_dirs
+ task create: tmp_dirs
namespace :sessions do
# desc "Clears all files in tmp/sessions"
diff --git a/railties/lib/rails/test_unit/railtie.rb b/railties/lib/rails/test_unit/railtie.rb
index 2b6170ebfb..ed89ce4128 100644
--- a/railties/lib/rails/test_unit/railtie.rb
+++ b/railties/lib/rails/test_unit/railtie.rb
@@ -1,8 +1,8 @@
module Rails
class TestUnitRailtie < Rails::Railtie
config.app_generators do |c|
- c.test_framework :test_unit, :fixture => true,
- :fixture_replacement => nil
+ c.test_framework :test_unit, fixture: true,
+ fixture_replacement: nil
c.integration_tool :test_unit
c.performance_tool :test_unit
diff --git a/railties/lib/rails/test_unit/testing.rake b/railties/lib/rails/test_unit/testing.rake
index 63cb955d44..cd59fbe599 100644
--- a/railties/lib/rails/test_unit/testing.rake
+++ b/railties/lib/rails/test_unit/testing.rake
@@ -43,7 +43,7 @@ module Kernel
end
end
-task :default => :test
+task default: :test
desc 'Runs test:units, test:functionals, test:integration together (also available: test:benchmark, test:profile)'
task :test do
@@ -61,7 +61,7 @@ namespace :test do
Rake::Task[task].invoke
nil
rescue => e
- { :task => task, :exception => e }
+ { task: task, exception: e }
end
end.compact
@@ -71,7 +71,7 @@ namespace :test do
end
end
- Rake::TestTask.new(:recent => "test:prepare") do |t|
+ Rake::TestTask.new(recent: "test:prepare") do |t|
since = TEST_CHANGES_SINCE
touched = FileList['test/**/*_test.rb'].select { |path| File.mtime(path) > since } +
recent_tests('app/models/**/*.rb', 'test/models', since) +
@@ -84,7 +84,7 @@ namespace :test do
end
Rake::Task['test:recent'].comment = "Test recent changes"
- Rake::TestTask.new(:uncommitted => "test:prepare") do |t|
+ Rake::TestTask.new(uncommitted: "test:prepare") do |t|
def t.file_list
if File.directory?(".svn")
changed_since_checkin = silence_stderr { `svn status` }.split.map { |path| path.chomp[7 .. -1] }
@@ -108,52 +108,52 @@ namespace :test do
end
Rake::Task['test:uncommitted'].comment = "Test changes since last checkin (only Subversion and Git)"
- Rake::TestTask.new(:single => "test:prepare") do |t|
+ Rake::TestTask.new(single: "test:prepare") do |t|
t.libs << "test"
end
- Rails::SubTestTask.new(:models => "test:prepare") do |t|
+ Rails::SubTestTask.new(models: "test:prepare") do |t|
t.libs << "test"
t.pattern = 'test/models/**/*_test.rb'
end
- Rails::SubTestTask.new(:helpers => "test:prepare") do |t|
+ Rails::SubTestTask.new(helpers: "test:prepare") do |t|
t.libs << "test"
t.pattern = 'test/helpers/**/*_test.rb'
end
- Rails::SubTestTask.new(:units => "test:prepare") do |t|
+ Rails::SubTestTask.new(units: "test:prepare") do |t|
t.libs << "test"
t.pattern = 'test/{models,helpers,unit}/**/*_test.rb'
end
- Rails::SubTestTask.new(:controllers => "test:prepare") do |t|
+ Rails::SubTestTask.new(controllers: "test:prepare") do |t|
t.libs << "test"
t.pattern = 'test/controllers/**/*_test.rb'
end
- Rails::SubTestTask.new(:mailers => "test:prepare") do |t|
+ Rails::SubTestTask.new(mailers: "test:prepare") do |t|
t.libs << "test"
t.pattern = 'test/mailers/**/*_test.rb'
end
- Rails::SubTestTask.new(:functionals => "test:prepare") do |t|
+ Rails::SubTestTask.new(functionals: "test:prepare") do |t|
t.libs << "test"
t.pattern = 'test/{controllers,mailers,functional}/**/*_test.rb'
end
- Rails::SubTestTask.new(:integration => "test:prepare") do |t|
+ Rails::SubTestTask.new(integration: "test:prepare") do |t|
t.libs << "test"
t.pattern = 'test/integration/**/*_test.rb'
end
- Rails::SubTestTask.new(:benchmark => 'test:prepare') do |t|
+ Rails::SubTestTask.new(benchmark: 'test:prepare') do |t|
t.libs << 'test'
t.pattern = 'test/performance/**/*_test.rb'
t.options = '-- --benchmark'
end
- Rails::SubTestTask.new(:profile => 'test:prepare') do |t|
+ Rails::SubTestTask.new(profile: 'test:prepare') do |t|
t.libs << 'test'
t.pattern = 'test/performance/**/*_test.rb'
end
diff --git a/railties/test/application/asset_debugging_test.rb b/railties/test/application/asset_debugging_test.rb
index ebafc7d670..1eddfac664 100644
--- a/railties/test/application/asset_debugging_test.rb
+++ b/railties/test/application/asset_debugging_test.rb
@@ -7,7 +7,7 @@ module ApplicationTests
include Rack::Test::Methods
def setup
- build_app(:initializers => true)
+ build_app(initializers: true)
app_file "app/assets/javascripts/application.js", "//= require_tree ."
app_file "app/assets/javascripts/xmlhr.js", "function f1() { alert(); }"
@@ -15,7 +15,7 @@ module ApplicationTests
app_file "config/routes.rb", <<-RUBY
AppTemplate::Application.routes.draw do
- get '/posts', :to => "posts#index"
+ get '/posts', to: "posts#index"
end
RUBY
@@ -36,9 +36,8 @@ module ApplicationTests
test "assets are concatenated when debug is off and compile is off either if debug_assets param is provided" do
# config.assets.debug and config.assets.compile are false for production environment
ENV["RAILS_ENV"] = "production"
- capture(:stdout) do
- Dir.chdir(app_path){ `bundle exec rake assets:precompile` }
- end
+ output = Dir.chdir(app_path){ `bundle exec rake assets:precompile --trace 2>&1` }
+ assert $?.success?, output
require "#{app_path}/config/environment"
class ::PostsController < ActionController::Base ; end
diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb
index be97855e1a..1311194ea6 100644
--- a/railties/test/application/assets_test.rb
+++ b/railties/test/application/assets_test.rb
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
require 'isolation/abstract_unit'
require 'rack/test'
+require 'active_support/json'
module ApplicationTests
class AssetsTest < ActiveSupport::TestCase
@@ -8,7 +9,7 @@ module ApplicationTests
include Rack::Test::Methods
def setup
- build_app(:initializers => true)
+ build_app(initializers: true)
boot_rails
end
@@ -18,7 +19,7 @@ module ApplicationTests
def precompile!(env = nil)
quietly do
- precompile_task = "bundle exec rake assets:precompile #{env} 2>&1"
+ precompile_task = "bundle exec rake assets:precompile #{env} --trace 2>&1"
output = Dir.chdir(app_path) { %x[ #{precompile_task} ] }
assert $?.success?, output
output
@@ -27,12 +28,12 @@ module ApplicationTests
def clean_assets!
quietly do
- assert Dir.chdir(app_path) { system('bundle exec rake assets:clean') }
+ assert Dir.chdir(app_path) { system('bundle exec rake assets:clobber') }
end
end
def assert_file_exists(filename)
- assert File.exists?(filename), "missing #{filename}"
+ assert Dir[filename].first, "missing #{filename}"
end
def assert_no_file_exists(filename)
@@ -44,7 +45,7 @@ module ApplicationTests
app_file 'config/routes.rb', <<-RUBY
AppTemplate::Application.routes.draw do
- get '*path', :to => lambda { |env| [200, { "Content-Type" => "text/html" }, "Not an asset"] }
+ get '*path', to: lambda { |env| [200, { "Content-Type" => "text/html" }, "Not an asset"] }
end
RUBY
@@ -75,12 +76,10 @@ module ApplicationTests
precompile!
files = Dir["#{app_path}/public/assets/application-*.js"]
- files << Dir["#{app_path}/public/assets/application.js"].first
files << Dir["#{app_path}/public/assets/foo/application-*.js"].first
- files << Dir["#{app_path}/public/assets/foo/application.js"].first
files.each do |file|
assert_not_nil file, "Expected application.js asset to be generated, but none found"
- assert_equal "alert();", File.read(file)
+ assert_equal "alert();\n", File.read(file)
end
end
@@ -108,21 +107,26 @@ module ApplicationTests
precompile!
+ images_should_compile = ["a-*.png", "happyface-*.png", "happy_face-*.png", "happy.face-*.png",
+ "happy-face-*.png", "happy.happy_face-*.png", "happy_happy.face-*.png",
+ "happy.happy.face-*.png", "-happy-*.png", "-happy.face-*.png",
+ "_happy.face-*.png", "_happy-*.png"]
+
images_should_compile.each do |filename|
assert_file_exists("#{app_path}/public/assets/#{filename}")
end
- assert_file_exists("#{app_path}/public/assets/application.js")
- assert_file_exists("#{app_path}/public/assets/application.css")
+ assert_file_exists("#{app_path}/public/assets/application-*.js")
+ assert_file_exists("#{app_path}/public/assets/application-*.css")
- assert_no_file_exists("#{app_path}/public/assets/someapplication.js")
- assert_no_file_exists("#{app_path}/public/assets/someapplication.css")
+ assert_no_file_exists("#{app_path}/public/assets/someapplication-*.js")
+ assert_no_file_exists("#{app_path}/public/assets/someapplication-*.css")
- assert_no_file_exists("#{app_path}/public/assets/something.min.js")
- assert_no_file_exists("#{app_path}/public/assets/something.min.css")
+ assert_no_file_exists("#{app_path}/public/assets/something.min-*.js")
+ assert_no_file_exists("#{app_path}/public/assets/something.min-*.css")
- assert_no_file_exists("#{app_path}/public/assets/something.else.js")
- assert_no_file_exists("#{app_path}/public/assets/something.else.css")
+ assert_no_file_exists("#{app_path}/public/assets/something.else-*.js")
+ assert_no_file_exists("#{app_path}/public/assets/something.else-*.css")
end
test "precompile something.js for directory containing index file" do
@@ -131,7 +135,7 @@ module ApplicationTests
precompile!
- assert_file_exists("#{app_path}/public/assets/something.js")
+ assert_file_exists("#{app_path}/public/assets/something-*.js")
end
test "asset pipeline should use a Sprockets::Index when config.assets.digest is true" do
@@ -151,11 +155,11 @@ module ApplicationTests
add_to_config "config.assets.digest = true"
precompile!
- manifest = "#{app_path}/public/assets/manifest.yml"
+ manifest = Dir["#{app_path}/public/assets/manifest-*.json"].first
- assets = YAML.load_file(manifest)
- assert_match(/application-([0-z]+)\.js/, assets["application.js"])
- assert_match(/application-([0-z]+)\.css/, assets["application.css"])
+ assets = ActiveSupport::JSON.decode(File.read(manifest))
+ assert_match(/application-([0-z]+)\.js/, assets["assets"]["application.js"])
+ assert_match(/application-([0-z]+)\.css/, assets["assets"]["application.css"])
end
test "the manifest file should be saved by default in the same assets folder" do
@@ -166,26 +170,9 @@ module ApplicationTests
precompile!
- manifest = "#{app_path}/public/x/manifest.yml"
- assets = YAML.load_file(manifest)
- assert_match(/application-([0-z]+)\.js/, assets["application.js"])
- end
-
- test "precompile does not append asset digests when config.assets.digest is false" do
- app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>"
- app_file "app/assets/javascripts/application.js", "alert();"
- add_to_config "config.assets.digest = false"
-
- precompile!
-
- assert_file_exists("#{app_path}/public/assets/application.js")
- assert_file_exists("#{app_path}/public/assets/application.css")
-
- manifest = "#{app_path}/public/assets/manifest.yml"
-
- assets = YAML.load_file(manifest)
- assert_equal "application.js", assets["application.js"]
- assert_equal "application.css", assets["application.css"]
+ manifest = Dir["#{app_path}/public/x/manifest-*.json"].first
+ assets = ActiveSupport::JSON.decode(File.read(manifest))
+ assert_match(/application-([0-z]+)\.js/, assets["assets"]["application.js"])
end
test "assets do not require any assets group gem when manifest file is present" do
@@ -195,9 +182,9 @@ module ApplicationTests
ENV["RAILS_ENV"] = "production"
precompile!
- manifest = "#{app_path}/public/assets/manifest.yml"
- assets = YAML.load_file(manifest)
- asset_path = assets["application.js"]
+ manifest = Dir["#{app_path}/public/assets/manifest-*.json"].first
+ assets = ActiveSupport::JSON.decode(File.read(manifest))
+ asset_path = assets["assets"]["application.js"]
require "#{app_path}/config/environment"
@@ -208,58 +195,6 @@ module ApplicationTests
assert !defined?(Uglifier)
end
- test "assets raise AssetNotPrecompiledError when manifest file is present and requested file isn't precompiled" do
- app_file "app/views/posts/index.html.erb", "<%= javascript_include_tag 'app' %>"
-
- app_file "config/routes.rb", <<-RUBY
- AppTemplate::Application.routes.draw do
- get '/posts', :to => "posts#index"
- end
- RUBY
-
- ENV["RAILS_ENV"] = "production"
- precompile!
-
- # Create file after of precompile
- app_file "app/assets/javascripts/app.js", "alert();"
-
- require "#{app_path}/config/environment"
- class ::PostsController < ActionController::Base
- def show_detailed_exceptions?() true end
- end
-
- get '/posts'
- assert_match(/AssetNotPrecompiledError/, last_response.body)
- assert_match(/app\.js isn&#39;t precompiled/, last_response.body)
- end
-
- test "assets raise AssetNotPrecompiledError when manifest file is present and requested file isn't precompiled if digest is disabled" do
- app_file "app/views/posts/index.html.erb", "<%= javascript_include_tag 'app' %>"
- add_to_config "config.assets.compile = false"
- add_to_config "config.assets.digest = false"
-
- app_file "config/routes.rb", <<-RUBY
- AppTemplate::Application.routes.draw do
- get '/posts', :to => "posts#index"
- end
- RUBY
-
- ENV["RAILS_ENV"] = "production"
- precompile!
-
- # Create file after of precompile
- app_file "app/assets/javascripts/app.js", "alert();"
-
- require "#{app_path}/config/environment"
- class ::PostsController < ActionController::Base
- def show_detailed_exceptions?() true end
- end
-
- get '/posts'
- assert_match(/AssetNotPrecompiledError/, last_response.body)
- assert_match(/app\.js isn&#39;t precompiled/, last_response.body)
- end
-
test "precompile properly refers files referenced with asset_path and and run in the provided RAILS_ENV" do
app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>"
# digest is default in false, we must enable it for test environment
@@ -267,33 +202,32 @@ module ApplicationTests
precompile!('RAILS_ENV=test')
- file = Dir["#{app_path}/public/assets/application.css"].first
- assert_match(/\/assets\/rails\.png/, File.read(file))
file = Dir["#{app_path}/public/assets/application-*.css"].first
assert_match(/\/assets\/rails-([0-z]+)\.png/, File.read(file))
end
- test "precompile shouldn't use the digests present in manifest.yml" do
- app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>"
+ test "precompile shouldn't use the digests present in manifest.json" do
+ app_file "app/assets/stylesheets/application.css.erb", "//= depend_on rails.png\np { url: <%= asset_path('rails.png') %> }"
ENV["RAILS_ENV"] = "production"
precompile!
- manifest = "#{app_path}/public/assets/manifest.yml"
- assets = YAML.load_file(manifest)
- asset_path = assets["application.css"]
+ manifest = Dir["#{app_path}/public/assets/manifest-*.json"].first
+ assets = ActiveSupport::JSON.decode(File.read(manifest))
+ asset_path = assets["assets"]["application.css"]
- app_file "app/assets/images/rails.png", "image changed"
+ app_file "app/assets/images/rails.png", "p { url: change }"
precompile!
- assets = YAML.load_file(manifest)
+ assets = ActiveSupport::JSON.decode(File.read(manifest))
- assert_not_equal asset_path, assets["application.css"]
+ assert_not_equal asset_path, assets["assets"]["application.css"]
end
- test "precompile appends the md5 hash to files referenced with asset_path and run in production as default even using RAILS_GROUPS=assets" do
+ test "precompile appends the md5 hash to files referenced with asset_path and run in production with digest true" do
app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>"
add_to_config "config.assets.compile = true"
+ add_to_config "config.assets.digest = true"
ENV["RAILS_ENV"] = nil
@@ -309,11 +243,16 @@ module ApplicationTests
add_to_config "config.assets.precompile = [ /\.png$/, /application.(css|js)$/ ]"
precompile!
+
+ manifest = Dir["#{app_path}/public/assets/manifest-*.json"].first
+ assets = ActiveSupport::JSON.decode(File.read(manifest))
+ assert asset_path = assets["assets"].find { |(k, v)| k !~ /rails.png/ && k =~ /.png/ }[1]
+
require "#{app_path}/config/environment"
- get "/assets/#{URI.parser.escape(filename)}"
+ get "/assets/#{URI.parser.escape(asset_path)}"
assert_match "not a image really", last_response.body
- assert_file_exists("#{app_path}/public/assets/#{filename}")
+ assert_file_exists("#{app_path}/public/assets/#{asset_path}")
end
test "assets are cleaned up properly" do
@@ -353,7 +292,7 @@ module ApplicationTests
class ::OmgController < ActionController::Base
def index
flash[:cool_story] = true
- render :text => "ok"
+ render text: "ok"
end
end
@@ -403,7 +342,7 @@ module ApplicationTests
add_to_config "config.assets.digest = false"
precompile!
- assert_equal "Post;\n", File.read("#{app_path}/public/assets/application.js")
+ assert_equal "Post;\n", File.read(Dir["#{app_path}/public/assets/application-*.js"].first)
end
test "assets can't access model information when precompiling if not initializing the app" do
@@ -415,7 +354,7 @@ module ApplicationTests
add_to_config "config.assets.initialize_on_precompile = false"
precompile!
- assert_equal "NoPost;\n", File.read("#{app_path}/public/assets/application.js")
+ assert_equal "NoPost;\n", File.read(Dir["#{app_path}/public/assets/application-*.js"].first)
end
test "initialization on the assets group should set assets_dir" do
@@ -449,7 +388,7 @@ module ApplicationTests
clean_assets!
- files = Dir["#{app_path}/public/production_assets/application.js"]
+ files = Dir["#{app_path}/public/production_assets/application-*.js"]
assert_equal 0, files.length, "Expected application.js asset to be removed, but still exists"
end
@@ -471,7 +410,7 @@ module ApplicationTests
add_to_config "config.asset_host = 'example.com'"
precompile!
- assert_match 'src="//example.com/assets/rails.png"', File.read("#{app_path}/public/assets/image_loader.js")
+ assert_match 'src="//example.com/assets/rails.png"', File.read(Dir["#{app_path}/public/assets/image_loader-*.js"].first)
end
test "asset paths should use RAILS_RELATIVE_URL_ROOT by default" do
@@ -481,19 +420,7 @@ module ApplicationTests
add_to_config "config.assets.precompile = %w{app.js}"
precompile!
- assert_match 'src="/sub/uri/assets/rails.png"', File.read("#{app_path}/public/assets/app.js")
- end
-
- test "html assets are compiled when executing precompile" do
- app_file "app/assets/pages/page.html.erb", "<%= javascript_include_tag :application %>"
- ENV["RAILS_ENV"] = "production"
- ENV["RAILS_GROUP"] = "assets"
-
- quietly do
- Dir.chdir(app_path){ `bundle exec rake assets:precompile` }
- end
-
- assert_file_exists("#{app_path}/public/assets/page.html")
+ assert_match 'src="/sub/uri/assets/rails.png"', File.read(Dir["#{app_path}/public/assets/app-*.js"].first)
end
test "assets:cache:clean should clean cache" do
@@ -501,11 +428,10 @@ module ApplicationTests
precompile!
quietly do
- Dir.chdir(app_path){ `bundle exec rake assets:cache:clean` }
+ Dir.chdir(app_path){ `bundle exec rake assets:clobber` }
end
- require "#{app_path}/config/environment"
- assert_equal 0, Dir.entries(Rails.application.assets.cache.cache_path).size - 2 # reject [".", ".."]
+ assert !File.exist?("#{app_path}/tmp/cache/assets")
end
private
diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb
index 07d47dc67b..c4c1100f19 100644
--- a/railties/test/application/configuration_test.rb
+++ b/railties/test/application/configuration_test.rb
@@ -56,14 +56,6 @@ module ApplicationTests
assert_match "ActiveRecord::PendingMigrationError", last_response.body
end
- test "multiple queue construction is possible" do
- require 'rails'
- require "#{app_path}/config/environment"
- mail_queue = Rails.application.build_queue
- image_processing_queue = Rails.application.build_queue
- assert_not_equal mail_queue, image_processing_queue
- end
-
test "Rails.groups returns available groups" do
require "rails"
@@ -162,11 +154,6 @@ module ApplicationTests
assert AppTemplate::Application, AppTemplate::Application.config.eager_load_namespaces
end
- test "asset_path defaults to nil for application" do
- require "#{app_path}/config/environment"
- assert_equal nil, AppTemplate::Application.config.asset_path
- end
-
test "the application can be eager loaded even when there are no frameworks" do
FileUtils.rm_rf("#{app_path}/config/environments")
add_to_config <<-RUBY
@@ -247,7 +234,7 @@ module ApplicationTests
class ::OmgController < ActionController::Base
def index
cookies.signed[:some_key] = "some_value"
- render :text => env["action_dispatch.secret_token"]
+ render text: env["action_dispatch.secret_token"]
end
end
@@ -260,7 +247,7 @@ module ApplicationTests
class ::OmgController < ActionController::Base
def index
- render :inline => "<%= csrf_meta_tags %>"
+ render inline: "<%= csrf_meta_tags %>"
end
end
@@ -280,11 +267,11 @@ module ApplicationTests
app_file 'app/controllers/posts_controller.rb', <<-RUBY
class PostsController < ApplicationController
def show
- render :inline => "<%= begin; form_for(Post.new) {}; rescue => e; e.to_s; end %>"
+ render inline: "<%= begin; form_for(Post.new) {}; rescue => e; e.to_s; end %>"
end
def update
- render :text => "update"
+ render text: "update"
end
end
RUBY
@@ -299,7 +286,7 @@ module ApplicationTests
token = "cf50faa3fe97702ca1ae"
PostsController.any_instance.stubs(:form_authenticity_token).returns(token)
- params = {:authenticity_token => token}
+ params = {authenticity_token: token}
get "/posts/1"
assert_match(/patch/, last_response.body)
@@ -324,7 +311,7 @@ module ApplicationTests
class ::OmgController < ActionController::Base
def index
- render :inline => "<%= csrf_meta_tags %>"
+ render inline: "<%= csrf_meta_tags %>"
end
end
@@ -441,21 +428,6 @@ module ApplicationTests
end
end
- test "config.asset_path is not passed through env" do
- make_basic_app do |app|
- app.config.asset_path = "/omg%s"
- end
-
- class ::OmgController < ActionController::Base
- def index
- render :inline => "<%= image_path('foo.jpg') %>"
- end
- end
-
- get "/"
- assert_equal "/omg/images/foo.jpg", last_response.body
- end
-
test "config.action_view.cache_template_loading with cache_classes default" do
add_to_config "config.cache_classes = true"
require "#{app_path}/config/environment"
@@ -501,7 +473,7 @@ module ApplicationTests
class ::OmgController < ActionController::Base
def index
- render :text => env["action_dispatch.show_exceptions"]
+ render text: env["action_dispatch.show_exceptions"]
end
end
@@ -511,7 +483,7 @@ module ApplicationTests
test "config.action_controller.wrap_parameters is set in ActionController::Base" do
app_file 'config/initializers/wrap_parameters.rb', <<-RUBY
- ActionController::Base.wrap_parameters :format => [:json]
+ ActionController::Base.wrap_parameters format: [:json]
RUBY
app_file 'app/models/post.rb', <<-RUBY
@@ -531,7 +503,7 @@ module ApplicationTests
app_file 'app/controllers/posts_controller.rb', <<-RUBY
class PostsController < ApplicationController
def create
- render :text => params[:post].inspect
+ render text: params[:post].inspect
end
end
RUBY
@@ -552,7 +524,7 @@ module ApplicationTests
app_file 'app/controllers/posts_controller.rb', <<-RUBY
class PostsController < ActionController::Base
def create
- render :text => params[:post].permitted? ? "permitted" : "forbidden"
+ render text: params[:post].permitted? ? "permitted" : "forbidden"
end
end
RUBY
@@ -566,7 +538,7 @@ module ApplicationTests
require "#{app_path}/config/environment"
- post "/posts", {:post => {"title" =>"zomg"}}
+ post "/posts", {post: {"title" =>"zomg"}}
assert_equal 'permitted', last_response.body
end
@@ -578,8 +550,8 @@ module ApplicationTests
class ::OmgController < ActionController::Base
def index
respond_to do |format|
- format.html { render :text => "HTML" }
- format.xml { render :text => "XML" }
+ format.html { render text: "HTML" }
+ format.xml { render text: "XML" }
end
end
end
@@ -587,7 +559,7 @@ module ApplicationTests
get "/", {}, "HTTP_ACCEPT" => "application/xml"
assert_equal 'HTML', last_response.body
- get "/", { :format => :xml }, "HTTP_ACCEPT" => "application/xml"
+ get "/", { format: :xml }, "HTTP_ACCEPT" => "application/xml"
assert_equal 'XML', last_response.body
end
diff --git a/railties/test/application/generators_test.rb b/railties/test/application/generators_test.rb
index b80244f1d2..bc0af499c1 100644
--- a/railties/test/application/generators_test.rb
+++ b/railties/test/application/generators_test.rb
@@ -48,22 +48,22 @@ module ApplicationTests
c.generators.orm = :data_mapper
c.generators.test_framework = :rspec
c.generators.helper = false
- expected = { :rails => { :orm => :data_mapper, :test_framework => :rspec, :helper => false } }
+ expected = { rails: { orm: :data_mapper, test_framework: :rspec, helper: false } }
assert_equal(expected, c.generators.options)
end
end
test "generators set rails aliases" do
with_config do |c|
- c.generators.aliases = { :rails => { :test_framework => "-w" } }
- expected = { :rails => { :test_framework => "-w" } }
+ c.generators.aliases = { rails: { test_framework: "-w" } }
+ expected = { rails: { test_framework: "-w" } }
assert_equal expected, c.generators.aliases
end
end
test "generators aliases, options, templates and fallbacks on initialization" do
add_to_config <<-RUBY
- config.generators.rails :aliases => { :test_framework => "-w" }
+ config.generators.rails aliases: { test_framework: "-w" }
config.generators.orm :data_mapper
config.generators.test_framework :rspec
config.generators.fallbacks[:shoulda] = :test_unit
@@ -76,7 +76,7 @@ module ApplicationTests
assert_equal :rspec, Rails::Generators.options[:rails][:test_framework]
assert_equal "-w", Rails::Generators.aliases[:rails][:test_framework]
- assert_equal Hash[:shoulda => :test_unit], Rails::Generators.fallbacks
+ assert_equal Hash[shoulda: :test_unit], Rails::Generators.fallbacks
assert_equal ["some/where"], Rails::Generators.templates_path
end
@@ -95,31 +95,31 @@ module ApplicationTests
test "generators with hashes for options and aliases" do
with_bare_config do |c|
c.generators do |g|
- g.orm :data_mapper, :migration => false
- g.plugin :aliases => { :generator => "-g" },
- :generator => true
+ g.orm :data_mapper, migration: false
+ g.plugin aliases: { generator: "-g" },
+ generator: true
end
expected = {
- :rails => { :orm => :data_mapper },
- :plugin => { :generator => true },
- :data_mapper => { :migration => false }
+ rails: { orm: :data_mapper },
+ plugin: { generator: true },
+ data_mapper: { migration: false }
}
assert_equal expected, c.generators.options
- assert_equal({ :plugin => { :generator => "-g" } }, c.generators.aliases)
+ assert_equal({ plugin: { generator: "-g" } }, c.generators.aliases)
end
end
test "generators with string and hash for options should generate symbol keys" do
with_bare_config do |c|
c.generators do |g|
- g.orm 'data_mapper', :migration => false
+ g.orm 'data_mapper', migration: false
end
expected = {
- :rails => { :orm => :data_mapper },
- :data_mapper => { :migration => false }
+ rails: { orm: :data_mapper },
+ data_mapper: { migration: false }
}
assert_equal expected, c.generators.options
diff --git a/railties/test/application/initializers/frameworks_test.rb b/railties/test/application/initializers/frameworks_test.rb
index 81f6096be8..528bec58ef 100644
--- a/railties/test/application/initializers/frameworks_test.rb
+++ b/railties/test/application/initializers/frameworks_test.rb
@@ -52,14 +52,13 @@ module ApplicationTests
test "uses the default queue for ActionMailer" do
require "#{app_path}/config/environment"
- assert_kind_of ActiveSupport::QueueContainer, ActionMailer::Base.queue
+ assert_kind_of ActiveSupport::Queue, ActionMailer::Base.queue
end
test "allows me to configure queue for ActionMailer" do
app_file "config/environments/development.rb", <<-RUBY
AppTemplate::Application.configure do
- Rails.queue[:mailer] = ActiveSupport::TestQueue.new
- config.action_mailer.queue = Rails.queue[:mailer]
+ config.action_mailer.queue = ActiveSupport::TestQueue.new
end
RUBY
diff --git a/railties/test/application/initializers/i18n_test.rb b/railties/test/application/initializers/i18n_test.rb
index 02d20bc150..489b7ddb92 100644
--- a/railties/test/application/initializers/i18n_test.rb
+++ b/railties/test/application/initializers/i18n_test.rb
@@ -143,7 +143,7 @@ en:
I18n::Railtie.config.i18n.fallbacks = true
load_app
assert I18n.backend.class.included_modules.include?(I18n::Backend::Fallbacks)
- assert_fallbacks :de => [:de, :en]
+ assert_fallbacks de: [:de, :en]
end
test "config.i18n.fallbacks = true initializes I18n.fallbacks with default settings even when backend changes" do
@@ -151,37 +151,37 @@ en:
I18n::Railtie.config.i18n.backend = Class.new(I18n::Backend::Simple).new
load_app
assert I18n.backend.class.included_modules.include?(I18n::Backend::Fallbacks)
- assert_fallbacks :de => [:de, :en]
+ assert_fallbacks de: [:de, :en]
end
test "config.i18n.fallbacks.defaults = [:'en-US'] initializes fallbacks with en-US as a fallback default" do
I18n::Railtie.config.i18n.fallbacks.defaults = [:'en-US']
load_app
- assert_fallbacks :de => [:de, :'en-US', :en]
+ assert_fallbacks de: [:de, :'en-US', :en]
end
test "config.i18n.fallbacks.map = { :ca => :'es-ES' } initializes fallbacks with a mapping ca => es-ES" do
I18n::Railtie.config.i18n.fallbacks.map = { :ca => :'es-ES' }
load_app
- assert_fallbacks :ca => [:ca, :"es-ES", :es, :en]
+ assert_fallbacks ca: [:ca, :"es-ES", :es, :en]
end
test "[shortcut] config.i18n.fallbacks = [:'en-US'] initializes fallbacks with en-US as a fallback default" do
I18n::Railtie.config.i18n.fallbacks = [:'en-US']
load_app
- assert_fallbacks :de => [:de, :'en-US', :en]
+ assert_fallbacks de: [:de, :'en-US', :en]
end
test "[shortcut] config.i18n.fallbacks = [{ :ca => :'es-ES' }] initializes fallbacks with a mapping de-AT => de-DE" do
I18n::Railtie.config.i18n.fallbacks.map = { :ca => :'es-ES' }
load_app
- assert_fallbacks :ca => [:ca, :"es-ES", :es, :en]
+ assert_fallbacks ca: [:ca, :"es-ES", :es, :en]
end
test "[shortcut] config.i18n.fallbacks = [:'en-US', { :ca => :'es-ES' }] initializes fallbacks with the given arguments" do
I18n::Railtie.config.i18n.fallbacks = [:'en-US', { :ca => :'es-ES' }]
load_app
- assert_fallbacks :ca => [:ca, :"es-ES", :es, :'en-US', :en]
+ assert_fallbacks ca: [:ca, :"es-ES", :es, :'en-US', :en]
end
end
end
diff --git a/railties/test/application/initializers/notifications_test.rb b/railties/test/application/initializers/notifications_test.rb
index d866a63fe0..baae6fd928 100644
--- a/railties/test/application/initializers/notifications_test.rb
+++ b/railties/test/application/initializers/notifications_test.rb
@@ -33,7 +33,7 @@ module ApplicationTests
ActiveRecord::Base.logger = logger
# Mimic Active Record notifications
- instrument "sql.active_record", :name => "SQL", :sql => "SHOW tables"
+ instrument "sql.active_record", name: "SQL", sql: "SHOW tables"
wait
assert_equal 1, logger.logged(:debug).size
diff --git a/railties/test/application/loading_test.rb b/railties/test/application/loading_test.rb
index fcbc3c048c..ad7172c514 100644
--- a/railties/test/application/loading_test.rb
+++ b/railties/test/application/loading_test.rb
@@ -19,14 +19,14 @@ class LoadingTest < ActiveSupport::TestCase
test "constants in app are autoloaded" do
app_file "app/models/post.rb", <<-MODEL
class Post < ActiveRecord::Base
- validates_acceptance_of :title, :accept => "omg"
+ validates_acceptance_of :title, accept: "omg"
end
MODEL
require "#{rails_root}/config/environment"
setup_ar!
- p = Post.create(:title => 'omg')
+ p = Post.create(title: 'omg')
assert_equal 1, Post.count
assert_equal 'omg', p.title
p = Post.first
@@ -36,7 +36,7 @@ class LoadingTest < ActiveSupport::TestCase
test "models without table do not panic on scope definitions when loaded" do
app_file "app/models/user.rb", <<-MODEL
class User < ActiveRecord::Base
- default_scope where(:published => true)
+ default_scope where(published: true)
end
MODEL
@@ -76,8 +76,8 @@ class LoadingTest < ActiveSupport::TestCase
app_file 'config/routes.rb', <<-RUBY
AppTemplate::Application.routes.draw do
- get '/load', :to => lambda { |env| [200, {}, Post.all] }
- get '/unload', :to => lambda { |env| [200, {}, []] }
+ get '/load', to: lambda { |env| [200, {}, Post.all] }
+ get '/unload', to: lambda { |env| [200, {}, []] }
end
RUBY
@@ -106,7 +106,7 @@ class LoadingTest < ActiveSupport::TestCase
app_file 'config/routes.rb', <<-RUBY
AppTemplate::Application.routes.draw do
- get '/c', :to => lambda { |env| [200, {"Content-Type" => "text/plain"}, [User.counter.to_s]] }
+ get '/c', to: lambda { |env| [200, {"Content-Type" => "text/plain"}, [User.counter.to_s]] }
end
RUBY
@@ -145,7 +145,7 @@ class LoadingTest < ActiveSupport::TestCase
app_file 'config/routes.rb', <<-RUBY
AppTemplate::Application.routes.draw do
- get '/c', :to => lambda { |env| [200, {"Content-Type" => "text/plain"}, [User.counter.to_s]] }
+ get '/c', to: lambda { |env| [200, {"Content-Type" => "text/plain"}, [User.counter.to_s]] }
end
RUBY
@@ -181,7 +181,7 @@ class LoadingTest < ActiveSupport::TestCase
app_file 'config/routes.rb', <<-RUBY
$counter = 0
AppTemplate::Application.routes.draw do
- get '/c', :to => lambda { |env| User; [200, {"Content-Type" => "text/plain"}, [$counter.to_s]] }
+ get '/c', to: lambda { |env| User; [200, {"Content-Type" => "text/plain"}, [$counter.to_s]] }
end
RUBY
@@ -212,8 +212,8 @@ class LoadingTest < ActiveSupport::TestCase
app_file 'config/routes.rb', <<-RUBY
AppTemplate::Application.routes.draw do
- get '/title', :to => lambda { |env| [200, {"Content-Type" => "text/plain"}, [Post.new.title]] }
- get '/body', :to => lambda { |env| [200, {"Content-Type" => "text/plain"}, [Post.new.body]] }
+ get '/title', to: lambda { |env| [200, {"Content-Type" => "text/plain"}, [Post.new.title]] }
+ get '/body', to: lambda { |env| [200, {"Content-Type" => "text/plain"}, [Post.new.body]] }
end
RUBY
@@ -229,7 +229,7 @@ class LoadingTest < ActiveSupport::TestCase
class CreatePosts < ActiveRecord::Migration
def change
create_table :posts do |t|
- t.string :title, :default => "TITLE"
+ t.string :title, default: "TITLE"
end
end
end
@@ -244,7 +244,7 @@ class LoadingTest < ActiveSupport::TestCase
app_file "db/migrate/2_add_body_to_posts.rb", <<-MIGRATION
class AddBodyToPosts < ActiveRecord::Migration
def change
- add_column :posts, :body, :text, :default => "BODY"
+ add_column :posts, :body, :text, default: "BODY"
end
end
MIGRATION
@@ -297,9 +297,9 @@ class LoadingTest < ActiveSupport::TestCase
protected
def setup_ar!
- ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
+ ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveRecord::Migration.verbose = false
- ActiveRecord::Schema.define(:version => 1) do
+ ActiveRecord::Schema.define(version: 1) do
create_table :posts do |t|
t.string :title
end
diff --git a/railties/test/application/middleware/cache_test.rb b/railties/test/application/middleware/cache_test.rb
index fffe79f9cc..c99666d7e4 100644
--- a/railties/test/application/middleware/cache_test.rb
+++ b/railties/test/application/middleware/cache_test.rb
@@ -19,17 +19,17 @@ module ApplicationTests
controller :expires, <<-RUBY
class ExpiresController < ApplicationController
def expires_header
- expires_in 10, :public => !params[:private]
- render :text => SecureRandom.hex(16)
+ expires_in 10, public: !params[:private]
+ render text: SecureRandom.hex(16)
end
def expires_etag
- render_conditionally(:etag => "1")
+ render_conditionally(etag: "1")
end
def expires_last_modified
$last_modified ||= Time.now.utc
- render_conditionally(:last_modified => $last_modified)
+ render_conditionally(last_modified: $last_modified)
end
def keeps_if_modified_since
@@ -37,8 +37,8 @@ module ApplicationTests
end
private
def render_conditionally(headers)
- if stale?(headers.merge(:public => !params[:private]))
- render :text => SecureRandom.hex(16)
+ if stale?(headers.merge(public: !params[:private]))
+ render text: SecureRandom.hex(16)
end
end
end
@@ -49,8 +49,6 @@ module ApplicationTests
get ':controller(/:action)'
end
RUBY
-
- add_to_config "config.action_dispatch.rack_cache = true"
end
def test_cache_keeps_if_modified_since
@@ -80,6 +78,8 @@ module ApplicationTests
def test_cache_works_with_expires
simple_controller
+ add_to_config "config.action_dispatch.rack_cache = true"
+
get "/expires/expires_header"
assert_equal "miss, store", last_response.headers["X-Rack-Cache"]
assert_equal "max-age=10, public", last_response.headers["Cache-Control"]
@@ -96,13 +96,15 @@ module ApplicationTests
def test_cache_works_with_expires_private
simple_controller
- get "/expires/expires_header", :private => true
+ add_to_config "config.action_dispatch.rack_cache = true"
+
+ get "/expires/expires_header", private: true
assert_equal "miss", last_response.headers["X-Rack-Cache"]
assert_equal "private, max-age=10", last_response.headers["Cache-Control"]
body = last_response.body
- get "/expires/expires_header", :private => true
+ get "/expires/expires_header", private: true
assert_equal "miss", last_response.headers["X-Rack-Cache"]
assert_not_equal body, last_response.body
end
@@ -110,6 +112,8 @@ module ApplicationTests
def test_cache_works_with_etags
simple_controller
+ add_to_config "config.action_dispatch.rack_cache = true"
+
get "/expires/expires_etag"
assert_equal "miss, store", last_response.headers["X-Rack-Cache"]
assert_equal "public", last_response.headers["Cache-Control"]
@@ -125,14 +129,16 @@ module ApplicationTests
def test_cache_works_with_etags_private
simple_controller
- get "/expires/expires_etag", :private => true
+ add_to_config "config.action_dispatch.rack_cache = true"
+
+ get "/expires/expires_etag", private: true
assert_equal "miss", last_response.headers["X-Rack-Cache"]
assert_equal "must-revalidate, private, max-age=0", last_response.headers["Cache-Control"]
body = last_response.body
etag = last_response.headers["ETag"]
- get "/expires/expires_etag", {:private => true}, "If-None-Match" => etag
+ get "/expires/expires_etag", {private: true}, "If-None-Match" => etag
assert_equal "miss", last_response.headers["X-Rack-Cache"]
assert_not_equal body, last_response.body
end
@@ -140,6 +146,8 @@ module ApplicationTests
def test_cache_works_with_last_modified
simple_controller
+ add_to_config "config.action_dispatch.rack_cache = true"
+
get "/expires/expires_last_modified"
assert_equal "miss, store", last_response.headers["X-Rack-Cache"]
assert_equal "public", last_response.headers["Cache-Control"]
@@ -155,14 +163,16 @@ module ApplicationTests
def test_cache_works_with_last_modified_private
simple_controller
- get "/expires/expires_last_modified", :private => true
+ add_to_config "config.action_dispatch.rack_cache = true"
+
+ get "/expires/expires_last_modified", private: true
assert_equal "miss", last_response.headers["X-Rack-Cache"]
assert_equal "must-revalidate, private, max-age=0", last_response.headers["Cache-Control"]
body = last_response.body
last = last_response.headers["Last-Modified"]
- get "/expires/expires_last_modified", {:private => true}, "If-Modified-Since" => last
+ get "/expires/expires_last_modified", {private: true}, "If-Modified-Since" => last
assert_equal "miss", last_response.headers["X-Rack-Cache"]
assert_not_equal body, last_response.body
end
diff --git a/railties/test/application/middleware/session_test.rb b/railties/test/application/middleware/session_test.rb
index 06dec81d40..5ce41caf61 100644
--- a/railties/test/application/middleware/session_test.rb
+++ b/railties/test/application/middleware/session_test.rb
@@ -36,7 +36,7 @@ module ApplicationTests
flash[:notice] = "notice"
end
- render :nothing => true
+ render nothing: true
end
end
diff --git a/railties/test/application/middleware_test.rb b/railties/test/application/middleware_test.rb
index b2443e6503..c5a0d02fe1 100644
--- a/railties/test/application/middleware_test.rb
+++ b/railties/test/application/middleware_test.rb
@@ -57,15 +57,12 @@ module ApplicationTests
end
test "Rack::Cache is not included by default" do
- add_to_config "config.action_controller.perform_caching = true"
-
boot!
assert !middleware.include?("Rack::Cache"), "Rack::Cache is not included in the default stack unless you set config.action_dispatch.rack_cache"
end
- test "Rack::Cache is present when action_controller.perform_caching is set and action_dispatch.rack_cache is set" do
- add_to_config "config.action_controller.perform_caching = true"
+ test "Rack::Cache is present when action_dispatch.rack_cache is set" do
add_to_config "config.action_dispatch.rack_cache = true"
boot!
@@ -81,10 +78,10 @@ module ApplicationTests
test "ActionDispatch::SSL is configured with options when given" do
add_to_config "config.force_ssl = true"
- add_to_config "config.ssl_options = { :host => 'example.com' }"
+ add_to_config "config.ssl_options = { host: 'example.com' }"
boot!
- assert_equal AppTemplate::Application.middleware.first.args, [{:host => 'example.com'}]
+ assert_equal AppTemplate::Application.middleware.first.args, [{host: 'example.com'}]
end
test "removing Active Record omits its middleware" do
@@ -169,9 +166,9 @@ module ApplicationTests
class ::OmgController < ActionController::Base
def index
if params[:nothing]
- render :text => ""
+ render text: ""
else
- render :text => "OMG"
+ render text: "OMG"
end
end
end
diff --git a/railties/test/application/queue_test.rb b/railties/test/application/queue_test.rb
index e67c6cc371..b0b3cf18e9 100644
--- a/railties/test/application/queue_test.rb
+++ b/railties/test/application/queue_test.rb
@@ -17,16 +17,16 @@ module ApplicationTests
@app_const ||= Class.new(Rails::Application)
end
- test "the queue is a TestQueue in test mode" do
+ test "the queue is a SynchronousQueue in test mode" do
app("test")
- assert_kind_of ActiveSupport::TestQueue, Rails.application.queue[:default]
- assert_kind_of ActiveSupport::TestQueue, Rails.queue[:default]
+ assert_kind_of ActiveSupport::SynchronousQueue, Rails.application.queue
+ assert_kind_of ActiveSupport::SynchronousQueue, Rails.queue
end
test "the queue is a SynchronousQueue in development mode" do
app("development")
- assert_kind_of ActiveSupport::SynchronousQueue, Rails.application.queue[:default]
- assert_kind_of ActiveSupport::SynchronousQueue, Rails.queue[:default]
+ assert_kind_of ActiveSupport::SynchronousQueue, Rails.application.queue
+ assert_kind_of ActiveSupport::SynchronousQueue, Rails.queue
end
class ThreadTrackingJob
@@ -58,54 +58,26 @@ module ApplicationTests
refute job.ran_in_different_thread?, "Expected job to run in the same thread"
end
- test "in test mode, explicitly draining the queue will process it in the same thread" do
+ test "in test mode, an enqueued job will be processed in the same thread" do
app("test")
- Rails.queue.push ThreadTrackingJob.new
- job = Rails.queue.jobs.last
- Rails.queue.drain
+ job = ThreadTrackingJob.new
+ Rails.queue.push job
+ sleep 0.1
assert job.ran?, "Expected job to be run"
refute job.ran_in_different_thread?, "Expected job to run in the same thread"
end
- class IdentifiableJob
- def initialize(id)
- @id = id
- end
-
- def ==(other)
- other.same_id?(@id)
- end
-
- def same_id?(other_id)
- other_id == @id
- end
-
- def run
- end
- end
-
- test "in test mode, the queue can be observed" do
- app("test")
-
- jobs = (1..10).map do |id|
- IdentifiableJob.new(id)
- end
+ test "in production, automatically spawn a queue consumer in a background thread" do
+ add_to_env_config "production", <<-RUBY
+ config.queue = ActiveSupport::Queue.new
+ RUBY
- jobs.each do |job|
- Rails.queue.push job
- end
+ app("production")
- assert_equal jobs, Rails.queue.jobs
- end
-
- test "in test mode, adding an unmarshallable job will raise an exception" do
- app("test")
- anonymous_class_instance = Struct.new(:run).new
- assert_raises TypeError do
- Rails.queue.push anonymous_class_instance
- end
+ assert_nil Rails.application.config.queue_consumer
+ assert_kind_of ActiveSupport::ThreadedQueueConsumer, Rails.application.queue_consumer
end
test "attempting to marshal a queue will raise an exception" do
@@ -115,18 +87,10 @@ module ApplicationTests
end
end
- test "attempting to add a reference to itself to the queue will raise an exception" do
- app("test")
- job = {reference: Rails.queue}
- assert_raises TypeError do
- Rails.queue.push job
- end
- end
-
def setup_custom_queue
add_to_env_config "production", <<-RUBY
require "my_queue"
- config.queue = MyQueue
+ config.queue = MyQueue.new
RUBY
app_file "lib/my_queue.rb", <<-RUBY
@@ -143,7 +107,7 @@ module ApplicationTests
test "a custom queue implementation can be provided" do
setup_custom_queue
- assert_kind_of MyQueue, Rails.queue[:default]
+ assert_kind_of MyQueue, Rails.queue
job = Struct.new(:id, :ran) do
def run
@@ -160,17 +124,16 @@ module ApplicationTests
test "a custom consumer implementation can be provided" do
add_to_env_config "production", <<-RUBY
require "my_queue_consumer"
- config.queue = ActiveSupport::Queue
- config.queue_consumer = MyQueueConsumer
+ config.queue = ActiveSupport::Queue.new
+ config.queue_consumer = MyQueueConsumer.new
RUBY
app_file "lib/my_queue_consumer.rb", <<-RUBY
- class MyQueueConsumer < ActiveSupport::ThreadedQueueConsumer
+ class MyQueueConsumer
attr_reader :started
def start
@started = true
- self
end
end
RUBY
diff --git a/railties/test/application/rake/notes_test.rb b/railties/test/application/rake/notes_test.rb
index 27de75b63b..7a227098ba 100644
--- a/railties/test/application/rake/notes_test.rb
+++ b/railties/test/application/rake/notes_test.rb
@@ -25,6 +25,7 @@ module ApplicationTests
app_file "app/assets/stylesheets/application.css", "// TODO: note in css"
app_file "app/assets/stylesheets/application.css.scss", "// TODO: note in scss"
app_file "app/controllers/application_controller.rb", 1000.times.map { "" }.join("\n") << "# TODO: note in ruby"
+ app_file "lib/tasks/task.rake", "# TODO: note in rake"
boot_rails
require 'rake'
@@ -45,8 +46,9 @@ module ApplicationTests
assert_match(/note in js/, output)
assert_match(/note in css/, output)
assert_match(/note in scss/, output)
+ assert_match(/note in rake/, output)
- assert_equal 8, lines.size
+ assert_equal 9, lines.size
lines.each do |line|
assert_equal 4, line[0].size
diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb
index 2e7426150c..c5a68a5152 100644
--- a/railties/test/application/rake_test.rb
+++ b/railties/test/application/rake_test.rb
@@ -46,7 +46,7 @@ module ApplicationTests
end
rake_tasks do
- task :do_nothing => :environment do
+ task do_nothing: :environment do
end
end
RUBY
@@ -60,7 +60,7 @@ module ApplicationTests
config.eager_load = true
rake_tasks do
- task :do_nothing => :environment do
+ task do_nothing: :environment do
Hello.new.world
end
end
@@ -109,7 +109,7 @@ module ApplicationTests
def test_rake_routes_calls_the_route_inspector
app_file "config/routes.rb", <<-RUBY
AppTemplate::Application.routes.draw do
- get '/cart', :to => 'cart#show'
+ get '/cart', to: 'cart#show'
end
RUBY
assert_equal "cart GET /cart(.:format) cart#show\n", Dir.chdir(app_path){ `rake routes` }
@@ -118,7 +118,7 @@ module ApplicationTests
def test_logger_is_flushed_when_exiting_production_rake_tasks
add_to_config <<-RUBY
rake_tasks do
- task :log_something => :environment do
+ task log_something: :environment do
Rails.logger.error("Sample log message")
end
end
@@ -233,7 +233,7 @@ module ApplicationTests
app_file "lib/tasks/count_user.rake", <<-RUBY
namespace :user do
- task :count => :environment do
+ task count: :environment do
puts User.count
end
end
diff --git a/railties/test/application/routing_test.rb b/railties/test/application/routing_test.rb
index 396b1849d8..ffcdeac7f0 100644
--- a/railties/test/application/routing_test.rb
+++ b/railties/test/application/routing_test.rb
@@ -50,7 +50,7 @@ module ApplicationTests
controller :foo, <<-RUBY
class FooController < ApplicationController
def index
- render :inline => "<%= foo_or_bar? %>"
+ render inline: "<%= foo_or_bar? %>"
end
end
RUBY
@@ -76,7 +76,7 @@ module ApplicationTests
test "mount rack app" do
app_file 'config/routes.rb', <<-RUBY
AppTemplate::Application.routes.draw do
- mount lambda { |env| [200, {}, [env["PATH_INFO"]]] }, :at => "/blog"
+ mount lambda { |env| [200, {}, [env["PATH_INFO"]]] }, at: "/blog"
# The line below is required because mount sometimes
# fails when a resource route is added.
resource :user
@@ -91,7 +91,7 @@ module ApplicationTests
controller :foo, <<-RUBY
class FooController < ApplicationController
def index
- render :text => "foo"
+ render text: "foo"
end
end
RUBY
@@ -99,7 +99,7 @@ module ApplicationTests
controller :bar, <<-RUBY
class BarController < ActionController::Base
def index
- render :text => "bar"
+ render text: "bar"
end
end
RUBY
@@ -121,7 +121,7 @@ module ApplicationTests
controller 'foo', <<-RUBY
class FooController < ApplicationController
def index
- render :text => "foo"
+ render text: "foo"
end
end
RUBY
@@ -130,7 +130,7 @@ module ApplicationTests
module Admin
class FooController < ApplicationController
def index
- render :text => "admin::foo"
+ render text: "admin::foo"
end
end
end
@@ -138,8 +138,8 @@ module ApplicationTests
app_file 'config/routes.rb', <<-RUBY
AppTemplate::Application.routes.draw do
- get 'admin/foo', :to => 'admin/foo#index'
- get 'foo', :to => 'foo#index'
+ get 'admin/foo', to: 'admin/foo#index'
+ get 'foo', to: 'foo#index'
end
RUBY
@@ -183,18 +183,18 @@ module ApplicationTests
controller :foo, <<-RUBY
class FooController < ApplicationController
def bar
- render :text => "bar"
+ render text: "bar"
end
def baz
- render :text => "baz"
+ render text: "baz"
end
end
RUBY
app_file 'config/routes.rb', <<-RUBY
AppTemplate::Application.routes.draw do
- get 'foo', :to => 'foo#bar'
+ get 'foo', to: 'foo#bar'
end
RUBY
@@ -205,7 +205,7 @@ module ApplicationTests
app_file 'config/routes.rb', <<-RUBY
AppTemplate::Application.routes.draw do
- get 'foo', :to => 'foo#baz'
+ get 'foo', to: 'foo#baz'
end
RUBY
@@ -226,7 +226,7 @@ module ApplicationTests
app_file 'config/routes.rb', <<-RUBY
AppTemplate::Application.routes.draw do
- get 'foo', :to => ::InitializeRackApp
+ get 'foo', to: ::InitializeRackApp
end
RUBY
@@ -257,7 +257,7 @@ module ApplicationTests
controller 'yazilar', <<-RUBY
class YazilarController < ApplicationController
def index
- render :text => 'yazilar#index'
+ render text: 'yazilar#index'
end
end
RUBY
diff --git a/railties/test/application/url_generation_test.rb b/railties/test/application/url_generation_test.rb
index f7e60749a7..2a48adae5c 100644
--- a/railties/test/application/url_generation_test.rb
+++ b/railties/test/application/url_generation_test.rb
@@ -15,8 +15,9 @@ module ApplicationTests
class MyApp < Rails::Application
config.secret_token = "3b7cd727ee24e8444053437c36cc66c4"
- config.session_store :cookie_store, :key => "_myapp_session"
+ config.session_store :cookie_store, key: "_myapp_session"
config.active_support.deprecation = :log
+ config.eager_load = false
end
MyApp.initialize!
@@ -26,12 +27,12 @@ module ApplicationTests
class ::OmgController < ::ApplicationController
def index
- render :text => omg_path
+ render text: omg_path
end
end
MyApp.routes.draw do
- get "/" => "omg#index", :as => :omg
+ get "/" => "omg#index", as: :omg
end
require 'rack/test'
diff --git a/railties/test/commands/console_test.rb b/railties/test/commands/console_test.rb
index 69e89d87ae..e047d4882d 100644
--- a/railties/test/commands/console_test.rb
+++ b/railties/test/commands/console_test.rb
@@ -58,8 +58,8 @@ class Rails::ConsoleTest < ActiveSupport::TestCase
end
def test_console_defaults_to_IRB
- config = mock("config", :console => nil)
- app = mock("app", :config => config)
+ config = mock("config", console: nil)
+ app = mock("app", config: config)
app.expects(:load_console).returns(nil)
assert_equal IRB, Rails::Console.new(app).console
@@ -115,8 +115,8 @@ class Rails::ConsoleTest < ActiveSupport::TestCase
def app
@app ||= begin
- config = mock("config", :console => FakeConsole)
- app = mock("app", :config => config)
+ config = mock("config", console: FakeConsole)
+ app = mock("app", config: config)
app.stubs(:sandbox=).returns(nil)
app.expects(:load_console)
app
diff --git a/railties/test/fixtures/lib/plugin_builders/spec_builder.rb b/railties/test/fixtures/lib/plugin_builders/spec_builder.rb
index aa18c7ddaa..2721429599 100644
--- a/railties/test/fixtures/lib/plugin_builders/spec_builder.rb
+++ b/railties/test/fixtures/lib/plugin_builders/spec_builder.rb
@@ -4,7 +4,7 @@ class PluginBuilder < Rails::PluginBuilder
append_file "Rakefile", <<-EOF
# spec tasks in rakefile
-task :default => :spec
+task default: :spec
EOF
end
diff --git a/railties/test/generators/actions_test.rb b/railties/test/generators/actions_test.rb
index bc086c5986..8af92479c3 100644
--- a/railties/test/generators/actions_test.rb
+++ b/railties/test/generators/actions_test.rb
@@ -99,7 +99,7 @@ class ActionsTest < Rails::Generators::TestCase
def test_environment_should_include_data_in_environment_initializer_block_with_env_option
run_generator
autoload_paths = 'config.autoload_paths += %w["#{Rails.root}/app/extras"]'
- action :environment, autoload_paths, :env => 'development'
+ action :environment, autoload_paths, env: 'development'
assert_file "config/environments/development.rb", /Application\.configure do\n #{Regexp.escape(autoload_paths)}/
end
@@ -124,7 +124,7 @@ class ActionsTest < Rails::Generators::TestCase
def test_git_with_hash_should_run_each_command_using_git_scm
generator.expects(:run).times(2)
- action :git, :rm => 'README', :add => '.'
+ action :git, rm: 'README', add: '.'
end
def test_vendor_should_write_data_to_file_in_vendor
@@ -138,8 +138,8 @@ class ActionsTest < Rails::Generators::TestCase
end
def test_rakefile_should_write_date_to_file_in_lib_tasks
- action :rakefile, 'myapp.rake', 'task :run => [:environment]'
- assert_file 'lib/tasks/myapp.rake', 'task :run => [:environment]'
+ action :rakefile, 'myapp.rake', 'task run: [:environment]'
+ assert_file 'lib/tasks/myapp.rake', 'task run: [:environment]'
end
def test_initializer_should_write_date_to_file_in_config_initializers
@@ -148,12 +148,12 @@ class ActionsTest < Rails::Generators::TestCase
end
def test_generate_should_run_script_generate_with_argument_and_options
- generator.expects(:run_ruby_script).once.with('script/rails generate model MyModel', :verbose => false)
+ generator.expects(:run_ruby_script).once.with('script/rails generate model MyModel', verbose: false)
action :generate, 'model', 'MyModel'
end
def test_rake_should_run_rake_command_with_default_env
- generator.expects(:run).once.with("rake log:clear RAILS_ENV=development", :verbose => false)
+ generator.expects(:run).once.with("rake log:clear RAILS_ENV=development", verbose: false)
old_env, ENV['RAILS_ENV'] = ENV["RAILS_ENV"], nil
action :rake, 'log:clear'
ensure
@@ -161,12 +161,12 @@ class ActionsTest < Rails::Generators::TestCase
end
def test_rake_with_env_option_should_run_rake_command_in_env
- generator.expects(:run).once.with('rake log:clear RAILS_ENV=production', :verbose => false)
- action :rake, 'log:clear', :env => 'production'
+ generator.expects(:run).once.with('rake log:clear RAILS_ENV=production', verbose: false)
+ action :rake, 'log:clear', env: 'production'
end
def test_rake_with_rails_env_variable_should_run_rake_command_in_env
- generator.expects(:run).once.with('rake log:clear RAILS_ENV=production', :verbose => false)
+ generator.expects(:run).once.with('rake log:clear RAILS_ENV=production', verbose: false)
old_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "production"
action :rake, 'log:clear'
ensure
@@ -174,29 +174,29 @@ class ActionsTest < Rails::Generators::TestCase
end
def test_env_option_should_win_over_rails_env_variable_when_running_rake
- generator.expects(:run).once.with('rake log:clear RAILS_ENV=production', :verbose => false)
+ generator.expects(:run).once.with('rake log:clear RAILS_ENV=production', verbose: false)
old_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "staging"
- action :rake, 'log:clear', :env => 'production'
+ action :rake, 'log:clear', env: 'production'
ensure
ENV["RAILS_ENV"] = old_env
end
def test_rake_with_sudo_option_should_run_rake_command_with_sudo
- generator.expects(:run).once.with("sudo rake log:clear RAILS_ENV=development", :verbose => false)
+ generator.expects(:run).once.with("sudo rake log:clear RAILS_ENV=development", verbose: false)
old_env, ENV['RAILS_ENV'] = ENV["RAILS_ENV"], nil
- action :rake, 'log:clear', :sudo => true
+ action :rake, 'log:clear', sudo: true
ensure
ENV["RAILS_ENV"] = old_env
end
def test_capify_should_run_the_capify_command
- generator.expects(:run).once.with('capify .', :verbose => false)
+ generator.expects(:run).once.with('capify .', verbose: false)
action :capify!
end
def test_route_should_add_data_to_the_routes_block_in_config_routes
run_generator
- route_command = "route '/login', :controller => 'sessions', :action => 'new'"
+ route_command = "route '/login', controller: 'sessions', action: 'new'"
action :route, route_command
assert_file 'config/routes.rb', /#{Regexp.escape(route_command)}/
end
@@ -208,7 +208,7 @@ class ActionsTest < Rails::Generators::TestCase
end
def test_readme_with_quiet
- generator(default_arguments, :quiet => true)
+ generator(default_arguments, quiet: true)
run_generator
Rails::Generators::AppGenerator.expects(:source_root).times(2).returns(destination_root)
assert_no_match(/Welcome to Rails/, action(:readme, "README.rdoc"))
@@ -223,12 +223,12 @@ class ActionsTest < Rails::Generators::TestCase
end
def test_log_with_quiet
- generator(default_arguments, :quiet => true)
+ generator(default_arguments, quiet: true)
assert_equal("", action(:log, "YES"))
end
def test_log_with_status_with_quiet
- generator(default_arguments, :quiet => true)
+ generator(default_arguments, quiet: true)
assert_equal("", action(:log, :yes, "YES"))
end
diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb
index 91575a38b6..62e1f3531e 100644
--- a/railties/test/generators/app_generator_test.rb
+++ b/railties/test/generators/app_generator_test.rb
@@ -107,8 +107,8 @@ class AppGeneratorTest < Rails::Generators::TestCase
FileUtils.mv(app_root, app_moved_root)
- generator = Rails::Generators::AppGenerator.new ["rails"], { :with_dispatchers => true },
- :destination_root => app_moved_root, :shell => @shell
+ generator = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true },
+ destination_root: app_moved_root, shell: @shell
generator.send(:app_const)
quietly { generator.send(:create_config_files) }
assert_file "myapp_moved/config/environment.rb", /Myapp::Application\.initialize!/
@@ -123,7 +123,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
Rails.application.class.stubs(:name).returns("Myapp")
Rails.application.stubs(:is_a?).returns(Rails::Application)
- generator = Rails::Generators::AppGenerator.new ["rails"], { :with_dispatchers => true }, :destination_root => app_root, :shell => @shell
+ generator = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true }, destination_root: app_root, shell: @shell
generator.send(:app_const)
quietly { generator.send(:create_config_files) }
assert_file "myapp/config/initializers/session_store.rb", /_myapp_session/
@@ -223,7 +223,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
def test_generator_if_skip_sprockets_is_given
run_generator [destination_root, "--skip-sprockets"]
assert_file "config/application.rb" do |content|
- assert_match(/#\s+require\s+["']sprockets\/rails\/railtie["']/, content)
+ assert_match(/#\s+require\s+["']sprockets\/railtie["']/, content)
assert_no_match(/config\.assets\.enabled = true/, content)
end
assert_file "Gemfile" do |content|
@@ -236,7 +236,8 @@ class AppGeneratorTest < Rails::Generators::TestCase
end
assert_file "config/environments/production.rb" do |content|
assert_no_match(/config\.assets\.digest = true/, content)
- assert_no_match(/config\.assets\.compress = true/, content)
+ assert_no_match(/config\.assets\.js_compressor = :uglifier/, content)
+ assert_no_match(/config\.assets\.css_compressor = :sass/, content)
end
assert_file "test/performance/browsing_test.rb"
end
@@ -302,11 +303,6 @@ class AppGeneratorTest < Rails::Generators::TestCase
assert_file "Gemfile", /# gem 'debugger'/
end
- def test_inclusion_of_rack_cache
- run_generator
- assert_file "Gemfile", /gem 'rack-cache'/
- end
-
def test_template_from_dir_pwd
FileUtils.cd(Rails.root)
assert_match(/It works from file!/, run_generator([destination_root, "-m", "lib/template.rb"]))
diff --git a/railties/test/generators/model_generator_test.rb b/railties/test/generators/model_generator_test.rb
index a90ad5cde0..0c7ff0ebe7 100644
--- a/railties/test/generators/model_generator_test.rb
+++ b/railties/test/generators/model_generator_test.rb
@@ -242,19 +242,19 @@ class ModelGeneratorTest < Rails::Generators::TestCase
def test_migration_is_skipped_on_skip_behavior
run_generator
- output = run_generator ["Account"], :behavior => :skip
+ output = run_generator ["Account"], behavior: :skip
assert_match %r{skip\s+db/migrate/\d+_create_accounts.rb}, output
end
def test_migration_error_is_not_shown_on_revoke
run_generator
- error = capture(:stderr){ run_generator ["Account"], :behavior => :revoke }
+ error = capture(:stderr){ run_generator ["Account"], behavior: :revoke }
assert_no_match(/Another migration is already named create_accounts/, error)
end
def test_migration_is_removed_on_revoke
run_generator
- run_generator ["Account"], :behavior => :revoke
+ run_generator ["Account"], behavior: :revoke
assert_no_migration "db/migrate/create_accounts.rb"
end
diff --git a/railties/test/generators/namespaced_generators_test.rb b/railties/test/generators/namespaced_generators_test.rb
index d48712e51f..4b168ae110 100644
--- a/railties/test/generators/namespaced_generators_test.rb
+++ b/railties/test/generators/namespaced_generators_test.rb
@@ -263,7 +263,7 @@ class NamespacedScaffoldGeneratorTest < NamespacedGeneratorTestCase
def test_scaffold_on_revoke
run_generator
- run_generator ["product_line"], :behavior => :revoke
+ run_generator ["product_line"], behavior: :revoke
# Model
assert_no_file "app/models/test_app/product_line.rb"
@@ -335,7 +335,7 @@ class NamespacedScaffoldGeneratorTest < NamespacedGeneratorTestCase
def test_scaffold_with_namespace_on_revoke
run_generator [ "admin/role", "name:string", "description:string" ]
- run_generator [ "admin/role" ], :behavior => :revoke
+ run_generator [ "admin/role" ], behavior: :revoke
# Model
assert_file "app/models/test_app/admin.rb" # ( should not be remove )
@@ -408,7 +408,7 @@ class NamespacedScaffoldGeneratorTest < NamespacedGeneratorTestCase
def test_scaffold_with_nested_namespace_on_revoke
run_generator [ "admin/user/special/role", "name:string", "description:string" ]
- run_generator [ "admin/user/special/role" ], :behavior => :revoke
+ run_generator [ "admin/user/special/role" ], behavior: :revoke
# Model
assert_file "app/models/test_app/admin/user/special.rb" # ( should not be remove )
diff --git a/railties/test/generators/orm_test.rb b/railties/test/generators/orm_test.rb
index 9dd3d3e0ec..88ae930554 100644
--- a/railties/test/generators/orm_test.rb
+++ b/railties/test/generators/orm_test.rb
@@ -20,12 +20,12 @@ class OrmTest < Rails::Generators::TestCase
tests Rails::Generators::ScaffoldControllerGenerator
def test_orm_class_returns_custom_generator_if_supported_custom_orm_set
- g = generator ["Foo"], :orm => "ORMWithGenerators"
+ g = generator ["Foo"], orm: "ORMWithGenerators"
assert_equal ORMWithGenerators::Generators::ActiveModel, g.send(:orm_class)
end
def test_orm_class_returns_rails_generator_if_unsupported_custom_orm_set
- g = generator ["Foo"], :orm => "ORMWithoutGenerators"
+ g = generator ["Foo"], orm: "ORMWithoutGenerators"
assert_equal Rails::Generators::ActiveModel, g.send(:orm_class)
end
diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb
index dddbfa64b6..6974db5751 100644
--- a/railties/test/generators/plugin_new_generator_test.rb
+++ b/railties/test/generators/plugin_new_generator_test.rb
@@ -379,7 +379,7 @@ class CustomPluginGeneratorTest < Rails::Generators::TestCase
run_generator([destination_root, "-b", "#{Rails.root}/lib/plugin_builders/spec_builder.rb"])
assert_file 'spec/spec_helper.rb'
assert_file 'spec/dummy'
- assert_file 'Rakefile', /task :default => :spec/
+ assert_file 'Rakefile', /task default: :spec/
assert_file 'Rakefile', /# spec tasks in rakefile/
end
diff --git a/railties/test/generators/resource_generator_test.rb b/railties/test/generators/resource_generator_test.rb
index 0ae0841442..3d4e694361 100644
--- a/railties/test/generators/resource_generator_test.rb
+++ b/railties/test/generators/resource_generator_test.rb
@@ -80,7 +80,7 @@ class ResourceGeneratorTest < Rails::Generators::TestCase
def test_route_is_removed_on_revoke
run_generator
- run_generator ["account"], :behavior => :revoke
+ run_generator ["account"], behavior: :revoke
assert_file "config/routes.rb" do |route|
assert_no_match(/resources :accounts$/, route)
diff --git a/railties/test/generators/scaffold_generator_test.rb b/railties/test/generators/scaffold_generator_test.rb
index dc825c7c99..efe47cdfcb 100644
--- a/railties/test/generators/scaffold_generator_test.rb
+++ b/railties/test/generators/scaffold_generator_test.rb
@@ -99,7 +99,7 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase
def test_scaffold_on_revoke
run_generator
- run_generator ["product_line"], :behavior => :revoke
+ run_generator ["product_line"], behavior: :revoke
# Model
assert_no_file "app/models/product_line.rb"
diff --git a/railties/test/generators/shared_generator_tests.rb b/railties/test/generators/shared_generator_tests.rb
index a4bdfcf438..1e5a4545a1 100644
--- a/railties/test/generators/shared_generator_tests.rb
+++ b/railties/test/generators/shared_generator_tests.rb
@@ -87,7 +87,7 @@ module SharedGeneratorTests
template = %{ say "It works!" }
template.instance_eval "def read; self; end" # Make the string respond to read
- generator([destination_root], :template => path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template)
+ generator([destination_root], template: path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template)
assert_match(/It works!/, capture(:stdout) { generator.invoke_all })
end
@@ -96,31 +96,31 @@ module SharedGeneratorTests
template = %{ say "It works!" }
template.instance_eval "def read; self; end" # Make the string respond to read
- generator([destination_root], :template => path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template)
+ generator([destination_root], template: path).expects(:open).with(path, 'Accept' => 'application/x-thor-template').returns(template)
assert_match(/It works!/, capture(:stdout) { generator.invoke_all })
end
def test_dev_option
- generator([destination_root], :dev => true).expects(:bundle_command).with('install').once
+ generator([destination_root], dev: true).expects(:bundle_command).with('install').once
quietly { generator.invoke_all }
rails_path = File.expand_path('../../..', Rails.root)
assert_file 'Gemfile', /^gem\s+["']rails["'],\s+path:\s+["']#{Regexp.escape(rails_path)}["']$/
end
def test_edge_option
- generator([destination_root], :edge => true).expects(:bundle_command).with('install').once
+ generator([destination_root], edge: true).expects(:bundle_command).with('install').once
quietly { generator.invoke_all }
assert_file 'Gemfile', %r{^gem\s+["']rails["'],\s+github:\s+["']#{Regexp.escape("rails/rails")}["']$}
end
def test_skip_gemfile
- generator([destination_root], :skip_gemfile => true).expects(:bundle_command).never
+ generator([destination_root], skip_gemfile: true).expects(:bundle_command).never
quietly { generator.invoke_all }
assert_no_file 'Gemfile'
end
def test_skip_bundle
- generator([destination_root], :skip_bundle => true).expects(:bundle_command).never
+ generator([destination_root], skip_bundle: true).expects(:bundle_command).never
quietly { generator.invoke_all }
# skip_bundle is only about running bundle install, ensure the Gemfile is still
@@ -192,7 +192,7 @@ module SharedCustomGeneratorTests
template = "class #{builder_class}; end"
template.instance_eval "def read; self; end" # Make the string respond to read
- generator([destination_root], :builder => url).expects(:open).with(url, 'Accept' => 'application/x-thor-template').returns(template)
+ generator([destination_root], builder: url).expects(:open).with(url, 'Accept' => 'application/x-thor-template').returns(template)
quietly { generator.invoke_all }
default_files.each{ |path| assert_no_file(path) }
diff --git a/railties/test/generators_test.rb b/railties/test/generators_test.rb
index 027d8eb9b7..9953aa929b 100644
--- a/railties/test/generators_test.rb
+++ b/railties/test/generators_test.rb
@@ -43,8 +43,8 @@ class GeneratorsTest < Rails::Generators::TestCase
end
def test_invoke_with_config_values
- Rails::Generators::ModelGenerator.expects(:start).with(["Account"], :behavior => :skip)
- Rails::Generators.invoke :model, ["Account"], :behavior => :skip
+ Rails::Generators::ModelGenerator.expects(:start).with(["Account"], behavior: :skip)
+ Rails::Generators.invoke :model, ["Account"], behavior: :skip
end
def test_find_by_namespace
@@ -165,7 +165,7 @@ class GeneratorsTest < Rails::Generators::TestCase
end
def test_developer_options_are_overwriten_by_user_options
- Rails::Generators.options[:with_options] = { :generate => false }
+ Rails::Generators.options[:with_options] = { generate: false }
self.class.class_eval(<<-end_eval, __FILE__, __LINE__ + 1)
class WithOptionsGenerator < Rails::Generators::Base
@@ -186,7 +186,7 @@ class GeneratorsTest < Rails::Generators::TestCase
File.open(template, 'w'){ |f| f.write "empty" }
capture(:stdout) do
- Rails::Generators.invoke :model, ["user"], :destination_root => destination_root
+ Rails::Generators.invoke :model, ["user"], destination_root: destination_root
end
assert_file "app/models/user.rb" do |content|
diff --git a/railties/test/initializable_test.rb b/railties/test/initializable_test.rb
index c84c7f204c..16e259be5d 100644
--- a/railties/test/initializable_test.rb
+++ b/railties/test/initializable_test.rb
@@ -43,17 +43,17 @@ module InitializableTests
class Child < Parent
include Rails::Initializable
- initializer :three, :before => :one do
+ initializer :three, before: :one do
$arr << 3
end
- initializer :four, :after => :one, :before => :two do
+ initializer :four, after: :one, before: :two do
$arr << 4
end
end
class Parent
- initializer :five, :before => :one do
+ initializer :five, before: :one do
$arr << 5
end
end
@@ -61,7 +61,7 @@ module InitializableTests
class Instance
include Rails::Initializable
- initializer :one, :group => :assets do
+ initializer :one, group: :assets do
$arr << 1
end
@@ -69,7 +69,7 @@ module InitializableTests
$arr << 2
end
- initializer :three, :group => :all do
+ initializer :three, group: :all do
$arr << 3
end
@@ -90,11 +90,11 @@ module InitializableTests
class MoreInitializers
include Rails::Initializable
- initializer :startup, :before => :last do
+ initializer :startup, before: :last do
$arr << 3
end
- initializer :terminate, :after => :first, :before => :startup do
+ initializer :terminate, after: :first, before: :startup do
$arr << two
end
@@ -134,11 +134,11 @@ module InitializableTests
class PluginB
include Rails::Initializable
- initializer "plugin_b.startup", :after => "plugin_a.startup" do
+ initializer "plugin_b.startup", after: "plugin_a.startup" do
$arr << 2
end
- initializer "plugin_b.terminate", :before => "plugin_a.terminate" do
+ initializer "plugin_b.terminate", before: "plugin_a.terminate" do
$arr << 3
end
end
diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb
index 0f36eb67e5..e59488f97d 100644
--- a/railties/test/isolation/abstract_unit.rb
+++ b/railties/test/isolation/abstract_unit.rb
@@ -113,14 +113,14 @@ module TestHelpers
routes = File.read("#{app_path}/config/routes.rb")
if routes =~ /(\n\s*end\s*)\Z/
File.open("#{app_path}/config/routes.rb", 'w') do |f|
- f.puts $` + "\nmatch ':controller(/:action(/:id))(.:format)', :via => :all\n" + $1
+ f.puts $` + "\nmatch ':controller(/:action(/:id))(.:format)', via: :all\n" + $1
end
end
add_to_config <<-RUBY
config.eager_load = false
config.secret_token = "3b7cd727ee24e8444053437c36cc66c4"
- config.session_store :cookie_store, :key => "_myapp_session"
+ config.session_store :cookie_store, key: "_myapp_session"
config.active_support.deprecation = :log
config.action_controller.allow_forgery_protection = false
RUBY
@@ -139,7 +139,7 @@ module TestHelpers
app = Class.new(Rails::Application)
app.config.eager_load = false
app.config.secret_token = "3b7cd727ee24e8444053437c36cc66c4"
- app.config.session_store :cookie_store, :key => "_myapp_session"
+ app.config.session_store :cookie_store, key: "_myapp_session"
app.config.active_support.deprecation = :log
yield app if block_given?
@@ -157,7 +157,7 @@ module TestHelpers
controller :foo, <<-RUBY
class FooController < ApplicationController
def index
- render :text => "foo"
+ render text: "foo"
end
end
RUBY
diff --git a/railties/test/paths_test.rb b/railties/test/paths_test.rb
index 76ff3ec3e4..12f18b9dbf 100644
--- a/railties/test/paths_test.rb
+++ b/railties/test/paths_test.rb
@@ -32,7 +32,7 @@ class PathsTest < ActiveSupport::TestCase
end
test "creating a root level path with options" do
- @root.add "app", :with => "/foo/bar"
+ @root.add "app", with: "/foo/bar"
assert_equal ["/foo/bar"], @root["app"].to_a
end
@@ -52,18 +52,18 @@ class PathsTest < ActiveSupport::TestCase
test "creating a child level path with option" do
@root.add "app"
- @root.add "app/models", :with => "/foo/bar/baz"
+ @root.add "app/models", with: "/foo/bar/baz"
assert_equal ["/foo/bar/baz"], @root["app/models"].to_a
end
test "child level paths are relative from the root" do
@root.add "app"
- @root.add "app/models", :with => "baz"
+ @root.add "app/models", with: "baz"
assert_equal ["/foo/bar/baz"], @root["app/models"].to_a
end
test "adding multiple physical paths as an array" do
- @root.add "app", :with => ["/app", "/app2"]
+ @root.add "app", with: ["/app", "/app2"]
assert_equal ["/app", "/app2"], @root["app"].to_a
end
@@ -92,7 +92,7 @@ class PathsTest < ActiveSupport::TestCase
end
test "it is possible to add a path that should be autoloaded only once" do
- @root.add "app", :with => "/app"
+ @root.add "app", with: "/app"
@root["app"].autoload_once!
assert @root["app"].autoload_once?
assert @root.autoload_once.include?(@root["app"].expanded.first)
@@ -109,13 +109,13 @@ class PathsTest < ActiveSupport::TestCase
end
test "it is possible to add a path without assignment and specify it should be loaded only once" do
- @root.add "app", :with => "/app", :autoload_once => true
+ @root.add "app", with: "/app", autoload_once: true
assert @root["app"].autoload_once?
assert @root.autoload_once.include?("/app")
end
test "it is possible to add multiple paths without assignment and specify it should be loaded only once" do
- @root.add "app", :with => ["/app", "/app2"], :autoload_once => true
+ @root.add "app", with: ["/app", "/app2"], autoload_once: true
assert @root["app"].autoload_once?
assert @root.autoload_once.include?("/app")
assert @root.autoload_once.include?("/app2")
@@ -153,20 +153,20 @@ class PathsTest < ActiveSupport::TestCase
end
test "it is possible to add a path without assignment and mark it as eager" do
- @root.add "app", :with => "/app", :eager_load => true
+ @root.add "app", with: "/app", eager_load: true
assert @root["app"].eager_load?
assert @root.eager_load.include?("/app")
end
test "it is possible to add multiple paths without assignment and mark them as eager" do
- @root.add "app", :with => ["/app", "/app2"], :eager_load => true
+ @root.add "app", with: ["/app", "/app2"], eager_load: true
assert @root["app"].eager_load?
assert @root.eager_load.include?("/app")
assert @root.eager_load.include?("/app2")
end
test "it is possible to create a path without assignment and mark it both as eager and load once" do
- @root.add "app", :with => "/app", :eager_load => true, :autoload_once => true
+ @root.add "app", with: "/app", eager_load: true, autoload_once: true
assert @root["app"].eager_load?
assert @root["app"].autoload_once?
assert @root.eager_load.include?("/app")
@@ -194,12 +194,12 @@ class PathsTest < ActiveSupport::TestCase
end
test "it should be possible to override a path's default glob without assignment" do
- @root.add "app", :with => "/app", :glob => "*.rb"
+ @root.add "app", with: "/app", glob: "*.rb"
assert_equal "*.rb", @root["app"].glob
end
test "it should be possible to replace a path and persist the original paths glob" do
- @root.add "app", :glob => "*.rb"
+ @root.add "app", glob: "*.rb"
@root["app"] = "app2"
assert_equal ["/foo/bar/app2"], @root["app"].to_a
assert_equal "*.rb", @root["app"].glob
@@ -213,7 +213,7 @@ class PathsTest < ActiveSupport::TestCase
end
test "a path can be added to the load path on creation" do
- @root.add "app", :with => "/app", :load_path => true
+ @root.add "app", with: "/app", load_path: true
assert @root["app"].load_path?
assert_equal ["/app"], @root.load_paths
end
@@ -226,7 +226,7 @@ class PathsTest < ActiveSupport::TestCase
end
test "a path can be marked as autoload on creation" do
- @root.add "app", :with => "/app", :autoload => true
+ @root.add "app", with: "/app", autoload: true
assert @root["app"].autoload?
assert_equal ["/app"], @root.autoload_paths
end
diff --git a/railties/test/rails_info_controller_test.rb b/railties/test/rails_info_controller_test.rb
index cfb32b7d35..08fcddd4bf 100644
--- a/railties/test/rails_info_controller_test.rb
+++ b/railties/test/rails_info_controller_test.rb
@@ -21,19 +21,19 @@ class InfoControllerTest < ActionController::TestCase
end
test "info controller does not allow remote requests" do
- @controller.stubs(:local_request? => false)
+ @controller.stubs(local_request?: false)
get :properties
assert_response :forbidden
end
test "info controller renders an error message when request was forbidden" do
- @controller.stubs(:local_request? => false)
+ @controller.stubs(local_request?: false)
get :properties
assert_select 'p'
end
test "info controller allows requests when all requests are considered local" do
- @controller.stubs(:local_request? => true)
+ @controller.stubs(local_request?: true)
get :properties
assert_response :success
end
diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb
index e52b3efdab..fcbe7b6cda 100644
--- a/railties/test/railties/engine_test.rb
+++ b/railties/test/railties/engine_test.rb
@@ -285,8 +285,8 @@ module RailtiesTest
@plugin.write "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
- get 'foo', :to => 'bar#index'
- get 'bar', :to => 'bar#index'
+ get 'foo', to: 'bar#index'
+ get 'bar', to: 'bar#index'
end
RUBY
@@ -366,7 +366,7 @@ YAML
Rails.application.routes.draw do
namespace :admin do
namespace :foo do
- get "bar", :to => "bar#index"
+ get "bar", to: "bar#index"
end
end
end
@@ -375,7 +375,7 @@ YAML
@plugin.write "app/controllers/admin/foo/bar_controller.rb", <<-RUBY
class Admin::Foo::BarController < ApplicationController
def index
- render :text => "Rendered from namespace"
+ render text: "Rendered from namespace"
end
end
RUBY
@@ -487,14 +487,14 @@ YAML
controller "foo", <<-RUBY
class FooController < ActionController::Base
def index
- render :text => params[:username]
+ render text: params[:username]
end
end
RUBY
@plugin.write "config/routes.rb", <<-RUBY
Bukkits::Engine.routes.draw do
- root :to => "foo#index"
+ root to: "foo#index"
end
RUBY
@@ -608,14 +608,14 @@ YAML
app_file "config/routes.rb", <<-RUBY
AppTemplate::Application.routes.draw do
- get "/bar" => "bar#index", :as => "bar"
- mount Bukkits::Engine => "/bukkits", :as => "bukkits"
+ get "/bar" => "bar#index", as: "bar"
+ mount Bukkits::Engine => "/bukkits", as: "bukkits"
end
RUBY
@plugin.write "config/routes.rb", <<-RUBY
Bukkits::Engine.routes.draw do
- get "/foo" => "foo#index", :as => "foo"
+ get "/foo" => "foo#index", as: "foo"
get "/foo/show" => "foo#show"
get "/from_app" => "foo#from_app"
get "/routes_helpers_in_view" => "foo#routes_helpers_in_view"
@@ -643,23 +643,23 @@ YAML
@plugin.write "app/controllers/bukkits/foo_controller.rb", <<-RUBY
class Bukkits::FooController < ActionController::Base
def index
- render :inline => "<%= help_the_engine %>"
+ render inline: "<%= help_the_engine %>"
end
def show
- render :text => foo_path
+ render text: foo_path
end
def from_app
- render :inline => "<%= (self.respond_to?(:bar_path) || self.respond_to?(:something)) %>"
+ render inline: "<%= (self.respond_to?(:bar_path) || self.respond_to?(:something)) %>"
end
def routes_helpers_in_view
- render :inline => "<%= foo_path %>, <%= main_app.bar_path %>"
+ render inline: "<%= foo_path %>, <%= main_app.bar_path %>"
end
def polymorphic_path_without_namespace
- render :text => polymorphic_path(Post.new)
+ render text: polymorphic_path(Post.new)
end
end
RUBY
@@ -726,7 +726,7 @@ YAML
app_file "config/routes.rb", <<-RUBY
AppTemplate::Application.routes.draw do
- mount Bukkits::Engine => "/bukkits", :as => "bukkits"
+ mount Bukkits::Engine => "/bukkits", as: "bukkits"
end
RUBY
@@ -1033,11 +1033,11 @@ YAML
controller "main", <<-RUBY
class MainController < ActionController::Base
def foo
- render :inline => '<%= render :partial => "shared/foo" %>'
+ render inline: '<%= render :partial => "shared/foo" %>'
end
def bar
- render :inline => '<%= render :partial => "shared/bar" %>'
+ render inline: '<%= render :partial => "shared/bar" %>'
end
end
RUBY
@@ -1113,7 +1113,7 @@ YAML
controller "main", <<-RUBY
class MainController < ActionController::Base
def foo
- render :inline => '<%= render :partial => "shared/foo" %>'
+ render inline: '<%= render :partial => "shared/foo" %>'
end
end
RUBY
@@ -1167,7 +1167,7 @@ YAML
fullpath: \#{request.fullpath}
path: \#{request.path}
TEXT
- render :text => text
+ render text: text
end
end
end
@@ -1205,7 +1205,7 @@ YAML
app_file "app/controllers/bar_controller.rb", <<-RUBY
class BarController < ApplicationController
def index
- render :text => bukkits.bukkit_path
+ render text: bukkits.bukkit_path
end
end
RUBY
@@ -1227,7 +1227,7 @@ YAML
@plugin.write "app/controllers/bukkits/bukkit_controller.rb", <<-RUBY
class Bukkits::BukkitController < ActionController::Base
def index
- render :text => main_app.bar_path
+ render text: main_app.bar_path
end
end
RUBY
diff --git a/railties/test/railties/generators_test.rb b/railties/test/railties/generators_test.rb
index c90b795d59..0abb2b7578 100644
--- a/railties/test/railties/generators_test.rb
+++ b/railties/test/railties/generators_test.rb
@@ -46,7 +46,7 @@ module RailtiesTests
f.write <<-GEMFILE.gsub(/^ {12}/, '')
source "http://rubygems.org"
- gem 'rails', :path => '#{RAILS_FRAMEWORK_ROOT}'
+ gem 'rails', path: '#{RAILS_FRAMEWORK_ROOT}'
gem 'sqlite3'
GEMFILE
end
diff --git a/railties/test/railties/mounted_engine_test.rb b/railties/test/railties/mounted_engine_test.rb
index bd13c3aba3..a1c52f01dc 100644
--- a/railties/test/railties/mounted_engine_test.rb
+++ b/railties/test/railties/mounted_engine_test.rb
@@ -42,14 +42,14 @@ module ApplicationTests
@simple_plugin.write "config/routes.rb", <<-RUBY
Weblog::Engine.routes.draw do
- get '/weblog' => "weblogs#index", :as => 'weblogs'
+ get '/weblog' => "weblogs#index", as: 'weblogs'
end
RUBY
@simple_plugin.write "app/controllers/weblogs_controller.rb", <<-RUBY
class WeblogsController < ActionController::Base
def index
- render :text => request.url
+ render text: request.url
end
end
RUBY
@@ -86,9 +86,9 @@ module ApplicationTests
@plugin.write "config/routes.rb", <<-RUBY
Blog::Engine.routes.draw do
resources :posts
- get '/generate_application_route', :to => 'posts#generate_application_route'
- get '/application_route_in_view', :to => 'posts#application_route_in_view'
- get '/engine_polymorphic_path', :to => 'posts#engine_polymorphic_path'
+ get '/generate_application_route', to: 'posts#generate_application_route'
+ get '/application_route_in_view', to: 'posts#application_route_in_view'
+ get '/engine_polymorphic_path', to: 'posts#engine_polymorphic_path'
end
RUBY
@@ -96,22 +96,22 @@ module ApplicationTests
module Blog
class PostsController < ActionController::Base
def index
- render :text => blog.post_path(1)
+ render text: blog.post_path(1)
end
def generate_application_route
- path = main_app.url_for(:controller => "/main",
- :action => "index",
- :only_path => true)
- render :text => path
+ path = main_app.url_for(controller: "/main",
+ action: "index",
+ only_path: true)
+ render text: path
end
def application_route_in_view
- render :inline => "<%= main_app.root_path %>"
+ render inline: "<%= main_app.root_path %>"
end
def engine_polymorphic_path
- render :text => polymorphic_path(Post.new)
+ render text: polymorphic_path(Post.new)
end
end
end
@@ -120,31 +120,31 @@ module ApplicationTests
app_file "app/controllers/application_generating_controller.rb", <<-RUBY
class ApplicationGeneratingController < ActionController::Base
def engine_route
- render :text => blog.posts_path
+ render text: blog.posts_path
end
def engine_route_in_view
- render :inline => "<%= blog.posts_path %>"
+ render inline: "<%= blog.posts_path %>"
end
def weblog_engine_route
- render :text => weblog.weblogs_path
+ render text: weblog.weblogs_path
end
def weblog_engine_route_in_view
- render :inline => "<%= weblog.weblogs_path %>"
+ render inline: "<%= weblog.weblogs_path %>"
end
def url_for_engine_route
- render :text => blog.url_for(:controller => "blog/posts", :action => "index", :user => "john", :only_path => true)
+ render text: blog.url_for(controller: "blog/posts", action: "index", user: "john", only_path: true)
end
def polymorphic_route
- render :text => polymorphic_url([blog, Blog::Post.new])
+ render text: polymorphic_url([blog, Blog::Post.new])
end
def application_polymorphic_path
- render :text => polymorphic_path(Blog::Post.new)
+ render text: polymorphic_path(Blog::Post.new)
end
end
RUBY