Filtering models using controller specific data - ruby-on-rails

I have an application which is used by several divisions, where each of them has a separate set of data. So i got many models with a division_id field which indicates the division the row belongs to.
Each user has the division information also, so when they log in, i have to filter the data according to the division. So there are many places in my code where i do this for example:
Contact.where(division_id: current_user.division_id)
My question is how to refactor this code fragment? First i have thought about utilizing the default scope of the ActiveRecord, but since the division_id is a controller specific data, that didn't seem right. Any ideas?

I'm not sure why you say division_id is controller-specific data because it looks like you're getting the division from the User object (current_user.division_id). Anyway, the best thing to do would probably be just to make use of scopes here and then repeat the scope. For example:
# app/models/contact.rb
scope :for_user_division, -> user { where(division_id: user.division_id }
But it's still going to be repetitive calling e.g.
Contact.for_user_division(current_user)
everywhere. The main advantage is you can now change the rules of the scope in one place if you need to add something like only considering active? divisions later.
I don't think there's need nor want to DRY this up further. In general, I think default scopes are a bad thing because, in cases like this, a little bit of repetition is useful in reminding yourself what it is your'e dealing with -- a limited set of Contacts.
UPDATE
If you find yourself writing the same scope in more than one model then you can surely DRY up the scope by putting it into a concern and including it into each model as needed.

Related

Rails MVC - Should database search logic go in the model or the controller

I would like to make sure my code is properly organized/designed according to the following paradigms/patterns:
- Model View Controller
- Rails Convention over Configuration
- Skinny Controller, Fat Model
I have listed them here in the order I think is most important.
My issue
After reading several articles, in particular this one and this one too, I started to move some of the logic in my controllers, to my models.
However, I can't decide whether or not to move my searching logic (explained in depth, later) from the controller to the model, even after reading more posts/articles like these: MVC Thinking, and Model vs. Controller, Separating concerns and many more not listed here.
The scenario
View
Two pages:
1 page contains a text field and submit button which sends the user's input as an argument in params in a POST request to the second page.
The second page simply renders each neatObject in a given array, let's call it #coolList.
Controller
A method, let's call it awesomeSearch, is invoked when the second page receives a POST request. (Thanks to Rails Routing)
awesomeSearch should take the user's input, available as params[:searchString], and work with the NeatObject model to build the #coolList and make that list available for the view to render.
Model
The NeatObject model handles requests from controllers and returns neatObjects back to those controllers.
The NeatObject model defines the relationship between neatObjects and other tables in our database.
Database
These are the attributes that make up each neatObject according to our database:
id - int
description - string
address - string
date_created - timestamp
What's Missing?
How the controller works with the model to get matches for the user's input.
This is the part I am confused about. The logic itself is very simple, but I am not sure which pieces belong in the model, and which pieces belong in the controller.
Should the controller pass the search string to the model, and the model pass back the results?
Should the controller ask the model for all of the neatObjects, then only keep the ones that match?
Is the solution a little of both?
To be able to ask questions about specific bits of the logic, I'll next outline the search process with more detail.
The search logic in depth
The process involves finding neatObjects that match the search string. It would be impossible to move on without defining what we consider matches for neatObjects. To keep things very simple, we will say that:
A neatObject matches a search string if the search string is contained within its description or its address, ignoring case and leading/trailing whitespace.
This definition is not guaranteed to be permanent. There are several things that may change our definition. We may need to test against more attributes than just address and description, perhaps if the database guys add a new important attribute, or the UI guys decide users should be able to search by ID. And of course, the opposite of these scenarios would mean we need to remove an attribute from the list of attributes we are testing. There are many situations that could change our definition of a match. We could even have to add or remove logic, perhaps if it is decided that we should only test the first word in the description attribute, or perhaps if we should no longer ignore case.
Now we know what defines a match and we know that our definition may change. Now we can more concretely define the search process.
Here is an outline of the steps:
Get a reference to all neatObjects
Loop through each neatObject, putting each individual one through the match test
Test passes - add/keep neatObject in results list
Test fails - do not keep neatObject for results
Make results available to the view
I will reference these steps as I show possible implementations.
Implementation
The search functionality can easily be implemented in either the NeatObject model, or the controller serving the view.
Normally, I would just write all of the logic in the controller, but after I learned about the "Skinny controller, Fat model" design, I thought it definitely applied in this situation. This article in particular made me think to reorganize my code, after I saw the author had implemented a "search-like" function in the model. The author's function did not handle user input though, so I was wondering how it should be handled.
This is how I would have written the code before learning about "SCFM":
Search logic in controller:
#searches_controller.rb
#This is the method invoked when second page receives POST request
def search
#neatObjects = NeatObjects.all.to_a
#neatObjects.delete_if {
|neatObject| !matches?(neatObject, params[:searchString])
}
end
def matches?(neatObject, searchString)
if((neatObject.description.downcase.include? searchString.downcase) ||
(neatObject.address.downcase.include? searchString.downcase))
return true
end
return false
end
This method gets its reference to all of the neatObjects (Step 1) by calling .all() on the NeatObject model. It uses the array function delete_if to perform the match test on each neatObject, and only keeps those that pass (Step 2). Step 3 is accomplished automatically automatically since we store our results in an instance variable in the controller which serves the view.
Placing the logic in the controller is very straight-forward, but when considering the "SCFM" design pattern, it seems very illogical.
I've written another option, in which the controller sends the user's input to a function in the model, which will return the the neatObjects which match the input.
Search logic in Model
#NeatObject.rb
def self.get_matches_for(searchString)
all.to_a.delete_if { |neighborhood| !matches?(searchString, neighborhood) }
end
def self.matches?(phrase, neighborhood)
fields = [neighborhood.name, neighborhood.address]
fields.map!(&:downcase)
phrase.downcase!
fields.each do |field|
if (
(phrase.include? field) ||
(field.include? phrase)
)
return true
end
end
return false
end
This method gets the complete list of neatObjects with all() (Step 1). Just like the first method, the model method uses delete_if to remove array elements (neatObjects) that don't meet a certain criteria (passing the match test) (Step 2). In this method, the controller serving the view would call get_matches_for on the NeatObject model, and store the results in an instance variable (Step 3), like this: #neatObjects = NeatObject.get_matches_for( params[:searchString] )
I do think that the model option is cleaner, and slightly more maintanable, but I'll go more in depth in the following section.
Concerns
I can see pros and cons to both the model method and the controller method, but there are things that I'm still unsure about.
When I read over that article I've referenced several times (just like I did here), it was very logical that the model defined a function to return the recently added people.
The controller didn't have to implement the logic to determine if a person had been recently added. It makes sense that the controller shouldn't, because that is dependent on the data itself. There might be a completely different implementation of the "recency" test for messages. The recent people might include people added this week, while recent messages are only those messages sent today.
A controller should just be able to say People.find_recent or Message.find_recent and know it got the correct results.
Is it correct to say the find_recent method could also be modified to take in a time symbol, and return objects for different time periods? Ex - People.find_in_time( :before_this_month ) or Messages.find_in_time( :last_year ). Does that still follow the MVC pattern and Rails convention?
Should a controller be able to find matches for user input with NeatObject.get_matches_for( searchString )?'
I think the matching logic belongs in the model, because there are certain/specific attributes that are used in testing, and those attributes are different depending on the data. We might have different attributes for different tables, and those attributes definitely shouldn't be defined by the controller. I know the controller depends on the model, not the other way around, so the model must define those attributes, even if the rest of the logic is in the controller.
And if the model defines the attributes that are used when searching, why shouldn't it define the entire search function?
The above text explains why I think the model should handle the searching logic and expresses the majority of my questions/concerns, however I do have some opinions favoring the other option.
If the model is concerned only with the data, how can one justify passing user input to it?
If the controller doesn't handle the search logic, it still needs to send the user's input to the model. Does it clean it up before it sends it? (Removing leading/trailing whitespace and downcasing the string.) Does it just send the exact input it got from the user?
Where is the testing done to make sure the input is not malicious?
Some of my biggest questions:
Does the answer for where the logic goes change for each case?
If the search/matching process was simpler, would the code's place change? For example, if the searching was simpler:
If the only attribute being tested was the address and that was unlikely to change, would we just handle the search with the controller?
If we were making an advanced search feature, where the user decided which attributes to include in the search and also controlled some other factors, there would be a lot of user input just to define the arguments to the search function. Would that be too much logic or user input to place in the model?
In conclusion
How can I always be sure that I am putting logic in the right place (MVC)?
For my specific case, with this data and this search/match process, how should I organize the code?
What guidelines can be followed when you find a gray area, or are unsure about where logic belongs?
This is something that varies a lot between cases (each application is different) but here's what I do on my end (large sports app that searches lots of tables from many different places):
start by performing small searches with non-repeating code patterns in the controller (or rarely view)
when it turns out the code is needed in more than one or two action/view I move it to the models
I also move the code to the model when the query complexity goes above the average .find or simple .where
Like this, you don't spam your model with one-time-use methods, and at the same time don't repeat the same code over multiple controllers/actions/views
As many thinks in IT and in life, It depends of the scale and the goal.
Considerations:
1) For design: If you see you are violating DRY in your controllers many times, its probably time to move your logic to models.
2) For performance: Since controllers are loaded more than models, Logic in controller tend to performs worst.
And not less important: Unless you are doing something very trivial, and you db has a few thousands rows, do NOT use db for text search. Instead, use a search engine like Solr, ElasticSearch, Sphinx, etc.

