Rails: storing arrays in DB vs. setting up relationship - ruby-on-rails

Setting: There are two models with the following attributes.
Person: name, age, work_experience, available_dates
WorkExperience: job_title, starting_date, ending_date
Then, I can do the following
Person
has_many work_experiences
WorkExperience
belongs_to Person
Q1: Should available_dates be an attribute (array of dates) or a child (e.g. Person has_many available_dates)?
Q2: Can Person have work_experiences field that's just an array of objects instead of an individual table in DB?

TL;DR: As in all design questions, I think the answer is "it depends."
On Q1:
I've done both ways before. If I were making this decision, I would consider the following:
Do I see myself adding more information to available_dates in a very near future? For example, it could be location, timezone, commute distance, and so on that would make this data into "availability" in general. In that
case, I'd rather create separate objects with association.
Do I see myself reusing these dates in some other place in my code? Then I'd rather make them into separate objects and persist.
On Q2:
I don't think it'd be good for your sanity. DB has simple datatypes and are not designed to retain object models.

On Q1 I would go with an association instead of an array as it provides more flexibility. So a child, as you call it is what I would do.
On Q2 I would also go with a separate WorkExperience Model as it also provides more flexibility and room for growth. Also the array might get a bit messy as a Person starts gathering work experiences and querying for information might get more complicated than it needs to be with an array. With a separate model Active Record will give you a lot of tools you can use to dig into a person's work experiences.
Hope that helps.

Related

calculated fields: to store in DB or not to store?

