1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Adds touch option to has_one association

This commit is contained in:
Abhay Nikam 2019-04-05 10:14:30 +05:30 committed by Ryuta Kamizono
parent aa5e6b5905
commit 3fe83d1dd9
5 changed files with 81 additions and 4 deletions

View file

@ -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

View file

@ -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

View file

@ -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"

View file

@ -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

View file

@ -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|