开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