Generic flags for a model in RoR - ruby-on-rails

I am making a Ruby on Rails app and am realizing that my User class could potentially end up with a lot of generic boolean / integer attributes. For example, suppose I have a promotion each quarter, and I only want a person to be able to use the promotion once. Then I'd have to make a new column each quarter has_used_promotion_N to track that promotion.
Alternatively, I'm thinking of creating a new column called "Generic Flags" which is just a comma separated value of flags set on the account. For example:
"has_used_promotion_1, has_used_promotion_2, limit_on_feature_a=20" etc. could be set for some particular user
(or maybe I'll store it as JSON)
In any case, I'm thinking of giving myself some sort of NoSQL-like functionality in my DB.
Is this really bad design for some reason? Has anyone else done this before? Anything I'm completely missing about RoR?

In my opinion Promotion should be a separate model with a many to many relationship with User. When you have a promotion you would create a Promotion instance and when a person uses that promotion you add that person to promotion.users relationship.
This is much better than your idea because you can now query those relationship. Want a list of all users that used the first quarter promotion? No problem. You can do that with your solution, but you have to resort to some hackiness (is that a word?) to do it, and you'd have to parse the generic flag string for EVERY user on EVERY query. Not ideal to say the least.

If there's an arbitrarily-sized collection of associations then it should be a real relation, modeled using the existing DB and facilities. Promotions sounds like that, and it seems like it would be something you'd be modeling in your DB already; no real reason to keep a duplicate value hierarchy.
For actually-generic flags, you could have a named-flag table and again use a real association.
You could also just serialize a flag object to a text column. Doing so impedes your ability to do trivial searches on a flag/flag value, however. This may not matter for a wad of flags associated with a single user that you don't care about unless they're logged in, but tread lightly--it depends on your usecase.

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 - best database design for existing model

So I have inherited some Rails 4 code and database models which I need to add to.
The model, called mpb_item has a table called mpb_items.
Inside this items table there are columns such as:
role1_start_date, role2_start_date, role3_start_date, role4_start_date
Not ideal but this is what it is. They should have been in a separate roles table I guess.
I need to add functionality to Suspend any one of these roles (or all of them).
I guess I can either:
To the existing table, I can add a new boolean column for each existing role column. e.g. role1_suspended, role2_suspended etc
Create table called mpb_suspensions, with 2 columns: mpb_item_id and role_name. Since the roles don't have ids themselves, the role_name column will store 'role1', or 'role2' etc depending on which role was suspended.
In my View, I need to have the ability to "suspend" each job, or all of them. I'm not sure how the model code would look to do this and which approach would be best.
If I had to build this, given the minimal info you provided I'd start by picking option 2 that you described. (a RoleSuspension is its own table) Benefits include:
fewer new columns total, and doesn't make any table indefinitely large
no redundant columns (role1, role2, etc.)
no need to add more columns if the # of possible roles changes (ie. it's more normalized)
no nil values (approach 1)
you can easily query for the overall state of RoleSuspensions (whereas with approach 1 you'd need to count the non-nil values in role1_suspended, role2_suspended, etc. then sum them up), and easier to index
you can attach logic to a RoleSuspension; it's a separate animal from its parent MbpItem. If it's just a bunch of boolean columns, any complex logic would need to be mushed into the MbpItem model, and would likely be much messier to maintain.
Following option 2's logic, suspending a role would involve creating a new record like this:
#mbp_item.role_suspensions.create!(role_number: 2)
and checking for suspension status would involve something like this:
if #mbp_item.role_suspensions.any?
# or....
RoleSuspension.where(role_number: 3).each do |s|
puts "Item #{s.mbp_item} is suspended for role #{s.role_number}."
end
Database performance will be a larger consideration with this approach, depending on the answers to the following questions:
Where and how often do you need to check for role suspensions?
When you check for role suspensions, how do you approach asking the question? In other words is some global task asking "What role suspensions exist, and for what mbp_items?" or do you check for suspensions on a given mbp_item when you render that object?
If you'll need to check for role suspensions very frequently, perhaps you should add a boolean column to mbp_items called has_suspensions, which will be a partial cache in that it will indicate whether any suspensions exist for this MbpItem (and must be maintained in after_create and after_destroy hooks).
On the other hand, if you know that suspension info never will need to have its own logic and never will need to be queried directly, you could add a single column to MbpItem, role_suspensions, containing a serialized array of integers for the suspended roles. This would be a much less invasive approach in terms of database structure, and probably much simpler even than your option 1 in that it would allow you to suspend and de-suspend any role number with less code and less metaprogramming, but if you ever need to add any fancy logic to the suspension or desuspension process (ie. if a RoleSuspension deserves status as its own object), you'd regret this approach.

How to create an Order Model with a type field that dictates other fields

I'm building a Ruby on Rails App for a business and will be utilizing an ActiveRecord database. My question really has to do with Database Architecture and really the best way I should organize all the different tables and models within my app. So the App I'm building is going to have a database of orders for an ECommerce Business that sells products through 2 different channels, a subscription service where they pick the products and sell it for a fixed monthly fee and a traditional ECommerce channel, where customers pay for their products directly. So essentially while all of these would be classified as the Order model, there are two types of Orders: Subscription Order and Regular Order.
So initially I thought I would classify all this activity in my Orders Table and include a field 'Type' that would indicate whether it is a subscription order or a regular order. My issue is that there are a bunch of fields that I would need that would be specific to each type. For instance, transaction_id, batch_id and sub_id are all fields that would only be present if that order type was a subscription, and conversely would be absent if the order type was regular.
My question is, would it be in my best interest to just create two separate tables, one for subscription orders and one for regular orders? Or is there a way that fields could only appear conditional on what the Type field is? I would hate to see so many Nil values, for instance, if the order type was a regular order.
Sorry this question isn't as technical as it is just pertaining to best practice and organization.
Thanks,
Sunny
What you've described is a pattern called Single Table Inheritance — aka, having one table store data for different types of objects with different behavior.
Generally, people will tell you not to do it, since it leads to a lot of empty fields in your database which will hurt performance long term. It also just looks gross.
You should probably instead store the data in separate tables. If you want to get fancy, you can try to implement Class Table Inheritance, in which there are actually separate but connected table for each of the child classes. This isn't supported natively by ActiveRecord. This gem and this gem might be able to help you, but I've never used either, so I can't give you a firm recommendation.
I would keep all of my orders in one table. You could create a second table for "subscription order information" that would only contain the columns transaction_id, batch_id and sub_id as well as a primary key to link it back to the main orders table. You would still want to include an order type column in the main database though to make it a little easier when debugging.
Assuming you're using Postgres, I might lean towards an Hstore for that.
Some reading:
http://www.devmynd.com/blog/2013-3-single-table-inheritance-hstore-lovely-combination
https://github.com/devmynd/hstore_accessor
Make an integer column called order_type.
In the model do:
SUBSCRIPTION = 0
ONLINE = 1
...
It'll query better than strings and whenever you want to call one you do Order:SUBSCRIPTION.
Make two+ other tables with a foreign key equal to whatever the ID of the corresponding row in orders.
Now you can keep all shared data in the orders table, for easy querying, and all unique data in the other tables so you don't have bloated models.

Howto "virtually" create and save an attribute of a separate model in rails

The title may appear as if I am asking howto access/find/update an attribute of a related/nested model but this is not the case and unfortunately this is the best title I could figure out.
I would like to build a soccer management game with ruby on rails, where routine total_attack_value and total_defense_values are matched etc. I don't plan to make the simulation too deep like in here and here, such as calculating and matching separate corner_attack or side_attack values but seriously intend to include the goalkeeper's skill in total_defense_value.
To clarify, the total_attack_value is going to be calculated as "total_shooting_value x total_pass_value x total_possess_value x/+ Rand() etc" and all of these ..._values are going to be calculated inside the Team model but the total_defense_value should have "goalkeeper_skill_value" which is going to be the skill of the player selected as the goalkeeper by the user for the coming match, as I planned.
I cannot think of anything else than saving and retrieving which player is put into goalkeeper position by the user using virtual attributes, since the user is going to schedule the match for a future time and the goalkeeper selection should persist until then. In this case I'm going to create a Player_Position model and an association model belonging to both Position and Player and an assign_positions function in Player model etc. However this is exactly what I am trying to avoid, code- and complexity-wise being the same as to offer the user the possibility to drag&drop players to positions separately as seen in some games like soccermanager and goalunited.
Does rails offer any simple/ready solution to this problem as it does to simple CRUD operations, like an attribute or STI?
I'm not sure if I completely understand what you are trying to achieve but the next version of Rails, 3.2, has simple Key Value Store functionality that you may be able to use. The release candidate is already out so you would be able to try it out to see if it met your needs.
A short note on the functionality was included in the latest release notes.

How do I handle a "fixed content" model in Rails?

In some of my forms I have to provide a dropdown where users can select some districts. The thing is, there will always be a fixed number of districts ( 31 in this case ). Should I create a model named District having only a string field,populate it with the data and be done with it?
It's content will not modify over time. Is there another way?
You should take a look at jnunemakers scam-gem. It mimics the AR for you and lets you define the models in your Rails app without a backing database/table.
I use this whenever I want something to do psuedo belongs to/has many relationships, but do not want to back a model with a database as the data does not change often, if ever.
Making a table-backed model is the simplest way. Otherwise you're going to end up implementing half of an AR model anyway, because you'll want to use collection_select at some point.
I guess it depends on how you want to store the districts and whether you want to do any querying etc.
For example, you could just have the list of districts as a constant, then store them as a string in your models (not very elegant), or as you say you could create a model and use active record associations - this would allow you to easily query on districts etc.

Resources