#132 invalid
Kieran Huggins

odd has_many assignment behaviour

Reported by Kieran Huggins | January 16th, 2008 @ 01:03 PM

The behaviour I'm seeing is that you have to assign the first child with an = before you can add more children with << in a has_many relationship.

http://pastie.caboo.se/139664

Comments and changes to this ticket

  • Kieran Huggins

    Kieran Huggins January 16th, 2008 @ 01:03 PM

    • Assigned user set to “Sam Smoot”
  • Kevin Bullock

    Kevin Bullock January 16th, 2008 @ 03:15 PM

    I can verify this against 0.2.5 and trunk. It works properly if you do this:

    article.revisions.create(:content => 'Foo!')
    

    ...but not if you do this (as in the pastie):

    x.article.revisions.create(:content => 'Foo!')
    
  • Kieran Huggins

    Kieran Huggins January 28th, 2008 @ 04:35 PM

    this is sort of frustrating to work around - and seems completely mysterious to me :-(

    I'll take a look through the source to see if I can track down the cause, but I doubt I'll be able to.

    Hope I can help!

  • Kieran Huggins
  • asceth

    asceth January 30th, 2008 @ 02:35 AM

    I'm not getting this problem. I wrote a spec for it in the data_mapper trunk and it passed.

    First modify spec/models/person.rb to include

    has_many :children, :class => 'Person', :foreign_key => 'parent_id'
    belongs_to :person, :foreign_key => 'parent_id'
    

    (I was writing other specs for a self-referential has_many)

    Then the has_many_association_spec:

    it "should allow children to be added with << from the get go" do
        parent = Person.create(:name => "Parent")
        parent.children << Person.create(:name => "Child")
        parent.children.size.should == 1
        parent.save
        parent.reload!
        parent.children.size.should == 1
      end
    
  • Kieran Huggins

    Kieran Huggins January 30th, 2008 @ 02:57 AM

    asceth: your code works for me too. does the code in the pastie work for you?

    http://pastie.caboo.se/139664

  • asceth

    asceth January 30th, 2008 @ 03:06 AM

    Yes its working for me but I have no idea what the "x." stuff is in the "merb -i" part. I did the code in the pastie without merb using a sandbox script that loads data_mapper and defines the classes like you had them. Then in irb I did the code you had in "merb -i" without the "x." parts.

  • Kieran Huggins

    Kieran Huggins January 30th, 2008 @ 03:55 AM

    The "x" seems to be the problem area, so I've re-pastied the example with the "x" explained:

    http://pastie.caboo.se/145270

    Thanks!

  • asceth

    asceth January 30th, 2008 @ 04:40 AM

    I believe the problem lies in HasManyAssociation::Set#method_missing...

    As per the pastie:

    x.article
    

    is actually returning an array since a has_one is still a has_many technically. Taking a look at the #method_missing method which will be called when

    x.article.revisions
    

    is used has itself check if the x.article set responds to the method (it doesn't) goes on to check if Article has any associations by the name of "revisions" (it does) and then stores the results of calling #revisions on every item in x.article (which in this case is just one 'has_one') into an array instead of a TypedSet.

    I believe thats the key to the problem because the array passed back does not have #create so the NoMethodError is thrown like in your pastie and also the array itself is not really an association persay.

    However everything would work if that part of method_missing would be bypassed on a 'has_one' and the 3rd check is done which is it checks if the first item in the 'has_many' (in this case the article since there is only one) responds (and it does since it has the revisions association) and calls it.

    So:

    x.article.first.revisions
    

    works like you'd expect it to. And allows the rest of the pastie to work.

    Maybe HasOneAssociation should be a sub-class of HasManyAssociation?

  • Kevin Bullock

    Kevin Bullock January 30th, 2008 @ 03:33 PM

    Interesting. So my question is, why is has_one behaving like has_many (with the association method returning an array)? That seems very strange. Shouldn't it return the single associated object, unboxed?

  • asceth

    asceth January 30th, 2008 @ 04:27 PM

    The has_one macro assigns a HasManyAssociation as there is no HasOneAssocation. I'm willing to write a sub-class of HasManyAssociation or maybe just sub-class HasNAssocation like HasMany does for HasOne if thats the direction it should be taken.

    This directly affects me as I have a couple has_one relationships I have to work with.

  • Kieran Huggins

    Kieran Huggins January 30th, 2008 @ 08:32 PM

    If I instantiate the Article separately, it works as advertised.

    If I then assign that article to a noun and save it, it won't update the ArticleRevision.article_id to Article.id ..... BUT: if I then add a revision using

    x.article.first.revisions << ArticleRevision.create(...)
    

    and then call save on "x", it updates all the revisions to the proper Article.id.

    Maybe that's just part of the same issue, but i thought I should bring it up!

  • Dan Kubb (dkubb)
  • Sam Smoot

    Sam Smoot May 21st, 2008 @ 01:20 AM

    • State changed from “new” to “invalid”

    OK, this was apparently not very clear. The previous distant-association syntax was a finder convenience only. As asceth mentioned, it doesn't return an actual association. So this ticket is invalid.

Please Sign in or create a free account to add a new ticket.

With your very own profile, you can contribute to projects, track your activity, watch tickets, receive and update tickets through your email and much more.

New-ticket Create new ticket

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

People watching this ticket

Pages