Skip to content

Commit

Permalink
Merge pull request rails#35869 from abhaynikam/35866-add-touch-option…
Browse files Browse the repository at this point in the history
…-for-has-one-association

Adds missing touch option to has_one association
  • Loading branch information
kamipo committed Apr 24, 2019
2 parents 3a4aa49 + 3fe83d1 commit 1864587
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 4 deletions.
4 changes: 4 additions & 0 deletions activerecord/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
36 changes: 34 additions & 2 deletions activerecord/lib/active_record/associations/builder/has_one.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ def self.macro
end

def self.valid_options(options)
valid = super + [:as]
valid = super + [:as, :touch]
valid += [:through, :source, :source_type] if options[:through]
valid
end
Expand All @@ -16,6 +16,11 @@ def self.valid_dependent_options
[: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
Expand All @@ -27,6 +32,33 @@ def self.define_validations(model, reflection)
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
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@
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
Expand Down Expand Up @@ -706,6 +709,40 @@ def test_with_polymorphic_has_one_with_custom_columns_name
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"
Expand Down
4 changes: 3 additions & 1 deletion activerecord/test/models/club.rb
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand Down
2 changes: 2 additions & 0 deletions activerecord/test/schema/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,8 @@
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|
Expand Down

0 comments on commit 1864587

Please sign in to comment.