has_many :through model names, controller and attributes best practices?

Disclaimer: I really spent time thinking about names of models and variables. If you also do, this question is for you.
I have a Rails project which contains two models: User and Project.
They are connected by the model ProjectsUser, which is a connection model in a many-to-many relationship. This model also holds the role of a user in the given project, along with other attributes such as tier and departments. So this is a has_many :through relationship.
Given this scenario, here is everything that always bothered me on all my rails projects since I started developing on it:
Should I use a ProjectsUserController or better add the relevant actions on UserController and ProjectController? At some point, I want to assign users to a project, or even changing the role of a user in a given project. Is it a better practice to leave those actions on the connection controller, or use the model controllers?
Should I write a method to get the role of a user for a given project? This is basically if I should have a method User#role_for(project) or not. Since this method basically is getting the information from the projects_user object it could make more sense to always let this explicity on the code, since most of the times I'll have the project and the user, but not the projects_user. Is this line of thinking correct, or maybe the problem is that I'm should have more project_user on my code than I really do? Are there good caveats for this?
Should I try to rename my table to a non-standard name if it is not obvious? Ok, I got that if I have the models User and NewsSite I should use has_many :subscriptions, but the thing is that naming those models in real life cases are usually harder, by my experience. When the name ends up not being that obvious (for exemple, in my case, maybe project_participation as #wonderingtomato suggested) is for the best, or in those cases it is better to fall back to the ProjectsUser approach?
One extra cookie for pointing beautiful open source Rails code, or by book indications that might help with my kind of questions.
I would use a specific controller. Even if now the interaction sounds simple, you can't know if in the future you'll need to add more advanced features.
I've been handling these kind of relationships in several projects, and using a controller for the join model has always paid off.
You can structure it this way, for example:
index should expect a params[:project_id], so that you can display only the index of users for a specific project.
create is where you add new users, that is where you create new join models.
update is to modify a value on an existing join model, for example when you want to update the role of a user in a project.
destroy is where you remove users from the project, that is where you delete the corresponding join models.
You might not need a show and edit actions, if you decide to manage everything in the index view.
Also, I'd suggest to choose a different name. Rails relies heavily on naming conventions, and projects_users is the default name for the join_table you would use with a has_and_belongs_to_many association. In theory you can use it for an independent model (and a has_many through:), but it's not immediately clear and you might break something. In addiction, it will confuse the hell out of any new programmer that could join the project in the future (personal experience).
What about calling the model something like project_participation?
If you haven't built a lot of functionality yet, and don't have yet that table in production, changing it now will save you a lot of headaches in the future.
update
1) I stand by what I said earlier: your join model is a full fledged record, it holds state, can be fetched, modified (by the user) and destroyed.
A dedicated controller is the way to go. Also, this controller should handle all the operations that modify the join model, that is that alter its properties.
2) You can define User#role_for(project), just remember that it should properly handle the situation where the user is not participating to the project.
You can also make it explicit with something like:
#user.project_participations.where(project_id: #project.id).first.try(:role)
# or...
ProjectParticipation.find_by(project_id: #project.id, user_id: #user.id).try(:role)
But I'd say that encapsulating this logic in a method (on one of the two models) would be better.
3) You are already using a non standard name for your table. What I mean is that it's the default name for a different kind of association (has_and_belongs_to_many), not the one you are using (has_many through:).
Ask yourself this: is the table backing an actual model? If yes, that model represents something in the real world, and thus should have an appropriate name. If, on the other hand, the table is not backing a model (e.g. it's a join table), then you should combine the names of the tables (models) it's joining.
In my mind, REST doesn't always have to map directly to DB records. A conceptual resource here is the association of Projects to Users. Implementation would be different depending on your persistence layer, but a RESTful API would be standard.
Convention over Configuration in Rails is a great helper, but it isn't necessarily applicable to every case 100% of the way through the stack. There doesn't need to be a 1-to-1 mapping between controllers, models, and their respective names. At the app-level, particularly, I want my routes/controllers to represent the public view of the API, not the internal implementation details of the persistence and domain layers.
You might have a UserProjectsController which you can perform CRUD on to add/remove project associations to users, and it will do the appropriate record manipulation without being overly bound to the DB implementation. Note the naming, where the route might be /user/:id/projects, so it's clear you are manipulating not Users or Projects, but their associations.
I think thinking about this sort of thing (both before and after the fact) is what leads to better designs.
I too start with the model and think about the application structurally. The next step in my oppinion is to build the user interface to make sense based on what makes it easy and useful for the user (spending more effort on things that matter more). So if it makes sense for the user to separately edit the ProjectsUser objects then the ProjectsUsersController is the way to go. More likely editing the join model objects as part of the Project (or User depending on the structure of you app) will be a better fit for the user. In that case using a nested form and editing via the controller (and model) that's the main model referenced by the form is better. The controller really lives to serve the UI, so decisions about it should be dependent on the UI.
Yes, if it makes your code simpler or more readable. If you use role more than once I suspect it will.
I would actually name that model something like Member, or ProjectMember (or Membership). It defines a relationship between a user and a project, so its name should reflect what relationship that is. In the occasions where such a name is too unwieldly or too hard to define then falling back to something like ProjectUser is reasonable (but not ProjectsUser). But I definitely like finding a more meaningful name when possible.

Is that a proper way to refactor ActiveRecord fat models?

If for example I've this ActiveRecord model:
app/models/order.rb
class Order < ActiveRecord::Base
# model logic
end
require "lib/someclass.rb"
lib/somelass.rb
class Order
before_save :something
# more logic here
end
Is that a good way to refactor/extract logic from model?
Or maybe use concern class, service class or something else?
Like someone told me a long time ago:
Code refactoring is not a matter of randomly moving code around.
In your example that is exactly what you are doing: moving code into another file
Why is it bad?
By moving code around like this, you are making your original class more complicated since the logic is randomly split into several other classes. Of course it looks better, less code in one file is visually better but that's all.
Prefer composition to inheritance. Using mixins like this is asking to "cleaning" a messy room by dumping the clutter into six separate junk drawers and slamming them shut. Sure, it looks cleaner at the surface, but the junk drawers actually make it harder to identify and implement the decompositions and extractions necessary to clarify the domain model.
What should I do then?
You should ask yourself:
Which code goes together and could be part of a new class / module ?
Where does it makes sense to extract code to somewhere else ?
Do I have some piece of code that is shared across my application ?
Can I extract recurrent patterns in my code base ?
Extract Service Object
I reach for Service Objects when an action meets one or more of these criteria:
The action is complex
The action reaches across multiple models
The action interacts with an external service
The action is not a core concern of the underlying model
There are multiple ways of performing the action
Extract Form Objects
When multiple model can be updated by a a single form submission, you might want to create a Form Object.
This enable to put all the form logic (name conventions, validations and so on) into one place.
Extract Query Objects
You should extract complex SQL/NoSQL queries into their own class. Each Query Object is responsible for returning a result set based on the criterias / business rules.
Extract Presenters / Decorators
Extract views logic into presenters. Your model should not deal with specific views logic. Moreover, it will enable you to use your presenter in multiple views.
More on decorators
Thanks to this blog post to help me putting these together.
Keeping the code in the same class moves logic, it doesn't extract it.
Externalizing callback declaration is misleading and potentially dangerous. Callbacks are abused enough; forcing readers to hunt down related files is cruel.
There's no general way to answer the question as asked; the "best" refactors depends on what's actually being refactoried. Lifecycle information should be obvious and precise, though.
Concerns, services, decorators, facades, etc. are good mechanisms that support refactoring. Without knowing what's being refactored it's impossible to provide meaningful advice regarding what's "best".

How do I sort the rows in a nested object form in rails for just one view?

When working with a nested model in a form, is there a way to sort the nested models in the view or in the controller? The closest answer I could find was here, but both of those solutions involve putting sort orders in the model. I'd rather avoid changing things fundamentally like that and keep this particular sort order to just one page.
You can always sort with ruby: parent.children.sort{|a,b| a.field <=> b.field} or something like that
Or you can add a find method to parent model, like def self.find_ordered_by_field
Can't think of another options...
Putting the sort in the models is absolutely the way to go. You shouldn't have any more ruby code than necessary in your views themselves, because it's much harder to test that your sorting is working the way you think it should.
When you add the sort at the model level (and either answer in the link you posted works well) you can add an automated test to verify that it is, in fact, sorting the way you'd like. This is business logic, and it belongs in the model.
Sometimes, however, you're looking to sort in a way that is NOT what you would normally want for this model. Maybe you normally want them sorted by name, but in this one view you want them sorted newest to oldest. At the very least, do the sort in the controller so once again it can be fully tested. But I would still put it in the model, personally.

Rails Model, View, Controller, and Helper: what goes where?

In Ruby on Rails Development (or MVC in general), what quick rule should I follow as to where to put logic.
Please answer in the affirmative - With Do put this here, rather than Don't put that there.
MVC
Controller: Put code here that has to do with working out what a user wants, and deciding what to give them, working out whether they are logged in, whether they should see certain data, etc. In the end, the controller looks at requests and works out what data (Models) to show and what Views to render. If you are in doubt about whether code should go in the controller, then it probably shouldn't. Keep your controllers skinny.
View: The view should only contain the minimum code to display your data (Model), it shouldn't do lots of processing or calculating, it should be displaying data calculated (or summarized) by the Model, or generated from the Controller. If your View really needs to do processing that can't be done by the Model or Controller, put the code in a Helper. Lots of Ruby code in a View makes the pages markup hard to read.
Model: Your model should be where all your code that relates to your data (the entities that make up your site e.g. Users, Post, Accounts, Friends etc.) lives. If code needs to save, update or summarise data related to your entities, put it here. It will be re-usable across your Views and Controllers.
To add to pauliephonic's answer:
Helper: functions to make creating the view easier. For example, if you're always iterating over a list of widgets to display their price, put it into a helper (along with a partial for the actual display). Or if you have a piece of RJS that you don't want cluttering up the view, put it into a helper.
The MVC pattern is really only concerned with UI and nothing else. You shouldn't put any complex business logic in the controller as it controls the view but not the logic. The Controller should concern itself with selecting the proper view and delegate more complex stuff to the domain model (Model) or the business layer.
Domain Driven Design has a concept of Services which is a place you stick logic which needs to orchestrate a number of various types of objects which generally means logic which doesn't naturally belong on a Model class.
I generally think of the Service layer as the API of my applications. My Services layers usually map pretty closely to the requirements of the application I'm creating thus the Service layer acts as a simplification of the more complex interactions found in the lower levels of my app, i.e. you could accomplish the same goal bypassing the Service layers but you'd have to pull a lot more levers to make it work.
Note that I'm not talking about Rails here I'm talking about a general architectural style which addresses your particular problem.
Perfect explanations here already, one very simple sentence as conclusion and easy to remember:
We need SMART Models, THIN Controllers, and DUMB Views.
http://c2.com/cgi/wiki?ModelViewController
The Rails way is to have skinny controllers and fat models.
Do put stuff related to authorization/access control in the controller.
Models are all about your data. Validation, Relationships, CRUD, Business Logic
Views are about showing your data. Display and getting input only.
Controllers are about controlling what data goes from your model to your view (and which view) and from your view to your model. Controllers can also exist without models.
I like to think of the controller as a security guard/receptionist who directs you the customer(request) to the appropriate counter where you ask a teller (view) a question. The teller (view) then goes and gets the answer from a manager (model), who you never see. You the request then go back to the security guard/receptionist (controller) and wait until you are directed to go another teller (view) who tells you the answer the manager (model) told them in response to the other teller's (view) question.
Likewise if you want to tell the teller (view) something then largely the same thing happens except the second teller will tell you whether the manager accepted your information. It is also possible that the security guard/receptionist (controller) may have told you to take a hike since you were not authorized to tell the manager that information.
So to extend the metaphor, in my stereotyped and unrealistic world, tellers (views) are pretty but empty-headed and often believe anything you tell them, security guard/receptionists are minimally polite but are not very knowledgeable but they know where people should and shouldn't go and managers are really ugly and mean but know everything and can tell what is true and what isn't.
One thing that helps separate properly is avoiding the "pass local variables from controller to view" anti-pattern. Instead of this:
# app/controllers/foos_controller.rb:
class FoosController < ApplicationController
def show
#foo = Foo.find(...)
end
end
#app/views/foos/show.html.erb:
...
<%= #foo.bar %>
...
Try moving it to a getter that is available as a helper method:
# app/controllers/foos_controller.rb:
class FoosController < ApplicationController
helper_method :foo
def show
end
protected
def foo
#foo ||= Foo.find(...)
end
end
#app/views/foos/show.html.erb:
...
<%= foo.bar %>
...
This makes it easier to modify what gets put in "#foo" and how it is used. It increases separation between controller and view without making them any more complicated.
Well, it sort of depends upon what the logic has to deal with...
Often, it makes sense to push more things into your models, leaving controllers small. This ensures that this logic can easily be used from anywhere you need to access the data that your model represents. Views should contain almost no logic. So really, in general, you should strive to make it so that you Don't Repeat Yourself.
Also, a quick bit of google reveals a few more concrete examples of what goes where.
Model: validation requirements, data relationships, create methods, update methods, destroy methods, find methods (note that you should have not only the generic versions of these methods, but if there is something you are doing a lot, like finding people with red hair by last name, then you should extract that logic so that all you have to do is call the find_redH_by_name("smith") or something like that)
View: This should be all about formatting of data, not the processing of data.
Controller: This is where data processing goes. From the internet: "The controller’s purpose is to respond to the action requested by the user, take any parameters the user has set, process the data, interact with the model, and then pass the requested data, in final form, off to the view."
Hope that helps.
In simple terms, generally,
Models will have all the codes related to table(s), their simple or complex relationships (think them as sql queries involving multiple tables), manipulation of the data/variables to arrive at a result using the business logic.
Controllers will have code/pointers towards the relevant models for the job requested.
Views will accept the user input/interaction and display the resultant response.
Any major deviation from these will put unwanted strain on that part and the overall application performance may get impacted.
Testing, Testing ...
Put as much logic as possible in the model and then you will be able to test it properly. Unit tests test the data and the way it is formed by testing the model, and functional tests test the way it is routed or controlled by testing the controllers, so it follows that you can't test the integrity of the data unless it is in the model.
j

Resources