How can I make has_many prevent a delete that would lead to

e.g.

class Asset < ActiveRecord::Base
validates_presence_of :asset_number, :make, :model, :location,
:name, :serial_number
validates_numericality_of :asset_number
validates_uniqueness_of :asset_number
belongs_to :user
belongs_to :location
belongs_to :asset_type, :foreign_key => ‘type_id’
end

class Location < ActiveRecord::Base
validates_presence_of :name
validates_uniqueness_of :name
has_many :assets
end

If I create a Location, with name ‘London’ and then create an Asset
with that location it makes sense for me to be able to delete the
asset but not to delete the location.

If the location is deleted I have a situation where the asset now has
a foreign key pointing to a non-existant record. In other words it
become orphaned.

I know that there are ways (in
http://api.rubyonrails.com/classes/ActiveRecord/Associations/ClassMethods.html)
to make the foreign keys be set to null, or to delete all the orphans
(a bit like ON DELETE CASCADE), but what I want is to prevent the
delete of the location if it has assets which belong to it.

I was expecting some way to do this would be fairly easy and built
into AR but my hopes of that are fading… Hopefully it’s just that
I’ve missed something though.

If there is no way to do it that is built into AR how might I mod AR
or something to add that functionality? Presumably some kind of call
to location.assets.is_empty? to check if the delete is going to be
allowed?

-Rob

“On two occasions, I have been asked [by members of Parliament],
‘Pray, Mr. Babbage, if you put into the machine wrong figures, will
the right answers come out?’ I am not able to rightly apprehend the
kind of confusion of ideas that could provoke such a question.”
– Charles Babbage (1791-1871)

“98.5% of DNA is considered to be junk DNA with no known purpose.
Maybe it’s XML tags.” – Anon

http://www.robhulme.com/
http://robhu.livejournal.com/

On 7/21/06, Robert H. [email protected] wrote:

belongs_to :asset_type, :foreign_key => ‘type_id’
with that location it makes sense for me to be able to delete the
to make the foreign keys be set to null, or to delete all the orphans
allowed?

“98.5% of DNA is considered to be junk DNA with no known purpose.
Maybe it’s XML tags.” – Anon

http://www.robhulme.com/
http://robhu.livejournal.com/


Rails mailing list
[email protected]
http://lists.rubyonrails.org/mailman/listinfo/rails

I think a before_destroy on the Location should automatically stop the
destroy action if a false is returned.

before_destroy :check_assets

protected

def check_assets
self.assets.count == 0
end

I think a before_destroy on the Location should automatically stop the
destroy action if a false is returned.

before_destroy :check_assets

protected

def check_assets
self.assets.count == 0
end
Thanks - that does work, but it makes me wonder why there isn’t a
built in way of saying to behave like this whenever there is a
has_many relationship.

Wouldn’t that be a sensible default? Otherwise you end up with orphans
so when you come to say list the assets Rails blows up.

Is there a simple way to propogate an error up ‘Some assets still use
this location’ or something?

-Rob

“On two occasions, I have been asked [by members of Parliament],
‘Pray, Mr. Babbage, if you put into the machine wrong figures, will
the right answers come out?’ I am not able to rightly apprehend the
kind of confusion of ideas that could provoke such a question.”
– Charles Babbage (1791-1871)

“98.5% of DNA is considered to be junk DNA with no known purpose.
Maybe it’s XML tags.” – Anon

http://www.robhulme.com/
http://robhu.livejournal.com/

On 7/21/06, Robert H. [email protected] wrote:

end
-Rob
Maybe it’s XML tags." – Anon

http://www.robhulme.com/
http://robhu.livejournal.com/


Rails mailing list
[email protected]
http://lists.rubyonrails.org/mailman/listinfo/rails

This could be a good plugin / patch to write and submit to the core
team.
It does seem like a good default behavior.

This could be a good plugin / patch to write and submit to the core team.
It does seem like a good default behavior.
If someone could tell me how I could sensibly bubble up an exception /
error code or something that would fit into how things are done in
rails I’ll look at making a patch for core.

“On two occasions, I have been asked [by members of Parliament],
‘Pray, Mr. Babbage, if you put into the machine wrong figures, will
the right answers come out?’ I am not able to rightly apprehend the
kind of confusion of ideas that could provoke such a question.”
– Charles Babbage (1791-1871)

“98.5% of DNA is considered to be junk DNA with no known purpose.
Maybe it’s XML tags.” – Anon

http://www.robhulme.com/
http://robhu.livejournal.com/

On Thursday, July 20, 2006, at 4:15 PM, Robert H. wrote:

Thanks - that does work, but it makes me wonder why there isn’t a

http://www.robhulme.com/
http://robhu.livejournal.com/


Rails mailing list
[email protected]
http://lists.rubyonrails.org/mailman/listinfo/rails

IIRC, the default behavior is to destroy all children of a record when
it is destroyed.

Of course the best solution here would be for you to protect the record
at the controller level too. Here are a couple of strategies you can
use.

  1. a helper method for the model like ‘can_destroy?’ so you can do
    something like this…

def destroy
@item = Item.find(params[:id])
if @item.can_destroy?
@item.destroy
flash[:notice] = ‘record destroyed’
else
flash[:warning] = ‘record not destroyed’
end
end

  1. having the before_destroy callback raise an exception…

def destroy
begin
Item.destroy(params[:id])
flash[:notice] = ‘record destroyed’
rescue
flash[:warning] = ‘record not destroyed’
end
end

I would probably go with the first one and write a function that
recursively tests all the children for dependents. Otherwise, you might
end up with a partial destroy if the rails first tries to destroy a
dependent object that has no children before encountering one that did.

_Kevin
www.sciwerks.com

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs