Forum: Ruby on Rails RANT: belongs_to -> refers_to

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
A63764f318f10379c8b51349b757cf4b?d=identicon&s=25 Jay Levitt (Guest)
on 2006-04-02 17:16
(Received via mailing list)
Every once in a while, I pipe up and whine that "belongs_to" should
really
be 'refers_to" [http://dev.rubyonrails.org/ticket/2130].  It's time
again.

I've got a bunch of stuff going onto eBay, so, like any good engineer, I
don't just post it manually: I design a Rails-based inventory database
that
creates a semantically-correct XHTML/CSS auction posting with a variable
number of thumbnails (stored with file_column) and Textile fields.

I start out with

class Item < ActiveRecord::Base
  :has_many :pictures
end class

But I want one of those pictures to be featured as the gallery photo.
So,
naturally, I gravitate towards adding

class Item < ActiveRecord::Base
  :has_one primary_picture, :class_name => 'Picture'
end

I am encouraged in this futile pursuit by the docs, which I quickly skim
to
see things like

  :has_one :last_comment, :class_name => "Comment", :order =>
"posted_on"

Of course, in the light of day, it's clear that this automagically
creates
the last_comment association by picking the most recent comment.  But at
3am, it just reinforced the tendency to use has_one.  Ditto the many
other
has_one examples I found - half of which used the automatic-first-record
feature, and half of which were probably just making the same mistake I
was.

I started getting nil objects, and was mystified until I finally tried
explicitly setting the foreign key:

  :has_one primary_picture, :class_name => 'Picture',
    :foreign_key => 'primary_picture_id'

at which point Rails helpfully told me that there was no
Picture.primary_picture_id field.  Then I remembered for the umpteenth
time
that has_one is for the record that does NOT have the foreign key, and
belongs_to is for the one that does, and I should not be misled by the
semantics of the actual has_one and belongs_to keywords.

Item :belongs_to primary_picture makes no sense.  Item :refers_to
primary_picture does.  This is way too small for even a plugin - and I
don't think that type of syntax change belongs in a plugin, anyway.  I
have
yet to hear anyone who's opposed to it... can't we PLEASE add this alias
and consider deprecating belongs_to over time?  It's... just... wrong.

Jay Levitt
Bc80625db60e9db4394c51d6c1892b49?d=identicon&s=25 Derrick Spell (Guest)
on 2006-04-02 18:52
(Received via mailing list)
I'm opposed to it.  I'm not sure if your problem is with grammar or
with the visual abstraction of what you are trying to do, but the
semantics are correct.  Think of it this way:

Let's say I have 50 widgets that I want to sell on eBay.  Each of
these widgets will have its own auction posting.  However, all the
widgets look alike, so I have a single picture of the widget.  I
don't want to have 50 pictures of my widget, so it would be incorrect
to say that each widget has_one picture.  Instead, each widget
belongs_to that picture of a widget.

Now, you are using the term Item, so perhaps you have another model
to handle postings of the Item on eBay.  This would change the
argument above slightly, but the semantics remain the same.  If a
picture is used on only a single Item, but an item might have
multiple pictures (which is how I interpret this domain), then the
foreign key should be on the picture, not on the Item, and then you
would be correctly using the has_one and has_many.

Now, by placing the foreign key on the picture, you can achieve the
concept of a primary picture by placing a boolean flag on the picture
tuple akin to IsPrimary.  Then set up your item model with a has_many
picture and a has_one primary picture (with the constraint that it
must have the IsPrimary flag set).

OR... you can have a has_may :pictures, belongs_to :primary_picture

OR... you can use acts_as_list on your has_many and maintain that the
first item in the list is the primary picture.  I kinda like this
approach.

-Derrick Spell
675475d0b65710be6d992eb5eb2c61c2?d=identicon&s=25 Gregory Seidman (Guest)
on 2006-04-02 18:55
(Received via mailing list)
On Sun, Apr 02, 2006 at 11:12:47AM -0400, Jay Levitt wrote:
} Every once in a while, I pipe up and whine that "belongs_to" should
really
} be 'refers_to" [http://dev.rubyonrails.org/ticket/2130].  It's time
again.
[...]
} Item :belongs_to primary_picture makes no sense.  Item :refers_to
} primary_picture does.  This is way too small for even a plugin - and I
} don't think that type of syntax change belongs in a plugin, anyway.  I
have
} yet to hear anyone who's opposed to it... can't we PLEASE add this
alias
} and consider deprecating belongs_to over time?  It's... just... wrong.

In some contexts it is wrong. In others it is right, such as has_many.
Perhaps this would make your life easier:

