Given the following class Programmer < ActiveRecord::Base has_many :assignments has_many :projects, :through => :assignments end if I call Programmer#projects.clear, it will delete_all the joining assignments; however, I have a situation where I''d like the assignments to get destroyed instead so that their after_destroy callbacks get called. It would be simple to implement (just call destroy_all rather than delete_all), it''s just not quite clear how the option should be set; since :dependent currently gets ignored when using :through, the seems a logical place, although it''s not quite intuitive either. Anybody have any thoughts on this? -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com. To unsubscribe from this group, send email to rubyonrails-core+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en.
On Sun, Jul 11, 2010 at 11:35 PM, Mateo Murphy <mateo.murphy@gmail.com> wrote:> Given the following > > class Programmer < ActiveRecord::Base > has_many :assignments > has_many :projects, :through => :assignments > end > > if I call Programmer#projects.clear, it will delete_all the joining > assignments; however, I have a situation where I''d like the assignments to > get destroyed instead so that their after_destroy callbacks get called. It > would be simple to implement (just call destroy_all rather than delete_all), > it''s just not quite clear how the option should be set; since :dependent > currently gets ignored when using :through, the seems a logical place, > although it''s not quite intuitive either.Yep, it is not implemented. I just added some docs about it this week: http://github.com/rails/rails/commit/92ff71bb14b1b589a3d5c04d120e4b9210b243b1 You can add :dependent => :destroy to the assignments has_many and clear those instead. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com. To unsubscribe from this group, send email to rubyonrails-core+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en.
On 11-Jul-10, at 6:31 PM, Xavier Noria wrote:> On Sun, Jul 11, 2010 at 11:35 PM, Mateo Murphy > <mateo.murphy@gmail.com> wrote: > >> Given the following >> >> class Programmer < ActiveRecord::Base >> has_many :assignments >> has_many :projects, :through => :assignments >> end >> >> if I call Programmer#projects.clear, it will delete_all the joining >> assignments; however, I have a situation where I''d like the >> assignments to >> get destroyed instead so that their after_destroy callbacks get >> called. It >> would be simple to implement (just call destroy_all rather than >> delete_all), >> it''s just not quite clear how the option should be set; >> since :dependent >> currently gets ignored when using :through, the seems a logical >> place, >> although it''s not quite intuitive either. > > Yep, it is not implemented. I just added some docs about it this week: > > http://github.com/rails/rails/commit/92ff71bb14b1b589a3d5c04d120e4b9210b243b1 > > You can add :dependent => :destroy to the assignments has_many and > clear those instead.Thanks for the info. I realize that clearing the source is one solution, but implementing this is quite simple, I''ve done it my own project via a small patch. I''d be willing to submit a patch, I''m just not certain what the configuration option should be and where it should go; maybe something like this? has_many :projects, :through => :assignments, :dependent => :destroy_source -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com. To unsubscribe from this group, send email to rubyonrails-core+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en.
On Mon, Jul 12, 2010 at 4:23 AM, Mateo Murphy <mateo.murphy@gmail.com> wrote:> Thanks for the info. I realize that clearing the source is one solution, but > implementing this is quite simple, I''ve done it my own project via a small > patch. I''d be willing to submit a patch, I''m just not certain what the > configuration option should be and where it should go; maybe something like > this? > > has_many :projects, :through => :assignments, :dependent => :destroy_sourceI think it should be just :destroy. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com. To unsubscribe from this group, send email to rubyonrails-core+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en.
On Mon, Jul 12, 2010 at 9:16 AM, Xavier Noria <fxn@hashref.com> wrote:> On Mon, Jul 12, 2010 at 4:23 AM, Mateo Murphy <mateo.murphy@gmail.com> wrote: > >> Thanks for the info. I realize that clearing the source is one solution, but >> implementing this is quite simple, I''ve done it my own project via a small >> patch. I''d be willing to submit a patch, I''m just not certain what the >> configuration option should be and where it should go; maybe something like >> this? >> >> has_many :projects, :through => :assignments, :dependent => :destroy_source > > I think it should be just :destroy.I believe this is essentially the issue discussed at https://rails.lighthouseapp.com/projects/8994/tickets/2251-associationcollectiondestroy-should-only-delete-join-table-records - where the suggestion to infer the destroyability from the belongs_to seemed most sensible. It is certainly not appropriate to always destroy the source records when the target records are destroyed, so calling the option just :destroy would be dangerous - see examples on that ticket. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com. To unsubscribe from this group, send email to rubyonrails-core+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en.
On 12-Jul-10, at 7:49 PM, Will Bryant wrote:> On Mon, Jul 12, 2010 at 9:16 AM, Xavier Noria <fxn@hashref.com> wrote: >> On Mon, Jul 12, 2010 at 4:23 AM, Mateo Murphy >> <mateo.murphy@gmail.com> wrote: >> >>> Thanks for the info. I realize that clearing the source is one >>> solution, but >>> implementing this is quite simple, I''ve done it my own project via >>> a small >>> patch. I''d be willing to submit a patch, I''m just not certain what >>> the >>> configuration option should be and where it should go; maybe >>> something like >>> this? >>> >>> has_many :projects, :through => :assignments, :dependent >>> => :destroy_source >> >> I think it should be just :destroy. > > I believe this is essentially the issue discussed at > https://rails.lighthouseapp.com/projects/8994/tickets/2251-associationcollectiondestroy-should-only-delete-join-table-records > - where the suggestion to infer the destroyability from the belongs_to > seemed most sensible. > > It is certainly not appropriate to always destroy the source records > when the target records are destroyed, so calling the option just > :destroy would be dangerous - see examples on that ticket.This isn''t the same issue; what I want is the source records destroyed (rather than deleted, which is what currently happens) when the target records are removed from the collection, not when the target records are destroyed. But I think that points out a certain confusion if :dependent => :destroy option is reused, as in all other cases it implies what happens to the target; maybe we need a separate option to configure what happens to the source, something like :source_dependent ? -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com. To unsubscribe from this group, send email to rubyonrails-core+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en.
On Tue, Jul 13, 2010 at 4:41 AM, Mateo Murphy <mateo.murphy@gmail.com> wrote:> But I think that points out a certain confusion if :dependent => :destroy > option is reused, as in all other cases it implies what happens to the > target; maybe we need a separate option to configure what happens to the > source, something like :source_dependent ?As a guideline in my mind, has many through is an augmented habtm. In that sense, destroying the owner of the association does not affect the models in the target collection themselves, only the join models. In a habtm there''s no join model, just an auxiliary table. But in hmt the join table is a model, and thus support for some sort of :dependent would be nice. Since the target is gonna be untouched, :destroy is enough for me. It can only mean what you want to do with the join table. It could also be the case that we implement and document that you are gonna use whatever is configured in the ordinary has many of the join model in the owner side. (People in examples seem to forget :dependent in the has many with the join model, but you rarely want the default :dependent.) class User < AR::Base # this :dependent is what you normally would configure has_many :subscriptions, :dependent => :destroy has_many :magazines, :through => :subscriptions end In that case user.magazines=, user.magazines.clear, etc. could check the config of has_many :subscriptions. That interface could also emphasize that the important bit in these associations is has_many :subscriptions, while the hmt is just a convenience way to let AR do the joins and maintain the m-n table for you. Should use it a bit to be convinced, but at first sight it looks reasonable to me. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com. To unsubscribe from this group, send email to rubyonrails-core+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en.
On 13-Jul-10, at 4:15 AM, Xavier Noria wrote:> On Tue, Jul 13, 2010 at 4:41 AM, Mateo Murphy > <mateo.murphy@gmail.com> wrote: > >> But I think that points out a certain confusion if :dependent >> => :destroy >> option is reused, as in all other cases it implies what happens to >> the >> target; maybe we need a separate option to configure what happens >> to the >> source, something like :source_dependent ? > > As a guideline in my mind, has many through is an augmented habtm. In > that sense, destroying the owner of the association does not affect > the models in the target collection themselves, only the join models.In some case has_many through is an augmented habtm, but not all; sometimes it''s just a convenient way of traversing associations i.e.: class Company has_many :contacts has_many :projects, :through => :contacts end> In a habtm there''s no join model, just an auxiliary table. But in hmt > the join table is a model, and thus support for some sort of > :dependent would be nice. > > Since the target is gonna be untouched, :destroy is enough for me. It > can only mean what you want to do with the join table.I''m not sure that is necessarily obvious, given that the :dependent option has a very specific meaning in other contexts. Reusing it here this way may lead to confusion.> > It could also be the case that we implement and document that you are > gonna use whatever is configured in the ordinary has many of the join > model in the owner side. (People in examples seem to forget :dependent > in the has many with the join model, but you rarely want the default > :dependent.) > > class User < AR::Base > # this :dependent is what you normally would configure > has_many :subscriptions, :dependent => :destroy > has_many :magazines, :through => :subscriptions > end > > In that case user.magazines=, user.magazines.clear, etc. could check > the config of has_many :subscriptions.There may be cases where you wouldn''t want the same behavior though, not to mention that the default dependent behavior of has_many (nullify) is not the same as the current behavior of has_many through. I think a seperate configuration option is the most logical way of dealing with this... -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com. To unsubscribe from this group, send email to rubyonrails-core+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en.
On Thu, Jul 15, 2010 at 6:44 PM, Mateo Murphy <mateo.murphy@gmail.com> wrote:> In some case has_many through is an augmented habtm, but not all; sometimes > it''s just a convenient way of traversing associations i.e.: > class Company > has_many :contacts > has_many :projects, :through => :contacts > endYeah.>> It could also be the case that we implement and document that you are >> gonna use whatever is configured in the ordinary has many of the join >> model in the owner side. (People in examples seem to forget :dependent >> in the has many with the join model, but you rarely want the default >> :dependent.) > > There may be cases where you wouldn''t want the same behavior though > > not to > mention that the default dependent behavior of has_many (nullify) is not the > same as the current behavior of has_many through.That''s a good point (indeed by default it does nothing). And I think you are right, they could be different. It could be the case that the has many of the join model has no :dependent option because the parent model does cascade delete in the database, while clearing the has many through should delete the join models. I think the most common case is that they match though, and it would be a smell to be forced to repeat :dependent => :destroy twice in every single pair (with or without that name). Also think that new :dependent should have a good default. Can we combine them somehow perhaps? -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com. To unsubscribe from this group, send email to rubyonrails-core+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en.
On Thu, Jul 15, 2010 at 6:44 PM, Mateo Murphy <mateo.murphy@gmail.com> wrote:>> Since the target is gonna be untouched, :destroy is enough for me. It >> can only mean what you want to do with the join table. > > I''m not sure that is necessarily obvious, given that the :dependent option > has a very specific meaning in other contexts. Reusing it here this way may > lead to confusion.Regarding the name, if there''s a problem there I see it in overloading :dependent rather than :destroy. Because that''s a ":dependent" that has nothing to do with the deletion of the parent model. The option should say "what to do with the join models when we undo the association?", and the natural answer I think would be :destroy, :delete_all, or :nullify. Same option values as in has_many. It could be called instead... I don''t know, :unlink, :clear perhaps... I don''t know something that makes apparent we are talking about unlinking them, no deletion of the models at both ends of the has many through is involved here. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com. To unsubscribe from this group, send email to rubyonrails-core+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en.
On 15-Jul-10, at 3:05 PM, Xavier Noria wrote:> On Thu, Jul 15, 2010 at 6:44 PM, Mateo Murphy > <mateo.murphy@gmail.com> wrote: > >>> Since the target is gonna be untouched, :destroy is enough for me. >>> It >>> can only mean what you want to do with the join table. >> >> I''m not sure that is necessarily obvious, given that the :dependent >> option >> has a very specific meaning in other contexts. Reusing it here this >> way may >> lead to confusion. > > Regarding the name, if there''s a problem there I see it in overloading > :dependent rather than :destroy. Because that''s a ":dependent" that > has nothing to do with the deletion of the parent model. > > The option should say "what to do with the join models when we undo > the association?", and the natural answer I think would be :destroy, > :delete_all, or :nullify. Same option values as in has_many.Agreed> It could be called instead... I don''t know, :unlink, :clear perhaps... > I don''t know something that makes apparent we are talking about > unlinking them, no deletion of the models at both ends of the has many > through is involved here.The way I see it is, :dependent governs what happens to a target when it''s removed from the collection, and we want to configure what happens to the source when the target is removed from the collection. I think that something like :source_dependent might make sense?> > -- > You received this message because you are subscribed to the Google > Groups "Ruby on Rails: Core" group. > To post to this group, send email to rubyonrails- > core@googlegroups.com. > To unsubscribe from this group, send email to rubyonrails-core+unsubscribe@googlegroups.com > . > For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en > . >-- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com. To unsubscribe from this group, send email to rubyonrails-core+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en.