Add support for nullifying CPK has_one associations

Composite primary key records need to conditionally unset multiple
column attributes from the associated record in order to properly
support dependent: nullify.
This commit is contained in:
Gannon McGibbon 2023-06-20 22:47:04 -05:00
parent 7dd27be1a2
commit 622485ae4b
7 changed files with 55 additions and 1 deletions

View File

@ -121,7 +121,9 @@ module ActiveRecord
end
def nullify_owner_attributes(record)
record[reflection.foreign_key] = nil
Array(reflection.foreign_key).each do |foreign_key_column|
record[foreign_key_column] = nil unless foreign_key_column.in?(Array(record.class.primary_key))
end
end
def transaction_if(value, &block)

View File

@ -145,6 +145,28 @@ class HasOneAssociationsTest < ActiveRecord::TestCase
assert_not_predicate developer, :persisted?
end
def test_nullification_on_cpk_association
book = Cpk::Book.create!(author_id: 1, number: 2)
other_book = Cpk::Book.create!(author_id: 3, number: 4)
order = Cpk::OrderWithNullifiedBook.create!(book: book)
order.book = other_book
assert_nil book.order_id
assert_nil book.shop_id
end
def test_nullification_on_cpk_association_with_pk_column
chapter = Cpk::Chapter.create!(author_id: 1, number: 2)
other_chapter = Cpk::Chapter.create!(author_id: 1, number: 4)
book = Cpk::NullifiedBook.create!(chapter: chapter, number: 1, author_id: 1)
book.chapter = other_chapter
assert_nil chapter.book_number
assert_not_nil chapter.author_id
end
def test_natural_assignment_to_nil_after_destroy
firm = companies(:rails_core)
old_account_id = firm.account.id

View File

@ -7,3 +7,4 @@ require_relative "cpk/review"
require_relative "cpk/order_agreement"
require_relative "cpk/order_tag"
require_relative "cpk/tag"
require_relative "cpk/chapter"

View File

@ -6,6 +6,8 @@ module Cpk
belongs_to :order, autosave: true, query_constraints: [:shop_id, :order_id]
belongs_to :author, class_name: "Cpk::Author"
has_many :chapters, query_constraints: [:author_id, :book_number]
end
class BestSeller < Book
@ -14,4 +16,8 @@ module Cpk
class BrokenBook < Book
belongs_to :order
end
class NullifiedBook < Book
has_one :chapter, query_constraints: [:author_id, :book_number], dependent: :nullify
end
end

View File

@ -0,0 +1,12 @@
# frozen_string_literal: true
module Cpk
class Chapter < ActiveRecord::Base
self.table_name = :cpk_chapters
# explicit definition is to allow schema definition to be simplified
# to be shared between different databases
self.primary_key = [:author_id, :number]
belongs_to :book, query_constraints: [:author_id, :book_number]
end
end

View File

@ -20,4 +20,8 @@ module Cpk
class OrderWithPrimaryKeyAssociatedBook < Order
has_one :book, primary_key: :id, foreign_key: :order_id
end
class OrderWithNullifiedBook < Order
has_one :book, query_constraints: [:shop_id, :order_id], dependent: :nullify
end
end

View File

@ -249,6 +249,13 @@ ActiveRecord::Schema.define do
t.integer :shop_id
end
create_table :cpk_chapters, primary_key: [:author_id, :number], force: true do |t|
t.integer :author_id
t.integer :number
t.integer :book_number
t.string :title
end
create_table :cpk_authors, force: true do |t|
t.string :name
end