class ActiveRecord::Base
  class << self
    alias :refers_to :belongs_to
  end
end

} Jay Levitt
--Greg
Cb610750ee94ca103aef4b2dc7b1b768?d=identicon&s=25 Nick Stuart (Guest)
on 2006-04-02 19:04
(Received via mailing list)
If you really want this, just place this in your environment.rb

module ActiveRecord::Associations::ClassMethods
  alias :refers_to :belongs_to
end

And there you have your refers_to method.
Df040ca3576504b24a73744179903277?d=identicon&s=25 Tobias Lütke (Guest)
on 2006-04-02 19:07
(Received via mailing list)
Improve your code

class Picture < AR:B
   acts_as_list
end

class Item < ActiveRecord::Base
  has_one :primary_picture, :class_name => 'Picture', :order =>
'position ASC'
end

On 4/2/06, Jay Levitt <jay+news@jay.fm> wrote:
> class Item < ActiveRecord::Base
> I am encouraged in this futile pursuit by the docs, which I quickly skim to
>
> semantics of the actual has_one and belongs_to keywords.
> Rails mailing list
> Rails@lists.rubyonrails.org
> http://lists.rubyonrails.org/mailman/listinfo/rails
>


--
Tobi
http://shopify.com       - modern e-commerce software
http://typo.leetsoft.com - Open source weblog engine
http://blog.leetsoft.com - Technical weblog
A63764f318f10379c8b51349b757cf4b?d=identicon&s=25 Jay Levitt (Guest)
on 2006-04-02 20:18
(Received via mailing list)
On Sun, 2 Apr 2006 12:50:22 -0400, Derrick Spell wrote:

> Now, you are using the term Item, so perhaps you have another model
> to handle postings of the Item on eBay.  This would change the
> argument above slightly, but the semantics remain the same.  If a
> picture is used on only a single Item, but an item might have
> multiple pictures (which is how I interpret this domain), then the
> foreign key should be on the picture, not on the Item, and then you
> would be correctly using the has_one and has_many.

Your second guess is right - I'm not actually posting to eBay with this
model (yet), and the items are one-of-a-kind, so there's no habtm
relationship; each picture is associated with one and only one item, but
each item has_many pictures.
>
> Now, by placing the foreign key on the picture, you can achieve the
> concept of a primary picture by placing a boolean flag on the picture
> tuple akin to IsPrimary.  Then set up your item model with a has_many
> picture and a has_one primary picture (with the constraint that it
> must have the IsPrimary flag set).

The problem with that is that there's no way to enforce "one and only
one
primary picture" if the boolean's in the picture.

>
> OR... you can have a has_may :pictures, belongs_to :primary_picture

Which is what I'm doing now, but semantically, in this context, an item
doesn't belong to a picture - it's the other way around.  Don't you
think?

>
> OR... you can use acts_as_list on your has_many and maintain that the
> first item in the list is the primary picture.  I kinda like this
> approach.

Yep, I hadn't thought of that, but it makes the most sense, and probably
would have fallen out once I started thinking about being able to
re-order
the pictures!  That one's nice.

Jay
A63764f318f10379c8b51349b757cf4b?d=identicon&s=25 Jay Levitt (Guest)
on 2006-04-02 20:21
(Received via mailing list)
On Sun, 2 Apr 2006 12:51:54 -0400, Gregory Seidman wrote:

> In some contexts it is wrong. In others it is right, such as has_many.
> Perhaps this would make your life easier:
>
> class ActiveRecord::Base
>   class << self
>     alias :refers_to :belongs_to
>   end
> end

Yep, I keep swearing I'm gonna do that.  I just think it might help
other
programmers as well - I often see belongs_to confusion here, especially
among novices.

Jay
59ea1b450935b9d70abfec4186b7a4d5?d=identicon&s=25 Jeff Coleman (progressions)
on 2006-04-02 20:24
Jay,

Just wanted to say that I pretty much agree with you.  I was in
basically the exact same situation you were the other day, with a
listing of Items where each Item has_many :images, and I thought I could
do "has_one :main_image", like you described.  Of course I realized the
same thing you did and it still feels kinda funny, since semantically,
my Item doesn't belong to its main picture, the picture belongs to the
item.

They even take time in Agile Web Dev to say "we know it seems funny to
say 'belongs_to', so think of it as 'refers_to'".  Not sure I understand
why it was coded that way in the first place, since so many of Rails
conventions are based on easily translating coding semantics into
natural language semantics.

Jeff
This topic is locked and can not be replied to.