I’m trying to model this inheritance for a simple blog system
Blog has many Entries, but they may be different in their nature. I don’t want to model the Blog table, my concern is about the entries:
- simplest entry is an
Articlethat hastitleandtext Quote, however, does not have a title and has shorttextMediahas aurland acomment…- etc…
What is a proper way to model this with Ruby on Rails? That is
- Should I use ActiverRecord for this or switch to DataMapper?
- I would like to avoid the “one big table” approach with lots of empty cells
When I split the data into Entry + PostData, QuoteData etc can I have belongs_to :entry in these Datas without having has_one ??? in the Entry class? That would be standard way to do it in sql and entry.post_data may be resolved by the entry_id in the postdata table.
EDIT: I don’t want to model the Blog table, I can do that, my concern is about the entries and how would the inheritance be mapped to the table(s).
I’ve come across this data problem several times and have tried a few different strategies. I think the one I’m a biggest fan of, is the STI approach as mentioned by cicloon. Make sure you have a
typecolumn on your entry table.The thing I like about this approach, is you can keep the generic Entry data in the entry model. Abstract out any of the sub-entry type data into their own data tables, and have a has_one association to them, resulting in no extra columns on your entries table. It also works very well for when you’re doing your views:
and from your views you can do either:
or have more control:
You can find a pretty generic way of generating forms as well, I usually render the generic entry fields in an
entries/_form.html.erbpartial. Inside that partial, I also have atype render for the sub form data. The sub forms in turn can use
accepts_nested_attributes_for+fields_forto get the data passed through properly.The only pain I have with this approach, is how to handle the controllers and route helpers. Since each entry is of its own type, you’ll either have to create custom controllers / routes for each type (you may want this…) or make a generic one. If you take the generic approach, two things to remember.
1) You can’t set a
:typefield through update attributes, your controller will have to instantiate the appropriateArticle.newto save it (you may use a factory here).2) You’ll have to use the
becomes()method (@article.becomes(Entry)) to work with the entry as an Entry and not a subclass.Hope this helps.
Warning, I’ve actually used Media as a model name in the past. In my case it resulted in a table called medias in rails 2.3.x however in rails 3, it wanted my model to be named Medium and my table media. You may have to add a custom Inflection on this naming, though I’m not sure.