Business logic dependent on model attribute - ruby-on-rails

I have a User model that has an introduced_by attribute. Based on that attributes value, I calculate my commission differently. What would be the best, most flexible way of doing this?
Should I do a switch, or maybe put everything in a flat file? Also, should I create a Commission model?

It's a very broad question, as there is no code and no example. However, it seems to be the perfect case of a Strategy design pattern.
What I would do, is to create a class that represents the strategy for every specific range of attribute values.
E.g
PersonalCommission
CompanyCommission
HighValueCommission
DefaultCommission
Each class has a single method, let's say calculate that you can call passing an instance of the object and that returns the value of the commission.
Wherever you need to perform the calculation, just initialize a new Commission strategy object based on the User attribute and call calculate on it.
You don't even have to use a switch, as you can initialize the class dynamically.
strategy = "#{user.introduced_by}Commission".constantize
strategy.new.compute(whatever)
Of course, that's just a very simple example you'll have to adapt to your needs.

Related

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.

Add new model or extend existing one?

Hi I have a model Workout and model Set.
Workout has_many sets, set belongs_to workout.
Set has certain properties, like number of repetitions for left hand, for right hand, total repetitions etc.
Now I'm in front of a dilemma how to create additional/different kind of sets with different properties (say set for time, set that goal is to reach certain number of repetitions etc.)
Should I extend set model and change form via javascript based on some choice (it would be easier with counting statistics out of sets but IMHO it would make validation more complicated) or shall I create new kind of sets?
Ideas/tips ?
Thank you
Petr
I'd create a new model but If they're similar enough I'd use Single Table Inheritance and simply inherit say the statistics methods from Set.

Is there a standard model to controller 'ratio' when trying to implement good ASP.NET MVC?

I'm not sure if this question is non-sense or not, please tell me if so. I am wondering do I create my models like one per each table in my database, or do you do one per controller? Is there something I am missing here?
From what I read the Model is suppose to be a representation of the real business objects, so would I just want to make it one big model or divide them out based on things in the app? based on real user/client perception of the data?
Thanks for your advice.
There's nothing wrong with controllers sharing models. But trying to serve every controller with the same model doesn't make sense.
Models and controllers really are't related, nor should they be. Models also aren't directly related to how data is stored in your application.
Models encapsulate data. Their design should be dictated by the data they are encapsulating. The demands of the system dictate what models you'll need and what data they must hold.
Don't try to overthink it. For a given request, determine what you need to show in your view and how it will be displayed. Determine what an appropriate model would look like for this scenario. If one already exists, use it. If not, create a new model. Save the overengineering later when you know what your needs are and can find commonalities between models.
Models can also contain other models, that's fine. Think of a model for a sales report. You would have a model for the report which would contain not only a report name, a total, but also a collection of other models which make up the report's line items.
It depends on what you mean by "Model". If by model you mean the business rule layer of your application, then there is no relationship in terms of numbers. One model of that type is used for any amount of views you need to build.
Personally, however, I would not bind any view to any model, but create an intermediary layer called a ViewModel that essentially taylors the data from your model to fit a particular view. In that case, the relationship is one-to-one. This is essentially how Presenter patterns work. Every view is strongly typed to it's own ViewModel that is populated from the Model layer.
Models do not necessarily have a literal coorespondence with the database either. How you store data your model is different from how your "Model" uses that data.

Rails - are validations only for data from user input via forms?

My models produce a lot of values for attributes which the user can not specify in any forms.
Should I be specifying validations for those attributes to prevent any of my model logic creating dodgy values or is that something I should just check for in my tests?
As well as being essential for confirming user input, Active Record validations also provide a useful DSL for specifying the intent behind your domain design.
It depends on what values the model is producing.
If it is producing values depending on the user input, then yes validate them.
Otherwise this is something you should check in your tests.
In relation to ActiveRecord. Any attribute that has a corresponding column in the database (and would ultimately be used to populate that column) and requires a specific level of continuity/integrity should be validated.
Ex: if an attribute requires the data it accepts falls between a range of 1..10 then you probably want to validate that the data set for that attribute meets those requirements.
You should always test, well, usually. But, if the code is of your own design then you should test it.
-
*Also, please do not confuse Validation for Sanitization, or vice versa, at least in their traditional roles. Just because you sanitize something does not mean it's valid.
If you sanitize ABCD so it does not contain <script> but your database column only accepts integers, ABCD is not exactly "valid", though it may have been sanitized.
Since the model represents the data of your system, you should specify constraints on that data. Since Ruby is a dynamic interpreted language, all constraints are validated at run-time, every time you create, update, or delete an ActiveRecord object.
It is a good practice to have explicit constraints on all attributes of a model class, whether they correspond to database fields or not. Quite often, the data from your model will drive the behaviour of your controller and the rendering of your views, and it would be a shame (and possibly an exception) if the accessible data did not for some reason fall within a constraint.
You should, of course, test all of these validation functions as a part of your system testing.
The fact that you are worried about "dodgy" values suggests to me that your data is not properly normalized. I suggest you read up on the various normal forms, and try to design your data schemas to at least third normal form. That should help you get rid of the possibility of having "dodgy" model attributes.
Validation is for sanitizing user input.

What attributes should belong to a page and what should belong to a model?

Say you have an Events model that contains information about the event. But what about things like slugs, titles and meta description that would go into the html?
It would seem like such things properly belong as attributes to a Page model rather than to an Events model.
Is there a correct way to do this? What are the pros and cons of one approach over the other?
An Event has some first-class attributes and some "derived" attributes.
Let's focus on Django.
For example, your model might have a big long title and a derived slug.
You can easily define class methods for this derived data.
However, in some cases, you need to denormalize your model to make derived data persistent. In this case, you'll have additional attributes and you'll set those attributes through the save() method.
"Correct" is well-defined -- 3rd Normal Form is correct. You can afford to compute derived fields if they aren't computed all that often. In some cases, you have to break 3NF and persist the data for performance.

Resources