Paul
2011-Feb-04 20:30 UTC
Why does Rails not reset the association when the id is changed?
Rails is great and most things just work easily. However, I''ve never been able to get a definite answer on whether one should do, validates :parent, :presence => true or, validates :parent_id, :presence => true given, class Parent end class Child belongs_to :parent end I''ve always thought that validating the :parent (and not the foreign key) is the *more* correct thing to do ... but I don''t understand why Rails does not reset the parent association when the parent_id is changed as demonstrated here, child = Child.find(..) child.parent_id = nil puts child.valid? # outputs false child = Child.find(..) child.parent child.parent_id = nil puts child.valid? # outputs true! Any thoughts? -- 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.
Michael Pavling
2011-Feb-04 20:36 UTC
Re: Why does Rails not reset the association when the id is changed?
On 4 February 2011 20:30, Paul <pkmiec@gmail.com> wrote:> I''ve always thought that validating the :parent (and not the foreign > key) is the *more* correct thing to do ... but I don''t understand why > Rails does not reset the parent association when the parent_id is > changed as demonstrated here, > > Any thoughts?yep... don''t update foreign ids - update associated objects:> child = Child.find(..) > child.parent = nilone less step ;-)> I''ve never > been able to get a definite answer on whether one should do, > > validates :parent, :presence => trueyep - always validate the object - no sense validating a foreign key field, when the foreign key might not link to a row in the association table. That''s my preference anyhoo... -- 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.
Michael Pavling
2011-Feb-04 20:37 UTC
Re: Why does Rails not reset the association when the id is changed?
On 4 February 2011 20:36, Michael Pavling <pavling@gmail.com> wrote:> That''s my preference anyhoo...oops! This is rails-core list... take it over to "talk" apologies... -- 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.
Ernie Miller
2011-Feb-04 20:39 UTC
Re: Why does Rails not reset the association when the id is changed?
On Feb 4, 2011, at 3:30 PM, Paul wrote:> Rails is great and most things just work easily. However, I''ve never > been able to get a definite answer on whether one should do, > > validates :parent, :presence => true > > or, > > validates :parent_id, :presence => true > > given, > > class Parent > end > > class Child > belongs_to :parent > end > > I''ve always thought that validating the :parent (and not the foreign > key) is the *more* correct thing to do ... but I don''t understand why > Rails does not reset the parent association when the parent_id is > changed as demonstrated here, > > child = Child.find(..) > child.parent_id = nil > puts child.valid? # outputs false > > child = Child.find(..) > child.parent > child.parent_id = nil > puts child.valid? # outputs true! > > Any thoughts? >This is due to the way that association proxies lazy load their targets. In the first case, if you only loaded the child record, and modified the parent_id attribute, then you never load the parent object, because you never accessed the association proxy. In the latter case, you did access the association proxy, so the parent got loaded, but then you modified the parent_id, directly. I''d recommend that you be consistent -- if you''re checking if the associated object exists, set the association to nil, instead of the id, and you shouldn''t have a problem. -- 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.
Jon Leighton
2011-Feb-04 22:43 UTC
Re: Why does Rails not reset the association when the id is changed?
Hey, In edge rails there is a mechanism for checking whether the loaded association target is "stale" - so if you do record.foo_id = x, then record.foo will load the target afresh. I''m not sure whether it necessarily works with validation like this, but hopefully it does. [I haven''t tried.] Just to emphasise, this is new in edge - it is not in the 3-0-stable branch. Jon On Fri, 2011-02-04 at 15:39 -0500, Ernie Miller wrote:> On Feb 4, 2011, at 3:30 PM, Paul wrote: > > > Rails is great and most things just work easily. However, I''ve never > > been able to get a definite answer on whether one should do, > > > > validates :parent, :presence => true > > > > or, > > > > validates :parent_id, :presence => true > > > > given, > > > > class Parent > > end > > > > class Child > > belongs_to :parent > > end > > > > I''ve always thought that validating the :parent (and not the foreign > > key) is the *more* correct thing to do ... but I don''t understand why > > Rails does not reset the parent association when the parent_id is > > changed as demonstrated here, > > > > child = Child.find(..) > > child.parent_id = nil > > puts child.valid? # outputs false > > > > child = Child.find(..) > > child.parent > > child.parent_id = nil > > puts child.valid? # outputs true! > > > > Any thoughts? > > > > This is due to the way that association proxies lazy load their targets. In the first case, if you only loaded the child record, and modified the parent_id attribute, then you never load the parent object, because you never accessed the association proxy. > > In the latter case, you did access the association proxy, so the parent got loaded, but then you modified the parent_id, directly. I''d recommend that you be consistent -- if you''re checking if the associated object exists, set the association to nil, instead of the id, and you shouldn''t have a problem. >-- http://jonathanleighton.com/
Paul
2011-Feb-05 00:13 UTC
Re: Why does Rails not reset the association when the id is changed?
Thanks for confirming validate :parent is the preferred way.> yep... don''t update foreign ids - update associated objects: > > > child = Child.find(..) > > child.parent = nil > > one less step ;-)Sure ... sometimes the parent_id though is passed via form params. Which works in 99% cases, however, I had one or two cases where something loaded the parent before setting parent_id and validating :). -- 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.
Paul
2011-Feb-05 00:14 UTC
Re: Why does Rails not reset the association when the id is changed?
This seems helpful. I''ll take a look at edge. On Feb 4, 2:43 pm, Jon Leighton <j...@jonathanleighton.com> wrote:> Hey, > > In edge rails there is a mechanism for checking whether the loaded > association target is "stale" - so if you do record.foo_id = x, then > record.foo will load the target afresh. > > I''m not sure whether it necessarily works with validation like this, but > hopefully it does. [I haven''t tried.] > > Just to emphasise, this is new in edge - it is not in the 3-0-stable > branch. > > Jon > > > > > > > > > > On Fri, 2011-02-04 at 15:39 -0500, Ernie Miller wrote: > > On Feb 4, 2011, at 3:30 PM, Paul wrote: > > > > Rails is great and most things just work easily. However, I''ve never > > > been able to get a definite answer on whether one should do, > > > > validates :parent, :presence => true > > > > or, > > > > validates :parent_id, :presence => true > > > > given, > > > > class Parent > > > end > > > > class Child > > > belongs_to :parent > > > end > > > > I''ve always thought that validating the :parent (and not the foreign > > > key) is the *more* correct thing to do ... but I don''t understand why > > > Rails does not reset the parent association when the parent_id is > > > changed as demonstrated here, > > > > child = Child.find(..) > > > child.parent_id = nil > > > puts child.valid? # outputs false > > > > child = Child.find(..) > > > child.parent > > > child.parent_id = nil > > > puts child.valid? # outputs true! > > > > Any thoughts? > > > This is due to the way that association proxies lazy load their targets. In the first case, if you only loaded the child record, and modified the parent_id attribute, then you never load the parent object, because you never accessed the association proxy. > > > In the latter case, you did access the association proxy, so the parent got loaded, but then you modified the parent_id, directly. I''d recommend that you be consistent -- if you''re checking if the associated object exists, set the association to nil, instead of the id, and you shouldn''t have a problem. > > --http://jonathanleighton.com/ > > signature.asc > < 1KViewDownload-- 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.
Michael Koziarski
2011-Feb-06 04:53 UTC
Re: Why does Rails not reset the association when the id is changed?
On 5/02/2011, at 9:30 AM, Paul <pkmiec@gmail.com> wrote:> Rails is great and most things just work easily. However, I''ve never > been able to get a definite answer on whether one should do, > > validates :parent, :presence => true > > or, > > validates :parent_id, :presence => true >Validate the object, not the foreign key. Otherwise a record with parent_id of -99, 0 or some other nonsense will still pass.> given, > > class Parent > end > > class Child > belongs_to :parent > end > > I''ve always thought that validating the :parent (and not the foreign > key) is the *more* correct thing to do ... but I don''t understand why > Rails does not reset the parent association when the parent_id is > changed as demonstrated here,As Jon mentioned there is some code for this kind of thing in master. As for the historical reason it did that, it''s trickier than it looks :) There can be multiple (or zero) associations for a given _id column, and a patch we tried a while back didn''t handle all those potential cases. There''s no deep philosophical reason it works that way, it''s just historical / evolutionary artifacts sneaking up on you.> > child = Child.find(. > child.parent_id = nil > puts child.valid? # outputs false > > child = Child.find(..) > child.parent > child.parent_id = nil > puts child.valid? # outputs true! > > Any thoughts? > > -- > 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.
Rainer Frey
2011-Feb-06 13:10 UTC
Re: Why does Rails not reset the association when the id is changed?
On Fri, Feb 4, 2011 at 9:36 PM, Michael Pavling <pavling@gmail.com> wrote:> On 4 February 2011 20:30, Paul <pkmiec@gmail.com> wrote: >> I''ve always thought that validating the :parent (and not the foreign >> key) is the *more* correct thing to do >> I''ve never >> been able to get a definite answer on whether one should do, >> >> validates :parent, :presence => true > > yep - always validate the object - no sense validating a foreign key > field, when the foreign key might not link to a row in the association > table.Unfortunately the Rails Guide on Active Record Validation and Callbacks says (Section 3.9): "If you want to be sure that an association is present, you’ll need to test whether the foreign key used to map the association is present, and not the associated object itself." Maybe the guide needs to be updated. Rainer -- 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.
Xavier Noria
2011-Feb-07 10:58 UTC
Re: Why does Rails not reset the association when the id is changed?
On Sun, Feb 6, 2011 at 2:10 PM, Rainer Frey <frey.rainer@gmail.com> wrote:> Unfortunately the Rails Guide on Active Record Validation and > Callbacks says (Section 3.9): > "If you want to be sure that an association is present, you’ll need to > test whether the foreign key used to map the association is present, > and not the associated object itself." > > Maybe the guide needs to be updated.Yeah, I think the wording is unfortunate. Certainly you can''t be sure the association is present by checking that the FK attribute is present. Rather, this topic deserves a warning in my view. Something in the line that if you check whether the FK attribute is present then you *don''t know* whether it is valid. You can decide to take the risk, that''s up to you, but the reader should be warned. A pointer to the validates_existence plugin would be nice. Also to FK constraints as the most robust solution, though they are kinda weird to explain in a generic way nowadays because then #save, #update_attributes and friends can throw exceptions for ordinary validation errors, and that doesn''t fit well with standard idioms. This would deserve its own section in the guide with all practicals details and gotchas. If you''d like to have a stab at any of these revisions please give it a go through docrails. -- 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.
Rainer Frey
2011-Feb-07 13:28 UTC
Re: Why does Rails not reset the association when the id is changed?
On Mon, Feb 7, 2011 at 11:58 AM, Xavier Noria <fxn@hashref.com> wrote:> On Sun, Feb 6, 2011 at 2:10 PM, Rainer Frey <frey.rainer@gmail.com> wrote: > >> Unfortunately the Rails Guide on Active Record Validation and >> Callbacks says (Section 3.9): >> "If you want to be sure that an association is present, you’ll need to >> test whether the foreign key used to map the association is present, >> and not the associated object itself." >> >> Maybe the guide needs to be updated. > > Yeah, I think the wording is unfortunate. Certainly you can''t be sure > the association is present by checking that the FK attribute is > present. > > Rather, this topic deserves a warning in my view. Something in the > line that if you check whether the FK attribute is present then you > *don''t know* whether it is valid. You can decide to take the risk, > that''s up to you, but the reader should be warned.But this thread seems to suggest one should simply validate the association attribute instead. Is that not sufficient then?> If you''d like to have a stab at any of these revisions please give it > a go through docrails.Sorry, my understanding is too limited. Rainer -- 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.
Jon Leighton
2011-Feb-07 14:13 UTC
Re: Why does Rails not reset the association when the id is changed?
On Mon, 2011-02-07 at 14:28 +0100, Rainer Frey wrote:> On Mon, Feb 7, 2011 at 11:58 AM, Xavier Noria <fxn@hashref.com> wrote: > > On Sun, Feb 6, 2011 at 2:10 PM, Rainer Frey <frey.rainer@gmail.com> wrote: > > > >> Unfortunately the Rails Guide on Active Record Validation and > >> Callbacks says (Section 3.9): > >> "If you want to be sure that an association is present, you’ll need to > >> test whether the foreign key used to map the association is present, > >> and not the associated object itself." > >> > >> Maybe the guide needs to be updated. > > > > Yeah, I think the wording is unfortunate. Certainly you can''t be sure > > the association is present by checking that the FK attribute is > > present. > > > > Rather, this topic deserves a warning in my view. Something in the > > line that if you check whether the FK attribute is present then you > > *don''t know* whether it is valid. You can decide to take the risk, > > that''s up to you, but the reader should be warned. > > But this thread seems to suggest one should simply validate the > association attribute instead. Is that not sufficient then?I''d say validating the association attribute would be the best practice in 3.1, but it may result in an extra query to the database to fetch the associated record, if it''s not loaded or if it''s stale. If users wish to avoid that overhead, they can check the FK, but should be aware that this does not guarantee the associated record actually exists. -- http://jonathanleighton.com/
Xavier Noria
2011-Feb-07 14:22 UTC
Re: Why does Rails not reset the association when the id is changed?
On Mon, Feb 7, 2011 at 2:28 PM, Rainer Frey <frey.rainer@gmail.com> wrote:> But this thread seems to suggest one should simply validate the > association attribute instead. Is that not sufficient then?You can''t still be sure the association is valid, because the associated object is cached if previously fetched, and the FK can be changed directly: fxn@halmos:~/tmp/test_belongs_to ∵ cat app/models/post.rb class Post < ActiveRecord::Base has_many :comments end fxn@halmos:~/tmp/test_belongs_to ∵ cat app/models/comment.rb class Comment < ActiveRecord::Base belongs_to :post validates :post, :presence => true end fxn@halmos:~/tmp/test_belongs_to ∵ cat bypass_validation.rb post = Post.create comment = post.comments.create comment.post_id = -1 p comment.save comment.reload p comment.post_id fxn@halmos:~/tmp/test_belongs_to ∵ rails runner bypass_validation.rb true -1 You''re going to store the post_id in the database anyway. So if you''re going to take the risk of having dangling records, in my view it''s better to take the risk on the post_id rather than on the association. I believe that''s what the quote from the guide tries to say. The validates_existence plugin performs a query. That''s closer to checking the association holds an existing record, but there''s still subject to race conditions (say, a concurrent request deleting the associated record outside your transaction). The only way to be totally sure the association does exist is to move the check to who has the key to guarantee that, which is the database with FK constraints. -- 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.
Jon Leighton
2011-Feb-07 18:44 UTC
Re: Why does Rails not reset the association when the id is changed?
Hey, On Mon, 2011-02-07 at 15:22 +0100, Xavier Noria wrote:> On Mon, Feb 7, 2011 at 2:28 PM, Rainer Frey <frey.rainer@gmail.com> wrote: > > > But this thread seems to suggest one should simply validate the > > association attribute instead. Is that not sufficient then? > > You can''t still be sure the association is valid, because the > associated object is cached if previously fetched, and the FK can be > changed directly:This does work ''properly'' on edge, due to the stale-checking mechanism. I just tried it. Voila: $ rails c Loading development environment (Rails 3.1.0.beta) ruby-1.9.2-p136 :001 > post = Post.create => #<Post id: 1> ruby-1.9.2-p136 :002 > comment = post.comments.create => #<Comment id: 1, post_id: 1> ruby-1.9.2-p136 :003 > comment.post_id = -1 => -1 ruby-1.9.2-p136 :004 > comment.save => false ruby-1.9.2-p136 :005 > comment.errors => {:post=>["can''t be blank"]} ruby-1.9.2-p136 :006 > comment.post => nil Jon -- http://jonathanleighton.com/