I have several classes that use the same set of address details. Rather that repeat the same fields for each class, I decide to use an Address object backed by an addresses table. So, for those model classes that need an Address object, I did this class Client < ActiveRecord::Base has_one :address # ... end class Account < ActiveRecord::Base has_one :address # ... end and so on, and created an addresses table and Address model. But, after getting some interesting errors from my unit tests and jumping around though assorted Rails docs and discussion sites, I''ve come to the understanding that, if using "has one", the Address class needs to know about all classes that use it; the addresses table must have client_id, account_id, and so on. Is this correct? (This runs counter to my initial intuition, that since this is a "has-a" relation, the Client class/table, for example, would link to the Address class/table using address_id.) From what I''ve manage to find, the alternative is to express the association in the Address class: class Address < ActiveRecord::Base belongs_to :client belongs_to :account end But this seems backwards; why should this class need to know about what other classes are going to use it? I don''t want to ask an address object who owns it, but rather ask an object for its address. Have I misunderstood something? Do I have to use ''belongs_to'' in order to reuse the Address class for different owner classes, if I also want to avoid altering the addresses table every time I decide some other object needs to use the Address class? Thanks, James
you''ve got belongs_to and has_one backwards. You''d want to use something like: class Client < ActiveRecord::Base belongs_to :address end class Account < ActiveRecord::Base belongs_to :address end belongs_to means that the foreign key for the relationship is in the same model as the relationship is defined. So your clients table will have an address_id, as will your accounts table. has_one implies that the foriegn key is in the table at the other end of the relationship. so has_one :address would mean that the foreign key is in the address table. By default, the foreign key is expected to be modelname_id, but this is configurable: class Account < ActiveRecord::Base has_one :address, :foreign_key => ''linked_id'' end class Client < ActiveRecord::Base has_one :address, :foreign_key => ''linked_id'' end This lets you put the foreign key in the addresses table and the Address class needs to know nothing about the classes that it is linked to. These relations seem to be the #1 source of confusion for most Rails newbies. The naming is unfortunate, but you only have to learn it once. :) Jason On 6/26/05, James Britt <james.britt-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> I have several classes that use the same set of address details. > > Rather that repeat the same fields for each class, I decide to use an > Address object backed by an addresses table. > > So, for those model classes that need an Address object, I did this > > class Client < ActiveRecord::Base > has_one :address > # ... > end > > class Account < ActiveRecord::Base > has_one :address > # ... > end > > and so on, and created an addresses table and Address model. > > But, after getting some interesting errors from my unit tests and > jumping around though assorted Rails docs and discussion sites, I''ve > come to the understanding that, if using "has one", the Address class > needs to know about all classes that use it; the addresses table must > have client_id, account_id, and so on. > > Is this correct? > > (This runs counter to my initial intuition, that since this is a "has-a" > relation, the Client class/table, for example, would link to the > Address class/table using address_id.) > > From what I''ve manage to find, the alternative is to express the > association in the Address class: > > class Address < ActiveRecord::Base > belongs_to :client > belongs_to :account > end > > But this seems backwards; why should this class need to know > about what other classes are going to use it? I don''t want to ask an > address object who owns it, but rather ask an object for its address. > > Have I misunderstood something? > > Do I have to use ''belongs_to'' in order to reuse the Address class for > different owner classes, if I also want to avoid altering the addresses > table every time I decide some other object needs to use the Address class? > > > Thanks, > > James > > > > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails >
> Do I have to use ''belongs_to'' in order to reuse the Address class for > different owner classes, if I also want to avoid altering the addresses > table every time I decide some other object needs to use the Address class?It''s a bit confusing at first, but what you want is class Client < ActiveRecord::Base belongs_to :address end That way the address object need not know about clients or any of its other ''users''. -- Cheers Koz
James Britt <james.britt-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:> class Address < ActiveRecord::Base > belongs_to :client > belongs_to :account > end > > But this seems backwards; why should this class need to know > about what other classes are going to use it? I don''t want to ask an > address object who owns it, but rather ask an object for its address.The docs point out that when to use belongs_to and when to use has_one depends on where the foreign key is. Sometimes the right place to put the foreign key makes reading the code a little awkward. Rather than "belongs_to" you should just read "has_foreign_key". So, I''d make class Customer < ActiveRecord::Base belongs_to :address end Then the customers table will have an address_id field pointing to the appropriate Address record. -- doug-jGAhs73c5XxeoWH0uzbU5w@public.gmane.org
Ha I''ve been down this road... of the fun... as long as you never have any has_many situations that will arise for addresses then what you really have is... client: address_id account: address_id client belongs to address account belongs to address see the Is it a belongs_to or has_one at http://api.rubyonrails.com/classes/ActiveRecord/Associations/ClassMethods.html and you dont need an association on the address side as long as you dont care to get the parent of the address... ie the client or account which if you want to be able to add new types is probably what you want. in the controller because you have a belongs_to relation... you want something like @venue = Venue.new(@params[:venue]) @venue.address = Address.new(@params[:address]) if @venue.save in create and @venue = Venue.find(@params[:id]) if @venue.address.update_attributes(@params[:address]) if @venue.update_attributes(@params[:venue]) in update You have to go down a whole different path if you want something to has_many addresses and if you think that is going to come up anytime soon, I would just go ahead and design for it now... _______________________________________________ Rails mailing list Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org http://lists.rubyonrails.org/mailman/listinfo/rails
Michael Koziarski wrote:>>Do I have to use ''belongs_to'' in order to reuse the Address class for >>different owner classes, if I also want to avoid altering the addresses >>table every time I decide some other object needs to use the Address class? > > > It''s a bit confusing at first, but what you want is > > class Client < ActiveRecord::Base > belongs_to :address > end > > That way the address object need not know about clients or any of its > other ''users''.So I gather. Thanks, James
Jason Foreman wrote:> you''ve got belongs_to and has_one backwards.Well, I''d argue that the Address belongs to the Client, and so Client should be the class (and table) that maintains knowledge of the relationship, but that''s not The Rails Way.> > You''d want to use something like: > > class Client < ActiveRecord::Base > belongs_to :address > end > > class Account < ActiveRecord::Base > belongs_to :address > end > > > belongs_to means that the foreign key for the relationship is in the > same model as the relationship is defined. So your clients table will > have an address_id, as will your accounts table. has_one implies that > the foriegn key is in the table at the other end of the relationship. > so has_one :address would mean that the foreign key is in the address > table.OK, I now see this, as unintuitive as it may be. I can see "belongs_to" being used to define an explicit mapping from an object back to the thing to which it belongs, but not the point of "has_one" being used to put the foreign key into the thing being owned. It seems to get the coupling (needlessly) reversed. Anyway, as I prefer to have master objects be in control of subordinate objects, with subordinate objects and tables ignorant of their containers, I gather I have to use "belongs_to" in the primary classes. Thanks, James
Doug Alcorn wrote:> > The docs point out that when to use belongs_to and when to use has_one > depends on where the foreign key is. Sometimes the right place to put > the foreign key makes reading the code a little awkward. Rather than > "belongs_to" you should just read "has_foreign_key".Yet I''ve also seen docs that omitted this placement of the foreign key: For example: http://wiki.rubyonrails.com/rails/show/ForumExample has this: class Message < ActiveRecord::Base has_one :author end but Authors has no message_id field. And this is presented as an example of using has_one http://wiki.rubyonrails.com/rails/show/has_one "See Forum Example."> > So, I''d make > > class Customer < ActiveRecord::Base > belongs_to :address > end > > Then the customers table will have an address_id field pointing to the > appropriate Address record.After I posted my question I gave this approach a try, on the off chance that, as wrong as it struck me, it may be one of those "poor naming that has now stuck" deals. And, of course, I got the results I wanted. Thanks to all for the fast replies. Too fast, actually, for me to get back with my discoveries :) James
> Anyway, as I prefer to have master objects be in control of subordinate > objects, with subordinate objects and tables ignorant of their > containers, I gather I have to use "belongs_to" in the primary classes.belongs_to does exactly what you''re talking about, it''s just that in this case the name is a bit off. There''s no *ownership* or *control* implied by belongs_to, it''s just a matter of who has the foreign key. With belongs_to your subordiante objects and tables are ignorant of who owns them. We really need to come up with a nicer name for this and create a method alias. -- Cheers Koz
On Monday 27 June 2005 02:32, Michael Koziarski wrote:> belongs_to does exactly what you''re talking about, it''s just that in > this case the name is a bit off.[snip]> We really need to come up with a nicer name for this and create a > method alias.How about "refers to"? Michael -- Michael Schuerig Not only does lightning not strike mailto:michael-q5aiKMLteq4b1SvskN2V4Q@public.gmane.org twice, it usually doesn''t strike once. http://www.schuerig.de/michael/ --Salman Rushdie, Fury