I am building a ruby on rails application where a user can learn words from a story (having many stories on his list of stories to learn from), and conversely, a story can belong to many users. Although the story is not owned by the user (it's owned by the author), the user can track certain personal things about each story that relate to him and only to him, such as how many words are left to learn in each of his stories (which will obviously differ from user to user).
Currently, I have a has_many :through relationship set up through a third table called users_stories. My concern/question has to do with "calculated fields": is it really necessary to store things like words_learnt_in_this_story (or conversely, words_not_yet_learnt_in_this_story) in the database? It seems to me that things like this could be calculated by simply looking at a list of all the words that the user has already learnt (present on his learnt_words_list), and then simply contrast/compare that master list with the list of words in the story in order to calculate how many words are unlearnt.
The dilemma here is that if this is the case, if all these fields can simply be calculated, then there seems to be no reason to have a separate model. If this is the case, then there should just be a join model in the middle and have it be a has_and_belongs_to_many relationship, no? Furthermore, in such a scenario, where do calculated attributes such as words_to_learn get stored? Or maybe they don't need to get stored at all, and rather just get calculated on the fly every time the user loads his homepage?
Any thoughts on this would be much appreciated! Thanks, Michael.
If you're asking "is it really necessary to store calculated values in the DB" I answer you. No, it's not necessary.
But it can give you some pros. For example if you have lots of users and the users call those values calculating a lot then it could be more winnable strategy to calculate them once in a while. It will save your server resources.
Your real question now is "What will be more effective for you? Calculate values each time or calculate them once in a while and store in DB?"
In a true relational data model you don't need to store anything that can be calculated from the existing data.
If I understand you correctly you just want to have a master word list (table) and just reference those words in a relation. That is exactly how it should be modelled in a relational database and I suggest you stick with it for consistency reason. Just make sure you set the indices right in the database.
If further down the road you run into performance issue (usually you don't) you can solve that problems then by caching/views etc.
It is not necessary to store calculated values in the DB, but if the values are often used in logic or views its good idea to store it in Database once(calculate again on change) and use from there rather then calculating in views or model.

Rails model with multipe values for a field

I have a model Movie. That can have multiple Showtimes. Each Showtime is a pair of start and end times. Movies get saved in the database.
So although a Movie might have_many Showtimes, does that really need to be a model, or just a class, or some kind of custom tuple-like type?
I have seen where you can have a field with an array of values, but this would not be basic values as each value is a pair of times.
What is the best way to achieve this?
Showtimes should be a model, yes. Here are a few reasons:
Most relational databases don't natively support a tuple or array type.
What if you want to query movies occurring at a particular time? This would be difficult to do with a custom field, but would be relatively trivial with a separate table.
Most importantly, it enables better flexibility and extensibility through decreased coupling. For instance, does a showtime always exist exclusively to a movie? What if you want to extend your schema to add theatres where each theatre has many showtimes?

Parent Model that can only have one child in Rails?

Sorry the title is pretty unclear - I'm just not quiet sure how to phrase the question without explaining it.
I would like to record workouts with my app. I would like a Workout Table (what I'm calling the parent) that has basic information like date and sub_workout_type_id
A workout record can have either a Cardiovascular workout (One Model) or a Strength Workout (Another Model).
My thought on have 3 tables instead of just the 2 Cario Workout model and strength workout model is that I would be able to pull a feed of any type of workout, by pulling the Workout Records and then dig deeper as needed.
Perhaps there is a more ruby-ish way to do this? Because right now I don't know of a way to say has_one_model_or_the_other. Thanks!
I see two options, either you use STI (single table inheritance) : in that case you would have a single table that would be able to contain both a cardiovascular model or a strength workout, and a type. This would only work if the two models share some common characteristics.
Another solution is to write something like
has_one :cardiovascular
has_one :strength
and then use validations to enforce that only one of them is set.
Hope this helps.
As mentioned by #nathanvda, STI could be a good choice.
If you're looking to store class specific data with your models, maybe check out Modeling inheritance with Ruby/Rails ORMs to see if that answer gives you any ideas on how to model this relationship.
Note, the example there uses has_many's but a lot of the ideas are similar.

Rails 3.0 - best practices: multiple subtypes of a model object

So this is probably a fairly easy question to answer but here goes anyway.
I want to have this view, say media_objects/ that shows a list of media objects. Easy enough, right? However, I want the list of media objects to be a collection of things that are subtypes of MediaObject, CDMediaObject, DVDMediaObject, for example. Each of these subtypes needs to be represented with a db table for specific set of metadata that is not entirely common across the subtypes.
My first pass at this was to create a model for each of the subtypes, alter the MediaObject to be smart enough to join into those tables on it's conceptual 'all' behavior. This seems straightforward enough but I end up doing a lot of little things that feel not so rails-O-rific so I wanted to ask for advice here.
I don't have any concrete code for this example yet, obviously, but if you have questions I'll gladly edit this question to provide that information...
thanks!
Creating a model for each sub-type is the way to go, but what you're talking about is multiple-table inheritance. Rails assumes single-table inheritance and provides really easy support for setting it up. Add a type column to your media_objects table, and add all the columns for each of the specific types of MediaObject to the table. Then make each of your models a sub-class of MediaObject:
class MediaObject < ActiveRecord::Base
end
class CDMediaObject < MediaObject
end
Rails will handle pulling the records out and instantiating the correct subclass, so that when you MediaObject.find(:all) the results will contain a mixture of instances of the various subclasses of MediaObject.
Note this doesn't meet your requirement:
Each of these subtypes needs to be represented with a db table for specific set of metadata that is not entirely common across the subtypes.
Rails is all about convention-over-configuration, and it will make your life very easy if you write your application to it's strengths rather than expecting Rails to adapt to your requirements. Yes, STI will waste space leaving some columns unpopulated for every record. Should you care? Probably not; database storage is cheap, and extra columns won't affect lookup performance if your important columns have indexes on them.
That said, you can setup something very close to multiple-table inheritance, but you probably shouldn't.
I know this question is pretty old but just putting down my thoughts, if somebody lands up here.
In case the DB is postgres, I would suggest use STI along hstore column for storing attributes not common across different objects. This will avoid wasting space in DB yet the attributes can be accessed for different operations.
I would say, it depends on your data: For example, if the differences between the specific media objects do not have to be searchable, you could use a single db table with a TEXT column, say "additional_attributes". With rails, you could then serialize arbitrary data into that column.
If you can't go with that, you could have a general table "media_objects" which "has one :dataset". Within the dataset, you could then store the specifics between CDMediaObject, DVDMediaObject, etc.
A completely different approach would be to go with MongoDB (instead of MySQL) which is a document store. Each document can have a completely different form. The entire document tree is also searchable.

Attribute with multiple values in rails: booleans, string and serialize or hbtm?

Say you have a Book model that can belong to multiple categories. Categories are predefined, but we might let the user add his own even though most of the time default ones are enough.
What is the best way to deal with that according to you ?
a) a many to many relationship to a Category model ? But isn't that overkill given the fact default categories are enough most of the time ?
b) booleans for each default category and an extra string for user entered categories
C) just a string and the use of serialize ? But then it might be a bit more tricky to use checkbox inputs for the default choices
d) any other suggestion of yours...
Thanks for your time!
Thanks
You'll probably want to use HABTM. It's not overkill if you're ever going to want to collect any sort of information about the various categories; date created, for example. You'll also gain the ability to easily fetch all books for a given category without having to worry about scopes inside the book model.
Also, down the road you might want to be able to add other objects to categories. There's not much overhead, and it's quite simple to set up, so worth going for, IMHO.
For help on implementing HABTM with checkboxes, check out the HABTM Checkboxes railscast. For a discussion of the differences between HABTM and has_many :through, I really recommend the Two Many-to-Many railscasts.

Resources