开发者

How to define allow_destroy and :dependent => :destroy in Rails?

开发者 https://www.devze.com 2023-02-19 09:21 出处:网络
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

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.

How to define allow_destroy and :dependent => :destroy in Rails?

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

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号