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:
parent
aa5e6b5905
commit
3fe83d1dd9
5 changed files with 81 additions and 4 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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|
|
||||
|
|
Loading…
Reference in a new issue