class Assembly < ActiveRecord::Base
has_and_belongs_to_many :parts
end
class Part < ActiveRecord::Base
has_and_belongs_to_many :assemblies
end
In console:
part1 = Part.new
assembly1 = Assembly.new
assembly1.parts << part1
part1.delete
Parts.all
=> []
Checking assembly1.parts
shows that there is still a relationship.(!)
How is this possible when the record was deleted?
Also, how to prevent deletion of parts that are associated to assemblies?
Working in Rails 3.0.7.
Everything you were doing here was done from memory (nothing was stored in the database).
the ActiveRecord delete
method will remove an object from the database but it doesn't look for other objects in memory that may have already been referencing that object. I think if you did assembly1.parts.delete(part1)
that would likely do what you were expecting.
If you had saved the objects to the database:
part1 = Part.create
assembly1 = Assembly.create(:parts => [part1])
assembly1.parts
# => [part1]
part1.delete
assembly1.parts
# => [part1]
assembly1.reload
assembly1.parts
# => []
Note here how even if it's in the database part1.delete
won't necessarily remove it from your assembly object until you refresh the in-memory collection or delete it using the method I mentioned earlier assembly1.parts.delete(part1)
UPDATE
I think you usually shouldn't use the delete()
method. You should almost always use destroy()
. delete()
will just fire off a delete to the database and ignores all callbacks and I believe :dependent => :destroy
-style declarations in your model. If you use the destroy()
method then you can declare a before_destroy
callback in your model:
class MyClass
has_and_belongs_to_many :foos
before_destroy :allow_destroy
def allow_destroy
foos.empty?
end
end
That should get your requirement of not destroying it if it is part of an assembly. You cannot stop delete()
from executing because it ignores callbacks: ActiveRecord::Relation#delete documentation
More info about model callbacks (documentation)