Search code examples
model-view-controllerbusiness-logic

Where to put logic dealing with more than one models


In an MVC framework like Rails, the overall consensus is to put business logic in the model. However, when it comes to logic like "get all problems that a user solved", I am not sure which model class I should put the logic, as the it needs to first look up all solutions submitted by the user, and collect the problem id from each solution, then the problem ids to get all the problems needed.

It feels more elegant to put it in the User model, so we can call something like user.getAllProblemsSolved(). However, all we need from the user instance is the user id. In places where no user instance is readily available, we have to create one just to call its getAllProblemsSolved method.

What is more, as the logic mainly deal with Problem and Solution models, it smells Feature Envy to put it in the User model. To avoid Feature Envy, it feels equally fine to put in Problem or Solution. Intuitively, I would put it in Problem to be like Problem.getAllProblemsSolvedBy(userId), but I don't have good justification for that.

So where should I put that logic?


Solution

  • I can see that the relation between Problem and User is an m2m relation, so if you want to follow the rules and put the business logic in the model class, you can put getAllProblemsSolvedBy in the model class that is representing the m2m relationship, but using that logic the getAllProblemsSolvedBy will return problems ids, and then you'll have to get the problems from the Problem model class.

    I would put it in the Problem model class as the method will return instances of Problem class.


    Update Apr 23 2014, 07:00 UTC

    Note also that the m2m class, Solution in your case, depends on the existence of those two models User and Problem, so you can query both models from within this model, and therefore if I had an m2m model in my code I'd let it usually be responsible for querying both ends of the m2m relationship.

    So for example in your case the getAllProblemsSolvedBy can be implemented in the Solution model class and it can return a list of Problem instances and can be passed an instance of User.