views:

47

answers:

3

In the Rails ActiveRecord Associations guide, I'm confused over why the tables for has_one and has_many are identical:

Example tables for has_many:

customers(id,name)
orders(id,customer_id,order_date)

Example tables for has_one: these tables will, at the database level, also allow a supplier to have many accounts, but we just want one account per supplier

suppliers(id,name)
accounts(id,supplier_id,account_number) #Foreign Key to supplier here??

Shouldn't the tables for has_one be like this instead:

suppliers(id,name,account_id) #Foreign Key to account here
accounts(id,account_number)

Now because the account_id is in the suppliers table, a supplier can never have more than one account.

Is the example in the Rails Guide incorrect?

Or, does Rails use the has_many kind of approach but restricts the many part from happening?

+2  A: 

If you think about this way -- they are all the same:

1 customer can have many orders, so each order record points back to customer.

1 supplier can have one account, and it is a special case of "has many", so it equally works with account pointing back to supplier.

and it is the same case with many-to-many, with junction table pointing back to the individual records... (if a student can take many classes, and one class can have many students, then the enrollment table points back to the student and class records).

as to why account points back to supplier vs account points to supplier, that one I am not entirely sure whether we can have it either way, or one form is better than the other.

動靜能量
I found some links that might help once I pore over them.http://usernameguy.livejournal.com/5268.html and http://duanesbrain.blogspot.com/2006/05/ruby-on-rails-hasone-versus-belongsto.html . Do they make sense to you? Especially the info in the second link?
Zabba
+2  A: 

I believe it has to do with the constraints. With has_one rails will try to enforce that there is only one account per supplier. However, with a has_many, there will be no constraint enforced, so a supplier with has_many would be allowed to exist with multiple accounts.

It does take some getting used to when thinking about the relationships and their creation in rails. If you want to enforce foreign keys on the database side (since rails doesn't do this outside of the application layer), take a look at Mathew Higgins' foreigner

MunkiPhD
Got it. So Rails uses the has_many approach, but enforces that only one record ever will be associated - correct ? If so, I guess that might be a good thing, in a way. Since for some models, it could mean that a few changes in Rails code will allow a has_many in future without changing the database.?
Zabba
Essentially, yes. Just be aware that doing so leaves your database limp and at a low level of integrity (in my opinion). A lot of times if you look at a database you could figure out what's going on. However, if all the code is on the application level, integrating with different systems and maintenance could be a pain. And hope that you never have some kind of data mismatch.
MunkiPhD
+1  A: 

If I understand your question correctly, you believe there is a 1:1 relationship bi-directionally in a has_one/belongs_to relationship. That's not exactly true. You could have:

Class Account
  belongs_to :supplier
  belongs_to :wholesaler
  belongs_to :shipper
  # ...
end

account = supplier.account       # Get supplier's account
wholesaler = Wholesaler.new
wholesaler.accounts << account   # Tell wholesaler this is one of their suppliers
wholesaler.save

I'm not saying your app actually behaves this way, but you can see how a table -- no, let's say a model -- that "belongs to" another model is not precluded from belonging to any number of models. Right? So the relationship is really infinity:1.

I should add that has_one is really a degenerate case of has_many and just adds syntactic sugar of singularizing the association and a few other nits. Otherwise, it's pretty much the same thing and it's pretty much why they look alike.

Steve Ross
Thanks! that gives me some food for thought. So, Rails essentially enforces the "one" in a has_one. I wonder, is that "safe". Presuming only one Rails app will be using the database, it should be ok.
Zabba
One of the key guiding principles in Rails is that it is designed for an application database, not an integration database. That's why constraints are enforced at the application level and not the database level. It drives DBAs nuts :)
Steve Ross