rails3 and the proper way to use associations
I'm doing my first rails(3) application.
Associations don't make sense. First, even the rails guides don't really explain what they do, they just explain how to use them. From what I gather, associations do two things:
a) Allow ActiveRecord to optimize the structure of the database.
b) Allow ActiveRecord to offer an alternate ruby syntax for
joins and the like (SQL queries). I want this.
I'm trying to understand associations, and how to properly use them. Based on the example below, it seems like associations are 'broken' or at least the documentation is.
Consider a trivial version of my application. A teacher modifying wordlists for study.
There are 3 relevant tables for this discussion. For clarity, I've simply included the annotate(1) tool's definition of the table, and removed unnecessary fields/columns.
A wordlist management table:
Table name: wordlist_mgmnt_records
id :integer not null, primary key
byline_id :integer(8) not null
A table that maps words to a word list:
Table name: wordlists
wordlist_mgmnt_id :integer not null
word_id :integer not null
We don't actually care about the words themselves. But we do care about the last table, the bylines:
Table name: bylines
id :integer(8) not null, primary key
teacher_id :integer not null
comment :text not null
Bylines record who, what tool was used, where, when, etc. Bylines are mainly used to trouble shoot what happened so I can explain to users what they should have done (and/or repair their mistakes).
A teacher may modify one or more word list management records at a time (aka single byline). Said another way, a single change may update multiple word lists.
For wordlist_mgmnt_records the associations would be:
has_many :bylines # the same byline id can exist
# in many wordlist_mgmnt_records
But what's the corresponding entry for bylines?
The Beginning Rails 3 (Carneiro, et al) book says:
"Note: For has_one and has_many associations, adding a belongs_to
on the other side of the association is always recommended. The
rule of thumb is that the belongs_to declaration always goes in
the class with the foreign key."
[ Yes, I've also looked at the online rails guide(s) for this. Didn't help. ]
For the bylines table/class do I really want to say?
belongs_to :wordlist_mgmnt_records
That really doesn't make sense. the bylines table basically belongs_to every table in the data base with a bylines_id. So would I really say belongs_to all of them? Wouldn't that set up foreign keys in all of the other tables? That in turn would make changes more expensive (too many CPU cycles) than I really want. Some changes hit lots of tables, some of them very large. I prize speed in normal use, and am willing to wait to find bylines without foreign keys when using bylines for cleanup/repair.
Which brings us full circle. What are associations really doing in rail开发者_运维百科s, and how does one use them intelligently?
Just using associations because you can doesn't seem to be the right answer, but how do you get the added join syntax otherwise?
I'll try to help your confusion....
A byline can have multiple wordlist_mgmnt_records
, so defining the has_many
there seems to make sense.
I'm not sure I understand your confusion in the other direction. Since you have defined the attribute wordlist_mgmnt_records.byline_id
, any given wordlist_mgmnt_record
can only 'have' (belong_to) a single byline. You're simply defining the crows foot via ruby (if you like database diagrams):
wordlist_msgmnt_records (many)>>----------(one) byline
Or read in english: "One byline can have many wordlist_mgmnts, and many individual wordlist_mgmnt's can belong to a single byline"
Adding the belongs_to definition to the wordlist_mgmnt model doesn't affect the performance of the queries, it just let's you do things like:
@record = WordlistMgmntRecord.find(8)
@record_byline = @record.byline
Additionally you're able to do joins on tables like:
@records = WordlistMgmntRecord.joins(:byline).where({:byline => {:teacher_id => current_user.id}})
Which will execute this SQL:
SELECT wordlist_mgmnt_records.*
FROM wordlist_mgmnt_records
INNER JOIN bylines
ON wordlist_mgmnt_records.byline_id = bylines.id
WHERE bylines.teacher_id = 25
(Assuming current_user.id
returned 25)
This is based off of your current DB design. If you find that there's a way you can implement the functionality you want without having byline_id
as a foreign key in the wordlist_mgmnt_records
table then you would modify your models to accomodate it. However this seems to be how a normalized database should look, and I'm not really sure what other way you would do it.
精彩评论