Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix bug, when ':dependent => :destroy' violates foreign key constraints #12450

Merged
merged 1 commit into from Jun 27, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions activerecord/CHANGELOG.md
@@ -1,3 +1,10 @@
* Move 'dependent: :destroy' handling for 'belongs_to'
from 'before_destroy' to 'after_destroy' callback chain

Fix #12380.

*Ivan Antropov*

* Fixed `ActiveRecord::Associations::CollectionAssociation#find`
when using `has_many` association with `:inverse_of` and finding an array of one element,
it should return an array of one element too.
Expand Down
17 changes: 11 additions & 6 deletions activerecord/lib/active_record/associations/builder/association.rb
Expand Up @@ -69,7 +69,10 @@ def define_extensions(model)
end

def define_callbacks(model, reflection)
add_before_destroy_callbacks(model, name) if options[:dependent]
if options[:dependent]
check_dependent_options
add_destroy_callbacks(model, name)
end
Association.extensions.each do |extension|
extension.build model, reflection
end
Expand Down Expand Up @@ -110,12 +113,14 @@ def valid_dependent_options

private

def add_before_destroy_callbacks(model, name)
unless valid_dependent_options.include? options[:dependent]
raise ArgumentError, "The :dependent option must be one of #{valid_dependent_options}, but is :#{options[:dependent]}"
def check_dependent_options
unless valid_dependent_options.include? options[:dependent]
raise ArgumentError, "The :dependent option must be one of #{valid_dependent_options}, but is :#{options[:dependent]}"
end
end

model.before_destroy lambda { |o| o.association(name).handle_dependency }
end
def add_destroy_callbacks(model, name)
model.before_destroy lambda { |o| o.association(name).handle_dependency }
end
end
end
Expand Up @@ -133,5 +133,9 @@ def add_touch_callbacks(model, reflection)
model.after_touch callback
model.after_destroy callback
end

def add_destroy_callbacks(model, name)
model.after_destroy lambda { |o| o.association(name).handle_dependency }
end
end
end
Expand Up @@ -20,8 +20,8 @@ def valid_dependent_options

private

def add_before_destroy_callbacks(model, name)
super unless options[:through]
end
def add_destroy_callbacks(model, name)
super unless options[:through]
end
end
end
Expand Up @@ -831,3 +831,39 @@ def test_reflect_the_most_recent_change
assert_equal post.author_id, author2.id
end
end

class BelongsToWithForeignKeyTest < ActiveRecord::TestCase
def setup
ActiveRecord::Schema.define do
drop_table :authors, if_exists: true
drop_table :author_addresses, if_exists: true

create_table :author_addresses do |t|
end

exec_query <<-eos
create table authors(
id int,
author_address_id int,
name varchar(255),
PRIMARY KEY (id),
FOREIGN KEY (author_address_id) REFERENCES author_addresses(id)
);
eos
end
end

def teardown
ActiveRecord::Schema.define do
drop_table :authors, if_exists: true
drop_table :author_addresses, if_exists: true
end
end

def test_destroy_linked_models
address = AuthorAddress.create!
author = Author.create! id: 1, name: "Author", author_address_id: address.id

author.destroy!
end
end