aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRyuta Kamizono <kamipo@gmail.com>2019-04-25 03:32:36 +0900
committerRyuta Kamizono <kamipo@gmail.com>2019-04-25 03:32:36 +0900
commit186458753f3614623523ad079d92c537cf03cb4a (patch)
tree5e75374e3289543940d05735b4e3a4373abc4c6c
parent3a4aa492560d311f8d549f739bd69945f5d508ea (diff)
parent3fe83d1dd99ac2662852da0dcfe7e91dc08ae160 (diff)
downloadrails-186458753f3614623523ad079d92c537cf03cb4a.tar.gz
rails-186458753f3614623523ad079d92c537cf03cb4a.tar.bz2
rails-186458753f3614623523ad079d92c537cf03cb4a.zip
Merge pull request #35869 from abhaynikam/35866-add-touch-option-for-has-one-association
Adds missing touch option to has_one association
-rw-r--r--activerecord/CHANGELOG.md4
-rw-r--r--activerecord/lib/active_record/associations/builder/has_one.rb36
-rw-r--r--activerecord/test/cases/associations/has_one_associations_test.rb39
-rw-r--r--activerecord/test/models/club.rb4
-rw-r--r--activerecord/test/schema/schema.rb2
5 files changed, 81 insertions, 4 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index adc7e754a4..a8893d7164 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,7 @@
+* Add `touch` option to `has_one` association.
+
+ *Abhay Nikam*
+
* Deprecate `where.not` working as NOR and will be changed to NAND in Rails 6.1.
```ruby
diff --git a/activerecord/lib/active_record/associations/builder/has_one.rb b/activerecord/lib/active_record/associations/builder/has_one.rb
index a17cfcb805..27ebe8cb71 100644
--- a/activerecord/lib/active_record/associations/builder/has_one.rb
+++ b/activerecord/lib/active_record/associations/builder/has_one.rb
@@ -7,7 +7,7 @@ module ActiveRecord::Associations::Builder # :nodoc:
end
def self.valid_options(options)
- valid = super + [:as]
+ valid = super + [:as, :touch]
valid += [:through, :source, :source_type] if options[:through]
valid
end
@@ -16,6 +16,11 @@ module ActiveRecord::Associations::Builder # :nodoc:
[:destroy, :delete, :nullify, :restrict_with_error, :restrict_with_exception]
end
+ def self.define_callbacks(model, reflection)
+ super
+ add_touch_callbacks(model, reflection) if reflection.options[:touch]
+ end
+
def self.add_destroy_callbacks(model, reflection)
super unless reflection.options[:through]
end
@@ -27,6 +32,33 @@ module ActiveRecord::Associations::Builder # :nodoc:
end
end
- private_class_method :macro, :valid_options, :valid_dependent_options, :add_destroy_callbacks, :define_validations
+ def self.touch_record(o, name, touch)
+ record = o.send name
+
+ return unless record && record.persisted?
+
+ if touch != true
+ record.touch(touch)
+ else
+ record.touch
+ end
+ end
+
+ def self.add_touch_callbacks(model, reflection)
+ name = reflection.name
+ touch = reflection.options[:touch]
+
+ callback = lambda { |record|
+ HasOne.touch_record(record, name, touch)
+ }
+
+ model.after_create callback, if: :saved_changes?
+ model.after_update callback, if: :saved_changes?
+ model.after_destroy callback
+ model.after_touch callback
+ end
+
+ private_class_method :macro, :valid_options, :valid_dependent_options, :add_destroy_callbacks,
+ :define_callbacks, :define_validations, :add_touch_callbacks
end
end
diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb
index 7bb629466d..fd727757a3 100644
--- a/activerecord/test/cases/associations/has_one_associations_test.rb
+++ b/activerecord/test/cases/associations/has_one_associations_test.rb
@@ -15,10 +15,13 @@ require "models/post"
require "models/drink_designer"
require "models/chef"
require "models/department"
+require "models/club"
+require "models/membership"
class HasOneAssociationsTest < ActiveRecord::TestCase
self.use_transactional_tests = false unless supports_savepoints?
- fixtures :accounts, :companies, :developers, :projects, :developers_projects, :ships, :pirates, :authors, :author_addresses
+ fixtures :accounts, :companies, :developers, :projects, :developers_projects,
+ :ships, :pirates, :authors, :author_addresses, :memberships, :clubs
def setup
Account.destroyed_account_ids.clear
@@ -706,6 +709,40 @@ class HasOneAssociationsTest < ActiveRecord::TestCase
end
end
+ def test_has_one_with_touch_option_on_create
+ assert_queries(3) {
+ Club.create(name: "1000 Oaks", membership_attributes: { favourite: true })
+ }
+ end
+
+ def test_has_one_with_touch_option_on_update
+ new_club = Club.create(name: "1000 Oaks")
+ new_club.create_membership
+
+ assert_queries(2) { new_club.update(name: "Effingut") }
+ end
+
+ def test_has_one_with_touch_option_on_touch
+ new_club = Club.create(name: "1000 Oaks")
+ new_club.create_membership
+
+ assert_queries(1) { new_club.touch }
+ end
+
+ def test_has_one_with_touch_option_on_destroy
+ new_club = Club.create(name: "1000 Oaks")
+ new_club.create_membership
+
+ assert_queries(2) { new_club.destroy }
+ end
+
+ def test_has_one_with_touch_option_on_empty_update
+ new_club = Club.create(name: "1000 Oaks")
+ new_club.create_membership
+
+ assert_no_queries { new_club.save }
+ end
+
class SpecialBook < ActiveRecord::Base
self.table_name = "books"
belongs_to :author, class_name: "SpecialAuthor"
diff --git a/activerecord/test/models/club.rb b/activerecord/test/models/club.rb
index 13e72e9c50..bb49fb300c 100644
--- a/activerecord/test/models/club.rb
+++ b/activerecord/test/models/club.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
class Club < ActiveRecord::Base
- has_one :membership
+ has_one :membership, touch: true
has_many :memberships, inverse_of: false
has_many :members, through: :memberships
has_one :sponsor
@@ -12,6 +12,8 @@ class Club < ActiveRecord::Base
scope :general, -> { left_joins(:category).where(categories: { name: "General" }).unscope(:limit) }
+ accepts_nested_attributes_for :membership
+
private
def private_method
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index 7d9b8afeb6..41920b3719 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -524,6 +524,8 @@ ActiveRecord::Schema.define do
t.integer :club_id, :member_id
t.boolean :favourite, default: false
t.integer :type
+ t.datetime :created_at
+ t.datetime :updated_at
end
create_table :member_types, force: true do |t|