Assume the following contrived (but plausible) geometric model in which every Edge has two Vertices, every Vertex has many edges. ==== create_table "vertices", :force => true do |t| t.float "x" t.float "y" t.float "z" end create_table "edges", :force => true do |t| t.integer "vertex_a_id" t.integer "vertex_b_id" end ====When we destroy a Vertex, we want all of its attached Edges to be destroyed as well: ==== class Vertex << ActiveRecord::Base has_many :edges, :dependent => :destroy end class Edge << ActiveRecord::Base belongs_to :vertex_a, :class_name => ''Vertex'', :foreign_key => ''vertex_a_id'' belongs_to :vertex_b, :class_name => ''Vertex'', :foreign_key => ''vertex_b_id'' end ====Not surprisingly, the above associations won''t work when you try to delete a vertex: ==== >> va = Vertex.create => #<Vertex id: 1...> >> vb = Vertex.create => #<Vertex id: 2...> >> e = Edge.create(:vertex_a => va, :vertex_b => vb) => #<Edge id: 1, vertex_a_id: 1, vertex_b_id: 2...> >> vb.destroy => ActiveRecord::StatementInvalid: Mysql::Error: Unknown column ''edges.vertex_id'' in ''where clause'': SELECT * FROM `edges` WHERE (`edges`.vertex_id = 2) ====... since Edge does not have a column named ''vertex_id''. So: What''s the Rails-approved technique for destroying all Edges when you destroy their Vertex, regardless of the Vertex''s role (vertex_a or vertex_b)? TIA. - ff -- Posted via http://www.ruby-forum.com/. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Fearless Fool
2010-Jul-22 20:19 UTC
Re: :dependent => :destroy with nonstandard :foreign_key?
So I know it''s bad form to answer your own question, but I realized this must be a job for callbacks, so I RTFM''d. My new definition for Vertex is: class Vertex < ActiveRecord::Base before_destroy do |record| Edge.destroy_all "vertex_a_id = #{record.id}" Edge.destroy_all "vertex_b_id = #{record.id}" end end It appears to do exactly what you''d expect: deleting a Vertex deletes all connected Edges. Note that I also deleted the ":has_many edges" association for the same reason: Edge lacks the vertex_id field that AR depends upon to make the association, so you can''t ask for "va.edges()". But it''s simple enough to mimic its functionality, as in: class Vertex def edges Edge.find_all_by_vertex_a_id(self.id) + Edge.find_all_by_vertex_b_id(self.id) end end Thanks for listening... - ff -- Posted via http://www.ruby-forum.com/. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Marnen Laibow-Koser
2010-Jul-22 20:26 UTC
Re: :dependent => :destroy with nonstandard :foreign_key?
Fearless Fool wrote:> So I know it''s bad form to answer your own question, but I realized this > must be a job for callbacks, so I RTFM''d. My new definition for Vertex > is: > > class Vertex < ActiveRecord::Base > before_destroy do |record| > Edge.destroy_all "vertex_a_id = #{record.id}" > Edge.destroy_all "vertex_b_id = #{record.id}" > end > end > > It appears to do exactly what you''d expect: deleting a Vertex deletes > all connected Edges.Great! You can probably unify those into one query and get better performance at the expense of a bit of Rails magic.> > Note that I also deleted the ":has_many edges" association for the same > reason: Edge lacks the vertex_id field that AR depends upon to make the > association, so you can''t ask for "va.edges()". But it''s simple enough > to mimic its functionality, as in: > > class Vertex > def edges > Edge.find_all_by_vertex_a_id(self.id) + > Edge.find_all_by_vertex_b_id(self.id) > end > end...which you can now probably use a variant of in :finder_sql to restore your has_many :edges. Again, you may be able to refactor it into one query.> > Thanks for listening... > - ffBest, -- Marnen Laibow-Koser http://www.marnen.org marnen-sbuyVjPbboAdnm+yROfE0A@public.gmane.org -- Posted via http://www.ruby-forum.com/. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Fearless Fool
2011-Aug-12 17:35 UTC
Re: :dependent => :destroy with nonstandard :foreign_key?
Resurrecting an old thread because it has a useful lesson: Marnen Laibow-Koser wrote in post #927576:> Fearless Fool wrote: >> [stuff about a before_destroy method using two destroy_all calls] > > Great! You can probably unify those into one query and get better > performance at the expense of a bit of Rails magic. > >> [stuff about an edges method that concatenates two arrays] > > ...which you can now probably use a variant of in :finder_sql to restore > your has_many :edges. Again, you may be able to refactor it into one > query.So as usual, Marnen is right (if not ahead of his time). Using the scoping constructs in Rails 3.0, this all becomes elegant and simple: class Edge << ActiveRecord::Base belongs_to :vertex_a, :class_name => ''Vertex'', :foreign_key => ''vertex_a_id'' belongs_to :vertex_b, :class_name => ''Vertex'', :foreign_key => ''vertex_b_id'' scope :connected_to, lambda (vertex) { where("edges.vertex_a_id = ? OR edges.vertex_b_id = ?", vertex.id, vertex.id } end class Vertex < ActiveRecord::Base # caution: we are using delete_all for efficiency before_destroy { |vertex| Edge.connected_to(vertex).delete_all } end This generates exactly the compact SQL that you''d expect, both for finding: >> Edge.connected_to(v1) => SELECT "edges.*" FROM "edges" WHERE (edges.vertex_a_id = 2 OR edges.vertex_b_id = 2) and for deleting: >> Edge.connected_to(v1).delete_all => DELETE FROM "edges" WHERE (edges.vertex_a_id = 2 OR edges.vertex_b_id = 2) -- Posted via http://www.ruby-forum.com/. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Colin Law
2011-Aug-12 20:07 UTC
Re: Re: :dependent => :destroy with nonstandard :foreign_key?
On 12 August 2011 18:35, Fearless Fool <lists-fsXkhYbjdPsEEoCn2XhGlw@public.gmane.org> wrote:> Resurrecting an old thread because it has a useful lesson: > > Marnen Laibow-Koser wrote in post #927576: >> [snip]O Marnen, Marnen! wherefore art thou Marnen? -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Walter Lee Davis
2011-Aug-13 00:41 UTC
Re: Re: :dependent => :destroy with nonstandard :foreign_key?
On Aug 12, 2011, at 4:07 PM, Colin Law wrote:> On 12 August 2011 18:35, Fearless Fool <lists-fsXkhYbjdPsEEoCn2XhGlw@public.gmane.org> wrote: >> Resurrecting an old thread because it has a useful lesson: >> >> Marnen Laibow-Koser wrote in post #927576: >>> [snip] > > O Marnen, Marnen! wherefore art thou Marnen? >Fun fact: "wherefore" means "why". [1] I wonder where Marnen went, but I never wondered why he was Marnen. I did appreciate his unique brand of scorched earth and incredibly precise answers. Walter 1. In the famous quote, Juliet is wondering *why* Romeo is named the way he is; because of his name, she cannot be allowed to love him. Her logic, typical for Shakespeare women, is quite sound: "A rose by any other name would smell as sweet..." -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Marnen Laibow-Koser
2011-Aug-28 22:23 UTC
Re: Re: :dependent => :destroy with nonstandard :foreign_key?
Walter Davis wrote in post #1016477:> On Aug 12, 2011, at 4:07 PM, Colin Law wrote: > >> On 12 August 2011 18:35, Fearless Fool <lists-fsXkhYbjdPsEEoCn2XhGlw@public.gmane.org> wrote: >>> Resurrecting an old thread because it has a useful lesson: >>> >>> Marnen Laibow-Koser wrote in post #927576: >>>> [snip] >> >> O Marnen, Marnen! wherefore art thou Marnen? >> > > Fun fact: "wherefore" means "why". [1]Indeed.> > I wonder where Marnen went, but I never wondered why he was Marnen. I > did appreciate his unique brand of scorched earth and incredibly > precise answers.Um, thanks...? I don''t know whether to feel flattered or put down. :D Anyway, I''m still around. I just haven''t been posting much. I went on a self-imposed vacation from posting back in January (because I was getting too upset to respond as nicely as I wanted to!), and never got back into the habit. I''ll probably be a more regular contributor again in the near future.> > Walter > > 1. In the famous quote, Juliet is wondering *why* Romeo is named the > way he is; because of his name, she cannot be allowed to love him. Her > logic, typical for Shakespeare women, is quite sound: "A rose by any > other name would smell as sweet..."Yup. Best, -- Marnen Laibow-Koser http://www.marnen.org marnen-sbuyVjPbboAdnm+yROfE0A@public.gmane.org -- Posted via http://www.ruby-forum.com/. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Walter Lee Davis
2011-Aug-29 00:58 UTC
Re: Re: Re: :dependent => :destroy with nonstandard :foreign_key?
On Aug 28, 2011, at 6:23 PM, Marnen Laibow-Koser wrote:> Um, thanks...? I don''t know whether to feel flattered or put down. :DI hope you feel flattered, at least that was what I was aiming for. I did very much enjoy your posts, and learned quite a lot from them. I hope you can find a middle path between saint-like "suffer fools gladly" and and "getting too upset" to start answering again. I''m sure you have quite a lot more to teach me, and others here. Walter -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.