« My Ruby on Rails Experience, Part 3 | Main | Hacking Hours »

Nov 26, 2005

Comments

Bill Eisenhauer

Let me preface this by saying that I've only coded a "Hello World" RoR app...but I have done some reading.

It sounds like you have your belongs_to and has_one reversed. I have read examples that lead me to believe the has_one goes with the parent. As in (and pardon the formatting since it appears near impossible to add whitespace):

class Order < ActiveRecord::Base
has_one :invoice
end

class Invoice < ActiveRecord::Base
belongs_to :order
end

However, the table structure is not as I'd do it:

orders
id
name

invoices
id
order_id

I would have put an invoice_id within orders. And as I've read, you can do it this way, but the save behavior is slightly different.

As its complex, I'd rather have you research the save behavior. I'm getting this from the book, "Agile Web Development with Rails" by Dave Thomas and David Heinemeier Hansson. I would consider this book a must-have for what you are trying to achieve.

Hope this helps.

Bill

Graham Glass

Hi Bill,

I've using the book you recommend for the last few days, which is one of the reasons for my concern.

As far as I can tell, the belongs_to must go with the class whose table contains the foreign key. So the design approach that you would take is not supported by Rails. Ditto for the table design that I would use in my own example.

Let me know if you find out anything to the contrary.

Cheers,
Graham

Christopher St. John

Rails would very much prefer you to model things as "school has_one address" and "address belongs_to school", which means moving the keys around so that the address table has a school_id column. That gets you an auto-save when you assign an address to a school, and cascaded deletes and updates will the way you want. Hibernate is a lot more flexible with this sort of thing.

Tom

But "school has_one address" and "address belongs_to school" is, in any case, the right way around to do this; you shouldn't jump through hoops to get Rails to cope with your weird associations, just do it the more natural way.

Get rid of address_id in the schools table, put a school_id column in the addresses table, switch the associations around, and be happy when everything just works.

Graham Glass

Hi Tom,

I also need a Student to have an address, so your solution does not work. Besides, it is poor database design to have a low-level concept such as address have a reference back to a higher-level concept such as school. I should not have to warp my database design to fit Rail's current limitations. I've solved the problem in my code by adding a few lines of custom code into my School model that destroy the Address automatically using the before_destroy hook, but hopefully Rails will be improved in the future to make this unnecessary.

Regards,
Graham

Edward Frederick

Hi Graham,

17 hours? Now that's a bender of mythical proportions.

I think the underlying issue is that table-with-fk-is-child is a RDBMS convention as well as a Rails convention, and ActiveRecord is more of an ORM tool and less of a general purpose DAO layer.

As we know, cascade (in rails, :dependent) is provided to manage parent/child constraints, but if you want the reverse, you normally need to use triggers (in rails, callbacks). You could use a cascade set null fk constraint (if schools are allowed to have no address) combined with a trigger to delete the referenced address when the school is deleted. I guess the rails analogue would be the use of callbacks. These are both workarounds in a sense that they don't allow you to represent your constraint 'out of the box'.

So to play devil's advocate, the constraint isn't natural to represent in the underlying relational data store (I think--I'm not a database guy). That being said, there's no reason why ActiveRecord must strictly mimic RDBMS semantics--functionality could (and probably in your opinion, should) be added to handle this type of constraint automagically.

No help here,

Ed

Graham Glass

Hi Ed,

Actually, table-with-fk-is-child is *not* an RDBMS convention; see the IBM article at http://www-128.ibm.com/developerworks/web/library/wa-dbdsgn1.html and check out the section called "Complex Datatypes" which describes my use case.

I'm going to post some ideas tomorrow on how to improve and simplify ActiveRecord. Let me know what you think!

Regards,
Graham

Shane

I don't know if this will help, but have you tried has_many? I was using has_one and in my limited grasp of all of this resorted to using has_many. This method sort of makes sense in that if you will be using the address table for student addresses as well, then an address definitely needs has_many students. Just my $.02

ben

Well in English, the phrase "school belongs to address" does not sound like what you want anyway ("belongs_to" would seem to clearly denote ownership. AR correctly deletes anything you declare *owned* by a parent object when the parent is deleted).

I wonder what happens if you do "has_one" on either side?

Dan

This is the exact problem I ran into last night. It took me forever to figure out why it wasn't working and when I finally got it to work (how you did) it no longer made sense to me.

There needs to be some better support for these one-to-one type relationships.

The comments to this entry are closed.

Destiny

  • Destiny is my science fiction movie about the future of humanity. It's an epic, similar in breadth and scope to 2001: A Space Odyssey.

    To see the 18 minute video, click on the graphic below.

    Destiny17small

People