aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--.travis.yml1
-rw-r--r--Gemfile.lock281
-rw-r--r--actionmailer/lib/action_mailer/mail_helper.rb2
-rw-r--r--actionmailer/lib/rails/generators/mailer/USAGE4
-rw-r--r--actionpack/CHANGELOG.md4
-rw-r--r--actionpack/lib/action_controller/metal/conditional_get.rb18
-rw-r--r--actionpack/lib/action_dispatch/middleware/exception_wrapper.rb1
-rw-r--r--actionpack/lib/action_dispatch/testing/integration.rb30
-rw-r--r--actionpack/test/controller/render_test.rb53
-rw-r--r--actionpack/test/dispatch/response_test.rb4
-rw-r--r--actionview/CHANGELOG.md11
-rw-r--r--actionview/lib/action_view/base.rb8
-rw-r--r--actionview/lib/action_view/helpers/asset_tag_helper.rb1
-rw-r--r--actionview/lib/action_view/helpers/form_helper.rb2
-rw-r--r--actionview/lib/action_view/helpers/record_tag_helper.rb111
-rw-r--r--actionview/lib/action_view/template.rb15
-rw-r--r--actionview/test/template/asset_tag_helper_test.rb2
-rw-r--r--actionview/test/template/record_tag_helper_test.rb90
-rw-r--r--activemodel/CHANGELOG.md9
-rw-r--r--activemodel/lib/active_model/callbacks.rb2
-rw-r--r--activemodel/lib/active_model/dirty.rb17
-rw-r--r--activemodel/lib/active_model/errors.rb37
-rw-r--r--activemodel/lib/active_model/validations/length.rb24
-rw-r--r--activemodel/test/cases/errors_test.rb36
-rw-r--r--activemodel/test/cases/validations/length_validation_test.rb13
-rw-r--r--activemodel/test/models/topic.rb4
-rw-r--r--activerecord/CHANGELOG.md13
-rw-r--r--activerecord/lib/active_record/associations.rb10
-rw-r--r--activerecord/lib/active_record/associations/collection_association.rb2
-rw-r--r--activerecord/lib/active_record/attribute.rb6
-rw-r--r--activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb6
-rw-r--r--activerecord/lib/active_record/attributes.rb30
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/quoting.rb25
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb12
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb49
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_adapter.rb5
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb18
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb12
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/bit.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/bytea.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/cidr.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/enum.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/json.rb8
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/uuid.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/vector.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/xml.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb38
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb7
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb30
-rw-r--r--activerecord/lib/active_record/enum.rb23
-rw-r--r--activerecord/lib/active_record/locking/optimistic.rb2
-rw-r--r--activerecord/lib/active_record/nested_attributes.rb2
-rw-r--r--activerecord/lib/active_record/relation/batches.rb48
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb4
-rw-r--r--activerecord/lib/active_record/result.rb2
-rw-r--r--activerecord/lib/active_record/sanitization.rb2
-rw-r--r--activerecord/lib/active_record/secure_token.rb3
-rw-r--r--activerecord/lib/active_record/type.rb46
-rw-r--r--activerecord/lib/active_record/type/adapter_specific_registry.rb142
-rw-r--r--activerecord/lib/active_record/type/binary.rb6
-rw-r--r--activerecord/lib/active_record/type/date_time.rb2
-rw-r--r--activerecord/lib/active_record/type/float.rb2
-rw-r--r--activerecord/lib/active_record/type/helpers/accepts_multiparameter_time.rb2
-rw-r--r--activerecord/lib/active_record/type/helpers/mutable.rb6
-rw-r--r--activerecord/lib/active_record/type/helpers/numeric.rb2
-rw-r--r--activerecord/lib/active_record/type/integer.rb6
-rw-r--r--activerecord/lib/active_record/type/serialized.rb6
-rw-r--r--activerecord/lib/active_record/type/string.rb2
-rw-r--r--activerecord/lib/active_record/type/value.rb32
-rw-r--r--activerecord/lib/active_record/type_caster/map.rb2
-rw-r--r--activerecord/lib/active_record/validations/uniqueness.rb2
-rw-r--r--activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb4
-rw-r--r--activerecord/test/cases/adapters/mysql/reserved_word_test.rb2
-rw-r--r--activerecord/test/cases/adapters/mysql/schema_test.rb2
-rw-r--r--activerecord/test/cases/adapters/mysql2/connection_test.rb2
-rw-r--r--activerecord/test/cases/adapters/mysql2/reserved_word_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/array_test.rb14
-rw-r--r--activerecord/test/cases/adapters/postgresql/bit_string_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/bytea_test.rb8
-rw-r--r--activerecord/test/cases/adapters/postgresql/cidr_test.rb6
-rw-r--r--activerecord/test/cases/adapters/postgresql/citext_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/composite_test.rb8
-rw-r--r--activerecord/test/cases/adapters/postgresql/connection_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/domain_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/enum_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/full_text_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/geometric_test.rb4
-rw-r--r--activerecord/test/cases/adapters/postgresql/hstore_test.rb32
-rw-r--r--activerecord/test/cases/adapters/postgresql/infinity_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/integer_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/json_test.rb10
-rw-r--r--activerecord/test/cases/adapters/postgresql/ltree_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/money_test.rb10
-rw-r--r--activerecord/test/cases/adapters/postgresql/network_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/numbers_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb4
-rw-r--r--activerecord/test/cases/adapters/postgresql/quoting_test.rb4
-rw-r--r--activerecord/test/cases/adapters/postgresql/range_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/rename_table_test.rb4
-rw-r--r--activerecord/test/cases/adapters/postgresql/schema_test.rb4
-rw-r--r--activerecord/test/cases/adapters/postgresql/type_lookup_test.rb8
-rw-r--r--activerecord/test/cases/adapters/postgresql/uuid_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/xml_test.rb2
-rw-r--r--activerecord/test/cases/adapters/sqlite3/quoting_test.rb2
-rw-r--r--activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb4
-rw-r--r--activerecord/test/cases/attribute_decorators_test.rb8
-rw-r--r--activerecord/test/cases/attribute_set_test.rb4
-rw-r--r--activerecord/test/cases/attribute_test.rb32
-rw-r--r--activerecord/test/cases/attributes_test.rb4
-rw-r--r--activerecord/test/cases/base_test.rb2
-rw-r--r--activerecord/test/cases/batches_test.rb35
-rw-r--r--activerecord/test/cases/connection_adapters/type_lookup_test.rb2
-rw-r--r--activerecord/test/cases/date_time_precision_test.rb2
-rw-r--r--activerecord/test/cases/dirty_test.rb6
-rw-r--r--activerecord/test/cases/enum_test.rb53
-rw-r--r--activerecord/test/cases/migration/change_schema_test.rb4
-rw-r--r--activerecord/test/cases/migration/columns_test.rb6
-rw-r--r--activerecord/test/cases/migration/foreign_key_test.rb21
-rw-r--r--activerecord/test/cases/primary_keys_test.rb2
-rw-r--r--activerecord/test/cases/reflection_test.rb6
-rw-r--r--activerecord/test/cases/relation_test.rb4
-rw-r--r--activerecord/test/cases/schema_dumper_test.rb2
-rw-r--r--activerecord/test/cases/secure_token_test.rb7
-rw-r--r--activerecord/test/cases/time_precision_test.rb65
-rw-r--r--activerecord/test/cases/transactions_test.rb2
-rw-r--r--activerecord/test/cases/type/adapter_specific_registry_test.rb133
-rw-r--r--activerecord/test/cases/type/decimal_test.rb16
-rw-r--r--activerecord/test/cases/type/integer_test.rb62
-rw-r--r--activerecord/test/cases/type/string_test.rb10
-rw-r--r--activerecord/test/cases/type/unsigned_integer_test.rb4
-rw-r--r--activerecord/test/cases/type_test.rb39
-rw-r--r--activerecord/test/cases/types_test.rb94
-rw-r--r--activerecord/test/migrations/missing/1000_people_have_middle_names.rb2
-rw-r--r--activerecord/test/migrations/missing/1_people_have_last_names.rb2
-rw-r--r--activerecord/test/migrations/missing/3_we_need_reminders.rb2
-rw-r--r--activerecord/test/migrations/missing/4_innocent_jointable.rb2
-rw-r--r--activerecord/test/migrations/rename/1_we_need_things.rb2
-rw-r--r--activerecord/test/migrations/rename/2_rename_things.rb2
-rw-r--r--activerecord/test/migrations/valid/2_we_need_reminders.rb2
-rw-r--r--activerecord/test/migrations/valid/3_innocent_jointable.rb2
-rw-r--r--activerecord/test/migrations/valid_with_subdirectories/sub/2_we_need_reminders.rb2
-rw-r--r--activerecord/test/migrations/valid_with_subdirectories/sub1/3_innocent_jointable.rb2
-rw-r--r--activerecord/test/models/admin.rb2
-rw-r--r--activerecord/test/models/admin/account.rb2
-rw-r--r--activerecord/test/models/binary.rb2
-rw-r--r--activerecord/test/models/event.rb2
-rw-r--r--activerecord/test/models/guid.rb2
-rw-r--r--activerecord/test/models/pirate.rb2
-rw-r--r--activerecord/test/schema/postgresql_specific_schema.rb2
-rw-r--r--activesupport/lib/active_support/callbacks.rb4
-rw-r--r--guides/CHANGELOG.md4
-rw-r--r--guides/source/action_controller_overview.md2
-rw-r--r--guides/source/action_mailer_basics.md33
-rw-r--r--guides/source/action_view_overview.md84
-rw-r--r--guides/source/active_record_querying.md18
-rw-r--r--guides/source/active_record_validations.md52
-rw-r--r--guides/source/association_basics.md17
-rw-r--r--guides/source/autoloading_and_reloading_constants.md4
-rw-r--r--guides/source/configuring.md18
-rw-r--r--guides/source/contributing_to_ruby_on_rails.md10
-rw-r--r--guides/source/debugging_rails_applications.md54
-rw-r--r--guides/source/i18n.md5
-rw-r--r--guides/source/layouts_and_rendering.md34
-rw-r--r--guides/source/testing.md3
-rw-r--r--guides/source/working_with_javascript_in_rails.md28
-rw-r--r--railties/lib/rails/application/finisher.rb7
-rw-r--r--railties/lib/rails/commands/server.rb4
-rw-r--r--railties/lib/rails/generators/erb/mailer/mailer_generator.rb6
-rw-r--r--railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb5
-rw-r--r--railties/lib/rails/generators/test_unit/mailer/templates/functional_test.rb2
-rw-r--r--railties/test/generators/mailer_generator_test.rb31
-rw-r--r--railties/test/generators/namespaced_generators_test.rb10
178 files changed, 1735 insertions, 955 deletions
diff --git a/.gitignore b/.gitignore
index bc96284375..c3cb009140 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,7 +5,6 @@ debug.log
.Gemfile
/.bundle
/.ruby-version
-/Gemfile.lock
pkg
/dist
/doc/rdoc
diff --git a/.travis.yml b/.travis.yml
index b38cb0032b..3130ee1b32 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,6 +3,7 @@ sudo: false
script: 'ci/travis.rb'
before_install:
- gem install bundler
+ - "rm ${BUNDLE_GEMFILE}.lock"
before_script:
- bundle update
cache: bundler
diff --git a/Gemfile.lock b/Gemfile.lock
new file mode 100644
index 0000000000..d48bfc31b1
--- /dev/null
+++ b/Gemfile.lock
@@ -0,0 +1,281 @@
+GIT
+ remote: git://github.com/bkeepers/qu.git
+ revision: d098e2657c92e89a6413bebd9c033930759c061f
+ branch: master
+ specs:
+ qu (0.2.0)
+ qu-rails (0.2.0)
+ qu (= 0.2.0)
+ railties (>= 3.2, < 5)
+ qu-redis (0.2.0)
+ qu (= 0.2.0)
+ redis-namespace
+
+GIT
+ remote: git://github.com/rails/arel.git
+ revision: aac9da257f291ad8d2d4f914528881c240848bb2
+ branch: master
+ specs:
+ arel (7.0.0.alpha)
+
+GIT
+ remote: git://github.com/rails/jquery-rails.git
+ revision: 272abdd319bb3381b23182b928b25320590096b0
+ branch: master
+ specs:
+ jquery-rails (4.0.3)
+ rails-dom-testing (~> 1.0)
+ railties (>= 4.2.0)
+ thor (>= 0.14, < 2.0)
+
+PATH
+ remote: .
+ specs:
+ actionmailer (5.0.0.alpha)
+ actionpack (= 5.0.0.alpha)
+ actionview (= 5.0.0.alpha)
+ activejob (= 5.0.0.alpha)
+ mail (~> 2.5, >= 2.5.4)
+ rails-dom-testing (~> 1.0, >= 1.0.5)
+ actionpack (5.0.0.alpha)
+ actionview (= 5.0.0.alpha)
+ activesupport (= 5.0.0.alpha)
+ rack (~> 1.6)
+ rack-test (~> 0.6.2)
+ rails-dom-testing (~> 1.0, >= 1.0.5)
+ rails-html-sanitizer (~> 1.0, >= 1.0.1)
+ actionview (5.0.0.alpha)
+ activesupport (= 5.0.0.alpha)
+ builder (~> 3.1)
+ erubis (~> 2.7.0)
+ rails-dom-testing (~> 1.0, >= 1.0.5)
+ rails-html-sanitizer (~> 1.0, >= 1.0.1)
+ activejob (5.0.0.alpha)
+ activesupport (= 5.0.0.alpha)
+ globalid (>= 0.3.0)
+ activemodel (5.0.0.alpha)
+ activesupport (= 5.0.0.alpha)
+ builder (~> 3.1)
+ activerecord (5.0.0.alpha)
+ activemodel (= 5.0.0.alpha)
+ activesupport (= 5.0.0.alpha)
+ arel (= 7.0.0.alpha)
+ activesupport (5.0.0.alpha)
+ i18n (~> 0.7)
+ json (~> 1.7, >= 1.7.7)
+ minitest (~> 5.1)
+ thread_safe (~> 0.3, >= 0.3.4)
+ tzinfo (~> 1.1)
+ rails (5.0.0.alpha)
+ actionmailer (= 5.0.0.alpha)
+ actionpack (= 5.0.0.alpha)
+ actionview (= 5.0.0.alpha)
+ activejob (= 5.0.0.alpha)
+ activemodel (= 5.0.0.alpha)
+ activerecord (= 5.0.0.alpha)
+ activesupport (= 5.0.0.alpha)
+ bundler (>= 1.3.0, < 2.0)
+ railties (= 5.0.0.alpha)
+ sprockets-rails
+ railties (5.0.0.alpha)
+ actionpack (= 5.0.0.alpha)
+ activesupport (= 5.0.0.alpha)
+ rake (>= 0.8.7)
+ thor (>= 0.18.1, < 2.0)
+
+GEM
+ remote: https://rubygems.org/
+ specs:
+ amq-protocol (1.9.2)
+ backburner (0.4.6)
+ beaneater (~> 0.3.1)
+ dante (~> 0.1.5)
+ bcrypt (3.1.10)
+ beaneater (0.3.3)
+ benchmark-ips (2.1.1)
+ builder (3.2.2)
+ bunny (1.1.9)
+ amq-protocol (>= 1.9.2)
+ celluloid (0.16.0)
+ timers (~> 4.0.0)
+ coffee-rails (4.1.0)
+ coffee-script (>= 2.2.0)
+ railties (>= 4.0.0, < 5.0)
+ coffee-script (2.3.0)
+ coffee-script-source
+ execjs
+ coffee-script-source (1.9.0)
+ connection_pool (2.1.1)
+ dalli (2.7.2)
+ dante (0.1.5)
+ delayed_job (4.0.6)
+ activesupport (>= 3.0, < 5.0)
+ erubis (2.7.0)
+ execjs (2.3.0)
+ globalid (0.3.3)
+ activesupport (>= 4.1.0)
+ hike (1.2.3)
+ hitimes (1.2.2)
+ i18n (0.7.0)
+ json (1.8.2)
+ kindlerb (0.1.1)
+ mustache
+ nokogiri
+ loofah (2.0.1)
+ nokogiri (>= 1.5.9)
+ mail (2.6.3)
+ mime-types (>= 1.16, < 3)
+ metaclass (0.0.4)
+ mime-types (2.4.3)
+ mini_portile (0.6.2)
+ minitest (5.3.3)
+ mocha (0.14.0)
+ metaclass (~> 0.0.1)
+ mono_logger (1.1.0)
+ multi_json (1.10.1)
+ mustache (1.0.0)
+ mysql (2.9.1)
+ mysql2 (0.3.18)
+ nokogiri (1.6.6.2)
+ mini_portile (~> 0.6.0)
+ pg (0.18.1)
+ psych (2.0.13)
+ que (0.9.2)
+ queue_classic (3.1.0)
+ pg (>= 0.17, < 0.19)
+ racc (1.4.12)
+ rack (1.6.0)
+ rack-cache (1.2)
+ rack (>= 0.4)
+ rack-protection (1.5.3)
+ rack
+ rack-test (0.6.3)
+ rack (>= 1.0)
+ rails-deprecated_sanitizer (1.0.3)
+ activesupport (>= 4.2.0.alpha)
+ rails-dom-testing (1.0.5)
+ activesupport (>= 4.2.0.beta, < 5.0)
+ nokogiri (~> 1.6.0)
+ rails-deprecated_sanitizer (>= 1.0.1)
+ rails-html-sanitizer (1.0.1)
+ loofah (~> 2.0)
+ rake (10.4.2)
+ rdoc (4.2.0)
+ redcarpet (3.2.2)
+ redis (3.2.1)
+ redis-namespace (1.5.1)
+ redis (~> 3.0, >= 3.0.4)
+ resque (1.25.2)
+ mono_logger (~> 1.0)
+ multi_json (~> 1.0)
+ redis-namespace (~> 1.3)
+ sinatra (>= 0.9.2)
+ vegas (~> 0.1.2)
+ resque-scheduler (4.0.0)
+ mono_logger (~> 1.0)
+ redis (~> 3.0)
+ resque (~> 1.25)
+ rufus-scheduler (~> 3.0)
+ ruby-prof (0.11.3)
+ rufus-scheduler (3.0.9)
+ tzinfo
+ sdoc (0.4.1)
+ json (~> 1.7, >= 1.7.7)
+ rdoc (~> 4.0)
+ sequel (4.19.0)
+ serverengine (1.5.10)
+ sigdump (~> 0.2.2)
+ sidekiq (3.3.2)
+ celluloid (>= 0.16.0)
+ connection_pool (>= 2.1.1)
+ json
+ redis (>= 3.0.6)
+ redis-namespace (>= 1.3.1)
+ sigdump (0.2.2)
+ sinatra (1.4.5)
+ rack (~> 1.4)
+ rack-protection (~> 1.4)
+ tilt (~> 1.3, >= 1.3.4)
+ sneakers (0.1.1.pre)
+ bunny (~> 1.1.3)
+ serverengine
+ thor
+ thread
+ sprockets (2.12.3)
+ hike (~> 1.2)
+ multi_json (~> 1.0)
+ rack (~> 1.0)
+ tilt (~> 1.1, != 1.3.0)
+ sprockets-rails (2.2.4)
+ actionpack (>= 3.0)
+ activesupport (>= 3.0)
+ sprockets (>= 2.8, < 4.0)
+ sqlite3 (1.3.10)
+ stackprof (0.2.7)
+ sucker_punch (1.3.2)
+ celluloid (~> 0.16.0)
+ thor (0.19.1)
+ thread (0.1.5)
+ thread_safe (0.3.4)
+ tilt (1.4.1)
+ timers (4.0.1)
+ hitimes
+ turbolinks (2.5.3)
+ coffee-rails
+ tzinfo (1.2.2)
+ thread_safe (~> 0.1)
+ uglifier (2.7.0)
+ execjs (>= 0.3.0)
+ json (>= 1.8.0)
+ vegas (0.1.11)
+ rack (>= 1.0.0)
+ w3c_validators (1.2)
+ json
+ nokogiri
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ activerecord-jdbcmysql-adapter (>= 1.3.0)
+ activerecord-jdbcpostgresql-adapter (>= 1.3.0)
+ activerecord-jdbcsqlite3-adapter (>= 1.3.0)
+ arel!
+ backburner
+ bcrypt (~> 3.1.7)
+ benchmark-ips
+ coffee-rails (~> 4.1.0)
+ dalli (>= 2.2.1)
+ delayed_job
+ jquery-rails!
+ json
+ kindlerb (= 0.1.1)
+ minitest (< 5.3.4)
+ mocha (~> 0.14)
+ mysql (>= 2.9.0)
+ mysql2 (>= 0.3.13)
+ nokogiri (>= 1.4.5)
+ pg (>= 0.18.0)
+ psych (~> 2.0)
+ qu-rails!
+ qu-redis
+ que
+ queue_classic
+ racc (>= 1.4.6)
+ rack-cache (~> 1.2)
+ rails!
+ rake (>= 10.3)
+ redcarpet (~> 3.2.2)
+ resque
+ resque-scheduler
+ ruby-prof (~> 0.11.2)
+ sdoc (~> 0.4.0)
+ sequel
+ sidekiq
+ sneakers (= 0.1.1.pre)
+ sqlite3 (~> 1.3.6)
+ stackprof
+ sucker_punch
+ turbolinks
+ uglifier (>= 1.3.0)
+ w3c_validators
diff --git a/actionmailer/lib/action_mailer/mail_helper.rb b/actionmailer/lib/action_mailer/mail_helper.rb
index cc7935a7e0..227192f48d 100644
--- a/actionmailer/lib/action_mailer/mail_helper.rb
+++ b/actionmailer/lib/action_mailer/mail_helper.rb
@@ -33,6 +33,8 @@ module ActionMailer
end
# Returns +text+ wrapped at +len+ columns and indented +indent+ spaces.
+ # By default column length +len+ equals 72 characters and indent
+ # +indent+ equal two spaces.
#
# my_text = 'Here is a sample text with more than 40 characters'
#
diff --git a/actionmailer/lib/rails/generators/mailer/USAGE b/actionmailer/lib/rails/generators/mailer/USAGE
index d9d9d064d8..2b0a078109 100644
--- a/actionmailer/lib/rails/generators/mailer/USAGE
+++ b/actionmailer/lib/rails/generators/mailer/USAGE
@@ -12,6 +12,6 @@ Example:
creates a Notifications mailer class, views, and test:
Mailer: app/mailers/notifications_mailer.rb
- Views: app/views/notifications/signup.text.erb [...]
- Test: test/mailers/notifications_test.rb
+ Views: app/views/notifications_mailer/signup.text.erb [...]
+ Test: test/mailers/notifications_mailer_test.rb
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index 0345d36760..055d4b4f5b 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -3,6 +3,10 @@
*Ville Lautanala*
+* Add http_cache_forever to Action Controller, so we can cache a response that never gets expired.
+
+ *arthurnn*
+
* ActionController#translate supports symbols as shortcuts.
When shortcut is given it also lookups without action name.
diff --git a/actionpack/lib/action_controller/metal/conditional_get.rb b/actionpack/lib/action_controller/metal/conditional_get.rb
index 28f0b6e349..858870d8b8 100644
--- a/actionpack/lib/action_controller/metal/conditional_get.rb
+++ b/actionpack/lib/action_controller/metal/conditional_get.rb
@@ -215,6 +215,24 @@ module ActionController
response.cache_control.replace(:no_cache => true)
end
+ # Cache or yield the block. The cache is supposed to never expire.
+ #
+ # You can use this method when you have a HTTP response that never changes,
+ # and the browser and proxies should cache it indefinitely.
+ #
+ # * +public+: By default, HTTP responses are private, cached only on the
+ # user's web browser. To allow proxies to cache the response, set +true+ to
+ # indicate that they can serve the cached response to all users.
+ #
+ # * +version+: the version passed as a key for the cache.
+ def http_cache_forever(public: false, version: 'v1')
+ expires_in 100.years, public: public
+
+ yield if stale?(etag: "#{version}-#{request.fullpath}",
+ last_modified: Time.parse('2011-01-01').utc,
+ public: public)
+ end
+
private
def combine_etags(options)
etags = etaggers.map { |etagger| instance_exec(options, &etagger) }.compact
diff --git a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
index 5595a73887..d176a73633 100644
--- a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
+++ b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
@@ -1,5 +1,6 @@
require 'action_controller/metal/exceptions'
require 'active_support/core_ext/module/attribute_accessors'
+require 'rack/utils'
module ActionDispatch
class ExceptionWrapper
diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb
index f6b6c57a83..9b00616968 100644
--- a/actionpack/lib/action_dispatch/testing/integration.rb
+++ b/actionpack/lib/action_dispatch/testing/integration.rb
@@ -305,18 +305,17 @@ module ActionDispatch
def non_kwarg_request_warning
ActiveSupport::Deprecation.warn(<<-MSG.strip_heredoc)
- ActionDispatch::Integration::TestCase HTTP request methods will accept only
- keyword arguments in future Rails versions.
+ ActionDispatch::IntegrationTest HTTP request methods will accept only
+ the following keyword arguments in future Rails versions:
+ #{REQUEST_KWARGS.join(', ')}
Examples:
get '/profile',
params: { id: 1 },
headers: { 'X-Extra-Header' => '123' },
- env: { 'action_dispatch.custom' => 'custom' }
-
- xhr :post, '/profile',
- params: { id: 1 }
+ env: { 'action_dispatch.custom' => 'custom' },
+ xhr: true
MSG
end
@@ -389,7 +388,7 @@ module ActionDispatch
APP_SESSIONS = {}
- attr_reader :app, :integration_session
+ attr_reader :app
def before_setup
super
@@ -397,6 +396,10 @@ module ActionDispatch
@integration_session = nil
end
+ def integration_session
+ @integration_session ||= create_session(app)
+ end
+
# Reset the current session. This is useful for testing multiple sessions
# in a single test case.
def reset!
@@ -422,8 +425,6 @@ module ActionDispatch
%w(get post patch put head delete cookies assigns
xml_http_request xhr get_via_redirect post_via_redirect).each do |method|
define_method(method) do |*args|
- reset! unless integration_session
-
# reset the html_document variable, except for cookies/assigns calls
unless method == 'cookies' || method == 'assigns'
@html_document = nil
@@ -455,19 +456,16 @@ module ActionDispatch
# Copy the instance variables from the current session instance into the
# test instance.
def copy_session_variables! #:nodoc:
- return unless integration_session
- %w(controller response request).each do |var|
- instance_variable_set("@#{var}", @integration_session.__send__(var))
- end
+ @controller = @integration_session.controller
+ @response = @integration_session.response
+ @request = @integration_session.request
end
def default_url_options
- reset! unless integration_session
integration_session.default_url_options
end
def default_url_options=(options)
- reset! unless integration_session
integration_session.default_url_options = options
end
@@ -477,7 +475,6 @@ module ActionDispatch
# Delegate unhandled messages to the current session instance.
def method_missing(sym, *args, &block)
- reset! unless integration_session
if integration_session.respond_to?(sym)
integration_session.__send__(sym, *args, &block).tap do
copy_session_variables!
@@ -662,7 +659,6 @@ module ActionDispatch
end
def url_options
- reset! unless integration_session
integration_session.url_options
end
diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb
index 8d6b62f2bf..488585c7a4 100644
--- a/actionpack/test/controller/render_test.rb
+++ b/actionpack/test/controller/render_test.rb
@@ -561,3 +561,56 @@ class HeadRenderTest < ActionController::TestCase
assert_response :forbidden
end
end
+
+class HttpCacheForeverTest < ActionController::TestCase
+ class HttpCacheForeverController < ActionController::Base
+ def cache_me_forever
+ http_cache_forever(public: params[:public], version: params[:version] || 'v1') do
+ render text: 'hello'
+ end
+ end
+ end
+
+ tests HttpCacheForeverController
+
+ def test_cache_with_public
+ get :cache_me_forever, params: {public: true}
+ assert_equal "max-age=#{100.years.to_i}, public", @response.headers["Cache-Control"]
+ assert_not_nil @response.etag
+ end
+
+ def test_cache_with_private
+ get :cache_me_forever
+ assert_equal "max-age=#{100.years.to_i}, private", @response.headers["Cache-Control"]
+ assert_not_nil @response.etag
+ assert_response :success
+ end
+
+ def test_cache_response_code_with_if_modified_since
+ get :cache_me_forever
+ assert_response :success
+ @request.if_modified_since = @response.headers['Last-Modified']
+ get :cache_me_forever
+ assert_response :not_modified
+ end
+
+ def test_cache_response_code_with_etag
+ get :cache_me_forever
+ assert_response :success
+ @request.if_modified_since = @response.headers['Last-Modified']
+ @request.if_none_match = @response.etag
+
+ get :cache_me_forever
+ assert_response :not_modified
+ @request.if_modified_since = @response.headers['Last-Modified']
+ @request.if_none_match = @response.etag
+
+ get :cache_me_forever, params: {version: 'v2'}
+ assert_response :success
+ @request.if_modified_since = @response.headers['Last-Modified']
+ @request.if_none_match = @response.etag
+
+ get :cache_me_forever, params: {version: 'v2'}
+ assert_response :not_modified
+ end
+end
diff --git a/actionpack/test/dispatch/response_test.rb b/actionpack/test/dispatch/response_test.rb
index c61423dce4..5fbd19acdf 100644
--- a/actionpack/test/dispatch/response_test.rb
+++ b/actionpack/test/dispatch/response_test.rb
@@ -254,10 +254,6 @@ class ResponseTest < ActiveSupport::TestCase
end
class ResponseIntegrationTest < ActionDispatch::IntegrationTest
- def app
- @app
- end
-
test "response cache control from railsish app" do
@app = lambda { |env|
ActionDispatch::Response.new.tap { |resp|
diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md
index 7fc32a3b5c..5557285ef5 100644
--- a/actionview/CHANGELOG.md
+++ b/actionview/CHANGELOG.md
@@ -1,3 +1,14 @@
+* Extracted `ActionView::Helpers::RecordTagHelper` to external gem
+ (`record_tag_helper`) and added removal notices.
+
+ *Todd Bealmear*
+
+* Allow to pass a string value to `size` option in `image_tag` and `video_tag`.
+
+ This makes the behavior more consistent with `width` or `height` options.
+
+ *Mehdi Lahmam*
+
* Partial template name does no more have to be a valid Ruby identifier.
There used to be a naming rule that the partial name should start with
diff --git a/actionview/lib/action_view/base.rb b/actionview/lib/action_view/base.rb
index 1feafc1094..43124bb904 100644
--- a/actionview/lib/action_view/base.rb
+++ b/actionview/lib/action_view/base.rb
@@ -70,6 +70,14 @@ module ActionView #:nodoc:
# Headline: <%= headline %>
# First name: <%= person.first_name %>
#
+ # The local variables passed to sub templates can be accessed as a hash using the <tt>local_assigns</tt> hash. This lets you access the
+ # variables as:
+ #
+ # Headline: <%= local_assigns[:headline] %>
+ #
+ # This is useful in cases where you aren't sure if the local variable has been assigned. Alternately, you could also use
+ # <tt>defined? headline</tt> to first check if the variable has been assigned before using it.
+ #
# === Template caching
#
# By default, Rails will compile each template to a method in order to render it. When you alter a template,
diff --git a/actionview/lib/action_view/helpers/asset_tag_helper.rb b/actionview/lib/action_view/helpers/asset_tag_helper.rb
index b7fdc16a9d..5c28043f8a 100644
--- a/actionview/lib/action_view/helpers/asset_tag_helper.rb
+++ b/actionview/lib/action_view/helpers/asset_tag_helper.rb
@@ -318,6 +318,7 @@ module ActionView
end
def extract_dimensions(size)
+ size = size.to_s
if size =~ %r{\A\d+x\d+\z}
size.split('x')
elsif size =~ %r{\A\d+\z}
diff --git a/actionview/lib/action_view/helpers/form_helper.rb b/actionview/lib/action_view/helpers/form_helper.rb
index 8d78ba13d5..cd52763f31 100644
--- a/actionview/lib/action_view/helpers/form_helper.rb
+++ b/actionview/lib/action_view/helpers/form_helper.rb
@@ -4,6 +4,7 @@ require 'action_view/helpers/tag_helper'
require 'action_view/helpers/form_tag_helper'
require 'action_view/helpers/active_model_helper'
require 'action_view/model_naming'
+require 'action_view/record_identifier'
require 'active_support/core_ext/module/attribute_accessors'
require 'active_support/core_ext/hash/slice'
require 'active_support/core_ext/string/output_safety'
@@ -110,6 +111,7 @@ module ActionView
include FormTagHelper
include UrlHelper
include ModelNaming
+ include RecordIdentifier
# Creates a form that allows the user to create or update the attributes
# of a specific model object.
diff --git a/actionview/lib/action_view/helpers/record_tag_helper.rb b/actionview/lib/action_view/helpers/record_tag_helper.rb
index 77c3e6d394..f7ee573035 100644
--- a/actionview/lib/action_view/helpers/record_tag_helper.rb
+++ b/actionview/lib/action_view/helpers/record_tag_helper.rb
@@ -1,108 +1,21 @@
-require 'action_view/record_identifier'
-
module ActionView
- # = Action View Record Tag Helpers
module Helpers
module RecordTagHelper
- include ActionView::RecordIdentifier
-
- # Produces a wrapper DIV element with id and class parameters that
- # relate to the specified Active Record object. Usage example:
- #
- # <%= div_for(@person, class: "foo") do %>
- # <%= @person.name %>
- # <% end %>
- #
- # produces:
- #
- # <div id="person_123" class="person foo"> Joe Bloggs </div>
- #
- # You can also pass an array of Active Record objects, which will then
- # get iterated over and yield each record as an argument for the block.
- # For example:
- #
- # <%= div_for(@people, class: "foo") do |person| %>
- # <%= person.name %>
- # <% end %>
- #
- # produces:
- #
- # <div id="person_123" class="person foo"> Joe Bloggs </div>
- # <div id="person_124" class="person foo"> Jane Bloggs </div>
- #
- def div_for(record, *args, &block)
- content_tag_for(:div, record, *args, &block)
+ def div_for(*)
+ raise NoMethodError, "The `div_for` method has been removed from " \
+ "Rails. To continue using it, add the `record_tag_helper` gem to " \
+ "your Gemfile:\n" \
+ " gem 'record_tag_helper', '~> 1.0'\n" \
+ "Consult the Rails upgrade guide for details."
end
- # content_tag_for creates an HTML element with id and class parameters
- # that relate to the specified Active Record object. For example:
- #
- # <%= content_tag_for(:tr, @person) do %>
- # <td><%= @person.first_name %></td>
- # <td><%= @person.last_name %></td>
- # <% end %>
- #
- # would produce the following HTML (assuming @person is an instance of
- # a Person object, with an id value of 123):
- #
- # <tr id="person_123" class="person">....</tr>
- #
- # If you require the HTML id attribute to have a prefix, you can specify it:
- #
- # <%= content_tag_for(:tr, @person, :foo) do %> ...
- #
- # produces:
- #
- # <tr id="foo_person_123" class="person">...
- #
- # You can also pass an array of objects which this method will loop through
- # and yield the current object to the supplied block, reducing the need for
- # having to iterate through the object (using <tt>each</tt>) beforehand.
- # For example (assuming @people is an array of Person objects):
- #
- # <%= content_tag_for(:tr, @people) do |person| %>
- # <td><%= person.first_name %></td>
- # <td><%= person.last_name %></td>
- # <% end %>
- #
- # produces:
- #
- # <tr id="person_123" class="person">...</tr>
- # <tr id="person_124" class="person">...</tr>
- #
- # content_tag_for also accepts a hash of options, which will be converted to
- # additional HTML attributes. If you specify a <tt>:class</tt> value, it will be combined
- # with the default class name for your object. For example:
- #
- # <%= content_tag_for(:li, @person, class: "bar") %>...
- #
- # produces:
- #
- # <li id="person_123" class="person bar">...
- #
- def content_tag_for(tag_name, single_or_multiple_records, prefix = nil, options = nil, &block)
- options, prefix = prefix, nil if prefix.is_a?(Hash)
-
- Array(single_or_multiple_records).map do |single_record|
- content_tag_for_single_record(tag_name, single_record, prefix, options, &block)
- end.join("\n").html_safe
+ def content_tag_for(*)
+ raise NoMethodError, "The `content_tag_for` method has been removed from " \
+ "Rails. To continue using it, add the `record_tag_helper` gem to " \
+ "your Gemfile:\n" \
+ " gem 'record_tag_helper', '~> 1.0'\n" \
+ "Consult the Rails upgrade guide for details."
end
-
- private
-
- # Called by <tt>content_tag_for</tt> internally to render a content tag
- # for each record.
- def content_tag_for_single_record(tag_name, record, prefix, options, &block)
- options = options ? options.dup : {}
- options[:class] = [ dom_class(record, prefix), options[:class] ].compact
- options[:id] = dom_id(record, prefix)
-
- if block_given?
- content_tag(tag_name, capture(record, &block), options)
- else
- content_tag(tag_name, "", options)
- end
- end
end
end
end
diff --git a/actionview/lib/action_view/template.rb b/actionview/lib/action_view/template.rb
index 6b61378a1f..305d9c6ee3 100644
--- a/actionview/lib/action_view/template.rb
+++ b/actionview/lib/action_view/template.rb
@@ -87,6 +87,19 @@ module ActionView
# expected_encoding
# )
+ ##
+ # :method: local_assigns
+ #
+ # Returns a hash with the defined local variables.
+ #
+ # Given this sub template rendering:
+ #
+ # <%= render "shared/header", { headline: "Welcome", person: person } %>
+ #
+ # You can use +local_assigns+ in the sub templates to access the local variables:
+ #
+ # local_assigns[:headline] # => "Welcome"
+
eager_autoload do
autoload :Error
autoload :Handlers
@@ -103,7 +116,7 @@ module ActionView
# This finalizer is needed (and exactly with a proc inside another proc)
# otherwise templates leak in development.
- Finalizer = proc do |method_name, mod|
+ Finalizer = proc do |method_name, mod| # :nodoc:
proc do
mod.module_eval do
remove_possible_method method_name
diff --git a/actionview/test/template/asset_tag_helper_test.rb b/actionview/test/template/asset_tag_helper_test.rb
index dac1c7024d..a15c6fac90 100644
--- a/actionview/test/template/asset_tag_helper_test.rb
+++ b/actionview/test/template/asset_tag_helper_test.rb
@@ -180,6 +180,7 @@ class AssetTagHelperTest < ActionView::TestCase
%(image_tag("xml.png")) => %(<img alt="Xml" src="/images/xml.png" />),
%(image_tag("rss.gif", :alt => "rss syndication")) => %(<img alt="rss syndication" src="/images/rss.gif" />),
%(image_tag("gold.png", :size => "20")) => %(<img alt="Gold" height="20" src="/images/gold.png" width="20" />),
+ %(image_tag("gold.png", :size => 20)) => %(<img alt="Gold" height="20" src="/images/gold.png" width="20" />),
%(image_tag("gold.png", :size => "45x70")) => %(<img alt="Gold" height="70" src="/images/gold.png" width="45" />),
%(image_tag("gold.png", "size" => "45x70")) => %(<img alt="Gold" height="70" src="/images/gold.png" width="45" />),
%(image_tag("error.png", "size" => "45 x 70")) => %(<img alt="Error" src="/images/error.png" />),
@@ -238,6 +239,7 @@ class AssetTagHelperTest < ActionView::TestCase
%(video_tag("gold.m4v", "size" => "320x240")) => %(<video height="240" src="/videos/gold.m4v" width="320"></video>),
%(video_tag("trailer.ogg", :poster => "screenshot.png")) => %(<video poster="/images/screenshot.png" src="/videos/trailer.ogg"></video>),
%(video_tag("error.avi", "size" => "100")) => %(<video height="100" src="/videos/error.avi" width="100"></video>),
+ %(video_tag("error.avi", "size" => 100)) => %(<video height="100" src="/videos/error.avi" width="100"></video>),
%(video_tag("error.avi", "size" => "100 x 100")) => %(<video src="/videos/error.avi"></video>),
%(video_tag("error.avi", "size" => "x")) => %(<video src="/videos/error.avi"></video>),
%(video_tag("http://media.rubyonrails.org/video/rails_blog_2.mov")) => %(<video src="http://media.rubyonrails.org/video/rails_blog_2.mov"></video>),
diff --git a/actionview/test/template/record_tag_helper_test.rb b/actionview/test/template/record_tag_helper_test.rb
index ab84bccb56..4b7b653916 100644
--- a/actionview/test/template/record_tag_helper_test.rb
+++ b/actionview/test/template/record_tag_helper_test.rb
@@ -24,94 +24,10 @@ class RecordTagHelperTest < ActionView::TestCase
end
def test_content_tag_for
- expected = %(<li class="record_tag_post" id="record_tag_post_45"></li>)
- actual = content_tag_for(:li, @post)
- assert_dom_equal expected, actual
+ assert_raises(NoMethodError) { content_tag_for(:li, @post) }
end
- def test_content_tag_for_prefix
- expected = %(<ul class="archived_record_tag_post" id="archived_record_tag_post_45"></ul>)
- actual = content_tag_for(:ul, @post, :archived)
- assert_dom_equal expected, actual
- end
-
- def test_content_tag_for_with_extra_html_options
- expected = %(<tr class="record_tag_post special" id="record_tag_post_45" style='background-color: #f0f0f0'></tr>)
- actual = content_tag_for(:tr, @post, class: "special", style: "background-color: #f0f0f0")
- assert_dom_equal expected, actual
- end
-
- def test_content_tag_for_with_array_css_class
- expected = %(<tr class="record_tag_post special odd" id="record_tag_post_45"></tr>)
- actual = content_tag_for(:tr, @post, class: ["special", "odd"])
- assert_dom_equal expected, actual
- end
-
- def test_content_tag_for_with_prefix_and_extra_html_options
- expected = %(<tr class="archived_record_tag_post special" id="archived_record_tag_post_45" style='background-color: #f0f0f0'></tr>)
- actual = content_tag_for(:tr, @post, :archived, class: "special", style: "background-color: #f0f0f0")
- assert_dom_equal expected, actual
- end
-
- def test_block_not_in_erb_multiple_calls
- expected = %(<div class="record_tag_post special" id="record_tag_post_45">What a wonderful world!</div>)
- actual = div_for(@post, class: "special") { @post.body }
- assert_dom_equal expected, actual
- actual = div_for(@post, class: "special") { @post.body }
- assert_dom_equal expected, actual
- end
-
- def test_block_works_with_content_tag_for_in_erb
- expected = %(<tr class="record_tag_post" id="record_tag_post_45">What a wonderful world!</tr>)
- actual = render_erb("<%= content_tag_for(:tr, @post) do %><%= @post.body %><% end %>")
- assert_dom_equal expected, actual
- end
-
- def test_div_for_in_erb
- expected = %(<div class="record_tag_post special" id="record_tag_post_45">What a wonderful world!</div>)
- actual = render_erb("<%= div_for(@post, class: 'special') do %><%= @post.body %><% end %>")
- assert_dom_equal expected, actual
- end
-
- def test_content_tag_for_collection
- post_1 = RecordTagPost.new { |post| post.id = 101; post.body = "Hello!" }
- post_2 = RecordTagPost.new { |post| post.id = 102; post.body = "World!" }
- expected = %(<li class="record_tag_post" id="record_tag_post_101">Hello!</li>\n<li class="record_tag_post" id="record_tag_post_102">World!</li>)
- actual = content_tag_for(:li, [post_1, post_2]) { |post| post.body }
- assert_dom_equal expected, actual
- end
-
- def test_content_tag_for_collection_without_given_block
- post_1 = RecordTagPost.new.tap { |post| post.id = 101; post.body = "Hello!" }
- post_2 = RecordTagPost.new.tap { |post| post.id = 102; post.body = "World!" }
- expected = %(<li class="record_tag_post" id="record_tag_post_101"></li>\n<li class="record_tag_post" id="record_tag_post_102"></li>)
- actual = content_tag_for(:li, [post_1, post_2])
- assert_dom_equal expected, actual
- end
-
- def test_div_for_collection
- post_1 = RecordTagPost.new { |post| post.id = 101; post.body = "Hello!" }
- post_2 = RecordTagPost.new { |post| post.id = 102; post.body = "World!" }
- expected = %(<div class="record_tag_post" id="record_tag_post_101">Hello!</div>\n<div class="record_tag_post" id="record_tag_post_102">World!</div>)
- actual = div_for([post_1, post_2]) { |post| post.body }
- assert_dom_equal expected, actual
- end
-
- def test_content_tag_for_single_record_is_html_safe
- result = div_for(@post, class: "special") { @post.body }
- assert result.html_safe?
- end
-
- def test_content_tag_for_collection_is_html_safe
- post_1 = RecordTagPost.new { |post| post.id = 101; post.body = "Hello!" }
- post_2 = RecordTagPost.new { |post| post.id = 102; post.body = "World!" }
- result = content_tag_for(:li, [post_1, post_2]) { |post| post.body }
- assert result.html_safe?
- end
-
- def test_content_tag_for_does_not_change_options_hash
- options = { class: "important" }
- content_tag_for(:li, @post, options)
- assert_equal({ class: "important" }, options)
+ def test_div_for
+ assert_raises(NoMethodError) { div_for(@post, class: "special") }
end
end
diff --git a/activemodel/CHANGELOG.md b/activemodel/CHANGELOG.md
index 5830a00bc5..a3e00e4dc9 100644
--- a/activemodel/CHANGELOG.md
+++ b/activemodel/CHANGELOG.md
@@ -1,3 +1,12 @@
+* Deprecate `ActiveModel::Errors#get`, `ActiveModel::Errors#set` and
+ `ActiveModel::Errors#[]=` methods that have inconsistent behaviour.
+
+ *Wojciech Wnętrzak*
+
+* Allow symbol as values for `tokenize` of `LengthValidator`
+
+ *Kensuke Naito*
+
* Assigning an unknown attribute key to an `ActiveModel` instance during initialization
will now raise `ActiveModel::AttributeAssignment::UnknownAttributeError` instead of
`NoMethodError`
diff --git a/activemodel/lib/active_model/callbacks.rb b/activemodel/lib/active_model/callbacks.rb
index 6214802074..2cf39b68fb 100644
--- a/activemodel/lib/active_model/callbacks.rb
+++ b/activemodel/lib/active_model/callbacks.rb
@@ -49,7 +49,7 @@ module ActiveModel
# puts 'block successfully called.'
# end
#
- # You can choose not to have all three callbacks by passing a hash to the
+ # You can choose to have only specific callbacks by passing a hash to the
# +define_model_callbacks+ method.
#
# define_model_callbacks :create, only: [:after, :before]
diff --git a/activemodel/lib/active_model/dirty.rb b/activemodel/lib/active_model/dirty.rb
index ca5dac272f..c03e5fac79 100644
--- a/activemodel/lib/active_model/dirty.rb
+++ b/activemodel/lib/active_model/dirty.rb
@@ -118,7 +118,7 @@ module ActiveModel
attribute_method_affix prefix: 'restore_', suffix: '!'
end
- # Returns +true+ if any attribute have unsaved changes, +false+ otherwise.
+ # Returns +true+ if any of the attributes have unsaved changes, +false+ otherwise.
#
# person.changed? # => false
# person.name = 'bob'
@@ -166,7 +166,7 @@ module ActiveModel
@changed_attributes ||= ActiveSupport::HashWithIndifferentAccess.new
end
- # Handle <tt>*_changed?</tt> for +method_missing+.
+ # Handles <tt>*_changed?</tt> for +method_missing+.
def attribute_changed?(attr, options = {}) #:nodoc:
result = changes_include?(attr)
result &&= options[:to] == __send__(attr) if options.key?(:to)
@@ -174,7 +174,7 @@ module ActiveModel
result
end
- # Handle <tt>*_was</tt> for +method_missing+.
+ # Handles <tt>*_was</tt> for +method_missing+.
def attribute_was(attr) # :nodoc:
attribute_changed?(attr) ? changed_attributes[attr] : __send__(attr)
end
@@ -186,6 +186,7 @@ module ActiveModel
private
+ # Returns +true+ if attr_name is changed, +false+ otherwise.
def changes_include?(attr_name)
attributes_changed_by_setter.include?(attr_name)
end
@@ -197,18 +198,18 @@ module ActiveModel
@changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
end
- # Clear all dirty data: current changes and previous changes.
+ # Clears all dirty data: current changes and previous changes.
def clear_changes_information # :doc:
@previously_changed = ActiveSupport::HashWithIndifferentAccess.new
@changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
end
- # Handle <tt>*_change</tt> for +method_missing+.
+ # Handles <tt>*_change</tt> for +method_missing+.
def attribute_change(attr)
[changed_attributes[attr], __send__(attr)] if attribute_changed?(attr)
end
- # Handle <tt>*_will_change!</tt> for +method_missing+.
+ # Handles <tt>*_will_change!</tt> for +method_missing+.
def attribute_will_change!(attr)
return if attribute_changed?(attr)
@@ -221,7 +222,7 @@ module ActiveModel
set_attribute_was(attr, value)
end
- # Handle <tt>restore_*!</tt> for +method_missing+.
+ # Handles <tt>restore_*!</tt> for +method_missing+.
def restore_attribute!(attr)
if attribute_changed?(attr)
__send__("#{attr}=", changed_attributes[attr])
@@ -230,7 +231,7 @@ module ActiveModel
end
# This is necessary because `changed_attributes` might be overridden in
- # other implemntations (e.g. in `ActiveRecord`)
+ # other implementations (e.g. in `ActiveRecord`)
alias_method :attributes_changed_by_setter, :changed_attributes # :nodoc:
# Force an attribute to have a particular "before" value
diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb
index a809c72ccd..b1d090b830 100644
--- a/activemodel/lib/active_model/errors.rb
+++ b/activemodel/lib/active_model/errors.rb
@@ -3,6 +3,7 @@
require 'active_support/core_ext/array/conversions'
require 'active_support/core_ext/string/inflections'
require 'active_support/core_ext/object/deep_dup'
+require 'active_support/deprecation'
module ActiveModel
# == Active \Model \Errors
@@ -72,7 +73,7 @@ module ActiveModel
# end
def initialize(base)
@base = base
- @messages = {}
+ @messages = Hash.new { |messages, attribute| messages[attribute] = [] }
@details = Hash.new { |details, attribute| details[attribute] = [] }
end
@@ -110,8 +111,14 @@ module ActiveModel
#
# person.errors.messages # => {:name=>["cannot be nil"]}
# person.errors.get(:name) # => ["cannot be nil"]
- # person.errors.get(:age) # => nil
+ # person.errors.get(:age) # => []
def get(key)
+ ActiveSupport::Deprecation.warn(<<-MESSAGE.squish)
+ ActiveModel::Errors#get is deprecated and will be removed in Rails 5.1
+
+ To achieve the same use messages[:#{key}]
+ MESSAGE
+
messages[key]
end
@@ -121,6 +128,12 @@ module ActiveModel
# person.errors.set(:name, ["can't be nil"])
# person.errors.get(:name) # => ["can't be nil"]
def set(key, value)
+ ActiveSupport::Deprecation.warn(<<-MESSAGE.squish)
+ ActiveModel::Errors#set is deprecated and will be removed in Rails 5.1
+
+ To achieve the same use messages[:#{key}] = "#{value}"
+ MESSAGE
+
messages[key] = value
end
@@ -128,7 +141,7 @@ module ActiveModel
#
# person.errors.get(:name) # => ["cannot be nil"]
# person.errors.delete(:name) # => ["cannot be nil"]
- # person.errors.get(:name) # => nil
+ # person.errors.get(:name) # => []
def delete(key)
messages.delete(key)
details.delete(key)
@@ -140,7 +153,7 @@ module ActiveModel
# person.errors[:name] # => ["cannot be nil"]
# person.errors['name'] # => ["cannot be nil"]
def [](attribute)
- get(attribute.to_sym) || set(attribute.to_sym, [])
+ messages[attribute.to_sym]
end
# Adds to the supplied attribute the supplied error message.
@@ -148,7 +161,13 @@ module ActiveModel
# person.errors[:name] = "must be set"
# person.errors[:name] # => ['must be set']
def []=(attribute, error)
- self[attribute] << error
+ ActiveSupport::Deprecation.warn(<<-MESSAGE.squish)
+ ActiveModel::Errors#[]= is deprecated and will be removed in Rails 5.1
+
+ To achieve the same use messages[:#{attribute}] << "#{error}"
+ MESSAGE
+
+ messages[attribute.to_sym] << error
end
# Iterates through each error key, value pair in the error messages hash.
@@ -167,7 +186,7 @@ module ActiveModel
# end
def each
messages.each_key do |attribute|
- self[attribute].each { |error| yield attribute, error }
+ messages[attribute].each { |error| yield attribute, error }
end
end
@@ -317,8 +336,8 @@ module ActiveModel
raise exception, full_message(attribute, message)
end
- details[attribute.to_sym] << detail
- self[attribute] << message
+ details[attribute.to_sym] << detail
+ messages[attribute.to_sym] << message
end
# Will add an error message to each of the attributes in +attributes+
@@ -384,7 +403,7 @@ module ActiveModel
# person.errors.full_messages_for(:name)
# # => ["Name is too short (minimum is 5 characters)", "Name can't be blank"]
def full_messages_for(attribute)
- (get(attribute) || []).map { |message| full_message(attribute, message) }
+ messages[attribute].map { |message| full_message(attribute, message) }
end
# Returns a full message for a given attribute.
diff --git a/activemodel/lib/active_model/validations/length.rb b/activemodel/lib/active_model/validations/length.rb
index a96b30cadd..23201b264a 100644
--- a/activemodel/lib/active_model/validations/length.rb
+++ b/activemodel/lib/active_model/validations/length.rb
@@ -38,7 +38,7 @@ module ActiveModel
end
def validate_each(record, attribute, value)
- value = tokenize(value)
+ value = tokenize(record, value)
value_length = value.respond_to?(:length) ? value.length : value.to_s.length
errors_options = options.except(*RESERVED_OPTIONS)
@@ -59,10 +59,14 @@ module ActiveModel
end
private
-
- def tokenize(value)
- if options[:tokenizer] && value.kind_of?(String)
- options[:tokenizer].call(value)
+ def tokenize(record, value)
+ tokenizer = options[:tokenizer]
+ if tokenizer && value.kind_of?(String)
+ if tokenizer.kind_of?(Proc)
+ tokenizer.call(value)
+ elsif record.respond_to?(tokenizer)
+ record.send(tokenizer, value)
+ end
end || value
end
@@ -108,10 +112,12 @@ module ActiveModel
# * <tt>:message</tt> - The error message to use for a <tt>:minimum</tt>,
# <tt>:maximum</tt>, or <tt>:is</tt> violation. An alias of the appropriate
# <tt>too_long</tt>/<tt>too_short</tt>/<tt>wrong_length</tt> message.
- # * <tt>:tokenizer</tt> - Specifies how to split up the attribute string.
- # (e.g. <tt>tokenizer: ->(str) { str.scan(/\w+/) }</tt> to count words
- # as in above example). Defaults to <tt>->(value) { value.split(//) }</tt>
- # which counts individual characters.
+ # * <tt>:tokenizer</tt> - A method (as a symbol), proc or string to
+ # specify how to split up the attribute string. (e.g.
+ # <tt>tokenizer: :word_tokenizer</tt> to call the +word_tokenizer+ method
+ # or <tt>tokenizer: ->(str) { str.scan(/\w+/) }</tt> to count words as in
+ # above example). Defaults to <tt>->(value) { value.split(//) }</tt> which
+ # counts individual characters.
#
# There is also a list of default options supported by every validator:
# +:if+, +:unless+, +:on+ and +:strict+.
diff --git a/activemodel/test/cases/errors_test.rb b/activemodel/test/cases/errors_test.rb
index 17dbb817d0..e736ccf6a0 100644
--- a/activemodel/test/cases/errors_test.rb
+++ b/activemodel/test/cases/errors_test.rb
@@ -29,28 +29,28 @@ class ErrorsTest < ActiveModel::TestCase
def test_delete
errors = ActiveModel::Errors.new(self)
- errors[:foo] = 'omg'
+ errors[:foo] << 'omg'
errors.delete(:foo)
assert_empty errors[:foo]
end
def test_include?
errors = ActiveModel::Errors.new(self)
- errors[:foo] = 'omg'
+ errors[:foo] << 'omg'
assert errors.include?(:foo), 'errors should include :foo'
end
def test_dup
errors = ActiveModel::Errors.new(self)
- errors[:foo] = 'bar'
+ errors[:foo] << 'bar'
errors_dup = errors.dup
- errors_dup[:bar] = 'omg'
+ errors_dup[:bar] << 'omg'
assert_not_same errors_dup.messages, errors.messages
end
def test_has_key?
errors = ActiveModel::Errors.new(self)
- errors[:foo] = 'omg'
+ errors[:foo] << 'omg'
assert_equal true, errors.has_key?(:foo), 'errors should have key :foo'
end
@@ -61,7 +61,7 @@ class ErrorsTest < ActiveModel::TestCase
def test_key?
errors = ActiveModel::Errors.new(self)
- errors[:foo] = 'omg'
+ errors[:foo] << 'omg'
assert_equal true, errors.key?(:foo), 'errors should have key :foo'
end
@@ -81,37 +81,41 @@ class ErrorsTest < ActiveModel::TestCase
test "get returns the errors for the provided key" do
errors = ActiveModel::Errors.new(self)
- errors[:foo] = "omg"
+ errors[:foo] << "omg"
- assert_equal ["omg"], errors.get(:foo)
+ assert_deprecated do
+ assert_equal ["omg"], errors.get(:foo)
+ end
end
test "sets the error with the provided key" do
errors = ActiveModel::Errors.new(self)
- errors.set(:foo, "omg")
+ assert_deprecated do
+ errors.set(:foo, "omg")
+ end
assert_equal({ foo: "omg" }, errors.messages)
end
test "error access is indifferent" do
errors = ActiveModel::Errors.new(self)
- errors[:foo] = "omg"
+ errors[:foo] << "omg"
assert_equal ["omg"], errors["foo"]
end
test "values returns an array of messages" do
errors = ActiveModel::Errors.new(self)
- errors.set(:foo, "omg")
- errors.set(:baz, "zomg")
+ errors.messages[:foo] = "omg"
+ errors.messages[:baz] = "zomg"
assert_equal ["omg", "zomg"], errors.values
end
test "keys returns the error keys" do
errors = ActiveModel::Errors.new(self)
- errors.set(:foo, "omg")
- errors.set(:baz, "zomg")
+ errors.messages[:foo] << "omg"
+ errors.messages[:baz] << "zomg"
assert_equal [:foo, :baz], errors.keys
end
@@ -133,7 +137,9 @@ class ErrorsTest < ActiveModel::TestCase
test "assign error" do
person = Person.new
- person.errors[:name] = 'should not be nil'
+ assert_deprecated do
+ person.errors[:name] = 'should not be nil'
+ end
assert_equal ["should not be nil"], person.errors[:name]
end
diff --git a/activemodel/test/cases/validations/length_validation_test.rb b/activemodel/test/cases/validations/length_validation_test.rb
index 29130ce46c..209903898e 100644
--- a/activemodel/test/cases/validations/length_validation_test.rb
+++ b/activemodel/test/cases/validations/length_validation_test.rb
@@ -330,6 +330,19 @@ class LengthValidationTest < ActiveModel::TestCase
assert_equal ["Your essay must be at least 5 words."], t.errors[:content]
end
+
+ def test_validates_length_of_with_symbol
+ Topic.validates_length_of :content, minimum: 5, too_short: "Your essay must be at least %{count} words.",
+ tokenizer: :my_word_tokenizer
+ t = Topic.new(content: "this content should be long enough")
+ assert t.valid?
+
+ t.content = "not long enough"
+ assert t.invalid?
+ assert t.errors[:content].any?
+ assert_equal ["Your essay must be at least 5 words."], t.errors[:content]
+ end
+
def test_validates_length_of_for_fixnum
Topic.validates_length_of(:approved, is: 4)
diff --git a/activemodel/test/models/topic.rb b/activemodel/test/models/topic.rb
index 1411a093e9..fed50bc361 100644
--- a/activemodel/test/models/topic.rb
+++ b/activemodel/test/models/topic.rb
@@ -37,4 +37,8 @@ class Topic
errors.add attr, "is missing" unless send(attr)
end
+ def my_word_tokenizer(str)
+ str.scan(/\w+/)
+ end
+
end
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index e1cace7d88..d0d5481d81 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,12 @@
+* Deprecated passing of `start` value to `find_in_batches` and `find_each`
+ in favour of `begin_at` value.
+
+ *Vipul A M*
+
+* Add `foreign_key_exists?` method.
+
+ *Tõnis Simo*
+
* Use SQL COUNT and LIMIT 1 queries for `none?` and `one?` methods if no block or limit is given,
instead of loading the entire collection to memory.
This applies to relations (e.g. `User.all`) as well as associations (e.g. `account.users`)
@@ -20,10 +29,6 @@
*Eugene Gilburg*
-* Allow `:precision` option for time type columns.
-
- *Ryuta Kamizono*
-
* Have `enum` perform type casting consistently with the rest of Active
Record, such as `where`.
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index 5a3b4f0c40..a146d78a5a 100644
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -1386,7 +1386,7 @@ module ActiveRecord
# has_one :last_comment, -> { order 'posted_on' }, class_name: "Comment"
# has_one :project_manager, -> { where role: 'project_manager' }, class_name: "Person"
# has_one :attachment, as: :attachable
- # has_one :boss, readonly: :true
+ # has_one :boss, -> { readonly }
# has_one :club, through: :membership
# has_one :primary_address, -> { where primary: true }, through: :addressables, source: :addressable
# has_one :credit_card, required: true
@@ -1438,7 +1438,7 @@ module ActiveRecord
# when you access the associated object.
#
# Scope examples:
- # belongs_to :user, -> { where(id: 2) }
+ # belongs_to :firm, -> { where(id: 2) }
# belongs_to :user, -> { joins(:friends) }
# belongs_to :level, ->(level) { where("game_level > ?", level.current) }
#
@@ -1514,11 +1514,11 @@ module ActiveRecord
# belongs_to :valid_coupon, ->(o) { where "discounts > ?", o.payments_count },
# class_name: "Coupon", foreign_key: "coupon_id"
# belongs_to :attachable, polymorphic: true
- # belongs_to :project, readonly: true
+ # belongs_to :project, -> { readonly }
# belongs_to :post, counter_cache: true
- # belongs_to :company, touch: true
+ # belongs_to :comment, touch: true
# belongs_to :company, touch: :employees_last_updated_at
- # belongs_to :company, required: true
+ # belongs_to :user, required: true
def belongs_to(name, scope = nil, options = {})
reflection = Builder::BelongsTo.build(self, name, scope, options)
Reflection.add_reflection self, name, reflection
diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb
index 33e4516bd1..eea847cfa3 100644
--- a/activerecord/lib/active_record/associations/collection_association.rb
+++ b/activerecord/lib/active_record/associations/collection_association.rb
@@ -63,7 +63,7 @@ module ActiveRecord
def ids_writer(ids)
pk_type = reflection.primary_key_type
ids = Array(ids).reject(&:blank?)
- ids.map! { |i| pk_type.type_cast_from_user(i) }
+ ids.map! { |i| pk_type.cast(i) }
replace(klass.find(ids).index_by(&:id).values_at(*ids))
end
diff --git a/activerecord/lib/active_record/attribute.rb b/activerecord/lib/active_record/attribute.rb
index 91886f1324..73dd3fa041 100644
--- a/activerecord/lib/active_record/attribute.rb
+++ b/activerecord/lib/active_record/attribute.rb
@@ -43,7 +43,7 @@ module ActiveRecord
end
def value_for_database
- type.type_cast_for_database(value)
+ type.serialize(value)
end
def changed_from?(old_value)
@@ -108,13 +108,13 @@ module ActiveRecord
class FromDatabase < Attribute # :nodoc:
def type_cast(value)
- type.type_cast_from_database(value)
+ type.deserialize(value)
end
end
class FromUser < Attribute # :nodoc:
def type_cast(value)
- type.type_cast_from_user(value)
+ type.cast(value)
end
def came_from_user?
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 90c36e4b02..f9beb43e4b 100644
--- a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
+++ b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
@@ -2,13 +2,13 @@ module ActiveRecord
module AttributeMethods
module TimeZoneConversion
class TimeZoneConverter < DelegateClass(Type::Value) # :nodoc:
- def type_cast_from_database(value)
+ def deserialize(value)
convert_time_to_time_zone(super)
end
- def type_cast_from_user(value)
+ def cast(value)
if value.is_a?(Array)
- value.map { |v| type_cast_from_user(v) }
+ value.map { |v| cast(v) }
elsif value.is_a?(Hash)
set_time_zone_without_conversion(super)
elsif value.respond_to?(:in_time_zone)
diff --git a/activerecord/lib/active_record/attributes.rb b/activerecord/lib/active_record/attributes.rb
index 2c475f3cda..c8979a60d7 100644
--- a/activerecord/lib/active_record/attributes.rb
+++ b/activerecord/lib/active_record/attributes.rb
@@ -102,14 +102,14 @@ module ActiveRecord
#
# Users may also define their own custom types, as long as they respond
# to the methods defined on the value type. The method
- # +type_cast_from_database+ or +type_cast_from_user+ will be called on
+ # +deserialize+ or +cast+ will be called on
# your type object, with raw input from the database or from your
# controllers. See ActiveRecord::Type::Value for the expected API. It is
# recommended that your type objects inherit from an existing type, or
# from ActiveRecord::Type::Value
#
# class MoneyType < ActiveRecord::Type::Integer
- # def type_cast_from_user(value)
+ # def cast(value)
# if value.include?('$')
# price_in_dollars = value.gsub(/\$/, '').to_f
# super(price_in_dollars * 100)
@@ -119,21 +119,27 @@ module ActiveRecord
# end
# end
#
+ # # config/initializers/types.rb
+ # ActiveRecord::Type.register(:money, MoneyType)
+ #
+ # # /app/models/store_listing.rb
# class StoreListing < ActiveRecord::Base
- # attribute :price_in_cents, MoneyType.new
+ # attribute :price_in_cents, :money
# end
#
# store_listing = StoreListing.new(price_in_cents: '$10.00')
# store_listing.price_in_cents # => 1000
#
# For more details on creating custom types, see the documentation for
- # ActiveRecord::Type::Value.
+ # ActiveRecord::Type::Value. For more details on registering your types
+ # to be referenced by a symbol, see ActiveRecord::Type.register. You can
+ # also pass a type object directly, in place of a symbol.
#
# ==== Querying
#
# When ActiveRecord::QueryMethods#where is called, it will
# use the type defined by the model class to convert the value to SQL,
- # calling +type_cast_for_database+ on your type object. For example:
+ # calling +serialize+ on your type object. For example:
#
# class Money < Struct.new(:amount, :currency)
# end
@@ -143,18 +149,20 @@ module ActiveRecord
# @currency_converter = currency_converter
# end
#
- # # value will be the result of +type_cast_from_database+ or
- # # +type_cast_from_user+. Assumed to be in instance of +Money+ in
+ # # value will be the result of +deserialize+ or
+ # # +cast+. Assumed to be in instance of +Money+ in
# # this case.
- # def type_cast_for_database(value)
+ # def serialize(value)
# value_in_bitcoins = @currency_converter.convert_to_bitcoins(value)
# value_in_bitcoins.amount
# end
# end
#
+ # ActiveRecord::Type.register(:money, MoneyType)
+ #
# class Product < ActiveRecord::Base
# currency_converter = ConversionRatesFromTheInternet.new
- # attribute :price_in_bitcoins, MoneyType.new(currency_converter)
+ # attribute :price_in_bitcoins, :money, currency_converter
# end
#
# Product.where(price_in_bitcoins: Money.new(5, "USD"))
@@ -195,7 +203,7 @@ module ActiveRecord
# Otherwise, the default will be +nil+.
#
# +user_provided_default+ Whether the default value should be cast using
- # +type_cast_from_user+ or +type_cast_from_database+.
+ # +cast+ or +deserialize+.
def define_attribute(
name,
cast_type,
@@ -210,7 +218,7 @@ module ActiveRecord
super
attributes_to_define_after_schema_loads.each do |name, (type, options)|
if type.is_a?(Symbol)
- type = connection.type_for_attribute_options(type, **options.except(:default))
+ type = ActiveRecord::Type.lookup(type, **options.except(:default))
end
define_attribute(name, type, **options.slice(:default))
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
index 947e11c7bf..d2840b9498 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
@@ -52,7 +52,7 @@ module ActiveRecord
def type_cast_from_column(column, value) # :nodoc:
if column
type = lookup_cast_type_from_column(column)
- type.type_cast_for_database(value)
+ type.serialize(value)
else
value
end
@@ -103,7 +103,7 @@ module ActiveRecord
end
def quote_default_expression(value, column) #:nodoc:
- value = lookup_cast_type(column.sql_type).type_cast_for_database(value)
+ value = lookup_cast_type(column.sql_type).serialize(value)
quote(value)
end
@@ -144,29 +144,8 @@ module ActiveRecord
binds.map(&:value_for_database)
end
- def type_for_attribute_options(type_name, **options)
- klass = type_classes_with_standard_constructor.fetch(type_name, Type::Value)
- klass.new(**options)
- end
-
private
- def type_classes_with_standard_constructor
- {
- big_integer: Type::BigInteger,
- binary: Type::Binary,
- boolean: Type::Boolean,
- date: Type::Date,
- date_time: Type::DateTime,
- decimal: Type::Decimal,
- float: Type::Float,
- integer: Type::Integer,
- string: Type::String,
- text: Type::Text,
- time: Type::Time,
- }
- end
-
def types_which_need_no_typecasting
[nil, Numeric, String]
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
index 8cd4b8e5b2..a2777fcd0a 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
@@ -50,6 +50,14 @@ module ActiveRecord
options[:primary_key] != default_primary_key
end
+ def defined_for?(options_or_to_table = {})
+ if options_or_to_table.is_a?(Hash)
+ options_or_to_table.all? {|key, value| options[key].to_s == value.to_s }
+ else
+ to_table == options_or_to_table.to_s
+ end
+ end
+
private
def default_primary_key
"id"
@@ -651,6 +659,10 @@ module ActiveRecord
@base.add_foreign_key(name, *args)
end
+ def foreign_key_exists?(*args) # :nodoc:
+ @base.foreign_key_exists?(name, *args)
+ end
+
private
def native
@base.native_database_types
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb
index 932aaf7aa7..af7ef7cbaa 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb
@@ -47,7 +47,7 @@ module ActiveRecord
def schema_default(column)
type = lookup_cast_type_from_column(column)
- default = type.type_cast_from_database(column.default)
+ default = type.deserialize(column.default)
unless default.nil?
type.type_cast_for_schema(default)
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
index c9180f64db..503b09d1fc 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -667,7 +667,7 @@ module ActiveRecord
# remove_reference(:products, :user, index: true, foreign_key: true)
#
def remove_reference(table_name, ref_name, options = {})
- remove_foreign_key table_name, ref_name if options[:foreign_key]
+ remove_foreign_key table_name, ref_name.to_s.pluralize if options[:foreign_key]
remove_column(table_name, "#{ref_name}_id")
remove_column(table_name, "#{ref_name}_type") if options[:polymorphic]
@@ -757,21 +757,7 @@ module ActiveRecord
def remove_foreign_key(from_table, options_or_to_table = {})
return unless supports_foreign_keys?
- if options_or_to_table.is_a?(Hash)
- options = options_or_to_table
- else
- options = { column: foreign_key_column_for(options_or_to_table) }
- end
-
- fk_name_to_delete = options.fetch(:name) do
- fk_to_delete = foreign_keys(from_table).detect {|fk| fk.column == options[:column].to_s }
-
- if fk_to_delete
- fk_to_delete.name
- else
- raise ArgumentError, "Table '#{from_table}' has no foreign key on column '#{options[:column]}'"
- end
- end
+ fk_name_to_delete = foreign_key_for!(from_table, options_or_to_table).name
at = create_alter_table from_table
at.drop_foreign_key fk_name_to_delete
@@ -779,6 +765,31 @@ module ActiveRecord
execute schema_creation.accept(at)
end
+ # Checks to see if a foreign key exists on a table for a given foreign key definition.
+ #
+ # # Check a foreign key exists
+ # foreign_key_exists?(:accounts, :branches)
+ #
+ # # Check a foreign key on specified column exists
+ # foreign_key_exists?(:accounts, column: :owner_id)
+ #
+ # # Check a foreign key with a custom name exists
+ # foreign_key_exists?(:accounts, name: "special_fk_name")
+ #
+ def foreign_key_exists?(from_table, options_or_to_table = {})
+ foreign_key_for(from_table, options_or_to_table).present?
+ end
+
+ def foreign_key_for(from_table, options_or_to_table = {}) # :nodoc:
+ return unless supports_foreign_keys?
+ foreign_keys(from_table).detect {|fk| fk.defined_for? options_or_to_table }
+ end
+
+ def foreign_key_for!(from_table, options_or_to_table = {}) # :nodoc:
+ foreign_key_for(from_table, options_or_to_table) or \
+ raise ArgumentError, "Table '#{from_table}' has no foreign key for #{options_or_to_table}"
+ end
+
def foreign_key_column_for(table_name) # :nodoc:
"#{table_name.to_s.singularize}_id"
end
@@ -840,12 +851,6 @@ module ActiveRecord
raise ArgumentError, "Error adding decimal column: precision cannot be empty if scale is specified"
end
- elsif [:datetime, :time].include?(type) && precision ||= native[:precision]
- if (0..6) === precision
- column_type_sql << "(#{precision})"
- else
- raise(ActiveRecordError, "No #{native[:name]} type has precision of #{precision}. The allowed range of precision is from 0 to 6")
- end
elsif (type != :primary_key) && (limit ||= native.is_a?(Hash) && native[:limit])
column_type_sql << "(#{limit})"
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index c307189980..ee11c0efa4 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -245,11 +245,6 @@ module ActiveRecord
false
end
- # Does this adapter support datetime with precision?
- def supports_datetime_with_precision?
- false
- end
-
# This is meant to be implemented by the adapters that support extensions
def disable_extension(name)
end
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 0a9e599c3c..0a1c66be1e 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -251,10 +251,6 @@ module ActiveRecord
version[0] >= 5
end
- def supports_datetime_with_precision?
- (version[0] == 5 && version[1] >= 6) || version[0] >= 6
- end
-
def native_database_types
NATIVE_DATABASE_TYPES
end
@@ -627,6 +623,13 @@ module ActiveRecord
when 0x1000000..0xffffffff; 'longtext'
else raise(ActiveRecordError, "No text type has character length #{limit}")
end
+ when 'datetime'
+ return super unless precision
+
+ case precision
+ when 0..6; "datetime(#{precision})"
+ else raise(ActiveRecordError, "No datetime type has precision of #{precision}. The allowed range of precision is from 0 to 6.")
+ end
else
super
end
@@ -923,7 +926,7 @@ module ActiveRecord
end
class MysqlString < Type::String # :nodoc:
- def type_cast_for_database(value)
+ def serialize(value)
case value
when true then "1"
when false then "0"
@@ -942,9 +945,8 @@ module ActiveRecord
end
end
- def type_classes_with_standard_constructor
- super.merge(string: MysqlString)
- end
+ ActiveRecord::Type.register(:string, MysqlString, adapter: :mysql)
+ ActiveRecord::Type.register(:string, MysqlString, adapter: :mysql2)
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
index 2608a2abab..fb4e0de2a8 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
@@ -25,22 +25,22 @@ module ActiveRecord
@delimiter = delimiter
end
- def type_cast_from_database(value)
+ def deserialize(value)
if value.is_a?(::String)
- type_cast_array(parse_pg_array(value), :type_cast_from_database)
+ type_cast_array(parse_pg_array(value), :deserialize)
else
super
end
end
- def type_cast_from_user(value)
+ def cast(value)
if value.is_a?(::String)
value = parse_pg_array(value)
end
- type_cast_array(value, :type_cast_from_user)
+ type_cast_array(value, :cast)
end
- def type_cast_for_database(value)
+ def serialize(value)
if value.is_a?(::Array)
cast_value_for_database(value)
else
@@ -69,7 +69,7 @@ module ActiveRecord
casted_values = value.map { |item| cast_value_for_database(item) }
"{#{casted_values.join(delimiter)}}"
else
- quote_and_escape(subtype.type_cast_for_database(value))
+ quote_and_escape(subtype.serialize(value))
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/bit.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/bit.rb
index 1dbb40ca1d..ea0fa2517f 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/bit.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/bit.rb
@@ -7,7 +7,7 @@ module ActiveRecord
:bit
end
- def type_cast(value)
+ def cast(value)
if ::String === value
case value
when /^0x/i
@@ -20,7 +20,7 @@ module ActiveRecord
end
end
- def type_cast_for_database(value)
+ def serialize(value)
Data.new(super) if value
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/bytea.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/bytea.rb
index 6bd1b8ecae..8f9d6e7f9b 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/bytea.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/bytea.rb
@@ -3,7 +3,7 @@ module ActiveRecord
module PostgreSQL
module OID # :nodoc:
class Bytea < Type::Binary # :nodoc:
- def type_cast_from_database(value)
+ def deserialize(value)
return if value.nil?
return value.to_s if value.is_a?(Type::Binary::Data)
PGconn.unescape_bytea(super)
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/cidr.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/cidr.rb
index 222f10fa8f..eeccb09bdf 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/cidr.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/cidr.rb
@@ -18,7 +18,7 @@ module ActiveRecord
end
end
- def type_cast_for_database(value)
+ def serialize(value)
if IPAddr === value
"#{value}/#{value.instance_variable_get(:@mask_addr).to_s(2).count('1')}"
else
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/enum.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/enum.rb
index 77d5038efd..b3b610a5f6 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/enum.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/enum.rb
@@ -7,7 +7,7 @@ module ActiveRecord
:enum
end
- def type_cast(value)
+ def cast(value)
value.to_s
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb
index b46e50c865..9270fc9f21 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb
@@ -9,7 +9,7 @@ module ActiveRecord
:hstore
end
- def type_cast_from_database(value)
+ def deserialize(value)
if value.is_a?(::String)
::Hash[value.scan(HstorePair).map { |k, v|
v = v.upcase == 'NULL' ? nil : v.gsub(/\A"(.*)"\Z/m,'\1').gsub(/\\(.)/, '\1')
@@ -21,7 +21,7 @@ module ActiveRecord
end
end
- def type_cast_for_database(value)
+ def serialize(value)
if value.is_a?(::Hash)
value.map { |k, v| "#{escape_hstore(k)}=>#{escape_hstore(v)}" }.join(', ')
else
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/json.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/json.rb
index 13dd037314..8e1256baad 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/json.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/json.rb
@@ -9,19 +9,19 @@ module ActiveRecord
:json
end
- def type_cast_from_database(value)
+ def deserialize(value)
if value.is_a?(::String)
::ActiveSupport::JSON.decode(value) rescue nil
else
- super
+ value
end
end
- def type_cast_for_database(value)
+ def serialize(value)
if value.is_a?(::Array) || value.is_a?(::Hash)
::ActiveSupport::JSON.encode(value)
else
- super
+ value
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb
index 380c50fc14..afc9383f91 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb
@@ -13,7 +13,7 @@ module ActiveRecord
# the comparison here. Therefore, we need to parse and re-dump the
# raw value here to ensure the insignificant whitespaces are
# consistent with our encoder's output.
- raw_old_value = type_cast_for_database(type_cast_from_database(raw_old_value))
+ raw_old_value = serialize(deserialize(raw_old_value))
super(raw_old_value, new_value)
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb
index 4084725ed7..bf565bcf47 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb
@@ -9,13 +9,13 @@ module ActiveRecord
:point
end
- def type_cast(value)
+ def cast(value)
case value
when ::String
if value[0] == '(' && value[-1] == ')'
value = value[1...-1]
end
- type_cast(value.split(','))
+ cast(value.split(','))
when ::Array
value.map { |v| Float(v) }
else
@@ -23,7 +23,7 @@ module ActiveRecord
end
end
- def type_cast_for_database(value)
+ def serialize(value)
if value.is_a?(::Array)
"(#{number_for_point(value[0])},#{number_for_point(value[1])})"
else
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb
index 9d3633d109..fc201f8fb9 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb
@@ -30,7 +30,7 @@ module ActiveRecord
::Range.new(from, to, extracted[:exclude_end])
end
- def type_cast_for_database(value)
+ def serialize(value)
if value.is_a?(::Range)
from = type_cast_single_for_database(value.begin)
to = type_cast_single_for_database(value.end)
@@ -49,11 +49,11 @@ module ActiveRecord
private
def type_cast_single(value)
- infinity?(value) ? value : @subtype.type_cast_from_database(value)
+ infinity?(value) ? value : @subtype.deserialize(value)
end
def type_cast_single_for_database(value)
- infinity?(value) ? '' : @subtype.type_cast_for_database(value)
+ infinity?(value) ? '' : @subtype.serialize(value)
end
def extract_bounds(value)
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/uuid.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/uuid.rb
index 97b4fd3d08..5e839228e9 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/uuid.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/uuid.rb
@@ -5,13 +5,13 @@ module ActiveRecord
class Uuid < Type::Value # :nodoc:
ACCEPTABLE_UUID = %r{\A\{?([a-fA-F0-9]{4}-?){8}\}?\z}x
- alias_method :type_cast_for_database, :type_cast_from_database
+ alias_method :serialize, :deserialize
def type
:uuid
end
- def type_cast(value)
+ def cast(value)
value.to_s[ACCEPTABLE_UUID, 0]
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/vector.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/vector.rb
index de4187b028..b26e876b54 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/vector.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/vector.rb
@@ -16,7 +16,7 @@ module ActiveRecord
# FIXME: this should probably split on +delim+ and use +subtype+
# to cast the values. Unfortunately, the current Rails behavior
# is to just return the string.
- def type_cast(value)
+ def cast(value)
value
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/xml.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/xml.rb
index 334af7c598..d40d837cee 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/xml.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/xml.rb
@@ -7,7 +7,7 @@ module ActiveRecord
:xml
end
- def type_cast_for_database(value)
+ def serialize(value)
return unless value
Data.new(super)
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
index b8d0e26f85..b7755c4593 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
@@ -67,23 +67,6 @@ module ActiveRecord
type_map.lookup(column.oid, column.fmod, column.sql_type)
end
- def type_for_attribute_options(
- type_name,
- array: false,
- range: false,
- **options
- )
- if array
- subtype = type_for_attribute_options(type_name, **options)
- OID::Array.new(subtype)
- elsif range
- subtype = type_for_attribute_options(type_name, **options)
- OID::Range.new(subtype)
- else
- super(type_name, **options)
- end
- end
-
private
def _quote(value)
@@ -122,27 +105,6 @@ module ActiveRecord
super
end
end
-
- def type_classes_with_standard_constructor
- super.merge(
- bit: OID::Bit,
- bit_varying: OID::BitVarying,
- binary: OID::Bytea,
- cidr: OID::Cidr,
- date_time: OID::DateTime,
- decimal: OID::Decimal,
- enum: OID::Enum,
- hstore: OID::Hstore,
- inet: OID::Inet,
- json: OID::Json,
- jsonb: OID::Jsonb,
- money: OID::Money,
- point: OID::Point,
- uuid: OID::Uuid,
- vector: OID::Vector,
- xml: OID::Xml,
- )
- end
end
end
end
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 503dda60f4..81fde18f64 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
@@ -534,6 +534,13 @@ module ActiveRecord
when 5..8; 'bigint'
else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with precision 0 instead.")
end
+ when 'datetime'
+ return super unless precision
+
+ case precision
+ when 0..6; "timestamp(#{precision})"
+ else raise(ActiveRecordError, "No timestamp type has precision of #{precision}. The allowed range of precision is from 0 to 6")
+ end
else
super
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 6d7e1075d7..5a887ea529 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -180,10 +180,6 @@ module ActiveRecord
true
end
- def supports_datetime_with_precision?
- true
- end
-
def index_algorithms
{ concurrently: 'CONCURRENTLY' }
end
@@ -481,6 +477,7 @@ module ActiveRecord
register_class_with_limit m, 'varbit', OID::BitVarying
m.alias_type 'timestamptz', 'timestamp'
m.register_type 'date', Type::Date.new
+ m.register_type 'time', Type::Time.new
m.register_type 'money', OID::Money.new
m.register_type 'bytea', OID::Bytea.new
@@ -506,8 +503,10 @@ module ActiveRecord
m.alias_type 'lseg', 'varchar'
m.alias_type 'box', 'varchar'
- register_class_with_precision m, 'time', Type::Time
- register_class_with_precision m, 'timestamp', OID::DateTime
+ m.register_type 'timestamp' do |_, _, sql_type|
+ precision = extract_precision(sql_type)
+ OID::DateTime.new(precision: precision)
+ end
m.register_type 'numeric' do |_, fmod, sql_type|
precision = extract_precision(sql_type)
@@ -813,6 +812,25 @@ module ActiveRecord
return unless coder_class
coder_class.new(oid: row['oid'], name: row['typname'])
end
+
+ ActiveRecord::Type.add_modifier({ array: true }, OID::Array, adapter: :postgresql)
+ ActiveRecord::Type.add_modifier({ range: true }, OID::Range, adapter: :postgresql)
+ ActiveRecord::Type.register(:bit, OID::Bit, adapter: :postgresql)
+ ActiveRecord::Type.register(:bit_varying, OID::BitVarying, adapter: :postgresql)
+ ActiveRecord::Type.register(:binary, OID::Bytea, adapter: :postgresql)
+ ActiveRecord::Type.register(:cidr, OID::Cidr, adapter: :postgresql)
+ ActiveRecord::Type.register(:date_time, OID::DateTime, adapter: :postgresql)
+ ActiveRecord::Type.register(:decimal, OID::Decimal, adapter: :postgresql)
+ ActiveRecord::Type.register(:enum, OID::Enum, adapter: :postgresql)
+ ActiveRecord::Type.register(:hstore, OID::Hstore, adapter: :postgresql)
+ ActiveRecord::Type.register(:inet, OID::Inet, adapter: :postgresql)
+ ActiveRecord::Type.register(:json, OID::Json, adapter: :postgresql)
+ ActiveRecord::Type.register(:jsonb, OID::Jsonb, adapter: :postgresql)
+ ActiveRecord::Type.register(:money, OID::Money, adapter: :postgresql)
+ ActiveRecord::Type.register(:point, OID::Point, adapter: :postgresql)
+ ActiveRecord::Type.register(:uuid, OID::Uuid, adapter: :postgresql)
+ ActiveRecord::Type.register(:vector, OID::Vector, adapter: :postgresql)
+ ActiveRecord::Type.register(:xml, OID::Xml, adapter: :postgresql)
end
end
end
diff --git a/activerecord/lib/active_record/enum.rb b/activerecord/lib/active_record/enum.rb
index 3086f13f96..ea88983917 100644
--- a/activerecord/lib/active_record/enum.rb
+++ b/activerecord/lib/active_record/enum.rb
@@ -32,6 +32,12 @@ module ActiveRecord
# Conversation.active
# Conversation.archived
#
+ # Of course, you can also query them directly if the scopes doesn't fit your
+ # needs:
+ #
+ # Conversation.where(status: [:active, :archived])
+ # Conversation.where.not(status: :active)
+ #
# You can set the default value from the database declaration, like:
#
# create_table :conversations do |t|
@@ -59,15 +65,17 @@ module ActiveRecord
#
# In rare circumstances you might need to access the mapping directly.
# The mappings are exposed through a class method with the pluralized attribute
- # name:
+ # name, which return the mapping in a +HashWithIndifferentAccess+:
#
- # Conversation.statuses # => { "active" => 0, "archived" => 1 }
+ # Conversation.statuses[:active] # => 0
+ # Conversation.statuses["archived"] # => 1
#
- # Use that class method when you need to know the ordinal value of an enum:
+ # Use that class method when you need to know the ordinal value of an enum.
+ # For example, you can use that when manually building SQL strings:
#
# Conversation.where("status <> ?", Conversation.statuses[:archived])
#
- # Where conditions on an enum attribute must use the ordinal value of an enum.
+
module Enum
def self.extended(base) # :nodoc:
base.class_attribute(:defined_enums)
@@ -85,7 +93,7 @@ module ActiveRecord
@mapping = mapping
end
- def type_cast_from_user(value)
+ def cast(value)
return if value.blank?
if mapping.has_key?(value)
@@ -97,11 +105,12 @@ module ActiveRecord
end
end
- def type_cast_from_database(value)
+ def deserialize(value)
+ return if value.nil?
mapping.key(value.to_i)
end
- def type_cast_for_database(value)
+ def serialize(value)
mapping.fetch(value, value)
end
diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb
index c5b10fcddf..a58d8355aa 100644
--- a/activerecord/lib/active_record/locking/optimistic.rb
+++ b/activerecord/lib/active_record/locking/optimistic.rb
@@ -185,7 +185,7 @@ module ActiveRecord
end
class LockingType < DelegateClass(Type::Value) # :nodoc:
- def type_cast_from_database(value)
+ def deserialize(value)
# `nil` *should* be changed to 0
super.to_i
end
diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb
index 117a128579..084ef397a8 100644
--- a/activerecord/lib/active_record/nested_attributes.rb
+++ b/activerecord/lib/active_record/nested_attributes.rb
@@ -521,7 +521,7 @@ module ActiveRecord
# Determines if a hash contains a truthy _destroy key.
def has_destroy_flag?(hash)
- Type::Boolean.new.type_cast_from_user(hash['_destroy'])
+ Type::Boolean.new.cast(hash['_destroy'])
end
# Determines if a new record should be rejected by checking
diff --git a/activerecord/lib/active_record/relation/batches.rb b/activerecord/lib/active_record/relation/batches.rb
index a543341149..e07580a563 100644
--- a/activerecord/lib/active_record/relation/batches.rb
+++ b/activerecord/lib/active_record/relation/batches.rb
@@ -27,15 +27,15 @@ module ActiveRecord
#
# ==== Options
# * <tt>:batch_size</tt> - Specifies the size of the batch. Default to 1000.
- # * <tt>:start</tt> - Specifies the primary key value to start from, inclusive of the value.
+ # * <tt>:begin_at</tt> - Specifies the primary key value to start from, inclusive of the value.
# * <tt>:end_at</tt> - Specifies the primary key value to end at, inclusive of the value.
# This is especially useful if you want multiple workers dealing with
# the same processing queue. You can make worker 1 handle all the records
# between id 0 and 10,000 and worker 2 handle from 10,000 and beyond
- # (by setting the +:start+ and +:end_at+ option on each worker).
+ # (by setting the +:begin_at+ and +:end_at+ option on each worker).
#
# # Let's process for a batch of 2000 records, skipping the first 2000 rows
- # Person.find_each(start: 2000, batch_size: 2000) do |person|
+ # Person.find_each(begin_at: 2000, batch_size: 2000) do |person|
# person.party_all_night!
# end
#
@@ -46,15 +46,22 @@ module ActiveRecord
#
# NOTE: You can't set the limit either, that's used to control
# the batch sizes.
- def find_each(start: nil, end_at: nil, batch_size: 1000)
+ def find_each(begin_at: nil, end_at: nil, batch_size: 1000, start: nil)
+ if start
+ begin_at = start
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ Passing `start` value to find_each is deprecated, and will be removed in Rails 5.1.
+ Please pass `begin_at` instead.
+ MSG
+ end
if block_given?
- find_in_batches(start: start, end_at: end_at, batch_size: batch_size) do |records|
+ find_in_batches(begin_at: begin_at, end_at: end_at, batch_size: batch_size) do |records|
records.each { |record| yield record }
end
else
- enum_for(:find_each, start: start, end_at: end_at, batch_size: batch_size) do
+ enum_for(:find_each, begin_at: begin_at, end_at: end_at, batch_size: batch_size) do
relation = self
- apply_limits(relation, start, end_at).size
+ apply_limits(relation, begin_at, end_at).size
end
end
end
@@ -79,15 +86,15 @@ module ActiveRecord
#
# ==== Options
# * <tt>:batch_size</tt> - Specifies the size of the batch. Default to 1000.
- # * <tt>:start</tt> - Specifies the primary key value to start from, inclusive of the value.
+ # * <tt>:begin_at</tt> - Specifies the primary key value to start from, inclusive of the value.
# * <tt>:end_at</tt> - Specifies the primary key value to end at, inclusive of the value.
# This is especially useful if you want multiple workers dealing with
# the same processing queue. You can make worker 1 handle all the records
# between id 0 and 10,000 and worker 2 handle from 10,000 and beyond
- # (by setting the +:start+ and +:end_at+ option on each worker).
+ # (by setting the +:begin_at+ and +:end_at+ option on each worker).
#
# # Let's process the next 2000 records
- # Person.find_in_batches(start: 2000, batch_size: 2000) do |group|
+ # Person.find_in_batches(begin_at: 2000, batch_size: 2000) do |group|
# group.each { |person| person.party_all_night! }
# end
#
@@ -98,12 +105,19 @@ module ActiveRecord
#
# NOTE: You can't set the limit either, that's used to control
# the batch sizes.
- def find_in_batches(start: nil, end_at: nil, batch_size: 1000)
- relation = self
+ def find_in_batches(begin_at: nil, end_at: nil, batch_size: 1000, start: nil)
+ if start
+ begin_at = start
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ Passing `start` value to find_in_batches is deprecated, and will be removed in Rails 5.1.
+ Please pass `begin_at` instead.
+ MSG
+ end
+ relation = self
unless block_given?
- return to_enum(:find_in_batches, start: start, end_at: end_at, batch_size: batch_size) do
- total = apply_limits(relation, start, end_at).size
+ return to_enum(:find_in_batches, begin_at: begin_at, end_at: end_at, batch_size: batch_size) do
+ total = apply_limits(relation, begin_at, end_at).size
(total - 1).div(batch_size) + 1
end
end
@@ -113,7 +127,7 @@ module ActiveRecord
end
relation = relation.reorder(batch_order).limit(batch_size)
- relation = apply_limits(relation, start, end_at)
+ relation = apply_limits(relation, begin_at, end_at)
records = relation.to_a
while records.any?
@@ -131,8 +145,8 @@ module ActiveRecord
private
- def apply_limits(relation, start, end_at)
- relation = relation.where(table[primary_key].gteq(start)) if start
+ def apply_limits(relation, begin_at, end_at)
+ relation = relation.where(table[primary_key].gteq(begin_at)) if begin_at
relation = relation.where(table[primary_key].lteq(end_at)) if end_at
relation
end
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index 63e0d2fc21..4a4de86d48 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -353,9 +353,9 @@ module ActiveRecord
def type_cast_calculated_value(value, type, operation = nil)
case operation
when 'count' then value.to_i
- when 'sum' then type.type_cast_from_database(value || 0)
+ when 'sum' then type.deserialize(value || 0)
when 'average' then value.respond_to?(:to_d) ? value.to_d : value
- else type.type_cast_from_database(value)
+ else type.deserialize(value)
end
end
diff --git a/activerecord/lib/active_record/result.rb b/activerecord/lib/active_record/result.rb
index 3a3e65ef32..500c478e65 100644
--- a/activerecord/lib/active_record/result.rb
+++ b/activerecord/lib/active_record/result.rb
@@ -81,7 +81,7 @@ module ActiveRecord
def cast_values(type_overrides = {}) # :nodoc:
types = columns.map { |name| column_type(name, type_overrides) }
result = rows.map do |values|
- types.zip(values).map { |type, value| type.type_cast_from_database(value) }
+ types.zip(values).map { |type, value| type.deserialize(value) }
end
columns.one? ? result.map!(&:first) : result
diff --git a/activerecord/lib/active_record/sanitization.rb b/activerecord/lib/active_record/sanitization.rb
index 313e767dcb..c7f55ebaa1 100644
--- a/activerecord/lib/active_record/sanitization.rb
+++ b/activerecord/lib/active_record/sanitization.rb
@@ -75,7 +75,7 @@ module ActiveRecord
def sanitize_sql_hash_for_assignment(attrs, table)
c = connection
attrs.map do |attr, value|
- value = type_for_attribute(attr.to_s).type_cast_for_database(value)
+ value = type_for_attribute(attr.to_s).serialize(value)
"#{c.quote_table_name_for_assignment(table, attr)} = #{c.quote(value)}"
end.join(', ')
end
diff --git a/activerecord/lib/active_record/secure_token.rb b/activerecord/lib/active_record/secure_token.rb
index 07031b6371..0990f815a7 100644
--- a/activerecord/lib/active_record/secure_token.rb
+++ b/activerecord/lib/active_record/secure_token.rb
@@ -27,7 +27,7 @@ module ActiveRecord
# Load securerandom only when has_secure_token is used.
require 'active_support/core_ext/securerandom'
define_method("regenerate_#{attribute}") { update! attribute => self.class.generate_unique_secure_token }
- before_create { self.send("#{attribute}=", self.class.generate_unique_secure_token) }
+ before_create { self.send("#{attribute}=", self.class.generate_unique_secure_token) unless self.send("#{attribute}?")}
end
def generate_unique_secure_token
@@ -36,4 +36,3 @@ module ActiveRecord
end
end
end
-
diff --git a/activerecord/lib/active_record/type.rb b/activerecord/lib/active_record/type.rb
index f18b076d58..2c0cda69d0 100644
--- a/activerecord/lib/active_record/type.rb
+++ b/activerecord/lib/active_record/type.rb
@@ -16,5 +16,51 @@ require 'active_record/type/text'
require 'active_record/type/time'
require 'active_record/type/unsigned_integer'
+require 'active_record/type/adapter_specific_registry'
require 'active_record/type/type_map'
require 'active_record/type/hash_lookup_type_map'
+
+module ActiveRecord
+ module Type
+ @registry = AdapterSpecificRegistry.new
+
+ class << self
+ attr_accessor :registry # :nodoc:
+ delegate :add_modifier, to: :registry
+
+ # Add a new type to the registry, allowing it to be referenced as a
+ # symbol by ActiveRecord::Attributes::ClassMethods#attribute. If your
+ # type is only meant to be used with a specific database adapter, you can
+ # do so by passing +adapter: :postgresql+. If your type has the same
+ # name as a native type for the current adapter, an exception will be
+ # raised unless you specify an +:override+ option. +override: true+ will
+ # cause your type to be used instead of the native type. +override:
+ # false+ will cause the native type to be used over yours if one exists.
+ def register(type_name, klass = nil, **options, &block)
+ registry.register(type_name, klass, **options, &block)
+ end
+
+ def lookup(*args, adapter: current_adapter_name, **kwargs) # :nodoc:
+ registry.lookup(*args, adapter: adapter, **kwargs)
+ end
+
+ private
+
+ def current_adapter_name
+ ActiveRecord::Base.connection.adapter_name.downcase.to_sym
+ end
+ end
+
+ register(:big_integer, Type::BigInteger, override: false)
+ register(:binary, Type::Binary, override: false)
+ register(:boolean, Type::Boolean, override: false)
+ register(:date, Type::Date, override: false)
+ register(:date_time, Type::DateTime, override: false)
+ register(:decimal, Type::Decimal, override: false)
+ register(:float, Type::Float, override: false)
+ register(:integer, Type::Integer, override: false)
+ register(:string, Type::String, override: false)
+ register(:text, Type::Text, override: false)
+ register(:time, Type::Time, override: false)
+ end
+end
diff --git a/activerecord/lib/active_record/type/adapter_specific_registry.rb b/activerecord/lib/active_record/type/adapter_specific_registry.rb
new file mode 100644
index 0000000000..5f71b3cb94
--- /dev/null
+++ b/activerecord/lib/active_record/type/adapter_specific_registry.rb
@@ -0,0 +1,142 @@
+module ActiveRecord
+ # :stopdoc:
+ module Type
+ class AdapterSpecificRegistry
+ def initialize
+ @registrations = []
+ end
+
+ def register(type_name, klass = nil, **options, &block)
+ block ||= proc { |_, *args| klass.new(*args) }
+ registrations << Registration.new(type_name, block, **options)
+ end
+
+ def lookup(symbol, *args)
+ registration = registrations
+ .select { |r| r.matches?(symbol, *args) }
+ .max
+
+ if registration
+ registration.call(self, symbol, *args)
+ else
+ raise ArgumentError, "Unknown type #{symbol.inspect}"
+ end
+ end
+
+ def add_modifier(options, klass, **args)
+ registrations << DecorationRegistration.new(options, klass, **args)
+ end
+
+ protected
+
+ attr_reader :registrations
+ end
+
+ class Registration
+ def initialize(name, block, adapter: nil, override: nil)
+ @name = name
+ @block = block
+ @adapter = adapter
+ @override = override
+ end
+
+ def call(_registry, *args, adapter: nil, **kwargs)
+ if kwargs.any? # https://bugs.ruby-lang.org/issues/10856
+ block.call(*args, **kwargs)
+ else
+ block.call(*args)
+ end
+ end
+
+ def matches?(type_name, *args, **kwargs)
+ type_name == name && matches_adapter?(**kwargs)
+ end
+
+ def <=>(other)
+ if conflicts_with?(other)
+ raise TypeConflictError.new("Type #{name} was registered for all
+ adapters, but shadows a native type with
+ the same name for #{other.adapter}".squish)
+ end
+ priority <=> other.priority
+ end
+
+ protected
+
+ attr_reader :name, :block, :adapter, :override
+
+ def priority
+ result = 0
+ if adapter
+ result |= 1
+ end
+ if override
+ result |= 2
+ end
+ result
+ end
+
+ def priority_except_adapter
+ priority & 0b111111100
+ end
+
+ private
+
+ def matches_adapter?(adapter: nil, **)
+ (self.adapter.nil? || adapter == self.adapter)
+ end
+
+ def conflicts_with?(other)
+ same_priority_except_adapter?(other) &&
+ has_adapter_conflict?(other)
+ end
+
+ def same_priority_except_adapter?(other)
+ priority_except_adapter == other.priority_except_adapter
+ end
+
+ def has_adapter_conflict?(other)
+ (override.nil? && other.adapter) ||
+ (adapter && other.override.nil?)
+ end
+ end
+
+ class DecorationRegistration < Registration
+ def initialize(options, klass, adapter: nil)
+ @options = options
+ @klass = klass
+ @adapter = adapter
+ end
+
+ def call(registry, *args, **kwargs)
+ subtype = registry.lookup(*args, **kwargs.except(*options.keys))
+ klass.new(subtype)
+ end
+
+ def matches?(*args, **kwargs)
+ matches_adapter?(**kwargs) && matches_options?(**kwargs)
+ end
+
+ def priority
+ super | 4
+ end
+
+ protected
+
+ attr_reader :options, :klass
+
+ private
+
+ def matches_options?(**kwargs)
+ options.all? do |key, value|
+ kwargs[key] == value
+ end
+ end
+ end
+ end
+
+ class TypeConflictError < StandardError
+ end
+
+ # :startdoc:
+end
diff --git a/activerecord/lib/active_record/type/binary.rb b/activerecord/lib/active_record/type/binary.rb
index 005a48ef0d..0baf8c63ad 100644
--- a/activerecord/lib/active_record/type/binary.rb
+++ b/activerecord/lib/active_record/type/binary.rb
@@ -9,7 +9,7 @@ module ActiveRecord
true
end
- def type_cast(value)
+ def cast(value)
if value.is_a?(Data)
value.to_s
else
@@ -17,13 +17,13 @@ module ActiveRecord
end
end
- def type_cast_for_database(value)
+ def serialize(value)
return if value.nil?
Data.new(super)
end
def changed_in_place?(raw_old_value, value)
- old_value = type_cast_from_database(raw_old_value)
+ old_value = deserialize(raw_old_value)
old_value != value
end
diff --git a/activerecord/lib/active_record/type/date_time.rb b/activerecord/lib/active_record/type/date_time.rb
index a25f2521bb..05d2af3808 100644
--- a/activerecord/lib/active_record/type/date_time.rb
+++ b/activerecord/lib/active_record/type/date_time.rb
@@ -10,7 +10,7 @@ module ActiveRecord
:datetime
end
- def type_cast_for_database(value)
+ def serialize(value)
if precision && value.respond_to?(:usec)
number_of_insignificant_digits = 6 - precision
round_power = 10 ** number_of_insignificant_digits
diff --git a/activerecord/lib/active_record/type/float.rb b/activerecord/lib/active_record/type/float.rb
index b3928242b7..d88482b85d 100644
--- a/activerecord/lib/active_record/type/float.rb
+++ b/activerecord/lib/active_record/type/float.rb
@@ -7,7 +7,7 @@ module ActiveRecord
:float
end
- alias type_cast_for_database type_cast
+ alias serialize cast
private
diff --git a/activerecord/lib/active_record/type/helpers/accepts_multiparameter_time.rb b/activerecord/lib/active_record/type/helpers/accepts_multiparameter_time.rb
index 640943c5e9..be571fc1c7 100644
--- a/activerecord/lib/active_record/type/helpers/accepts_multiparameter_time.rb
+++ b/activerecord/lib/active_record/type/helpers/accepts_multiparameter_time.rb
@@ -3,7 +3,7 @@ module ActiveRecord
module Helpers
class AcceptsMultiparameterTime < Module # :nodoc:
def initialize(defaults: {})
- define_method(:type_cast_from_user) do |value|
+ define_method(:cast) do |value|
if value.is_a?(Hash)
value_from_multiparameter_assignment(value)
else
diff --git a/activerecord/lib/active_record/type/helpers/mutable.rb b/activerecord/lib/active_record/type/helpers/mutable.rb
index dc37f4a885..88a9099277 100644
--- a/activerecord/lib/active_record/type/helpers/mutable.rb
+++ b/activerecord/lib/active_record/type/helpers/mutable.rb
@@ -2,15 +2,15 @@ module ActiveRecord
module Type
module Helpers
module Mutable # :nodoc:
- def type_cast_from_user(value)
- type_cast_from_database(type_cast_for_database(value))
+ def cast(value)
+ deserialize(serialize(value))
end
# +raw_old_value+ will be the `_before_type_cast` version of the
# value (likely a string). +new_value+ will be the current, type
# cast value.
def changed_in_place?(raw_old_value, new_value)
- raw_old_value != type_cast_for_database(new_value)
+ raw_old_value != serialize(new_value)
end
end
end
diff --git a/activerecord/lib/active_record/type/helpers/numeric.rb b/activerecord/lib/active_record/type/helpers/numeric.rb
index b0d4f03117..a755a02a59 100644
--- a/activerecord/lib/active_record/type/helpers/numeric.rb
+++ b/activerecord/lib/active_record/type/helpers/numeric.rb
@@ -2,7 +2,7 @@ module ActiveRecord
module Type
module Helpers
module Numeric # :nodoc:
- def type_cast(value)
+ def cast(value)
value = case value
when true then 1
when false then 0
diff --git a/activerecord/lib/active_record/type/integer.rb b/activerecord/lib/active_record/type/integer.rb
index 2ab2402dfd..2a1b04ac7f 100644
--- a/activerecord/lib/active_record/type/integer.rb
+++ b/activerecord/lib/active_record/type/integer.rb
@@ -16,13 +16,13 @@ module ActiveRecord
:integer
end
- def type_cast_from_database(value)
+ def deserialize(value)
return if value.nil?
value.to_i
end
- def type_cast_for_database(value)
- result = type_cast(value)
+ def serialize(value)
+ result = cast(value)
if result
ensure_in_range(result)
end
diff --git a/activerecord/lib/active_record/type/serialized.rb b/activerecord/lib/active_record/type/serialized.rb
index 6c6c520048..732029c723 100644
--- a/activerecord/lib/active_record/type/serialized.rb
+++ b/activerecord/lib/active_record/type/serialized.rb
@@ -11,7 +11,7 @@ module ActiveRecord
super(subtype)
end
- def type_cast_from_database(value)
+ def deserialize(value)
if default_value?(value)
value
else
@@ -19,7 +19,7 @@ module ActiveRecord
end
end
- def type_cast_for_database(value)
+ def serialize(value)
return if value.nil?
unless default_value?(value)
super coder.dump(value)
@@ -28,7 +28,7 @@ module ActiveRecord
def changed_in_place?(raw_old_value, value)
return false if value.nil?
- subtype.changed_in_place?(raw_old_value, type_cast_for_database(value))
+ subtype.changed_in_place?(raw_old_value, serialize(value))
end
def accessor
diff --git a/activerecord/lib/active_record/type/string.rb b/activerecord/lib/active_record/type/string.rb
index fbc0af2c5a..2662b7e874 100644
--- a/activerecord/lib/active_record/type/string.rb
+++ b/activerecord/lib/active_record/type/string.rb
@@ -11,7 +11,7 @@ module ActiveRecord
end
end
- def type_cast_for_database(value)
+ def serialize(value)
case value
when ::Numeric, ActiveSupport::Duration then value.to_s
when ::String then ::String.new(value)
diff --git a/activerecord/lib/active_record/type/value.rb b/activerecord/lib/active_record/type/value.rb
index 7338920f3b..fc3ef5e83b 100644
--- a/activerecord/lib/active_record/type/value.rb
+++ b/activerecord/lib/active_record/type/value.rb
@@ -14,12 +14,12 @@ module ActiveRecord
# Convert a value from database input to the appropriate ruby type. The
# return value of this method will be returned from
- # ActiveRecord::AttributeMethods::Read#read_attribute. See also
- # Value#type_cast and Value#cast_value.
+ # ActiveRecord::AttributeMethods::Read#read_attribute. The default
+ # implementation just calls Value#cast.
#
# +value+ The raw input, as provided from the database.
- def type_cast_from_database(value)
- type_cast(value)
+ def deserialize(value)
+ cast(value)
end
# Type casts a value from user input (e.g. from a setter). This value may
@@ -29,18 +29,18 @@ module ActiveRecord
#
# The return value of this method will be returned from
# ActiveRecord::AttributeMethods::Read#read_attribute. See also:
- # Value#type_cast and Value#cast_value.
+ # Value#cast_value.
#
# +value+ The raw input, as provided to the attribute setter.
- def type_cast_from_user(value)
- type_cast(value)
+ def cast(value)
+ cast_value(value) unless value.nil?
end
# Cast a value from the ruby type to a type that the database knows how
# to understand. The returned value from this method should be a
# +String+, +Numeric+, +Date+, +Time+, +Symbol+, +true+, +false+, or
# +nil+.
- def type_cast_for_database(value)
+ def serialize(value)
value
end
@@ -68,16 +68,16 @@ module ActiveRecord
# which could be mutated, you should override this method. You will need
# to either:
#
- # - pass +new_value+ to Value#type_cast_for_database and compare it to
+ # - pass +new_value+ to Value#serialize and compare it to
# +raw_old_value+
#
# or
#
- # - pass +raw_old_value+ to Value#type_cast_from_database and compare it to
+ # - pass +raw_old_value+ to Value#deserialize and compare it to
# +new_value+
#
# +raw_old_value+ The original value, before being passed to
- # +type_cast_from_database+.
+ # +deserialize+.
#
# +new_value+ The current value, after type casting.
def changed_in_place?(raw_old_value, new_value)
@@ -93,16 +93,8 @@ module ActiveRecord
private
- # Convenience method. If you don't need separate behavior for
- # Value#type_cast_from_database and Value#type_cast_from_user, you can override
- # this method instead. The default behavior of both methods is to call
- # this one. See also Value#cast_value.
- def type_cast(value) # :doc:
- cast_value(value) unless value.nil?
- end
-
# Convenience method for types which do not need separate type casting
- # behavior for user and database inputs. Called by Value#type_cast for
+ # behavior for user and database inputs. Called by Value#cast for
# values except +nil+.
def cast_value(value) # :doc:
value
diff --git a/activerecord/lib/active_record/type_caster/map.rb b/activerecord/lib/active_record/type_caster/map.rb
index 03c9e8ff83..4b1941351c 100644
--- a/activerecord/lib/active_record/type_caster/map.rb
+++ b/activerecord/lib/active_record/type_caster/map.rb
@@ -8,7 +8,7 @@ module ActiveRecord
def type_cast_for_database(attr_name, value)
return value if value.is_a?(Arel::Nodes::BindParam)
type = types.type_for_attribute(attr_name.to_s)
- type.type_cast_for_database(value)
+ type.serialize(value)
end
protected
diff --git a/activerecord/lib/active_record/validations/uniqueness.rb b/activerecord/lib/active_record/validations/uniqueness.rb
index a766d77e88..9be4b10a55 100644
--- a/activerecord/lib/active_record/validations/uniqueness.rb
+++ b/activerecord/lib/active_record/validations/uniqueness.rb
@@ -61,7 +61,7 @@ module ActiveRecord
column = klass.columns_hash[attribute_name]
cast_type = klass.type_for_attribute(attribute_name)
- value = cast_type.type_cast_for_database(value)
+ value = cast_type.serialize(value)
value = klass.connection.type_cast(value)
if value.is_a?(String) && column.limit
value = value.to_s[0, column.limit]
diff --git a/activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb b/activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb
index 7d0bd24ba7..48ceef365e 100644
--- a/activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb
+++ b/activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb
@@ -15,7 +15,7 @@ module ActiveRecord
assert_raise ActiveRecord::NoDatabaseError do
configuration = ActiveRecord::Base.configurations['arunit'].merge(database: 'inexistent_activerecord_unittest')
connection = ActiveRecord::Base.mysql_connection(configuration)
- connection.exec_query('drop table if exists ex')
+ connection.drop_table 'ex', if_exists: true
end
end
@@ -110,7 +110,7 @@ module ActiveRecord
result = @conn.exec_query('SELECT status FROM ex')
- assert_equal 2, result.column_types['status'].type_cast_from_database(result.last['status'])
+ assert_equal 2, result.column_types['status'].deserialize(result.last['status'])
end
end
diff --git a/activerecord/test/cases/adapters/mysql/reserved_word_test.rb b/activerecord/test/cases/adapters/mysql/reserved_word_test.rb
index 403f7cbc74..2f9c070255 100644
--- a/activerecord/test/cases/adapters/mysql/reserved_word_test.rb
+++ b/activerecord/test/cases/adapters/mysql/reserved_word_test.rb
@@ -139,7 +139,7 @@ class MysqlReservedWordTest < ActiveRecord::TestCase
# custom drop table, uses execute on connection to drop a table if it exists. note: escapes table_name
def drop_tables_directly(table_names, connection = @connection)
table_names.each do |name|
- connection.execute("DROP TABLE IF EXISTS `#{name}`")
+ connection.drop_table name, if_exists: true
end
end
diff --git a/activerecord/test/cases/adapters/mysql/schema_test.rb b/activerecord/test/cases/adapters/mysql/schema_test.rb
index ab547747df..b7f9c2ce84 100644
--- a/activerecord/test/cases/adapters/mysql/schema_test.rb
+++ b/activerecord/test/cases/adapters/mysql/schema_test.rb
@@ -22,7 +22,7 @@ module ActiveRecord
end
teardown do
- @connection.execute "drop table if exists mysql_doubles"
+ @connection.drop_table "mysql_doubles", if_exists: true
end
class MysqlDouble < ActiveRecord::Base
diff --git a/activerecord/test/cases/adapters/mysql2/connection_test.rb b/activerecord/test/cases/adapters/mysql2/connection_test.rb
index ff8ce93248..a8b39b21d4 100644
--- a/activerecord/test/cases/adapters/mysql2/connection_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/connection_test.rb
@@ -22,7 +22,7 @@ class MysqlConnectionTest < ActiveRecord::TestCase
assert_raise ActiveRecord::NoDatabaseError do
configuration = ActiveRecord::Base.configurations['arunit'].merge(database: 'inexistent_activerecord_unittest')
connection = ActiveRecord::Base.mysql2_connection(configuration)
- connection.exec_query('drop table if exists ex')
+ connection.drop_table 'ex', if_exists: true
end
end
diff --git a/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb b/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb
index 7f97b454bb..beb829fc46 100644
--- a/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb
@@ -138,7 +138,7 @@ class MysqlReservedWordTest < ActiveRecord::TestCase
# custom drop table, uses execute on connection to drop a table if it exists. note: escapes table_name
def drop_tables_directly(table_names, connection = @connection)
table_names.each do |name|
- connection.execute("DROP TABLE IF EXISTS `#{name}`")
+ connection.drop_table name, if_exists: true
end
end
diff --git a/activerecord/test/cases/adapters/postgresql/array_test.rb b/activerecord/test/cases/adapters/postgresql/array_test.rb
index 3d5b7e5137..2163e35e70 100644
--- a/activerecord/test/cases/adapters/postgresql/array_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/array_test.rb
@@ -28,7 +28,7 @@ class PostgresqlArrayTest < ActiveRecord::TestCase
end
teardown do
- @connection.execute 'drop table if exists pg_arrays'
+ @connection.drop_table 'pg_arrays', if_exists: true
disable_extension!('hstore', @connection)
end
@@ -92,9 +92,9 @@ class PostgresqlArrayTest < ActiveRecord::TestCase
end
def test_type_cast_array
- assert_equal(['1', '2', '3'], @type.type_cast_from_database('{1,2,3}'))
- assert_equal([], @type.type_cast_from_database('{}'))
- assert_equal([nil], @type.type_cast_from_database('{NULL}'))
+ assert_equal(['1', '2', '3'], @type.deserialize('{1,2,3}'))
+ assert_equal([], @type.deserialize('{}'))
+ assert_equal([nil], @type.deserialize('{NULL}'))
end
def test_type_cast_integers
@@ -206,7 +206,7 @@ class PostgresqlArrayTest < ActiveRecord::TestCase
x = PgArray.create!(tags: tags)
x.reload
- assert_equal x.tags_before_type_cast, PgArray.type_for_attribute('tags').type_cast_for_database(tags)
+ assert_equal x.tags_before_type_cast, PgArray.type_for_attribute('tags').serialize(tags)
end
def test_quoting_non_standard_delimiters
@@ -214,8 +214,8 @@ class PostgresqlArrayTest < ActiveRecord::TestCase
comma_delim = OID::Array.new(ActiveRecord::Type::String.new, ',')
semicolon_delim = OID::Array.new(ActiveRecord::Type::String.new, ';')
- assert_equal %({"hello,",world;}), comma_delim.type_cast_for_database(strings)
- assert_equal %({hello,;"world;"}), semicolon_delim.type_cast_for_database(strings)
+ assert_equal %({"hello,",world;}), comma_delim.serialize(strings)
+ assert_equal %({hello,;"world;"}), semicolon_delim.serialize(strings)
end
def test_mutate_array
diff --git a/activerecord/test/cases/adapters/postgresql/bit_string_test.rb b/activerecord/test/cases/adapters/postgresql/bit_string_test.rb
index 6c6b4dc22a..1a5ff4316c 100644
--- a/activerecord/test/cases/adapters/postgresql/bit_string_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/bit_string_test.rb
@@ -20,7 +20,7 @@ class PostgresqlBitStringTest < ActiveRecord::TestCase
def teardown
return unless @connection
- @connection.execute 'DROP TABLE IF EXISTS postgresql_bit_strings'
+ @connection.drop_table 'postgresql_bit_strings', if_exists: true
end
def test_bit_string_column
diff --git a/activerecord/test/cases/adapters/postgresql/bytea_test.rb b/activerecord/test/cases/adapters/postgresql/bytea_test.rb
index 678a476661..16db5ab83d 100644
--- a/activerecord/test/cases/adapters/postgresql/bytea_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/bytea_test.rb
@@ -20,7 +20,7 @@ class PostgresqlByteaTest < ActiveRecord::TestCase
end
teardown do
- @connection.execute 'drop table if exists bytea_data_type'
+ @connection.drop_table 'bytea_data_type', if_exists: true
end
def test_column
@@ -40,16 +40,16 @@ class PostgresqlByteaTest < ActiveRecord::TestCase
data = "\u001F\x8B"
assert_equal('UTF-8', data.encoding.name)
- assert_equal('ASCII-8BIT', @type.type_cast_from_database(data).encoding.name)
+ assert_equal('ASCII-8BIT', @type.deserialize(data).encoding.name)
end
def test_type_cast_binary_value
data = "\u001F\x8B".force_encoding("BINARY")
- assert_equal(data, @type.type_cast_from_database(data))
+ assert_equal(data, @type.deserialize(data))
end
def test_type_case_nil
- assert_equal(nil, @type.type_cast_from_database(nil))
+ assert_equal(nil, @type.deserialize(nil))
end
def test_read_value
diff --git a/activerecord/test/cases/adapters/postgresql/cidr_test.rb b/activerecord/test/cases/adapters/postgresql/cidr_test.rb
index 54b679d3ab..6cb11d17b4 100644
--- a/activerecord/test/cases/adapters/postgresql/cidr_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/cidr_test.rb
@@ -10,14 +10,14 @@ module ActiveRecord
ip = IPAddr.new("255.0.0.0/8")
ip2 = IPAddr.new("127.0.0.1")
- assert_equal "255.0.0.0/8", type.type_cast_for_database(ip)
- assert_equal "127.0.0.1/32", type.type_cast_for_database(ip2)
+ assert_equal "255.0.0.0/8", type.serialize(ip)
+ assert_equal "127.0.0.1/32", type.serialize(ip2)
end
test "casting does nothing with non-IPAddr objects" do
type = OID::Cidr.new
- assert_equal "foo", type.type_cast_for_database("foo")
+ assert_equal "foo", type.serialize("foo")
end
end
end
diff --git a/activerecord/test/cases/adapters/postgresql/citext_test.rb b/activerecord/test/cases/adapters/postgresql/citext_test.rb
index 0ee2a21484..f706847890 100644
--- a/activerecord/test/cases/adapters/postgresql/citext_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/citext_test.rb
@@ -19,7 +19,7 @@ if ActiveRecord::Base.connection.supports_extensions?
end
teardown do
- @connection.execute 'DROP TABLE IF EXISTS citexts;'
+ @connection.drop_table 'citexts', if_exists: true
disable_extension!('citext', @connection)
end
diff --git a/activerecord/test/cases/adapters/postgresql/composite_test.rb b/activerecord/test/cases/adapters/postgresql/composite_test.rb
index 83dfb18e95..16e3f90a47 100644
--- a/activerecord/test/cases/adapters/postgresql/composite_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/composite_test.rb
@@ -29,7 +29,7 @@ module PostgresqlCompositeBehavior
def teardown
super
- @connection.execute 'DROP TABLE IF EXISTS postgresql_composites'
+ @connection.drop_table 'postgresql_composites', if_exists: true
@connection.execute 'DROP TYPE IF EXISTS full_address'
reset_connection
PostgresqlComposite.reset_column_information
@@ -83,17 +83,17 @@ class PostgresqlCompositeWithCustomOIDTest < ActiveRecord::TestCase
class FullAddressType < ActiveRecord::Type::Value
def type; :full_address end
- def type_cast_from_database(value)
+ def deserialize(value)
if value =~ /\("?([^",]*)"?,"?([^",]*)"?\)/
FullAddress.new($1, $2)
end
end
- def type_cast_from_user(value)
+ def cast(value)
value
end
- def type_cast_for_database(value)
+ def serialize(value)
return if value.nil?
"(#{value.city},#{value.street})"
end
diff --git a/activerecord/test/cases/adapters/postgresql/connection_test.rb b/activerecord/test/cases/adapters/postgresql/connection_test.rb
index 7bf8d12eae..55ad76c8c0 100644
--- a/activerecord/test/cases/adapters/postgresql/connection_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/connection_test.rb
@@ -131,7 +131,7 @@ module ActiveRecord
name = @subscriber.payloads.last[:statement_name]
assert name
res = @connection.exec_query("EXPLAIN (FORMAT JSON) EXECUTE #{name}(1)")
- plan = res.column_types['QUERY PLAN'].type_cast_from_database res.rows.first.first
+ plan = res.column_types['QUERY PLAN'].deserialize res.rows.first.first
assert_operator plan.length, :>, 0
end
diff --git a/activerecord/test/cases/adapters/postgresql/domain_test.rb b/activerecord/test/cases/adapters/postgresql/domain_test.rb
index b7d776b40c..26e064c937 100644
--- a/activerecord/test/cases/adapters/postgresql/domain_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/domain_test.rb
@@ -19,7 +19,7 @@ class PostgresqlDomainTest < ActiveRecord::TestCase
end
teardown do
- @connection.execute 'DROP TABLE IF EXISTS postgresql_domains'
+ @connection.drop_table 'postgresql_domains', if_exists: true
@connection.execute 'DROP DOMAIN IF EXISTS custom_money'
reset_connection
end
diff --git a/activerecord/test/cases/adapters/postgresql/enum_test.rb b/activerecord/test/cases/adapters/postgresql/enum_test.rb
index acb09b0607..7458de23d8 100644
--- a/activerecord/test/cases/adapters/postgresql/enum_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/enum_test.rb
@@ -21,7 +21,7 @@ class PostgresqlEnumTest < ActiveRecord::TestCase
end
teardown do
- @connection.execute 'DROP TABLE IF EXISTS postgresql_enums'
+ @connection.drop_table 'postgresql_enums', if_exists: true
@connection.execute 'DROP TYPE IF EXISTS mood'
reset_connection
end
diff --git a/activerecord/test/cases/adapters/postgresql/full_text_test.rb b/activerecord/test/cases/adapters/postgresql/full_text_test.rb
index 81891a90fa..b83063c94e 100644
--- a/activerecord/test/cases/adapters/postgresql/full_text_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/full_text_test.rb
@@ -13,7 +13,7 @@ class PostgresqlFullTextTest < ActiveRecord::TestCase
end
teardown do
- @connection.execute 'DROP TABLE IF EXISTS tsvectors;'
+ @connection.drop_table 'tsvectors', if_exists: true
end
def test_tsvector_column
diff --git a/activerecord/test/cases/adapters/postgresql/geometric_test.rb b/activerecord/test/cases/adapters/postgresql/geometric_test.rb
index 4b25381a83..41e9572907 100644
--- a/activerecord/test/cases/adapters/postgresql/geometric_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/geometric_test.rb
@@ -18,7 +18,7 @@ class PostgresqlPointTest < ActiveRecord::TestCase
end
teardown do
- @connection.execute 'DROP TABLE IF EXISTS postgresql_points'
+ @connection.drop_table 'postgresql_points', if_exists: true
end
def test_column
@@ -84,7 +84,7 @@ class PostgresqlGeometricTest < ActiveRecord::TestCase
end
teardown do
- @connection.execute 'DROP TABLE IF EXISTS postgresql_geometrics'
+ @connection.drop_table 'postgresql_geometrics', if_exists: true
end
def test_geometric_types
diff --git a/activerecord/test/cases/adapters/postgresql/hstore_test.rb b/activerecord/test/cases/adapters/postgresql/hstore_test.rb
index 11053a6e38..e6835031c3 100644
--- a/activerecord/test/cases/adapters/postgresql/hstore_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/hstore_test.rb
@@ -32,7 +32,7 @@ if ActiveRecord::Base.connection.supports_extensions?
end
teardown do
- @connection.execute 'drop table if exists hstores'
+ @connection.drop_table 'hstores', if_exists: true
end
def test_hstore_included_in_extensions
@@ -110,10 +110,10 @@ if ActiveRecord::Base.connection.supports_extensions?
end
def test_type_cast_hstore
- assert_equal({'1' => '2'}, @type.type_cast_from_database("\"1\"=>\"2\""))
- assert_equal({}, @type.type_cast_from_database(""))
- assert_equal({'key'=>nil}, @type.type_cast_from_database('key => NULL'))
- assert_equal({'c'=>'}','"a"'=>'b "a b'}, @type.type_cast_from_database(%q(c=>"}", "\"a\""=>"b \"a b")))
+ assert_equal({'1' => '2'}, @type.deserialize("\"1\"=>\"2\""))
+ assert_equal({}, @type.deserialize(""))
+ assert_equal({'key'=>nil}, @type.deserialize('key => NULL'))
+ assert_equal({'c'=>'}','"a"'=>'b "a b'}, @type.deserialize(%q(c=>"}", "\"a\""=>"b \"a b")))
end
def test_with_store_accessors
@@ -165,47 +165,47 @@ if ActiveRecord::Base.connection.supports_extensions?
end
def test_gen1
- assert_equal(%q(" "=>""), @type.type_cast_for_database({' '=>''}))
+ assert_equal(%q(" "=>""), @type.serialize({' '=>''}))
end
def test_gen2
- assert_equal(%q(","=>""), @type.type_cast_for_database({','=>''}))
+ assert_equal(%q(","=>""), @type.serialize({','=>''}))
end
def test_gen3
- assert_equal(%q("="=>""), @type.type_cast_for_database({'='=>''}))
+ assert_equal(%q("="=>""), @type.serialize({'='=>''}))
end
def test_gen4
- assert_equal(%q(">"=>""), @type.type_cast_for_database({'>'=>''}))
+ assert_equal(%q(">"=>""), @type.serialize({'>'=>''}))
end
def test_parse1
- assert_equal({'a'=>nil,'b'=>nil,'c'=>'NuLl','null'=>'c'}, @type.type_cast_from_database('a=>null,b=>NuLl,c=>"NuLl",null=>c'))
+ assert_equal({'a'=>nil,'b'=>nil,'c'=>'NuLl','null'=>'c'}, @type.deserialize('a=>null,b=>NuLl,c=>"NuLl",null=>c'))
end
def test_parse2
- assert_equal({" " => " "}, @type.type_cast_from_database("\\ =>\\ "))
+ assert_equal({" " => " "}, @type.deserialize("\\ =>\\ "))
end
def test_parse3
- assert_equal({"=" => ">"}, @type.type_cast_from_database("==>>"))
+ assert_equal({"=" => ">"}, @type.deserialize("==>>"))
end
def test_parse4
- assert_equal({"=a"=>"q=w"}, @type.type_cast_from_database('\=a=>q=w'))
+ assert_equal({"=a"=>"q=w"}, @type.deserialize('\=a=>q=w'))
end
def test_parse5
- assert_equal({"=a"=>"q=w"}, @type.type_cast_from_database('"=a"=>q\=w'))
+ assert_equal({"=a"=>"q=w"}, @type.deserialize('"=a"=>q\=w'))
end
def test_parse6
- assert_equal({"\"a"=>"q>w"}, @type.type_cast_from_database('"\"a"=>q>w'))
+ assert_equal({"\"a"=>"q>w"}, @type.deserialize('"\"a"=>q>w'))
end
def test_parse7
- assert_equal({"\"a"=>"q\"w"}, @type.type_cast_from_database('\"a=>q"w'))
+ assert_equal({"\"a"=>"q\"w"}, @type.deserialize('\"a=>q"w'))
end
def test_rewrite
diff --git a/activerecord/test/cases/adapters/postgresql/infinity_test.rb b/activerecord/test/cases/adapters/postgresql/infinity_test.rb
index 74163ac712..24199c69b8 100644
--- a/activerecord/test/cases/adapters/postgresql/infinity_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/infinity_test.rb
@@ -15,7 +15,7 @@ class PostgresqlInfinityTest < ActiveRecord::TestCase
end
teardown do
- @connection.execute("DROP TABLE IF EXISTS postgresql_infinities")
+ @connection.drop_table 'postgresql_infinities', if_exists: true
end
test "type casting infinity on a float column" do
diff --git a/activerecord/test/cases/adapters/postgresql/integer_test.rb b/activerecord/test/cases/adapters/postgresql/integer_test.rb
index 7f8751281e..679a0fc7b3 100644
--- a/activerecord/test/cases/adapters/postgresql/integer_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/integer_test.rb
@@ -16,7 +16,7 @@ class PostgresqlIntegerTest < ActiveRecord::TestCase
end
teardown do
- @connection.execute "drop table if exists pg_integers"
+ @connection.drop_table "pg_integers", if_exists: true
end
test "schema properly respects bigint ranges" do
diff --git a/activerecord/test/cases/adapters/postgresql/json_test.rb b/activerecord/test/cases/adapters/postgresql/json_test.rb
index 3b123f979e..d8fded16b4 100644
--- a/activerecord/test/cases/adapters/postgresql/json_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/json_test.rb
@@ -80,13 +80,13 @@ module PostgresqlJSONSharedTestCases
type = JsonDataType.type_for_attribute("payload")
data = "{\"a_key\":\"a_value\"}"
- hash = type.type_cast_from_database(data)
+ hash = type.deserialize(data)
assert_equal({'a_key' => 'a_value'}, hash)
- assert_equal({'a_key' => 'a_value'}, type.type_cast_from_database(data))
+ assert_equal({'a_key' => 'a_value'}, type.deserialize(data))
- assert_equal({}, type.type_cast_from_database("{}"))
- assert_equal({'key'=>nil}, type.type_cast_from_database('{"key": null}'))
- assert_equal({'c'=>'}','"a"'=>'b "a b'}, type.type_cast_from_database(%q({"c":"}", "\"a\"":"b \"a b"})))
+ assert_equal({}, type.deserialize("{}"))
+ assert_equal({'key'=>nil}, type.deserialize('{"key": null}'))
+ assert_equal({'c'=>'}','"a"'=>'b "a b'}, type.deserialize(%q({"c":"}", "\"a\"":"b \"a b"})))
end
def test_rewrite
diff --git a/activerecord/test/cases/adapters/postgresql/ltree_test.rb b/activerecord/test/cases/adapters/postgresql/ltree_test.rb
index 2b3823f9f1..ce0ad16557 100644
--- a/activerecord/test/cases/adapters/postgresql/ltree_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/ltree_test.rb
@@ -22,7 +22,7 @@ class PostgresqlLtreeTest < ActiveRecord::TestCase
end
teardown do
- @connection.execute 'drop table if exists ltrees'
+ @connection.drop_table 'ltrees', if_exists: true
end
def test_column
diff --git a/activerecord/test/cases/adapters/postgresql/money_test.rb b/activerecord/test/cases/adapters/postgresql/money_test.rb
index ba9af4be6f..cedd399380 100644
--- a/activerecord/test/cases/adapters/postgresql/money_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/money_test.rb
@@ -16,7 +16,7 @@ class PostgresqlMoneyTest < ActiveRecord::TestCase
end
teardown do
- @connection.execute 'DROP TABLE IF EXISTS postgresql_moneys'
+ @connection.drop_table 'postgresql_moneys', if_exists: true
end
def test_column
@@ -47,10 +47,10 @@ class PostgresqlMoneyTest < ActiveRecord::TestCase
def test_money_type_cast
type = PostgresqlMoney.type_for_attribute('wealth')
- assert_equal(12345678.12, type.type_cast_from_user("$12,345,678.12"))
- assert_equal(12345678.12, type.type_cast_from_user("$12.345.678,12"))
- assert_equal(-1.15, type.type_cast_from_user("-$1.15"))
- assert_equal(-2.25, type.type_cast_from_user("($2.25)"))
+ assert_equal(12345678.12, type.cast("$12,345,678.12"))
+ assert_equal(12345678.12, type.cast("$12.345.678,12"))
+ assert_equal(-1.15, type.cast("-$1.15"))
+ assert_equal(-2.25, type.cast("($2.25)"))
end
def test_schema_dumping
diff --git a/activerecord/test/cases/adapters/postgresql/network_test.rb b/activerecord/test/cases/adapters/postgresql/network_test.rb
index 4cd2d4d5f3..033695518e 100644
--- a/activerecord/test/cases/adapters/postgresql/network_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/network_test.rb
@@ -15,7 +15,7 @@ class PostgresqlNetworkTest < ActiveRecord::TestCase
end
teardown do
- @connection.execute 'DROP TABLE IF EXISTS postgresql_network_addresses'
+ @connection.drop_table 'postgresql_network_addresses', if_exists: true
end
def test_cidr_column
diff --git a/activerecord/test/cases/adapters/postgresql/numbers_test.rb b/activerecord/test/cases/adapters/postgresql/numbers_test.rb
index 70aa898439..093b81fe8d 100644
--- a/activerecord/test/cases/adapters/postgresql/numbers_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/numbers_test.rb
@@ -12,7 +12,7 @@ class PostgresqlNumberTest < ActiveRecord::TestCase
end
teardown do
- @connection.execute 'DROP TABLE IF EXISTS postgresql_numbers'
+ @connection.drop_table 'postgresql_numbers', if_exists: true
end
def test_data_type
diff --git a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
index 564712522d..a934180a43 100644
--- a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
@@ -227,8 +227,8 @@ module ActiveRecord
"DELETE FROM pg_depend WHERE objid = 'ex2_id_seq'::regclass AND refobjid = 'ex'::regclass AND deptype = 'a'"
)
ensure
- @connection.exec_query('DROP TABLE IF EXISTS ex')
- @connection.exec_query('DROP TABLE IF EXISTS ex2')
+ @connection.drop_table 'ex', if_exists: true
+ @connection.drop_table 'ex2', if_exists: true
end
def test_exec_insert_number
diff --git a/activerecord/test/cases/adapters/postgresql/quoting_test.rb b/activerecord/test/cases/adapters/postgresql/quoting_test.rb
index 60baacf67a..e4420d9d13 100644
--- a/activerecord/test/cases/adapters/postgresql/quoting_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/quoting_test.rb
@@ -30,13 +30,13 @@ module ActiveRecord
def test_quote_range
range = "1,2]'; SELECT * FROM users; --".."a"
type = OID::Range.new(Type::Integer.new, :int8range)
- assert_equal "'[1,0]'", @conn.quote(type.type_cast_for_database(range))
+ assert_equal "'[1,0]'", @conn.quote(type.serialize(range))
end
def test_quote_bit_string
value = "'); SELECT * FROM users; /*\n01\n*/--"
type = OID::Bit.new
- assert_equal nil, @conn.quote(type.type_cast_for_database(value))
+ assert_equal nil, @conn.quote(type.serialize(value))
end
end
end
diff --git a/activerecord/test/cases/adapters/postgresql/range_test.rb b/activerecord/test/cases/adapters/postgresql/range_test.rb
index 70cf21100a..b6b451ca5c 100644
--- a/activerecord/test/cases/adapters/postgresql/range_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/range_test.rb
@@ -91,7 +91,7 @@ _SQL
end
teardown do
- @connection.execute 'DROP TABLE IF EXISTS postgresql_ranges'
+ @connection.drop_table 'postgresql_ranges', if_exists: true
@connection.execute 'DROP TYPE IF EXISTS floatrange'
reset_connection
end
diff --git a/activerecord/test/cases/adapters/postgresql/rename_table_test.rb b/activerecord/test/cases/adapters/postgresql/rename_table_test.rb
index 056a035622..f507328868 100644
--- a/activerecord/test/cases/adapters/postgresql/rename_table_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/rename_table_test.rb
@@ -7,8 +7,8 @@ class PostgresqlRenameTableTest < ActiveRecord::TestCase
end
def teardown
- @connection.execute 'DROP TABLE IF EXISTS "before_rename"'
- @connection.execute 'DROP TABLE IF EXISTS "after_rename"'
+ @connection.drop_table "before_rename", if_exists: true
+ @connection.drop_table "after_rename", if_exists: true
end
test "renaming a table also renames the primary key index" do
diff --git a/activerecord/test/cases/adapters/postgresql/schema_test.rb b/activerecord/test/cases/adapters/postgresql/schema_test.rb
index 83e35ad1a1..77ff6d01bc 100644
--- a/activerecord/test/cases/adapters/postgresql/schema_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/schema_test.rb
@@ -460,8 +460,8 @@ class SchemaForeignKeyTest < ActiveRecord::TestCase
output = dump_table_schema "wagons"
assert_match %r{\s+add_foreign_key "wagons", "my_schema\.trains", column: "train_id"$}, output
ensure
- @connection.execute "DROP TABLE IF EXISTS wagons"
- @connection.execute "DROP TABLE IF EXISTS my_schema.trains"
+ @connection.drop_table "wagons", if_exists: true
+ @connection.drop_table "my_schema.trains", if_exists: true
@connection.execute "DROP SCHEMA IF EXISTS my_schema"
end
end
diff --git a/activerecord/test/cases/adapters/postgresql/type_lookup_test.rb b/activerecord/test/cases/adapters/postgresql/type_lookup_test.rb
index 4506e874bc..c0907b8f21 100644
--- a/activerecord/test/cases/adapters/postgresql/type_lookup_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/type_lookup_test.rb
@@ -18,8 +18,8 @@ class PostgresqlTypeLookupTest < ActiveRecord::TestCase
bigint_array = @connection.type_map.lookup(1016, -1, "bigint[]")
big_array = [123456789123456789]
- assert_raises(RangeError) { int_array.type_cast_for_database(big_array) }
- assert_equal "{123456789123456789}", bigint_array.type_cast_for_database(big_array)
+ assert_raises(RangeError) { int_array.serialize(big_array) }
+ assert_equal "{123456789123456789}", bigint_array.serialize(big_array)
end
test "range types correctly respect registration of subtypes" do
@@ -27,7 +27,7 @@ class PostgresqlTypeLookupTest < ActiveRecord::TestCase
bigint_range = @connection.type_map.lookup(3926, -1, "int8range")
big_range = 0..123456789123456789
- assert_raises(RangeError) { int_range.type_cast_for_database(big_range) }
- assert_equal "[0,123456789123456789]", bigint_range.type_cast_for_database(big_range)
+ assert_raises(RangeError) { int_range.serialize(big_range) }
+ assert_equal "[0,123456789123456789]", bigint_range.serialize(big_range)
end
end
diff --git a/activerecord/test/cases/adapters/postgresql/uuid_test.rb b/activerecord/test/cases/adapters/postgresql/uuid_test.rb
index 6693843497..1219e197ab 100644
--- a/activerecord/test/cases/adapters/postgresql/uuid_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/uuid_test.rb
@@ -7,7 +7,7 @@ module PostgresqlUUIDHelper
end
def drop_table(name)
- connection.execute "drop table if exists #{name}"
+ connection.drop_table name, if_exists: true
end
end
diff --git a/activerecord/test/cases/adapters/postgresql/xml_test.rb b/activerecord/test/cases/adapters/postgresql/xml_test.rb
index 05b34dcf7d..b097deb2f4 100644
--- a/activerecord/test/cases/adapters/postgresql/xml_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/xml_test.rb
@@ -22,7 +22,7 @@ class PostgresqlXMLTest < ActiveRecord::TestCase
end
teardown do
- @connection.execute 'drop table if exists xml_data_type'
+ @connection.drop_table 'xml_data_type', if_exists: true
end
def test_column
diff --git a/activerecord/test/cases/adapters/sqlite3/quoting_test.rb b/activerecord/test/cases/adapters/sqlite3/quoting_test.rb
index c1d9b7c273..243f65df98 100644
--- a/activerecord/test/cases/adapters/sqlite3/quoting_test.rb
+++ b/activerecord/test/cases/adapters/sqlite3/quoting_test.rb
@@ -87,7 +87,7 @@ module ActiveRecord
value = "hello".encode('ascii-8bit')
type = Type::String.new
- assert_equal "'hello'", @conn.quote(type.type_cast_for_database(value))
+ assert_equal "'hello'", @conn.quote(type.serialize(value))
end
end
end
diff --git a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
index f916d99bcf..5ca3c92027 100644
--- a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
+++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
@@ -22,7 +22,7 @@ module ActiveRecord
def test_bad_connection
assert_raise ActiveRecord::NoDatabaseError do
connection = ActiveRecord::Base.sqlite3_connection(adapter: "sqlite3", database: "/tmp/should/_not/_exist/-cinco-dog.db")
- connection.exec_query('drop table if exists ex')
+ connection.drop_table 'ex', if_exists: true
end
end
@@ -191,7 +191,7 @@ module ActiveRecord
binary.save!
assert_equal str, binary.data
ensure
- DualEncoding.connection.execute('DROP TABLE IF EXISTS dual_encodings')
+ DualEncoding.connection.drop_table 'dual_encodings', if_exists: true
end
def test_type_cast_should_not_mutate_encoding
diff --git a/activerecord/test/cases/attribute_decorators_test.rb b/activerecord/test/cases/attribute_decorators_test.rb
index 0b96319cbd..2aeb2601c2 100644
--- a/activerecord/test/cases/attribute_decorators_test.rb
+++ b/activerecord/test/cases/attribute_decorators_test.rb
@@ -12,11 +12,11 @@ module ActiveRecord
super(delegate)
end
- def type_cast_from_user(value)
+ def cast(value)
"#{super} #{@decoration}"
end
- alias type_cast_from_database type_cast_from_user
+ alias deserialize cast
end
setup do
@@ -102,11 +102,11 @@ module ActiveRecord
end
class Multiplier < SimpleDelegator
- def type_cast_from_user(value)
+ def cast(value)
return if value.nil?
value * 2
end
- alias type_cast_from_database type_cast_from_user
+ alias deserialize cast
end
test "decorating with a proc" do
diff --git a/activerecord/test/cases/attribute_set_test.rb b/activerecord/test/cases/attribute_set_test.rb
index 112cd2fb14..9d927481ec 100644
--- a/activerecord/test/cases/attribute_set_test.rb
+++ b/activerecord/test/cases/attribute_set_test.rb
@@ -151,12 +151,12 @@ module ActiveRecord
end
class MyType
- def type_cast_from_user(value)
+ def cast(value)
return if value.nil?
value + " from user"
end
- def type_cast_from_database(value)
+ def deserialize(value)
return if value.nil?
value + " from database"
end
diff --git a/activerecord/test/cases/attribute_test.rb b/activerecord/test/cases/attribute_test.rb
index eac73e11e8..aa419c7a67 100644
--- a/activerecord/test/cases/attribute_test.rb
+++ b/activerecord/test/cases/attribute_test.rb
@@ -13,7 +13,7 @@ module ActiveRecord
end
test "from_database + read type casts from database" do
- @type.expect(:type_cast_from_database, 'type cast from database', ['a value'])
+ @type.expect(:deserialize, 'type cast from database', ['a value'])
attribute = Attribute.from_database(nil, 'a value', @type)
type_cast_value = attribute.value
@@ -22,7 +22,7 @@ module ActiveRecord
end
test "from_user + read type casts from user" do
- @type.expect(:type_cast_from_user, 'type cast from user', ['a value'])
+ @type.expect(:cast, 'type cast from user', ['a value'])
attribute = Attribute.from_user(nil, 'a value', @type)
type_cast_value = attribute.value
@@ -31,7 +31,7 @@ module ActiveRecord
end
test "reading memoizes the value" do
- @type.expect(:type_cast_from_database, 'from the database', ['whatever'])
+ @type.expect(:deserialize, 'from the database', ['whatever'])
attribute = Attribute.from_database(nil, 'whatever', @type)
type_cast_value = attribute.value
@@ -42,7 +42,7 @@ module ActiveRecord
end
test "reading memoizes falsy values" do
- @type.expect(:type_cast_from_database, false, ['whatever'])
+ @type.expect(:deserialize, false, ['whatever'])
attribute = Attribute.from_database(nil, 'whatever', @type)
attribute.value
@@ -58,27 +58,27 @@ module ActiveRecord
end
test "from_database + read_for_database type casts to and from database" do
- @type.expect(:type_cast_from_database, 'read from database', ['whatever'])
- @type.expect(:type_cast_for_database, 'ready for database', ['read from database'])
+ @type.expect(:deserialize, 'read from database', ['whatever'])
+ @type.expect(:serialize, 'ready for database', ['read from database'])
attribute = Attribute.from_database(nil, 'whatever', @type)
- type_cast_for_database = attribute.value_for_database
+ serialize = attribute.value_for_database
- assert_equal 'ready for database', type_cast_for_database
+ assert_equal 'ready for database', serialize
end
test "from_user + read_for_database type casts from the user to the database" do
- @type.expect(:type_cast_from_user, 'read from user', ['whatever'])
- @type.expect(:type_cast_for_database, 'ready for database', ['read from user'])
+ @type.expect(:cast, 'read from user', ['whatever'])
+ @type.expect(:serialize, 'ready for database', ['read from user'])
attribute = Attribute.from_user(nil, 'whatever', @type)
- type_cast_for_database = attribute.value_for_database
+ serialize = attribute.value_for_database
- assert_equal 'ready for database', type_cast_for_database
+ assert_equal 'ready for database', serialize
end
test "duping dups the value" do
- @type.expect(:type_cast_from_database, 'type cast', ['a value'])
+ @type.expect(:deserialize, 'type cast', ['a value'])
attribute = Attribute.from_database(nil, 'a value', @type)
value_from_orig = attribute.value
@@ -90,7 +90,7 @@ module ActiveRecord
end
test "duping does not dup the value if it is not dupable" do
- @type.expect(:type_cast_from_database, false, ['a value'])
+ @type.expect(:deserialize, false, ['a value'])
attribute = Attribute.from_database(nil, 'a value', @type)
assert_same attribute.value, attribute.dup.value
@@ -102,11 +102,11 @@ module ActiveRecord
end
class MyType
- def type_cast_from_user(value)
+ def cast(value)
value + " from user"
end
- def type_cast_from_database(value)
+ def deserialize(value)
value + " from database"
end
end
diff --git a/activerecord/test/cases/attributes_test.rb b/activerecord/test/cases/attributes_test.rb
index a753e8b74e..e7b76b1cf9 100644
--- a/activerecord/test/cases/attributes_test.rb
+++ b/activerecord/test/cases/attributes_test.rb
@@ -108,11 +108,11 @@ module ActiveRecord
test "the given default value is cast from user" do
custom_type = Class.new(Type::Value) do
- def type_cast_from_user(*)
+ def cast(*)
"from user"
end
- def type_cast_from_database(*)
+ def deserialize(*)
"from database"
end
end
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index ef1173a2ba..76907c832f 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -1427,7 +1427,7 @@ class BasicsTest < ActiveRecord::TestCase
attrs.delete 'id'
typecast = Class.new(ActiveRecord::Type::Value) {
- def type_cast value
+ def cast value
"t.lo"
end
}
diff --git a/activerecord/test/cases/batches_test.rb b/activerecord/test/cases/batches_test.rb
index c05382598b..9e428098e4 100644
--- a/activerecord/test/cases/batches_test.rb
+++ b/activerecord/test/cases/batches_test.rb
@@ -37,9 +37,9 @@ class EachTest < ActiveRecord::TestCase
if Enumerator.method_defined? :size
def test_each_should_return_a_sized_enumerator
- assert_equal 11, Post.find_each(:batch_size => 1).size
- assert_equal 5, Post.find_each(:batch_size => 2, :start => 7).size
- assert_equal 11, Post.find_each(:batch_size => 10_000).size
+ assert_equal 11, Post.find_each(batch_size: 1).size
+ assert_equal 5, Post.find_each(batch_size: 2, begin_at: 7).size
+ assert_equal 11, Post.find_each(batch_size: 10_000).size
end
end
@@ -99,7 +99,7 @@ class EachTest < ActiveRecord::TestCase
def test_find_in_batches_should_start_from_the_start_option
assert_queries(@total) do
- Post.find_in_batches(:batch_size => 1, :start => 2) do |batch|
+ Post.find_in_batches(batch_size: 1, begin_at: 2) do |batch|
assert_kind_of Array, batch
assert_kind_of Post, batch.first
end
@@ -172,7 +172,7 @@ class EachTest < ActiveRecord::TestCase
def test_find_in_batches_should_not_modify_passed_options
assert_nothing_raised do
- Post.find_in_batches({ batch_size: 42, start: 1 }.freeze){}
+ Post.find_in_batches({ batch_size: 42, begin_at: 1 }.freeze){}
end
end
@@ -181,7 +181,7 @@ class EachTest < ActiveRecord::TestCase
start_nick = nick_order_subscribers.second.nick
subscribers = []
- Subscriber.find_in_batches(:batch_size => 1, :start => start_nick) do |batch|
+ Subscriber.find_in_batches(batch_size: 1, begin_at: start_nick) do |batch|
subscribers.concat(batch)
end
@@ -209,11 +209,32 @@ class EachTest < ActiveRecord::TestCase
end
end
+ def test_find_in_batches_start_deprecated
+ assert_deprecated do
+ assert_queries(@total) do
+ Post.find_in_batches(batch_size: 1, start: 2) do |batch|
+ assert_kind_of Array, batch
+ assert_kind_of Post, batch.first
+ end
+ end
+ end
+ end
+
+ def test_find_each_start_deprecated
+ assert_deprecated do
+ assert_queries(@total) do
+ Post.find_each(batch_size: 1, start: 2) do |post|
+ assert_kind_of Post, post
+ end
+ end
+ end
+ end
+
if Enumerator.method_defined? :size
def test_find_in_batches_should_return_a_sized_enumerator
assert_equal 11, Post.find_in_batches(:batch_size => 1).size
assert_equal 6, Post.find_in_batches(:batch_size => 2).size
- assert_equal 4, Post.find_in_batches(:batch_size => 2, :start => 4).size
+ assert_equal 4, Post.find_in_batches(batch_size: 2, begin_at: 4).size
assert_equal 4, Post.find_in_batches(:batch_size => 3).size
assert_equal 1, Post.find_in_batches(:batch_size => 10_000).size
end
diff --git a/activerecord/test/cases/connection_adapters/type_lookup_test.rb b/activerecord/test/cases/connection_adapters/type_lookup_test.rb
index ac2e0053b8..05c57985a1 100644
--- a/activerecord/test/cases/connection_adapters/type_lookup_test.rb
+++ b/activerecord/test/cases/connection_adapters/type_lookup_test.rb
@@ -90,7 +90,7 @@ module ActiveRecord
cast_type = @connection.type_map.lookup(type)
assert_equal :decimal, cast_type.type
- assert_equal 2, cast_type.type_cast_from_user(2.1)
+ assert_equal 2, cast_type.cast(2.1)
end
end
diff --git a/activerecord/test/cases/date_time_precision_test.rb b/activerecord/test/cases/date_time_precision_test.rb
index 720f10a9d3..4602ba6d0d 100644
--- a/activerecord/test/cases/date_time_precision_test.rb
+++ b/activerecord/test/cases/date_time_precision_test.rb
@@ -1,7 +1,7 @@
require 'cases/helper'
require 'support/schema_dumping_helper'
-if ActiveRecord::Base.connection.supports_datetime_with_precision?
+if mysql_56? || current_adapter?(:PostgreSQLAdapter)
class DateTimePrecisionTest < ActiveRecord::TestCase
include SchemaDumpingHelper
self.use_transactional_fixtures = false
diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb
index c2573ac72b..3a7cc572e6 100644
--- a/activerecord/test/cases/dirty_test.rb
+++ b/activerecord/test/cases/dirty_test.rb
@@ -623,13 +623,13 @@ class DirtyTest < ActiveRecord::TestCase
end
end
- test "defaults with type that implements `type_cast_for_database`" do
+ test "defaults with type that implements `serialize`" do
type = Class.new(ActiveRecord::Type::Value) do
- def type_cast(value)
+ def cast(value)
value.to_i
end
- def type_cast_for_database(value)
+ def serialize(value)
value.to_s
end
end
diff --git a/activerecord/test/cases/enum_test.rb b/activerecord/test/cases/enum_test.rb
index ed568413a2..e70d492efd 100644
--- a/activerecord/test/cases/enum_test.rb
+++ b/activerecord/test/cases/enum_test.rb
@@ -26,15 +26,47 @@ class EnumTest < ActiveRecord::TestCase
assert_equal @book, Book.unread.first
end
- test "build from scope" do
- assert Book.proposed.build.proposed?
- refute Book.proposed.build.written?
- assert Book.where(status: Book.statuses[:proposed]).build.proposed?
+ test "find via where with values" do
+ proposed, written = Book.statuses[:proposed], Book.statuses[:written]
+
+ assert_equal @book, Book.where(status: proposed).first
+ refute_equal @book, Book.where(status: written).first
+ assert_equal @book, Book.where(status: [proposed]).first
+ refute_equal @book, Book.where(status: [written]).first
+ refute_equal @book, Book.where("status <> ?", proposed).first
+ assert_equal @book, Book.where("status <> ?", written).first
+ end
+
+ test "find via where with symbols" do
+ assert_equal @book, Book.where(status: :proposed).first
+ refute_equal @book, Book.where(status: :written).first
+ assert_equal @book, Book.where(status: [:proposed]).first
+ refute_equal @book, Book.where(status: [:written]).first
+ refute_equal @book, Book.where.not(status: :proposed).first
+ assert_equal @book, Book.where.not(status: :written).first
end
- test "find via where" do
+ test "find via where with strings" do
assert_equal @book, Book.where(status: "proposed").first
refute_equal @book, Book.where(status: "written").first
+ assert_equal @book, Book.where(status: ["proposed"]).first
+ refute_equal @book, Book.where(status: ["written"]).first
+ refute_equal @book, Book.where.not(status: "proposed").first
+ assert_equal @book, Book.where.not(status: "written").first
+ end
+
+ test "build from scope" do
+ assert Book.written.build.written?
+ refute Book.written.build.proposed?
+ end
+
+ test "build from where" do
+ assert Book.where(status: Book.statuses[:written]).build.written?
+ refute Book.where(status: Book.statuses[:written]).build.proposed?
+ assert Book.where(status: :written).build.written?
+ refute Book.where(status: :written).build.proposed?
+ assert Book.where(status: "written").build.written?
+ refute Book.where(status: "written").build.proposed?
end
test "update by declaration" do
@@ -140,19 +172,24 @@ class EnumTest < ActiveRecord::TestCase
assert_equal "'unknown' is not a valid status", e.message
end
+ test "NULL values from database should be casted to nil" do
+ Book.where(id: @book.id).update_all("status = NULL")
+ assert_nil @book.reload.status
+ end
+
test "assign nil value" do
@book.status = nil
- assert @book.status.nil?
+ assert_nil @book.status
end
test "assign empty string value" do
@book.status = ''
- assert @book.status.nil?
+ assert_nil @book.status
end
test "assign long empty string value" do
@book.status = ' '
- assert @book.status.nil?
+ assert_nil @book.status
end
test "constant to access the mapping" do
diff --git a/activerecord/test/cases/migration/change_schema_test.rb b/activerecord/test/cases/migration/change_schema_test.rb
index 3cd4073a38..30c91dfdcb 100644
--- a/activerecord/test/cases/migration/change_schema_test.rb
+++ b/activerecord/test/cases/migration/change_schema_test.rb
@@ -68,8 +68,8 @@ module ActiveRecord
five = columns.detect { |c| c.name == "five" } unless mysql
assert_equal "hello", one.default
- assert_equal true, connection.lookup_cast_type_from_column(two).type_cast_from_database(two.default)
- assert_equal false, connection.lookup_cast_type_from_column(three).type_cast_from_database(three.default)
+ assert_equal true, connection.lookup_cast_type_from_column(two).deserialize(two.default)
+ assert_equal false, connection.lookup_cast_type_from_column(three).deserialize(three.default)
assert_equal '1', four.default
assert_equal "hello", five.default unless mysql
end
diff --git a/activerecord/test/cases/migration/columns_test.rb b/activerecord/test/cases/migration/columns_test.rb
index 6f65288ac0..e5ccfe0f91 100644
--- a/activerecord/test/cases/migration/columns_test.rb
+++ b/activerecord/test/cases/migration/columns_test.rb
@@ -196,7 +196,7 @@ module ActiveRecord
old_columns = connection.columns(TestModel.table_name)
assert old_columns.find { |c|
- default = connection.lookup_cast_type_from_column(c).type_cast_from_database(c.default)
+ default = connection.lookup_cast_type_from_column(c).deserialize(c.default)
c.name == 'approved' && c.type == :boolean && default == true
}
@@ -204,11 +204,11 @@ module ActiveRecord
new_columns = connection.columns(TestModel.table_name)
assert_not new_columns.find { |c|
- default = connection.lookup_cast_type_from_column(c).type_cast_from_database(c.default)
+ default = connection.lookup_cast_type_from_column(c).deserialize(c.default)
c.name == 'approved' and c.type == :boolean and default == true
}
assert new_columns.find { |c|
- default = connection.lookup_cast_type_from_column(c).type_cast_from_database(c.default)
+ default = connection.lookup_cast_type_from_column(c).deserialize(c.default)
c.name == 'approved' and c.type == :boolean and default == false
}
change_column :test_models, :approved, :boolean, :default => true
diff --git a/activerecord/test/cases/migration/foreign_key_test.rb b/activerecord/test/cases/migration/foreign_key_test.rb
index b2f2d077eb..7f4790bf3e 100644
--- a/activerecord/test/cases/migration/foreign_key_test.rb
+++ b/activerecord/test/cases/migration/foreign_key_test.rb
@@ -147,6 +147,27 @@ module ActiveRecord
assert_equal :nullify, fk.on_update
end
+ def test_foreign_key_exists
+ @connection.add_foreign_key :astronauts, :rockets
+
+ assert @connection.foreign_key_exists?(:astronauts, :rockets)
+ assert_not @connection.foreign_key_exists?(:astronauts, :stars)
+ end
+
+ def test_foreign_key_exists_by_column
+ @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id"
+
+ assert @connection.foreign_key_exists?(:astronauts, column: "rocket_id")
+ assert_not @connection.foreign_key_exists?(:astronauts, column: "star_id")
+ end
+
+ def test_foreign_key_exists_by_name
+ @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", name: "fancy_named_fk"
+
+ assert @connection.foreign_key_exists?(:astronauts, name: "fancy_named_fk")
+ assert_not @connection.foreign_key_exists?(:astronauts, name: "other_fancy_named_fk")
+ end
+
def test_remove_foreign_key_inferes_column
@connection.add_foreign_key :astronauts, :rockets
diff --git a/activerecord/test/cases/primary_keys_test.rb b/activerecord/test/cases/primary_keys_test.rb
index 4b668f84dd..b45fbf0143 100644
--- a/activerecord/test/cases/primary_keys_test.rb
+++ b/activerecord/test/cases/primary_keys_test.rb
@@ -260,7 +260,7 @@ if current_adapter?(:PostgreSQLAdapter, :MysqlAdapter, :Mysql2Adapter)
end
teardown do
- @connection.execute("DROP TABLE IF EXISTS widgets")
+ @connection.drop_table 'widgets', if_exists: true
end
test "primary key column type with bigserial" do
diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb
index b0e40c7145..67e9bef808 100644
--- a/activerecord/test/cases/reflection_test.rb
+++ b/activerecord/test/cases/reflection_test.rb
@@ -92,9 +92,9 @@ class ReflectionTest < ActiveRecord::TestCase
type = @first.type_for_attribute("attribute_that_doesnt_exist")
object = Object.new
- assert_equal object, type.type_cast_from_database(object)
- assert_equal object, type.type_cast_from_user(object)
- assert_equal object, type.type_cast_for_database(object)
+ assert_equal object, type.deserialize(object)
+ assert_equal object, type.cast(object)
+ assert_equal object, type.serialize(object)
end
def test_reflection_klass_for_nested_class_name
diff --git a/activerecord/test/cases/relation_test.rb b/activerecord/test/cases/relation_test.rb
index c9c05b75a6..9353be1ba7 100644
--- a/activerecord/test/cases/relation_test.rb
+++ b/activerecord/test/cases/relation_test.rb
@@ -254,12 +254,12 @@ module ActiveRecord
:string
end
- def type_cast_from_database(value)
+ def deserialize(value)
raise value unless value == "type cast for database"
"type cast from database"
end
- def type_cast_for_database(value)
+ def serialize(value)
raise value unless value == "value from user"
"type cast for database"
end
diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb
index bafc9fa81b..0413984729 100644
--- a/activerecord/test/cases/schema_dumper_test.rb
+++ b/activerecord/test/cases/schema_dumper_test.rb
@@ -362,7 +362,7 @@ class SchemaDumperDefaultsTest < ActiveRecord::TestCase
teardown do
return unless @connection
- @connection.execute 'DROP TABLE defaults' if @connection.table_exists? 'defaults'
+ @connection.drop_table 'defaults', if_exists: true
end
def test_schema_dump_defaults_with_universally_supported_types
diff --git a/activerecord/test/cases/secure_token_test.rb b/activerecord/test/cases/secure_token_test.rb
index 3f7455d12d..e731443fc2 100644
--- a/activerecord/test/cases/secure_token_test.rb
+++ b/activerecord/test/cases/secure_token_test.rb
@@ -22,4 +22,11 @@ class SecureTokenTest < ActiveRecord::TestCase
assert_not_equal @user.token, old_token
assert_not_equal @user.auth_token, old_auth_token
end
+
+ def test_token_value_not_overwritten_when_present
+ @user.token = "custom-secure-token"
+ @user.save
+
+ assert_equal @user.token, "custom-secure-token"
+ end
end
diff --git a/activerecord/test/cases/time_precision_test.rb b/activerecord/test/cases/time_precision_test.rb
deleted file mode 100644
index 23422fd50a..0000000000
--- a/activerecord/test/cases/time_precision_test.rb
+++ /dev/null
@@ -1,65 +0,0 @@
-require 'cases/helper'
-
-if ActiveRecord::Base.connection.supports_datetime_with_precision?
-class TimePrecisionTest < ActiveRecord::TestCase
- setup do
- @connection = ActiveRecord::Base.connection
- end
-
- teardown do
- @connection.drop_table :foos, if_exists: true
- end
-
- def test_time_data_type_with_precision
- @connection.create_table(:foos, force: true)
- @connection.add_column :foos, :start, :time, precision: 3
- @connection.add_column :foos, :finish, :time, precision: 6
- assert_equal 3, activerecord_column_option('foos', 'start', 'precision')
- assert_equal 6, activerecord_column_option('foos', 'finish', 'precision')
- end
-
- def test_passing_precision_to_time_does_not_set_limit
- @connection.create_table(:foos, force: true) do |t|
- t.time :start, precision: 3
- t.time :finish, precision: 6
- end
- assert_nil activerecord_column_option('foos', 'start', 'limit')
- assert_nil activerecord_column_option('foos', 'finish', 'limit')
- end
-
- def test_invalid_time_precision_raises_error
- assert_raises ActiveRecord::ActiveRecordError do
- @connection.create_table(:foos, force: true) do |t|
- t.time :start, precision: 7
- t.time :finish, precision: 7
- end
- end
- end
-
- def test_database_agrees_with_activerecord_about_precision
- @connection.create_table(:foos, force: true) do |t|
- t.time :start, precision: 2
- t.time :finish, precision: 4
- end
- assert_equal 2, database_datetime_precision('foos', 'start')
- assert_equal 4, database_datetime_precision('foos', 'finish')
- end
-
- private
-
- def database_datetime_precision(table_name, column_name)
- results = @connection.exec_query("SELECT column_name, datetime_precision FROM information_schema.columns WHERE table_name = '#{table_name}'")
- result = results.find do |result_hash|
- result_hash["column_name"] == column_name
- end
- result && result["datetime_precision"].to_i
- end
-
- def activerecord_column_option(tablename, column_name, option)
- result = @connection.columns(tablename).find do |column|
- column.name == column_name
- end
- result && result.send(option)
- end
-end
-end
diff --git a/activerecord/test/cases/transactions_test.rb b/activerecord/test/cases/transactions_test.rb
index d1d8e71c34..88e595c39f 100644
--- a/activerecord/test/cases/transactions_test.rb
+++ b/activerecord/test/cases/transactions_test.rb
@@ -668,7 +668,7 @@ class TransactionTest < ActiveRecord::TestCase
end
end
ensure
- connection.execute("DROP TABLE IF EXISTS transaction_without_primary_keys")
+ connection.drop_table 'transaction_without_primary_keys', if_exists: true
end
private
diff --git a/activerecord/test/cases/type/adapter_specific_registry_test.rb b/activerecord/test/cases/type/adapter_specific_registry_test.rb
new file mode 100644
index 0000000000..8b836b4793
--- /dev/null
+++ b/activerecord/test/cases/type/adapter_specific_registry_test.rb
@@ -0,0 +1,133 @@
+require "cases/helper"
+
+module ActiveRecord
+ class AdapterSpecificRegistryTest < ActiveRecord::TestCase
+ test "a class can be registered for a symbol" do
+ registry = Type::AdapterSpecificRegistry.new
+ registry.register(:foo, ::String)
+ registry.register(:bar, ::Array)
+
+ assert_equal "", registry.lookup(:foo)
+ assert_equal [], registry.lookup(:bar)
+ end
+
+ test "a block can be registered" do
+ registry = Type::AdapterSpecificRegistry.new
+ registry.register(:foo) do |*args|
+ [*args, "block for foo"]
+ end
+ registry.register(:bar) do |*args|
+ [*args, "block for bar"]
+ end
+
+ assert_equal [:foo, 1, "block for foo"], registry.lookup(:foo, 1)
+ assert_equal [:foo, 2, "block for foo"], registry.lookup(:foo, 2)
+ assert_equal [:bar, 1, 2, 3, "block for bar"], registry.lookup(:bar, 1, 2, 3)
+ end
+
+ test "filtering by adapter" do
+ registry = Type::AdapterSpecificRegistry.new
+ registry.register(:foo, String, adapter: :sqlite3)
+ registry.register(:foo, Array, adapter: :postgresql)
+
+ assert_equal "", registry.lookup(:foo, adapter: :sqlite3)
+ assert_equal [], registry.lookup(:foo, adapter: :postgresql)
+ end
+
+ test "an error is raised if both a generic and adapter specific type match" do
+ registry = Type::AdapterSpecificRegistry.new
+ registry.register(:foo, String)
+ registry.register(:foo, Array, adapter: :postgresql)
+
+ assert_raises TypeConflictError do
+ registry.lookup(:foo, adapter: :postgresql)
+ end
+ assert_equal "", registry.lookup(:foo, adapter: :sqlite3)
+ end
+
+ test "a generic type can explicitly override an adapter specific type" do
+ registry = Type::AdapterSpecificRegistry.new
+ registry.register(:foo, String, override: true)
+ registry.register(:foo, Array, adapter: :postgresql)
+
+ assert_equal "", registry.lookup(:foo, adapter: :postgresql)
+ assert_equal "", registry.lookup(:foo, adapter: :sqlite3)
+ end
+
+ test "a generic type can explicitly allow an adapter type to be used instead" do
+ registry = Type::AdapterSpecificRegistry.new
+ registry.register(:foo, String, override: false)
+ registry.register(:foo, Array, adapter: :postgresql)
+
+ assert_equal [], registry.lookup(:foo, adapter: :postgresql)
+ assert_equal "", registry.lookup(:foo, adapter: :sqlite3)
+ end
+
+ test "a reasonable error is given when no type is found" do
+ registry = Type::AdapterSpecificRegistry.new
+
+ e = assert_raises(ArgumentError) do
+ registry.lookup(:foo)
+ end
+
+ assert_equal "Unknown type :foo", e.message
+ end
+
+ test "construct args are passed to the type" do
+ type = Struct.new(:args)
+ registry = Type::AdapterSpecificRegistry.new
+ registry.register(:foo, type)
+
+ assert_equal type.new, registry.lookup(:foo)
+ assert_equal type.new(:ordered_arg), registry.lookup(:foo, :ordered_arg)
+ assert_equal type.new(keyword: :arg), registry.lookup(:foo, keyword: :arg)
+ assert_equal type.new(keyword: :arg), registry.lookup(:foo, keyword: :arg, adapter: :postgresql)
+ end
+
+ test "registering a modifier" do
+ decoration = Struct.new(:value)
+ registry = Type::AdapterSpecificRegistry.new
+ registry.register(:foo, String)
+ registry.register(:bar, Hash)
+ registry.add_modifier({ array: true }, decoration)
+
+ assert_equal decoration.new(""), registry.lookup(:foo, array: true)
+ assert_equal decoration.new({}), registry.lookup(:bar, array: true)
+ assert_equal "", registry.lookup(:foo)
+ end
+
+ test "registering multiple modifiers" do
+ decoration = Struct.new(:value)
+ other_decoration = Struct.new(:value)
+ registry = Type::AdapterSpecificRegistry.new
+ registry.register(:foo, String)
+ registry.add_modifier({ array: true }, decoration)
+ registry.add_modifier({ range: true }, other_decoration)
+
+ assert_equal "", registry.lookup(:foo)
+ assert_equal decoration.new(""), registry.lookup(:foo, array: true)
+ assert_equal other_decoration.new(""), registry.lookup(:foo, range: true)
+ assert_equal(
+ decoration.new(other_decoration.new("")),
+ registry.lookup(:foo, array: true, range: true)
+ )
+ end
+
+ test "registering adapter specific modifiers" do
+ decoration = Struct.new(:value)
+ type = Struct.new(:args)
+ registry = Type::AdapterSpecificRegistry.new
+ registry.register(:foo, type)
+ registry.add_modifier({ array: true }, decoration, adapter: :postgresql)
+
+ assert_equal(
+ decoration.new(type.new(keyword: :arg)),
+ registry.lookup(:foo, array: true, adapter: :postgresql, keyword: :arg)
+ )
+ assert_equal(
+ type.new(array: true),
+ registry.lookup(:foo, array: true, adapter: :sqlite3)
+ )
+ end
+ end
+end
diff --git a/activerecord/test/cases/type/decimal_test.rb b/activerecord/test/cases/type/decimal_test.rb
index 34ed1d7b19..fe49d0e79a 100644
--- a/activerecord/test/cases/type/decimal_test.rb
+++ b/activerecord/test/cases/type/decimal_test.rb
@@ -5,29 +5,29 @@ module ActiveRecord
class DecimalTest < ActiveRecord::TestCase
def test_type_cast_decimal
type = Decimal.new
- assert_equal BigDecimal.new("0"), type.type_cast_from_user(BigDecimal.new("0"))
- assert_equal BigDecimal.new("123"), type.type_cast_from_user(123.0)
- assert_equal BigDecimal.new("1"), type.type_cast_from_user(:"1")
+ assert_equal BigDecimal.new("0"), type.cast(BigDecimal.new("0"))
+ assert_equal BigDecimal.new("123"), type.cast(123.0)
+ assert_equal BigDecimal.new("1"), type.cast(:"1")
end
def test_type_cast_decimal_from_float_with_large_precision
type = Decimal.new(precision: ::Float::DIG + 2)
- assert_equal BigDecimal.new("123.0"), type.type_cast_from_user(123.0)
+ assert_equal BigDecimal.new("123.0"), type.cast(123.0)
end
def test_type_cast_from_float_with_unspecified_precision
type = Decimal.new
- assert_equal 22.68.to_d, type.type_cast_from_user(22.68)
+ assert_equal 22.68.to_d, type.cast(22.68)
end
def test_type_cast_decimal_from_rational_with_precision
type = Decimal.new(precision: 2)
- assert_equal BigDecimal("0.33"), type.type_cast_from_user(Rational(1, 3))
+ assert_equal BigDecimal("0.33"), type.cast(Rational(1, 3))
end
def test_type_cast_decimal_from_rational_without_precision_defaults_to_18_36
type = Decimal.new
- assert_equal BigDecimal("0.333333333333333333E0"), type.type_cast_from_user(Rational(1, 3))
+ assert_equal BigDecimal("0.333333333333333333E0"), type.cast(Rational(1, 3))
end
def test_type_cast_decimal_from_object_responding_to_d
@@ -36,7 +36,7 @@ module ActiveRecord
BigDecimal.new("1")
end
type = Decimal.new
- assert_equal BigDecimal("1"), type.type_cast_from_user(value)
+ assert_equal BigDecimal("1"), type.cast(value)
end
def test_changed?
diff --git a/activerecord/test/cases/type/integer_test.rb b/activerecord/test/cases/type/integer_test.rb
index 1e836f2142..84fb05dd8e 100644
--- a/activerecord/test/cases/type/integer_test.rb
+++ b/activerecord/test/cases/type/integer_test.rb
@@ -6,45 +6,45 @@ module ActiveRecord
class IntegerTest < ActiveRecord::TestCase
test "simple values" do
type = Type::Integer.new
- assert_equal 1, type.type_cast_from_user(1)
- assert_equal 1, type.type_cast_from_user('1')
- assert_equal 1, type.type_cast_from_user('1ignore')
- assert_equal 0, type.type_cast_from_user('bad1')
- assert_equal 0, type.type_cast_from_user('bad')
- assert_equal 1, type.type_cast_from_user(1.7)
- assert_equal 0, type.type_cast_from_user(false)
- assert_equal 1, type.type_cast_from_user(true)
- assert_nil type.type_cast_from_user(nil)
+ assert_equal 1, type.cast(1)
+ assert_equal 1, type.cast('1')
+ assert_equal 1, type.cast('1ignore')
+ assert_equal 0, type.cast('bad1')
+ assert_equal 0, type.cast('bad')
+ assert_equal 1, type.cast(1.7)
+ assert_equal 0, type.cast(false)
+ assert_equal 1, type.cast(true)
+ assert_nil type.cast(nil)
end
test "random objects cast to nil" do
type = Type::Integer.new
- assert_nil type.type_cast_from_user([1,2])
- assert_nil type.type_cast_from_user({1 => 2})
- assert_nil type.type_cast_from_user((1..2))
+ assert_nil type.cast([1,2])
+ assert_nil type.cast({1 => 2})
+ assert_nil type.cast((1..2))
end
test "casting ActiveRecord models" do
type = Type::Integer.new
firm = Firm.create(:name => 'Apple')
- assert_nil type.type_cast_from_user(firm)
+ assert_nil type.cast(firm)
end
test "casting objects without to_i" do
type = Type::Integer.new
- assert_nil type.type_cast_from_user(::Object.new)
+ assert_nil type.cast(::Object.new)
end
test "casting nan and infinity" do
type = Type::Integer.new
- assert_nil type.type_cast_from_user(::Float::NAN)
- assert_nil type.type_cast_from_user(1.0/0.0)
+ assert_nil type.cast(::Float::NAN)
+ assert_nil type.cast(1.0/0.0)
end
test "casting booleans for database" do
type = Type::Integer.new
- assert_equal 1, type.type_cast_for_database(true)
- assert_equal 0, type.type_cast_for_database(false)
+ assert_equal 1, type.serialize(true)
+ assert_equal 0, type.serialize(false)
end
test "changed?" do
@@ -60,53 +60,53 @@ module ActiveRecord
test "values below int min value are out of range" do
assert_raises(::RangeError) do
- Integer.new.type_cast_for_database(-2147483649)
+ Integer.new.serialize(-2147483649)
end
end
test "values above int max value are out of range" do
assert_raises(::RangeError) do
- Integer.new.type_cast_for_database(2147483648)
+ Integer.new.serialize(2147483648)
end
end
test "very small numbers are out of range" do
assert_raises(::RangeError) do
- Integer.new.type_cast_for_database(-9999999999999999999999999999999)
+ Integer.new.serialize(-9999999999999999999999999999999)
end
end
test "very large numbers are out of range" do
assert_raises(::RangeError) do
- Integer.new.type_cast_for_database(9999999999999999999999999999999)
+ Integer.new.serialize(9999999999999999999999999999999)
end
end
test "normal numbers are in range" do
type = Integer.new
- assert_equal(0, type.type_cast_for_database(0))
- assert_equal(-1, type.type_cast_for_database(-1))
- assert_equal(1, type.type_cast_for_database(1))
+ assert_equal(0, type.serialize(0))
+ assert_equal(-1, type.serialize(-1))
+ assert_equal(1, type.serialize(1))
end
test "int max value is in range" do
- assert_equal(2147483647, Integer.new.type_cast_for_database(2147483647))
+ assert_equal(2147483647, Integer.new.serialize(2147483647))
end
test "int min value is in range" do
- assert_equal(-2147483648, Integer.new.type_cast_for_database(-2147483648))
+ assert_equal(-2147483648, Integer.new.serialize(-2147483648))
end
test "columns with a larger limit have larger ranges" do
type = Integer.new(limit: 8)
- assert_equal(9223372036854775807, type.type_cast_for_database(9223372036854775807))
- assert_equal(-9223372036854775808, type.type_cast_for_database(-9223372036854775808))
+ assert_equal(9223372036854775807, type.serialize(9223372036854775807))
+ assert_equal(-9223372036854775808, type.serialize(-9223372036854775808))
assert_raises(::RangeError) do
- type.type_cast_for_database(-9999999999999999999999999999999)
+ type.serialize(-9999999999999999999999999999999)
end
assert_raises(::RangeError) do
- type.type_cast_for_database(9999999999999999999999999999999)
+ type.serialize(9999999999999999999999999999999)
end
end
diff --git a/activerecord/test/cases/type/string_test.rb b/activerecord/test/cases/type/string_test.rb
index 4d78f287f1..56e9bf434d 100644
--- a/activerecord/test/cases/type/string_test.rb
+++ b/activerecord/test/cases/type/string_test.rb
@@ -4,16 +4,16 @@ module ActiveRecord
class StringTypeTest < ActiveRecord::TestCase
test "type casting" do
type = Type::String.new
- assert_equal "t", type.type_cast_from_user(true)
- assert_equal "f", type.type_cast_from_user(false)
- assert_equal "123", type.type_cast_from_user(123)
+ assert_equal "t", type.cast(true)
+ assert_equal "f", type.cast(false)
+ assert_equal "123", type.cast(123)
end
test "values are duped coming out" do
s = "foo"
type = Type::String.new
- assert_not_same s, type.type_cast_from_user(s)
- assert_not_same s, type.type_cast_from_database(s)
+ assert_not_same s, type.cast(s)
+ assert_not_same s, type.deserialize(s)
end
test "string mutations are detected" do
diff --git a/activerecord/test/cases/type/unsigned_integer_test.rb b/activerecord/test/cases/type/unsigned_integer_test.rb
index 4b8e2fb518..f2c910eade 100644
--- a/activerecord/test/cases/type/unsigned_integer_test.rb
+++ b/activerecord/test/cases/type/unsigned_integer_test.rb
@@ -4,12 +4,12 @@ module ActiveRecord
module Type
class UnsignedIntegerTest < ActiveRecord::TestCase
test "unsigned int max value is in range" do
- assert_equal(4294967295, UnsignedInteger.new.type_cast_for_database(4294967295))
+ assert_equal(4294967295, UnsignedInteger.new.serialize(4294967295))
end
test "minus value is out of range" do
assert_raises(::RangeError) do
- UnsignedInteger.new.type_cast_for_database(-1)
+ UnsignedInteger.new.serialize(-1)
end
end
end
diff --git a/activerecord/test/cases/type_test.rb b/activerecord/test/cases/type_test.rb
new file mode 100644
index 0000000000..d45a9b3141
--- /dev/null
+++ b/activerecord/test/cases/type_test.rb
@@ -0,0 +1,39 @@
+require "cases/helper"
+
+class TypeTest < ActiveRecord::TestCase
+ setup do
+ @old_registry = ActiveRecord::Type.registry
+ ActiveRecord::Type.registry = ActiveRecord::Type::AdapterSpecificRegistry.new
+ end
+
+ teardown do
+ ActiveRecord::Type.registry = @old_registry
+ end
+
+ test "registering a new type" do
+ type = Struct.new(:args)
+ ActiveRecord::Type.register(:foo, type)
+
+ assert_equal type.new(:arg), ActiveRecord::Type.lookup(:foo, :arg)
+ end
+
+ test "looking up a type for a specific adapter" do
+ type = Struct.new(:args)
+ pgtype = Struct.new(:args)
+ ActiveRecord::Type.register(:foo, type, override: false)
+ ActiveRecord::Type.register(:foo, pgtype, adapter: :postgresql)
+
+ assert_equal type.new, ActiveRecord::Type.lookup(:foo, adapter: :sqlite)
+ assert_equal pgtype.new, ActiveRecord::Type.lookup(:foo, adapter: :postgresql)
+ end
+
+ test "lookup defaults to the current adapter" do
+ current_adapter = ActiveRecord::Base.connection.adapter_name.downcase.to_sym
+ type = Struct.new(:args)
+ adapter_type = Struct.new(:args)
+ ActiveRecord::Type.register(:foo, type, override: false)
+ ActiveRecord::Type.register(:foo, adapter_type, adapter: current_adapter)
+
+ assert_equal adapter_type.new, ActiveRecord::Type.lookup(:foo)
+ end
+end
diff --git a/activerecord/test/cases/types_test.rb b/activerecord/test/cases/types_test.rb
index 34b6f2e8a5..9b1859c2ce 100644
--- a/activerecord/test/cases/types_test.rb
+++ b/activerecord/test/cases/types_test.rb
@@ -5,38 +5,38 @@ module ActiveRecord
class TypesTest < ActiveRecord::TestCase
def test_type_cast_boolean
type = Type::Boolean.new
- assert type.type_cast_from_user('').nil?
- assert type.type_cast_from_user(nil).nil?
-
- assert type.type_cast_from_user(true)
- assert type.type_cast_from_user(1)
- assert type.type_cast_from_user('1')
- assert type.type_cast_from_user('t')
- assert type.type_cast_from_user('T')
- assert type.type_cast_from_user('true')
- assert type.type_cast_from_user('TRUE')
- assert type.type_cast_from_user('on')
- assert type.type_cast_from_user('ON')
- assert type.type_cast_from_user(' ')
- assert type.type_cast_from_user("\u3000\r\n")
- assert type.type_cast_from_user("\u0000")
- assert type.type_cast_from_user('SOMETHING RANDOM')
+ assert type.cast('').nil?
+ assert type.cast(nil).nil?
+
+ assert type.cast(true)
+ assert type.cast(1)
+ assert type.cast('1')
+ assert type.cast('t')
+ assert type.cast('T')
+ assert type.cast('true')
+ assert type.cast('TRUE')
+ assert type.cast('on')
+ assert type.cast('ON')
+ assert type.cast(' ')
+ assert type.cast("\u3000\r\n")
+ assert type.cast("\u0000")
+ assert type.cast('SOMETHING RANDOM')
# explicitly check for false vs nil
- assert_equal false, type.type_cast_from_user(false)
- assert_equal false, type.type_cast_from_user(0)
- assert_equal false, type.type_cast_from_user('0')
- assert_equal false, type.type_cast_from_user('f')
- assert_equal false, type.type_cast_from_user('F')
- assert_equal false, type.type_cast_from_user('false')
- assert_equal false, type.type_cast_from_user('FALSE')
- assert_equal false, type.type_cast_from_user('off')
- assert_equal false, type.type_cast_from_user('OFF')
+ assert_equal false, type.cast(false)
+ assert_equal false, type.cast(0)
+ assert_equal false, type.cast('0')
+ assert_equal false, type.cast('f')
+ assert_equal false, type.cast('F')
+ assert_equal false, type.cast('false')
+ assert_equal false, type.cast('FALSE')
+ assert_equal false, type.cast('off')
+ assert_equal false, type.cast('OFF')
end
def test_type_cast_float
type = Type::Float.new
- assert_equal 1.0, type.type_cast_from_user("1")
+ assert_equal 1.0, type.cast("1")
end
def test_changing_float
@@ -50,54 +50,54 @@ module ActiveRecord
def test_type_cast_binary
type = Type::Binary.new
- assert_equal nil, type.type_cast_from_user(nil)
- assert_equal "1", type.type_cast_from_user("1")
- assert_equal 1, type.type_cast_from_user(1)
+ assert_equal nil, type.cast(nil)
+ assert_equal "1", type.cast("1")
+ assert_equal 1, type.cast(1)
end
def test_type_cast_time
type = Type::Time.new
- assert_equal nil, type.type_cast_from_user(nil)
- assert_equal nil, type.type_cast_from_user('')
- assert_equal nil, type.type_cast_from_user('ABC')
+ assert_equal nil, type.cast(nil)
+ assert_equal nil, type.cast('')
+ assert_equal nil, type.cast('ABC')
time_string = Time.now.utc.strftime("%T")
- assert_equal time_string, type.type_cast_from_user(time_string).strftime("%T")
+ assert_equal time_string, type.cast(time_string).strftime("%T")
end
def test_type_cast_datetime_and_timestamp
type = Type::DateTime.new
- assert_equal nil, type.type_cast_from_user(nil)
- assert_equal nil, type.type_cast_from_user('')
- assert_equal nil, type.type_cast_from_user(' ')
- assert_equal nil, type.type_cast_from_user('ABC')
+ assert_equal nil, type.cast(nil)
+ assert_equal nil, type.cast('')
+ assert_equal nil, type.cast(' ')
+ assert_equal nil, type.cast('ABC')
datetime_string = Time.now.utc.strftime("%FT%T")
- assert_equal datetime_string, type.type_cast_from_user(datetime_string).strftime("%FT%T")
+ assert_equal datetime_string, type.cast(datetime_string).strftime("%FT%T")
end
def test_type_cast_date
type = Type::Date.new
- assert_equal nil, type.type_cast_from_user(nil)
- assert_equal nil, type.type_cast_from_user('')
- assert_equal nil, type.type_cast_from_user(' ')
- assert_equal nil, type.type_cast_from_user('ABC')
+ assert_equal nil, type.cast(nil)
+ assert_equal nil, type.cast('')
+ assert_equal nil, type.cast(' ')
+ assert_equal nil, type.cast('ABC')
date_string = Time.now.utc.strftime("%F")
- assert_equal date_string, type.type_cast_from_user(date_string).strftime("%F")
+ assert_equal date_string, type.cast(date_string).strftime("%F")
end
def test_type_cast_duration_to_integer
type = Type::Integer.new
- assert_equal 1800, type.type_cast_from_user(30.minutes)
- assert_equal 7200, type.type_cast_from_user(2.hours)
+ assert_equal 1800, type.cast(30.minutes)
+ assert_equal 7200, type.cast(2.hours)
end
def test_string_to_time_with_timezone
[:utc, :local].each do |zone|
with_timezone_config default: zone do
type = Type::DateTime.new
- assert_equal Time.utc(2013, 9, 4, 0, 0, 0), type.type_cast_from_user("Wed, 04 Sep 2013 03:00:00 EAT")
+ assert_equal Time.utc(2013, 9, 4, 0, 0, 0), type.cast("Wed, 04 Sep 2013 03:00:00 EAT")
end
end
end
@@ -110,7 +110,7 @@ module ActiveRecord
def test_attributes_which_are_invalid_for_database_can_still_be_reassigned
type_which_cannot_go_to_the_database = Type::Value.new
- def type_which_cannot_go_to_the_database.type_cast_for_database(*)
+ def type_which_cannot_go_to_the_database.serialize(*)
raise
end
klass = Class.new(ActiveRecord::Base) do
diff --git a/activerecord/test/migrations/missing/1000_people_have_middle_names.rb b/activerecord/test/migrations/missing/1000_people_have_middle_names.rb
index 9fd495b97c..4b83d61beb 100644
--- a/activerecord/test/migrations/missing/1000_people_have_middle_names.rb
+++ b/activerecord/test/migrations/missing/1000_people_have_middle_names.rb
@@ -6,4 +6,4 @@ class PeopleHaveMiddleNames < ActiveRecord::Migration
def self.down
remove_column "people", "middle_name"
end
-end \ No newline at end of file
+end
diff --git a/activerecord/test/migrations/missing/1_people_have_last_names.rb b/activerecord/test/migrations/missing/1_people_have_last_names.rb
index 81af5fef5e..68209f3ce9 100644
--- a/activerecord/test/migrations/missing/1_people_have_last_names.rb
+++ b/activerecord/test/migrations/missing/1_people_have_last_names.rb
@@ -6,4 +6,4 @@ class PeopleHaveLastNames < ActiveRecord::Migration
def self.down
remove_column "people", "last_name"
end
-end \ No newline at end of file
+end
diff --git a/activerecord/test/migrations/missing/3_we_need_reminders.rb b/activerecord/test/migrations/missing/3_we_need_reminders.rb
index d5e71ce8ef..25bb49cb32 100644
--- a/activerecord/test/migrations/missing/3_we_need_reminders.rb
+++ b/activerecord/test/migrations/missing/3_we_need_reminders.rb
@@ -9,4 +9,4 @@ class WeNeedReminders < ActiveRecord::Migration
def self.down
drop_table "reminders"
end
-end \ No newline at end of file
+end
diff --git a/activerecord/test/migrations/missing/4_innocent_jointable.rb b/activerecord/test/migrations/missing/4_innocent_jointable.rb
index 21c9ca5328..002a1bf2a6 100644
--- a/activerecord/test/migrations/missing/4_innocent_jointable.rb
+++ b/activerecord/test/migrations/missing/4_innocent_jointable.rb
@@ -9,4 +9,4 @@ class InnocentJointable < ActiveRecord::Migration
def self.down
drop_table "people_reminders"
end
-end \ No newline at end of file
+end
diff --git a/activerecord/test/migrations/rename/1_we_need_things.rb b/activerecord/test/migrations/rename/1_we_need_things.rb
index cdbe0b1679..f5484ac54f 100644
--- a/activerecord/test/migrations/rename/1_we_need_things.rb
+++ b/activerecord/test/migrations/rename/1_we_need_things.rb
@@ -8,4 +8,4 @@ class WeNeedThings < ActiveRecord::Migration
def self.down
drop_table "things"
end
-end \ No newline at end of file
+end
diff --git a/activerecord/test/migrations/rename/2_rename_things.rb b/activerecord/test/migrations/rename/2_rename_things.rb
index d441b71fc9..533a113ea8 100644
--- a/activerecord/test/migrations/rename/2_rename_things.rb
+++ b/activerecord/test/migrations/rename/2_rename_things.rb
@@ -6,4 +6,4 @@ class RenameThings < ActiveRecord::Migration
def self.down
rename_table "awesome_things", "things"
end
-end \ No newline at end of file
+end
diff --git a/activerecord/test/migrations/valid/2_we_need_reminders.rb b/activerecord/test/migrations/valid/2_we_need_reminders.rb
index d5e71ce8ef..25bb49cb32 100644
--- a/activerecord/test/migrations/valid/2_we_need_reminders.rb
+++ b/activerecord/test/migrations/valid/2_we_need_reminders.rb
@@ -9,4 +9,4 @@ class WeNeedReminders < ActiveRecord::Migration
def self.down
drop_table "reminders"
end
-end \ No newline at end of file
+end
diff --git a/activerecord/test/migrations/valid/3_innocent_jointable.rb b/activerecord/test/migrations/valid/3_innocent_jointable.rb
index 21c9ca5328..002a1bf2a6 100644
--- a/activerecord/test/migrations/valid/3_innocent_jointable.rb
+++ b/activerecord/test/migrations/valid/3_innocent_jointable.rb
@@ -9,4 +9,4 @@ class InnocentJointable < ActiveRecord::Migration
def self.down
drop_table "people_reminders"
end
-end \ No newline at end of file
+end
diff --git a/activerecord/test/migrations/valid_with_subdirectories/sub/2_we_need_reminders.rb b/activerecord/test/migrations/valid_with_subdirectories/sub/2_we_need_reminders.rb
index d5e71ce8ef..25bb49cb32 100644
--- a/activerecord/test/migrations/valid_with_subdirectories/sub/2_we_need_reminders.rb
+++ b/activerecord/test/migrations/valid_with_subdirectories/sub/2_we_need_reminders.rb
@@ -9,4 +9,4 @@ class WeNeedReminders < ActiveRecord::Migration
def self.down
drop_table "reminders"
end
-end \ No newline at end of file
+end
diff --git a/activerecord/test/migrations/valid_with_subdirectories/sub1/3_innocent_jointable.rb b/activerecord/test/migrations/valid_with_subdirectories/sub1/3_innocent_jointable.rb
index 21c9ca5328..002a1bf2a6 100644
--- a/activerecord/test/migrations/valid_with_subdirectories/sub1/3_innocent_jointable.rb
+++ b/activerecord/test/migrations/valid_with_subdirectories/sub1/3_innocent_jointable.rb
@@ -9,4 +9,4 @@ class InnocentJointable < ActiveRecord::Migration
def self.down
drop_table "people_reminders"
end
-end \ No newline at end of file
+end
diff --git a/activerecord/test/models/admin.rb b/activerecord/test/models/admin.rb
index 00e69fbed8..a38e3f4846 100644
--- a/activerecord/test/models/admin.rb
+++ b/activerecord/test/models/admin.rb
@@ -2,4 +2,4 @@ module Admin
def self.table_name_prefix
'admin_'
end
-end \ No newline at end of file
+end
diff --git a/activerecord/test/models/admin/account.rb b/activerecord/test/models/admin/account.rb
index 46de28aae1..bd23192d20 100644
--- a/activerecord/test/models/admin/account.rb
+++ b/activerecord/test/models/admin/account.rb
@@ -1,3 +1,3 @@
class Admin::Account < ActiveRecord::Base
has_many :users
-end \ No newline at end of file
+end
diff --git a/activerecord/test/models/binary.rb b/activerecord/test/models/binary.rb
index 950c459199..39b2f5090a 100644
--- a/activerecord/test/models/binary.rb
+++ b/activerecord/test/models/binary.rb
@@ -1,2 +1,2 @@
class Binary < ActiveRecord::Base
-end \ No newline at end of file
+end
diff --git a/activerecord/test/models/event.rb b/activerecord/test/models/event.rb
index 99fa0feeb7..365ab32b0b 100644
--- a/activerecord/test/models/event.rb
+++ b/activerecord/test/models/event.rb
@@ -1,3 +1,3 @@
class Event < ActiveRecord::Base
validates_uniqueness_of :title
-end \ No newline at end of file
+end
diff --git a/activerecord/test/models/guid.rb b/activerecord/test/models/guid.rb
index 9208dc28fa..05653ba498 100644
--- a/activerecord/test/models/guid.rb
+++ b/activerecord/test/models/guid.rb
@@ -1,2 +1,2 @@
class Guid < ActiveRecord::Base
-end \ No newline at end of file
+end
diff --git a/activerecord/test/models/pirate.rb b/activerecord/test/models/pirate.rb
index 366c70f902..30545bdcd7 100644
--- a/activerecord/test/models/pirate.rb
+++ b/activerecord/test/models/pirate.rb
@@ -89,4 +89,4 @@ class FamousPirate < ActiveRecord::Base
self.table_name = 'pirates'
has_many :famous_ships
validates_presence_of :catchphrase, on: :conference
-end \ No newline at end of file
+end
diff --git a/activerecord/test/schema/postgresql_specific_schema.rb b/activerecord/test/schema/postgresql_specific_schema.rb
index 55360b9aa2..77d2f7fda2 100644
--- a/activerecord/test/schema/postgresql_specific_schema.rb
+++ b/activerecord/test/schema/postgresql_specific_schema.rb
@@ -2,7 +2,7 @@ ActiveRecord::Schema.define do
%w(postgresql_times postgresql_oids defaults postgresql_timestamp_with_zones
postgresql_partitioned_table postgresql_partitioned_table_parent).each do |table_name|
- execute "DROP TABLE IF EXISTS #{quote_table_name table_name}"
+ drop_table table_name, if_exists: true
end
execute 'DROP SEQUENCE IF EXISTS companies_nonstd_seq CASCADE'
diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb
index 51cf468d2b..f32bb8a0cc 100644
--- a/activesupport/lib/active_support/callbacks.rb
+++ b/activesupport/lib/active_support/callbacks.rb
@@ -741,8 +741,8 @@ module ActiveSupport
#
# * <tt>:skip_after_callbacks_if_terminated</tt> - Determines if after
# callbacks should be terminated by the <tt>:terminator</tt> option. By
- # default after callbacks executed no matter if callback chain was
- # terminated or not. Option makes sense only when <tt>:terminator</tt>
+ # default after callbacks are executed no matter if callback chain was
+ # terminated or not. This option makes sense only when <tt>:terminator</tt>
# option is specified.
#
# * <tt>:scope</tt> - Indicates which methods should be executed when an
diff --git a/guides/CHANGELOG.md b/guides/CHANGELOG.md
index 99d69d5eda..dd5ca4b395 100644
--- a/guides/CHANGELOG.md
+++ b/guides/CHANGELOG.md
@@ -6,4 +6,8 @@
*Andrey Nering*
+* New section in Configuring: Search Engines Indexing
+
+ *Andrey Nering*
+
Please check [4-2-stable](https://github.com/rails/rails/blob/4-2-stable/guides/CHANGELOG.md) for previous changes.
diff --git a/guides/source/action_controller_overview.md b/guides/source/action_controller_overview.md
index 80000baf66..f68179841e 100644
--- a/guides/source/action_controller_overview.md
+++ b/guides/source/action_controller_overview.md
@@ -737,7 +737,7 @@ You can choose not to yield and build the response yourself, in which case the a
While the most common way to use filters is by creating private methods and using *_action to add them, there are two other ways to do the same thing.
-The first is to use a block directly with the *_action methods. The block receives the controller as an argument, and the `require_login` filter from above could be rewritten to use a block:
+The first is to use a block directly with the *\_action methods. The block receives the controller as an argument, and the `require_login` filter from above could be rewritten to use a block:
```ruby
class ApplicationController < ActionController::Base
diff --git a/guides/source/action_mailer_basics.md b/guides/source/action_mailer_basics.md
index e55ff16495..73b240ff2c 100644
--- a/guides/source/action_mailer_basics.md
+++ b/guides/source/action_mailer_basics.md
@@ -442,6 +442,39 @@ end
Will render the HTML part using the `my_layout.html.erb` file and the text part
with the usual `user_mailer.text.erb` file if it exists.
+### Previewing Emails
+
+Action Mailer previews provide a way to see how emails look by visiting a
+special URL that renders them. In the above example, the preview class for
+`UserMailer` should be named `UserMailerPreview` and located in
+`test/mailers/previews/user_mailer_preview.rb`. To see the preview of
+`welcome_email`, implement a method that has the same name and call
+`UserMailer.welcome_email`:
+
+```ruby
+class UserMailerPreview < ActionMailer::Preview
+ def welcome_email
+ UserMailer.welcome_email(User.first)
+ end
+end
+```
+
+Then the preview will be available in <http://localhost:3000/rails/mailers/user_mailer/welcome_email>.
+
+If you change something in `app/views/user_mailer/welcome_email.html.erb`
+or the mailer itself, it'll automatically reload and render it so you can
+visually see the new style instantly. A list of previews are also available
+in <http://localhost:3000/rails/mailers>.
+
+By default, these preview classes live in `test/mailers/previews`.
+This can be configured using the `preview_path` option. For example, if you
+want to change it to `lib/mailer_previews`, you can configure it in
+`config/application.rb`:
+
+```ruby
+config.action_mailer.preview_path = "#{Rails.root}/lib/mailer_previews"
+```
+
### Generating URLs in Action Mailer Views
Unlike controllers, the mailer instance doesn't have any context about the
diff --git a/guides/source/action_view_overview.md b/guides/source/action_view_overview.md
index fa6d85a3ee..8f6676dc65 100644
--- a/guides/source/action_view_overview.md
+++ b/guides/source/action_view_overview.md
@@ -192,7 +192,9 @@ Here, the `_ad_banner.html.erb` and `_footer.html.erb` partials could contain co
#### `render` without `partial` and `locals` options
-In the above example, `render` takes 2 options: `partial` and `locals`. But if these are the only options you want to pass, you can skip using these options. For example, instead of:
+In the above example, `render` takes 2 options: `partial` and `locals`. But if
+these are the only options you want to pass, you can skip using these options.
+For example, instead of:
```erb
<%= render partial: "product", locals: {product: @product} %>
@@ -204,7 +206,6 @@ You can also do:
<%= render "product", product: @product %>
```
-
#### The `as` and `object` options
By default `ActionView::Partials::PartialRenderer` has its object in a local variable with the same name as the template. So, given:
@@ -364,83 +365,6 @@ WIP: Not all the helpers are listed here. For a full list see the [API documenta
The following is only a brief overview summary of the helpers available in Action View. It's recommended that you review the [API Documentation](http://api.rubyonrails.org/classes/ActionView/Helpers.html), which covers all of the helpers in more detail, but this should serve as a good starting point.
-### RecordTagHelper
-
-This module provides methods for generating container tags, such as `div`, for your record. This is the recommended way of creating a container for render your Active Record object, as it adds an appropriate class and id attributes to that container. You can then refer to those containers easily by following the convention, instead of having to think about which class or id attribute you should use.
-
-#### content_tag_for
-
-Renders a container tag that relates to your Active Record Object.
-
-For example, given `@article` is the object of `Article` class, you can do:
-
-```html+erb
-<%= content_tag_for(:tr, @article) do %>
- <td><%= @article.title %></td>
-<% end %>
-```
-
-This will generate this HTML output:
-
-```html
-<tr id="article_1234" class="article">
- <td>Hello World!</td>
-</tr>
-```
-
-You can also supply HTML attributes as an additional option hash. For example:
-
-```html+erb
-<%= content_tag_for(:tr, @article, class: "frontpage") do %>
- <td><%= @article.title %></td>
-<% end %>
-```
-
-Will generate this HTML output:
-
-```html
-<tr id="article_1234" class="article frontpage">
- <td>Hello World!</td>
-</tr>
-```
-
-You can pass a collection of Active Record objects. This method will loop through your objects and create a container for each of them. For example, given `@articles` is an array of two `Article` objects:
-
-```html+erb
-<%= content_tag_for(:tr, @articles) do |article| %>
- <td><%= article.title %></td>
-<% end %>
-```
-
-Will generate this HTML output:
-
-```html
-<tr id="article_1234" class="article">
- <td>Hello World!</td>
-</tr>
-<tr id="article_1235" class="article">
- <td>Ruby on Rails Rocks!</td>
-</tr>
-```
-
-#### div_for
-
-This is actually a convenient method which calls `content_tag_for` internally with `:div` as the tag name. You can pass either an Active Record object or a collection of objects. For example:
-
-```html+erb
-<%= div_for(@article, class: "frontpage") do %>
- <td><%= @article.title %></td>
-<% end %>
-```
-
-Will generate this HTML output:
-
-```html
-<div id="article_1234" class="article frontpage">
- <td>Hello World!</td>
-</div>
-```
-
### AssetTagHelper
This module provides methods for generating HTML that links views to assets such as images, JavaScript files, stylesheets, and feeds.
@@ -1616,7 +1540,7 @@ details can be found in the [Rails Security Guide](security.html#cross-site-requ
Localized Views
---------------
-Action View has the ability render different templates depending on the current locale.
+Action View has the ability to render different templates depending on the current locale.
For example, suppose you have a `ArticlesController` with a show action. By default, calling this action will render `app/views/articles/show.html.erb`. But if you set `I18n.locale = :de`, then `app/views/articles/show.de.html.erb` will be rendered instead. If the localized template isn't present, the undecorated version will be used. This means you're not required to provide localized views for all cases, but they will be preferred and used if available.
diff --git a/guides/source/active_record_querying.md b/guides/source/active_record_querying.md
index c5ca848753..ad5103da69 100644
--- a/guides/source/active_record_querying.md
+++ b/guides/source/active_record_querying.md
@@ -317,7 +317,7 @@ end
The `find_each` method accepts most of the options allowed by the regular `find` method, except for `:order` and `:limit`, which are reserved for internal use by `find_each`.
-Two additional options, `:batch_size` and `:start`, are available as well.
+Two additional options, `:batch_size` and `:begin_at`, are available as well.
**`:batch_size`**
@@ -329,29 +329,29 @@ User.find_each(batch_size: 5000) do |user|
end
```
-**`:start`**
+**`:begin_at`**
-By default, records are fetched in ascending order of the primary key, which must be an integer. The `:start` option allows you to configure the first ID of the sequence whenever the lowest ID is not the one you need. This would be useful, for example, if you wanted to resume an interrupted batch process, provided you saved the last processed ID as a checkpoint.
+By default, records are fetched in ascending order of the primary key, which must be an integer. The `:begin_at` option allows you to configure the first ID of the sequence whenever the lowest ID is not the one you need. This would be useful, for example, if you wanted to resume an interrupted batch process, provided you saved the last processed ID as a checkpoint.
For example, to send newsletters only to users with the primary key starting from 2000, and to retrieve them in batches of 5000:
```ruby
-User.find_each(start: 2000, batch_size: 5000) do |user|
+User.find_each(begin_at: 2000, batch_size: 5000) do |user|
NewsMailer.weekly(user).deliver_now
end
```
-Another example would be if you wanted multiple workers handling the same processing queue. You could have each worker handle 10000 records by setting the appropriate `:start` option on each worker.
+Another example would be if you wanted multiple workers handling the same processing queue. You could have each worker handle 10000 records by setting the appropriate `:begin_at` option on each worker.
**`:end_at`**
-Similar to the `:start` option, `:end_at` allows you to configure the last ID of the sequence whenever the highest ID is not the one you need.
-This would be useful, for example, if you wanted to run a batch process, using a subset of records based on `:start` and `:end_at`
+Similar to the `:begin_at` option, `:end_at` allows you to configure the last ID of the sequence whenever the highest ID is not the one you need.
+This would be useful, for example, if you wanted to run a batch process, using a subset of records based on `:begin_at` and `:end_at`
For example, to send newsletters only to users with the primary key starting from 2000 upto 10000 and to retrieve them in batches of 1000:
```ruby
-User.find_each(start: 2000, end_at: 10000, batch_size: 5000) do |user|
+User.find_each(begin_at: 2000, end_at: 10000, batch_size: 5000) do |user|
NewsMailer.weekly(user).deliver_now
end
```
@@ -369,7 +369,7 @@ end
##### Options for `find_in_batches`
-The `find_in_batches` method accepts the same `:batch_size`, `:start` and `:end_at` options as `find_each`.
+The `find_in_batches` method accepts the same `:batch_size`, `:begin_at` and `:end_at` options as `find_each`.
Conditions
----------
diff --git a/guides/source/active_record_validations.md b/guides/source/active_record_validations.md
index 67cc6a4db3..de26a9bd6d 100644
--- a/guides/source/active_record_validations.md
+++ b/guides/source/active_record_validations.md
@@ -231,9 +231,9 @@ Errors](#working-with-validation-errors) section.
### `errors.details`
-To check what validator type was used on invalid attribute, you can use
-`errors.details[:attribute]`. It returns array of hashes where under `:error`
- key you will find symbol of used validator.
+To check which validations failed on an invalid attribute, you can use
+`errors.details[:attribute]`. It returns an array of hashes with an `:error`
+key to get the symbol of the validator:
```ruby
class Person < ActiveRecord::Base
@@ -245,7 +245,7 @@ end
>> person.errors.details[:name] #=> [{error: :blank}]
```
-Using `details` with custom validators are covered in the [Working with
+Using `details` with custom validators is covered in the [Working with
Validation Errors](#working-with-validation-errors) section.
Validation Helpers
@@ -606,9 +606,7 @@ This helper validates that the attribute's value is unique right before the
object gets saved. It does not create a uniqueness constraint in the database,
so it may happen that two different database connections create two records
with the same value for a column that you intend to be unique. To avoid that,
-you must create a unique index on both columns in your database. See
-[the MySQL manual](http://dev.mysql.com/doc/refman/5.6/en/multiple-column-indexes.html)
-for more details about multiple column indexes.
+you must create a unique index on that column in your database.
```ruby
class Account < ActiveRecord::Base
@@ -628,6 +626,7 @@ class Holiday < ActiveRecord::Base
message: "should happen once per year" }
end
```
+Should you wish to create a database constraint to prevent possible violations of a uniqueness validation using the `:scope` option, you must create a unique index on both columns in your database. See [the MySQL manual](http://dev.mysql.com/doc/refman/5.6/en/multiple-column-indexes.html) for more details about multiple column indexes or [the PostgreSQL manual](http://www.postgresql.org/docs/9.4/static/ddl-constraints.html) for examples of unique constraints that refer to a group of columns.
There is also a `:case_sensitive` option that you can use to define whether the
uniqueness constraint will be case sensitive or not. This option defaults to
@@ -1094,39 +1093,40 @@ Another way to do this is using `[]=` setter
### `errors.details`
-You can add validator type to details hash when using `errors.add` method.
+You can specify a validator type to the returned error details hash using the
+`errors.add` method.
```ruby
- class Person < ActiveRecord::Base
- def a_method_used_for_validation_purposes
- errors.add(:name, :invalid_characters)
- end
+class Person < ActiveRecord::Base
+ def a_method_used_for_validation_purposes
+ errors.add(:name, :invalid_characters)
end
+end
- person = Person.create(name: "!@#")
+person = Person.create(name: "!@#")
- person.errors.details[:name]
- # => [{error: :invalid_characters}]
+person.errors.details[:name]
+# => [{error: :invalid_characters}]
```
-To improve error details to contain not allowed characters set, you can
-pass additional options to `errors.add` method.
+To improve the error details to contain the unallowed characters set for instance,
+you can pass additional keys to `errors.add`.
```ruby
- class Person < ActiveRecord::Base
- def a_method_used_for_validation_purposes
- errors.add(:name, :invalid_characters, not_allowed: "!@#%*()_-+=")
- end
+class Person < ActiveRecord::Base
+ def a_method_used_for_validation_purposes
+ errors.add(:name, :invalid_characters, not_allowed: "!@#%*()_-+=")
end
+end
- person = Person.create(name: "!@#")
+person = Person.create(name: "!@#")
- person.errors.details[:name]
- # => [{error: :invalid_characters, not_allowed: "!@#%*()_-+="}]
+person.errors.details[:name]
+# => [{error: :invalid_characters, not_allowed: "!@#%*()_-+="}]
```
-All built in Rails validators populate details hash with corresponding
-validator types.
+All built in Rails validators populate the details hash with the corresponding
+validator type.
### `errors[:base]`
diff --git a/guides/source/association_basics.md b/guides/source/association_basics.md
index 8633cc4f10..cd715aba1f 100644
--- a/guides/source/association_basics.md
+++ b/guides/source/association_basics.md
@@ -171,7 +171,7 @@ class CreateCustomers < ActiveRecord::Migration
end
create_table :orders do |t|
- t.belongs_to :customer, index:true
+ t.belongs_to :customer, index: true
t.datetime :order_date
t.timestamps null: false
end
@@ -691,7 +691,7 @@ c.first_name = 'Manny'
c.first_name == o.customer.first_name # => false
```
-This happens because c and o.customer are two different in-memory representations of the same data, and neither one is automatically refreshed from changes to the other. Active Record provides the `:inverse_of` option so that you can inform it of these relations:
+This happens because `c` and `o.customer` are two different in-memory representations of the same data, and neither one is automatically refreshed from changes to the other. Active Record provides the `:inverse_of` option so that you can inform it of these relations:
```ruby
class Customer < ActiveRecord::Base
@@ -726,10 +726,10 @@ Most associations with standard names will be supported. However, associations
that contain the following options will not have their inverses set
automatically:
-* :conditions
-* :through
-* :polymorphic
-* :foreign_key
+* `:conditions`
+* `:through`
+* `:polymorphic`
+* `:foreign_key`
Detailed Association Reference
------------------------------
@@ -1986,8 +1986,8 @@ While Rails uses intelligent defaults that will work well in most situations, th
```ruby
class Parts < ActiveRecord::Base
- has_and_belongs_to_many :assemblies, autosave: true,
- readonly: true
+ has_and_belongs_to_many :assemblies, -> { readonly },
+ autosave: true
end
```
@@ -1999,7 +1999,6 @@ The `has_and_belongs_to_many` association supports these options:
* `:foreign_key`
* `:join_table`
* `:validate`
-* `:readonly`
##### `:association_foreign_key`
diff --git a/guides/source/autoloading_and_reloading_constants.md b/guides/source/autoloading_and_reloading_constants.md
index 8f9125f311..9e78eebf82 100644
--- a/guides/source/autoloading_and_reloading_constants.md
+++ b/guides/source/autoloading_and_reloading_constants.md
@@ -301,7 +301,9 @@ order. The ancestors of those elements are ignored.
2. If not found, then the algorithm walks up the ancestor chain of the cref.
-3. If not found, `const_missing` is invoked on the cref. The default
+3. If not found and the cref is a module, the constant is looked up in `Object`.
+
+4. If not found, `const_missing` is invoked on the cref. The default
implementation of `const_missing` raises `NameError`, but it can be overridden.
Rails autoloading **does not emulate this algorithm**, but its starting point is
diff --git a/guides/source/configuring.md b/guides/source/configuring.md
index 9c0f2ddc8a..994cc31cff 100644
--- a/guides/source/configuring.md
+++ b/guides/source/configuring.md
@@ -1049,3 +1049,21 @@ These configuration points are then available through the configuration object:
Rails.configuration.x.super_debugger # => true
Rails.configuration.x.super_debugger.not_set # => nil
```
+
+Search Engines Indexing
+-----------------------
+
+Sometimes, you may want to prevent some pages of your application be visible on search sites like Google,
+Bing, Yahoo or Duck Duck Go. The robots that index these sites will first analyse the
+`https://your-site.com/robots.txt` file to know what pages it is allowed to index.
+
+Rails creates this file for you on `/public` folder. By default, it allows search engines to index all
+pages of your application. If you want to block indexing on all pages of you application, use this:
+
+```
+User-agent: *
+Disallow: /
+```
+
+To block just specific pages, it's necessary to use a more complex syntax. Learn it on the
+[official documentation](http://www.robotstxt.org/robotstxt.html).
diff --git a/guides/source/contributing_to_ruby_on_rails.md b/guides/source/contributing_to_ruby_on_rails.md
index e06706d750..32d1e2c6e7 100644
--- a/guides/source/contributing_to_ruby_on_rails.md
+++ b/guides/source/contributing_to_ruby_on_rails.md
@@ -173,12 +173,12 @@ $ git checkout -b my_new_branch
It doesn't matter much what name you use, because this branch will only exist on your local computer and your personal repository on GitHub. It won't be part of the Rails Git repository.
-### Bundle Update
+### Bundle install
-Update and install the required gems.
+Install the required gems.
```bash
-$ bundle update
+$ bundle install
```
### Running an Application Against Your Local Branch
@@ -376,6 +376,10 @@ A CHANGELOG entry should summarize what was changed and should end with author's
Your name can be added directly after the last word if you don't provide any code examples or don't need multiple paragraphs. Otherwise, it's best to make as a new paragraph.
+### Updating the Gemfile.lock
+
+Some changes requires the dependencies to be upgraded. In these cases make sure you run `bundle update` to get the right version of the dependency and commit the `Gemfile.lock` file within your changes.
+
### Sanity Check
You should not be the only person who looks at the code before you submit it.
diff --git a/guides/source/debugging_rails_applications.md b/guides/source/debugging_rails_applications.md
index f6e7980fe2..6113a61f4c 100644
--- a/guides/source/debugging_rails_applications.md
+++ b/guides/source/debugging_rails_applications.md
@@ -242,6 +242,58 @@ The contents of the block, and therefore the string interpolation, is only
evaluated if debug is enabled. This performance savings is only really
noticeable with large amounts of logging, but it's a good practice to employ.
+
+Debugging with the `web-console` gem
+-------------------------------------
+
+The web console allows you to create an interactive ruby session in your browser. An interactive
+console is launched automatically in case on an error but can also be launched for debugging purposes
+by invoking `console` in a view or controller.
+
+For example in a view:
+
+```ruby
+# new.html.erb
+<%= console %>
+```
+
+Or in a controller:
+
+```ruby
+# posts_controller.rb
+class PostsController < ApplicationController
+ def new
+ console
+ @post = Post.new
+ end
+end
+```
+###config.web_console.whitelisted_ips
+
+By default the web console can only be accessed from localhost. `config.web_console.whitelisted_ips`
+lets you control which IPs have access to the console.
+
+For example, to allow access from both localhost and 192.168.0.100:
+
+```ruby
+# config/application.rb
+class Application < Rails::Application
+ config.web_console.whitelisted_ips = %w( 127.0.0.1 192.168.0.100 )
+end
+```
+
+To allow access from an entire network:
+
+```ruby
+# config/application.rb
+class Application < Rails::Application
+ config.web_console.whitelisted_ips = %w( 127.0.0.1 192.168.0.0/16 )
+end
+```
+
+Web console is a powerful tool so be careful who you open access to.
+
+
Debugging with the `byebug` gem
---------------------------------
@@ -832,7 +884,7 @@ application. Here is a list of useful plugins for debugging:
* [Footnotes](https://github.com/josevalim/rails-footnotes) Every Rails page has
footnotes that give request information and link back to your source via
TextMate.
-* [Query Trace](https://github.com/ntalbott/query_trace/tree/master) Adds query
+* [Query Trace](https://github.com/ruckus/active-record-query-trace/tree/master) Adds query
origin tracing to your logs.
* [Query Reviewer](https://github.com/nesquena/query_reviewer) This rails plugin
not only runs "EXPLAIN" before each of your select queries in development, but
diff --git a/guides/source/i18n.md b/guides/source/i18n.md
index 8f24c53edb..9b049ea8b8 100644
--- a/guides/source/i18n.md
+++ b/guides/source/i18n.md
@@ -588,7 +588,7 @@ you can look up the `books.index.title` value **inside** `app/views/books/index.
NOTE: Automatic translation scoping by partial is only available from the `translate` view helper method.
-"Lazy" lookup can also be used in _controllers_:
+"Lazy" lookup can also be used in controllers:
```yaml
en:
@@ -596,7 +596,8 @@ en:
create:
success: Book created!
```
-which is especially useful for setting flash messages:
+
+This is useful for setting flash messages for instance:
```ruby
class BooksController < ApplicationController
diff --git a/guides/source/layouts_and_rendering.md b/guides/source/layouts_and_rendering.md
index 69d3f6e86c..329d501ce0 100644
--- a/guides/source/layouts_and_rendering.md
+++ b/guides/source/layouts_and_rendering.md
@@ -1049,7 +1049,7 @@ As you already could see from the previous sections of this guide, `yield` is a
<p>
Name contains: <%= f.text_field :name_contains %>
</p>
- <%= end %>
+ <% end %>
```
* `roles/index.html.erb`
@@ -1059,7 +1059,7 @@ As you already could see from the previous sections of this guide, `yield` is a
<p>
Title contains: <%= f.text_field :title_contains %>
</p>
- <%= end %>
+ <% end %>
```
* `shared/_search_filters.html.erb`
@@ -1124,6 +1124,36 @@ You can also pass local variables into partials, making them even more powerful
Although the same partial will be rendered into both views, Action View's submit helper will return "Create Zone" for the new action and "Update Zone" for the edit action.
+To pass a local variable to a partial in only specific cases use the `local_assigns`.
+
+* `index.html.erb`
+
+ ```erb
+ <%= render user.articles %>
+ ```
+
+* `show.html.erb`
+
+ ```erb
+ <%= render article, full: true %>
+ ```
+
+* `_articles.html.erb`
+
+ ```erb
+ <%= content_tag_for :article, article do |article| %>
+ <h2><%= article.title %></h2>
+
+ <% if local_assigns[:full] %>
+ <%= simple_format article.body %>
+ <% else %>
+ <%= truncate article.body %>
+ <% end %>
+ <% end %>
+ ```
+
+This way it is possible to use the partial without the need to declare all local variables.
+
Every partial also has a local variable with the same name as the partial (minus the underscore). You can pass an object in to this local variable via the `:object` option:
```erb
diff --git a/guides/source/testing.md b/guides/source/testing.md
index 625f366db1..14bc75aa7d 100644
--- a/guides/source/testing.md
+++ b/guides/source/testing.md
@@ -545,7 +545,8 @@ NOTE: Functional tests do not verify whether the specified request type is accep
### Testing XHR (AJAX) requests
-Enable set `xhr: true` option as an argument to `get/post/patch/put/delete` method:
+To test AJAX requests, you can specify the `xhr: true` option to `get`, `post`,
+`patch`, `put`, and `delete` methods:
```ruby
test "ajax request responds with no layout" do
diff --git a/guides/source/working_with_javascript_in_rails.md b/guides/source/working_with_javascript_in_rails.md
index f3d3a83afc..e3856a285a 100644
--- a/guides/source/working_with_javascript_in_rails.md
+++ b/guides/source/working_with_javascript_in_rails.md
@@ -191,6 +191,34 @@ $(document).ready ->
Obviously, you'll want to be a bit more sophisticated than that, but it's a
start. You can see more about the events [in the jquery-ujs wiki](https://github.com/rails/jquery-ujs/wiki/ajax).
+Another possibility is returning javascript directly from the server side on
+remote calls:
+
+```ruby
+# articles_controller
+def create
+ respond_to do |format|
+ if @article.save
+ format.html { ... }
+ format.js do
+ render js: <<-endjs
+ alert('Article saved successfully!');
+ window.location = '#{article_path(@article)}';
+ endjs
+ end
+ else
+ format.html { ... }
+ format.js do
+ render js: "alert('There are empty fields in the form!');"
+ end
+ end
+ end
+end
+```
+
+NOTE: If javascript is disabled in the user browser, `format.html { ... }`
+block should be executed as fallback.
+
### form_tag
[`form_tag`](http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html#method-i-form_tag)
diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb
index 7a1bb1e25c..0599e988d9 100644
--- a/railties/lib/rails/application/finisher.rb
+++ b/railties/lib/rails/application/finisher.rb
@@ -108,6 +108,13 @@ module Rails
ActionDispatch::Reloader.to_cleanup(&callback)
end
end
+
+ # Disable dependency loading during request cycle
+ initializer :disable_dependency_loading do
+ if config.eager_load && config.cache_classes
+ ActiveSupport::Dependencies.unhook!
+ end
+ end
end
end
end
diff --git a/railties/lib/rails/commands/server.rb b/railties/lib/rails/commands/server.rb
index bc8f1a8dea..546d3725d8 100644
--- a/railties/lib/rails/commands/server.rb
+++ b/railties/lib/rails/commands/server.rb
@@ -91,10 +91,6 @@ module Rails
Hash.new(middlewares)
end
- def log_path
- "log/#{options[:environment]}.log"
- end
-
def default_options
super.merge({
Port: 3000,
diff --git a/railties/lib/rails/generators/erb/mailer/mailer_generator.rb b/railties/lib/rails/generators/erb/mailer/mailer_generator.rb
index 7d27321610..65563aa6db 100644
--- a/railties/lib/rails/generators/erb/mailer/mailer_generator.rb
+++ b/railties/lib/rails/generators/erb/mailer/mailer_generator.rb
@@ -6,7 +6,7 @@ module Erb # :nodoc:
argument :actions, type: :array, default: [], banner: "method method"
def copy_view_files
- view_base_path = File.join("app/views", class_path, file_name)
+ view_base_path = File.join("app/views", class_path, file_name + '_mailer')
empty_directory view_base_path
if self.behavior == :invoke
@@ -31,6 +31,10 @@ module Erb # :nodoc:
def formats
[:text, :html]
end
+
+ def file_name
+ @_file_name ||= super.gsub(/\_mailer/i, '')
+ end
end
end
end
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 ba131da79d..343c8a3949 100644
--- a/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb
+++ b/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb
@@ -16,6 +16,11 @@ module TestUnit # :nodoc:
def create_preview_files
template "preview.rb", File.join('test/mailers/previews', class_path, "#{file_name}_mailer_preview.rb")
end
+
+ protected
+ def file_name
+ @_file_name ||= super.gsub(/\_mailer/i, '')
+ end
end
end
end
diff --git a/railties/lib/rails/generators/test_unit/mailer/templates/functional_test.rb b/railties/lib/rails/generators/test_unit/mailer/templates/functional_test.rb
index 3cee517db3..a2f2d30de5 100644
--- a/railties/lib/rails/generators/test_unit/mailer/templates/functional_test.rb
+++ b/railties/lib/rails/generators/test_unit/mailer/templates/functional_test.rb
@@ -4,7 +4,7 @@ require 'test_helper'
class <%= class_name %>MailerTest < ActionMailer::TestCase
<% actions.each do |action| -%>
test "<%= action %>" do
- mail = <%= class_name %>.<%= action %>
+ mail = <%= class_name %>Mailer.<%= action %>
assert_equal <%= action.to_s.humanize.inspect %>, mail.subject
assert_equal ["to@example.org"], mail.to
assert_equal ["from@example.com"], mail.from
diff --git a/railties/test/generators/mailer_generator_test.rb b/railties/test/generators/mailer_generator_test.rb
index febd2fd12e..584e7a82aa 100644
--- a/railties/test/generators/mailer_generator_test.rb
+++ b/railties/test/generators/mailer_generator_test.rb
@@ -78,13 +78,13 @@ class MailerGeneratorTest < Rails::Generators::TestCase
def test_invokes_default_text_template_engine
run_generator
- assert_file "app/views/notifier/foo.text.erb" do |view|
- assert_match(%r(\sapp/views/notifier/foo\.text\.erb), view)
+ assert_file "app/views/notifier_mailer/foo.text.erb" do |view|
+ assert_match(%r(\sapp/views/notifier_mailer/foo\.text\.erb), view)
assert_match(/<%= @greeting %>/, view)
end
- assert_file "app/views/notifier/bar.text.erb" do |view|
- assert_match(%r(\sapp/views/notifier/bar\.text\.erb), view)
+ assert_file "app/views/notifier_mailer/bar.text.erb" do |view|
+ assert_match(%r(\sapp/views/notifier_mailer/bar\.text\.erb), view)
assert_match(/<%= @greeting %>/, view)
end
@@ -95,13 +95,13 @@ class MailerGeneratorTest < Rails::Generators::TestCase
def test_invokes_default_html_template_engine
run_generator
- assert_file "app/views/notifier/foo.html.erb" do |view|
- assert_match(%r(\sapp/views/notifier/foo\.html\.erb), view)
+ assert_file "app/views/notifier_mailer/foo.html.erb" do |view|
+ assert_match(%r(\sapp/views/notifier_mailer/foo\.html\.erb), view)
assert_match(/<%= @greeting %>/, view)
end
- assert_file "app/views/notifier/bar.html.erb" do |view|
- assert_match(%r(\sapp/views/notifier/bar\.html\.erb), view)
+ assert_file "app/views/notifier_mailer/bar.html.erb" do |view|
+ assert_match(%r(\sapp/views/notifier_mailer/bar\.html\.erb), view)
assert_match(/<%= @greeting %>/, view)
end
@@ -112,7 +112,7 @@ class MailerGeneratorTest < Rails::Generators::TestCase
def test_invokes_default_template_engine_even_with_no_action
run_generator ["notifier"]
- assert_file "app/views/notifier"
+ assert_file "app/views/notifier_mailer"
assert_file "app/views/layouts/mailer.text.erb"
assert_file "app/views/layouts/mailer.html.erb"
end
@@ -133,8 +133,8 @@ class MailerGeneratorTest < Rails::Generators::TestCase
assert_match(/class Farm::AnimalMailerPreview < ActionMailer::Preview/, preview)
assert_match(/\# Preview this email at http:\/\/localhost\:3000\/rails\/mailers\/farm\/animal\/moos/, preview)
end
- assert_file "app/views/farm/animal/moos.text.erb"
- assert_file "app/views/farm/animal/moos.html.erb"
+ assert_file "app/views/farm/animal_mailer/moos.text.erb"
+ assert_file "app/views/farm/animal_mailer/moos.html.erb"
end
def test_actions_are_turned_into_methods
@@ -173,5 +173,14 @@ class MailerGeneratorTest < Rails::Generators::TestCase
assert_no_file "app/mailers/notifier_mailer_mailer.rb"
assert_file "app/mailers/notifier_mailer.rb"
+
+ assert_no_file "app/views/notifier_mailer_mailer/"
+ assert_file "app/views/notifier_mailer/"
+
+ assert_no_file "test/mailers/notifier_mailer_mailer_test.rb"
+ assert_file "test/mailers/notifier_mailer_test.rb"
+
+ assert_no_file "test/mailers/previews/notifier_mailer_mailer_preview.rb"
+ assert_file "test/mailers/previews/notifier_mailer_preview.rb"
end
end
diff --git a/railties/test/generators/namespaced_generators_test.rb b/railties/test/generators/namespaced_generators_test.rb
index d0ea01dfb0..e839b67960 100644
--- a/railties/test/generators/namespaced_generators_test.rb
+++ b/railties/test/generators/namespaced_generators_test.rb
@@ -173,20 +173,20 @@ class NamespacedMailerGeneratorTest < NamespacedGeneratorTestCase
def test_invokes_default_template_engine
run_generator
- assert_file "app/views/test_app/notifier/foo.text.erb" do |view|
- assert_match(%r(app/views/test_app/notifier/foo\.text\.erb), view)
+ assert_file "app/views/test_app/notifier_mailer/foo.text.erb" do |view|
+ assert_match(%r(app/views/test_app/notifier_mailer/foo\.text\.erb), view)
assert_match(/<%= @greeting %>/, view)
end
- assert_file "app/views/test_app/notifier/bar.text.erb" do |view|
- assert_match(%r(app/views/test_app/notifier/bar\.text\.erb), view)
+ assert_file "app/views/test_app/notifier_mailer/bar.text.erb" do |view|
+ assert_match(%r(app/views/test_app/notifier_mailer/bar\.text\.erb), view)
assert_match(/<%= @greeting %>/, view)
end
end
def test_invokes_default_template_engine_even_with_no_action
run_generator ["notifier"]
- assert_file "app/views/test_app/notifier"
+ assert_file "app/views/test_app/notifier_mailer"
end
end