Fat model, activeModel or in the controller? - ruby-on-rails

My question has to do with data modeling.
We have a Score-model which links to both a Division model and a Element model. Between the Division and the Element model a habtm-relation exists. The score has to be evaluated against an attribute of the Element model (criterium attribute).
Now we want to introduce the concept of "Problems". A problem is each score which does not pass the criterium. (additional info: Multiple scores will be recorded over time, different types of scores exist. Filters on score_types and date ranges are desired)
What is the best way to model the Problem concept?
Just calculate the problems in the controller each time the view of the problems is requested
Introduce a Problems-model (which does not really contain any new information from the Score and Element info
Create a tableless Model like ActiveModel.
None of the above, as it is a newbie question and you should do it like so and so ... (fill in the blanks)
Any help would be much appreciated.

Without knowing what your codebase looks like and assuming the Problem model would only be storing the id of an associated Score, I'm going to suggest using a scope on your Score model. You can create the ARel query (or queries) to get the desired Scores without adding too much more code. Check the Rails Guide on Active Record Querying - Scopes section for more info.
If you need the Problem model to do anything that the Score can't do, I'd consider creating an actual model (persisted or not is another decision).

Related

Rails - How to Model Dynamic Form Fields?

I have a request model. A request has one classification. What I want to set up is to store a bunch of form fields in the DB. Their types, names etc. Different classifications will have different form fields for the user to fill out on a request form. So ultimately User creates new request with classification C, and they are presented with a form with the appropriate fields for classification C.
I would like the values stored in a table with the request. My question is how should this be modeled?
Request has one classification.
Classification has_many requests.
I'm just not sure what to do with the dynamic form fields. I would like to be able to create the fields and attach them to the classification. So if first name, last name are fields needed I wouldn't have to create them for every classification. Just create them once and set associate them with a classification through a join table.
Looking for advice on how to model this out and be able to easily reference them from a request.
Thanks! Any info or thoughts are appreciated.
I would say that you should first try to model it according the relational model as far as possible.
# beware of potential conflicts with this name as it clashes with core method in controllers
class Request < ApplicationRecord
has_many :classifications
end
class Classification < ApplicationRecord
belongs_to :request
end
Model everything you know you can normalize. It's usually more then you think.
Dealing with data that doesn't adhere to a fixed schema can then be dealt with a few ways:
Just define all the fields and live with a few nulls here and there.
The Entity–attribute–value (EAV) pattern. This classic approach consists of a separate table where each row represents a value for a classification eg rails g model ClassificationAttribute classification:references attr_name attr_value. This is largely made obsolete by JSON data types.
A JSON/JSONB column. This additional column would be used to shove any unstructured data that cannot be normalized.
Serialized data columns. This also made obsolete by JSON/JSONB.
All of these can be combined with the Single Table Inheritance pattern.
If classification can be broken down into a limited number of variants you could consider Multiple Table Inheritance where you store the base data in the classification table and then use separate tables for the more specific data. Rails delegated_type feature can be used for this.
Your question is really confused and it is hard to understand what you are trying to achieve. But a few remarks:
You say "Request has one classification. Classification has_many requests" But if Request has one classification. Then classification should belongs to request. This way The Classification model holds a field called request_id (foreign key) that will help ActiveRecord link the two models together. (The child model is the one holding a foreign key)
If each is the parent of the other (has_one or has_many), then where is the foreign key ?
dynamic fields is not something possible. Your databse if hard coded: each field is declared in the relational database and Rails ActiveRecord's allows to access it easily and validate it. There is indeed a solution: have one of the model holds a JSON or JSONB field. And the value instead of being of the common types: string, text, integer.. be of JSON type and holds a value that is converted to a hash by Rails :
{
first_name: "Arthur",
last_name: "Smith",
age: "23"
}
This is pretty convenient for shopping carts as you can save an actual list of items rather than an association. Having an association would need to version your items changes (when the price of an item changes for example) which need some good engineering.
The question is : is it what you really want to do ? Because this is an option that doesn't fit all apps or uses.
Also you say the request depends on the classification. I have mentionned the problem of the foreign key above. But it seems weird that one of your record behavior is set by a direct relationship relationship. Who creates the classification ? Is it one of the app models such as the User ? an Admin ? or is it seeded by the app creator (then Classification is a standalone model) ? In this case the classification preexists the request the Request and maybe a has_and_belongs_to_many association (a join table ) would fit better...
Maybe give us a clearer view of what you want to achieve with real life examples so we can help further

Ruby on rails: What kind of object should I use when it doesn't represent the database?

There is something I don't really get with ruby-on-rails (I'm very new to it).
If my understanding is correct we use the model objects in the views.
The model object is the exact representation of the database. But in a lot of cases what we want to show in the view isn't the exact representation of the database.
Let's say we have an object line in the database:
line [line_id, quantity, category_id]
So if I want to show a list of lines there is no problem I can use the model object "line". But what if I want to show one line by category with a sum of the quantity for that category ?
Should I use the line object ? I feel bad about that because each line will not reflect a line in the database.
Should I create another kind of object ? Some sort of ViewModel that doesn't exist in the database but is usefull for rendering.
I'm not sure this is very clear... Thanks in advance for any help.
Always displaying data exactly as it is in the database happens only in tutorials :)
In real-world apps it is often necessary to transform data before presenting. This has many names: ViewModel (as you mentioned), Decorator, Presenter and others. So yes, make new objects for this, there's no reason not to.
If you display categories with a column in the view that shows the total quantity for each category, it would make sense to use the Category class in your application. This should be an ActiveRecord model.
On this model, you can define a method that reads the lines and sums the quantity. It could look like this:
def total_quantity
lines.map(&:quantity).sum
end
This method will read your lines (assuming you have set up a has_many :lines relationship in the Category class. Then it will read the quantity method on each lines and put the result in an array. Finally it will add the values together.
Note that this approach is a starting point and not very fast for larger sets of data. The approach can be improved through either lazy loading or specialized queries.
As your application grows in size, the number of methods such as the one above may grow in size to the point where the Category class becomes hard to understand. At this point, you may want to start looking for an intuitive ways to extract these methods into separate classes.

Should I use 2 models to store similar data but with different uses in rails

Hi there I'm currently in the process of planning a very basic rails app. I want to create small weight tracking app this will store a weight(number) within a Weight model there will also be the ability to add a goal-weight(number) every week a user would enter their new weight and it will be compared against the goal weight and show completion % etc to the user.
Now my question is would I have both a Weight model and a Goal model or should it be a single Weight model with some extra meta information to set a weight as a goal? I will admit im very much a noob with rails my gut says 2 models but I could be completely wrong.
This is a pretty subjective answer, but I would separate them for two reasons.
More modular. For example, you might want some model validations on Weight model, but not Goal model. In this case, it's easier to make them into two different models rather than have them in one.
Model associations. You may want to create model associations in the future.
Weight wouldn't even be a model for me, weight would be a parameter from user, as so would goal_weight. You could implement a method weight_over_goal_weight? afterwards to check if weight is over or equal goal_weight.

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.

Tracking changes on instances of a class and their associations - thoughts?

I have a class Question which has a lot of assocated models. On one page on my app i list a summary of all the current questions, with various info from associated records. Ultimately this is a hash of values that i then just print out into a csv-style row (i'll call this the 'row hash' from hereon)
I now have a requirement to only show the changes to questions (or their associated data) over a given period. I'm currently deliberating the best way to do this. Here's some ideas i've had so far, i'd welcome any feedback, thoughts, suggestions etc.
1) Approach 1 - acts_as_audited
This was my first thought as i've used this before in other apps. The porblem with aaa though is that it only tracks changes to the record's data (ie it doesn't care if the associations change). So, i could audit all of the associated records as well but then trying to piece together what had changed by tying different audit records together sounds like a nightmare.
2) Save the old and new hash out into serialized fields: ie
- when someone goes to the question/edit page, i calculate the current row hash and save it in a serialized field "old_data" in the question table. Then after they save the question i calculate the new current row hash and save it into a serialized field "new_data" in the question table. Also, i compare the two serialized hashes and save the differences into another serialized hash field 'changes'. Now to do my report i just look for questions updated in the last x days and output their changes data.
3) make a view
- i make a view which corresponds to the data that i want to output (ie that amalgamates all the data that i pull into my report). Then i track changes to the view - somehow. I'm not sure how exactly i would do that.
I'm leaning towards option 2 right now.
Any other thoughts/comments? grateful for any suggestions - max.
So, like you said, you only want to show changes to the records between time x and time y, right? This would seem perfect to me using the acts_as_audited plugin because you end up with a table of changes, right? So make a has_many_through association from Question to all these related tables, then search it for related changes, where date created is after time X. This would return a list of changes. From there, you could connect this list back to the parent object if you need to, or whatever - but it in the end seems like a more reasonable thing to search. You're not looking for a list of related objects, after all, you're looking for a list of changes, so having a table of changes seems a reasonable way to accomplish that?
Hey I had a similar problem, check this out. If you can, go with Mongoid or Mongomapper, embedded versioned documents are sweet.
Thanks guys. I ended up rolling my own solution because what i really needed to do was to capture changes in the results of various methods called on the object, some of which involved associated objects. I wasn't so much interested in the associated objects as (for example) a text string generated as a result of looking at a few different associated objects. I had methods to do all of this already so i really just needed to track changes in the results of calling these methods.
None of the plugins i saw could really do that simply and effectively, so i ended making a table called states which just holds a serialized hash with results of all of these method calls. This gets saved when the record is altered and saved or when any of the relevant associated objects get altered and saved. Then i have some methods to return the differences between different saved state records. It works well for my needs. Thanks very much for your advice anyway.

Resources