How to define allow_destroy and :dependent => :destroy in Rails?
Given the following database model, how and where would you define the deletion relationships between the models? I figured out the basic table association setup but when I want to add dependencies to enable the deletion of nested objects I get lost.
Here is the relationship model I created.
class User < ActiveRecord::Base
has_many :studies
end
class Study < ActiveRecord::Base
has_many :internships
belongs_to :student, :class_name => "User", :foreign_key => "user_id"
belongs_to :subject
belongs_to :university, :class_name => "Facility", :foreign_key => "facility_id"
accepts_nested_attributes_for :subject, :university, :locations
end
class Subject < ActiveRecord::Base
has_many :studies
end
class Internship <开发者_开发百科 ActiveRecord::Base
belongs_to :study
belongs_to :company, :class_name => "Facility", :foreign_key => 'facility_id'
accepts_nested_attributes_for :company, :study
end
class Facility < ActiveRecord::Base
has_many :internships
has_many :locations
has_many :studies
accepts_nested_attributes_for :locations
end
class Location < ActiveRecord::Base
belongs_to :facility
end
Where would you put :dependent => :destroy
and :allow_destroy => true
to enable the following scenarios? I do not want to confuse you. Therefore, I leave out my tryings.
Internship scenario: A user wants to delete an internship.
- Its associated company (facility) can be deleted if the company is not related to another internship.
- If so, the locations of the associated company can be deleted.
- The related study will not be affected.
Study scenario: A user wants to delete a study.
- Its associated subject can be deleted if no other study refers to this subject.
- Its associated university (facility) can be deleted if no other study refers to this university.
- Its associated internships can be deleted. The company can only be deleted if no other internship refers to it.
I am totally unsure whether I can add :dependent => :destroy
only after has_one
and has_many
or also after belongs_to
.
Edit: To simplify the problem please stick to the following (reduced) example implementation.
class Study < ActiveRecord::Base
belongs_to :subject
accepts_nested_attributes_for :subject, :allow_destroy => true
end
class Subject < ActiveRecord::Base
has_many :studies, :dependent => :destroy
end
In my view I provide the following link.
<%= link_to "Destroy", study, :method => :delete, :confirm => "Are you sure?" %>
The path is based on the named routes given by a restful configuration in routes.rb
.
resources :studies
resources :subjects
The study will be deleted when I click the link - the subjects stays untouched. Why?
I think your relations are the wrong way around here...
The accepts_nested_attributes_for
should be declared on the model that has_many
for the model that it has_many
of. Also, in your example, destroying the subject would enforce dependent_destroy
on the many studies
, not the other way around.
You can add :dependent => :destroy
to all three but I'm not sure if that'll give you enough power to do the checks required before determining whether an associated object should be destroyed.
You have a few options.
Add a before_destroy callback on each model that raises an exception or stops the delete from occurring.
class Facility < ActiveRecord::Base
has_many :internships
has_many :locations
has_many :studies
def before_destroy
raise SomethingException if internships.any? || ...
# or
errors.add(...
end
end
or do it silently by overriding destroy
class Facility < ActiveRecord::Base
has_many :internships
has_many :locations
has_many :studies
def destroy
return false if internships.any || ...
super
end
end
Note: this is basically meant for guidance only and may not be the correct way of overriding destroy etc...
精彩评论