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
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 On Apr 2, 2006, at 11:12 AM, 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. > > 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 > > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >
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
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.
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:> 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 > > _______________________________________________ > 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
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_pictureWhich 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
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 > endYep, 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
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 -- Posted via http://www.ruby-forum.com/.