I'm all for the skinnier controller, fatter model mindset.
I wanted to know how to go about:
How you identify things that should be moved to your model (assuming you're like me and you get lazy and need to refactor your controllers because you just shove code in there)
How you write and structure the creation of new elements in your controller. See following example.
Example
I had a relatively messy controller for a polymophic "vote". I've cleaned it up pretty well, but I wanted to know if I could improve this action a little better:
def up
vote = Vote.new
vote.vote = true
vote.voter = current_user
vote.voteable = Recipe.find params[:id]
vote.save
end
To me it's just a little ugly, and I probably should just use create instead of new, but I'm wondering if I'm driving down a deadly path here by using a non-standard action (concerning REST).
I'm working on switching it to new right now. But I definitely wanted to get the point of view of the community about.
The key to this is Test-Driven Development. Once you make it a habit, the question of where to put code is answered for you 95% of the time. Here's why.
Unit testing (model testing in Rails) is the easiest place to test code. Model methods should be unit tested "black box" style - meaning you don't care what's inside the method, only that input X provides output Y. This will also cause you to write a greater number of smaller methods in your model, instead of very large methods. The easier it is to test, the better - and not just for testing's sake. Simpler methods are easier to override by other code, which is a big advantage of Ruby.
Controller (functional) tests, on the other hand, will find you caring more about what happens inside the action, since those methods aren't cut and dry input/output scenarios. Database calls happen, session variables are set, etc. Shoulda is a great test suite that automates a lot of this for you.
Finally, my advice is to look inside some of your favorite plugins to see how they're doing things. And if you're interested more in testing, I have an article about restful controller tests in Shoulda that might get you started.
In RESTful controllers, especially with a lot of actions I sometimes create a before_filter to load the object:
before_filter :load_recipe, :only => %w(show edit update destroy up down)
private
def load_recipe
#recipe = Recipe.find(params[:id])
end
In your case I might consider moving voting to the user model so you would have something like:
def up
current_user.vote(#recipe)
end
And then in your model:
class User < ActiveRecord::Base
has_many :votes
def vote(object)
votes.create(:vote => true, :voteable => object)
end
end
The benefit of that is that you can easily test the behavior of voting in isolation, and it can be re-used if there are other places you might want to enable voting (voting as in implicit result of another action, voting via API, mass-voting, etc).
Related
I'm in the process of updating a website I made almost 2 years ago. It was my first real website and I made some mistakes (some more serious that others).
What apparently is one of my biggest is making database calls from the view.
I'm pretty damn sure there is a better way to do this:
Use Case:
Someone fills out a form for a new subject, populating the Subject table, and they have been marked "enrolled", Subject.enrolled = 1
Based on that, I now need to create a record in 5 other tables (such as Baseline)
Downhill from here, here is my method
Determine if the record exist based on subject_id from Subject (sub)
<$ if Baseline.where(subject_id: sub.subject_id).first != nil $>
If it does not exist, create the record, (otherwise display the link)
<%= Baseline.create(subject_id: sub.subject_id) %>
This all happens in the view, and creates a front-end table with links to each record in the process. So I'm creating records based on for-loop logic...
Question:
So I'm looking for direction. I don't want to guess how to do this - I'm pretty sure the model/controller should do this - I want to learn how to do it correctly. How do I create records automatically, based on a value in a table?
Thank you for your time.
Not quite sure how your domain and code looks like, but to answer this question: 'How do I create records automatically, based on a value in a table?', it seems that you could use ActiveRecord callbacks, like this:
class Subject < ActiveRecord::Base
after_commit :create_baseline_if_enrolled, on: [:create, :update]
private
def create_baseline_if_enrolled
return unless enrolled?
# enrolled? == true, you may create these models here
end
end
To answer your question:
It depends :) This is just one possible solution. Another one would be to put such a custom logic in your SubjectsController and call it directly from the #create, #update methods. Both approaches have pros and cons. For example, abusing callbacks (anywhere) makes code less readable and harder to debug. On the other hand, putting such logic in controllers puts a burden on you that you have to remember about calling it if you happen to be editing subjects in other places (but is more explicit). Whichever way you choose, remember not to make your classes too fat, for example try to use service object pattern to separate such custom logic as soon as you feel like it is getting out of hand. :) And don't forget about tests - when things go wrong, tests make refactoring easier.
Background
I'm fairly new to Rails. I'm working with Ruby 2.1.1 and Rails 4.1 and have been reading a lot of books and tutorials but haven't quite got to the point of understanding what the best way is to keep controllers lean.
It looks like with Rails 4 there are concerns available for both models and controllers. At least for the controller concerns, it seems like the primary purpose is to help keep the routes and controllers DRY. A good example seems to be the defensible example at codeschool.
I also read some questions asking about similar things but couldn't find what I felt to be an exact match, especially in the context of Rails 4. What I saw seemed to say that that it would be possible to create a custom class or module and then invoke that in the controller action.
Specific Issues
I have a controller where most of the actions are lean but there is one that has to do a lot of data processing and this one has grown pretty large.
I created some private helper methods in the controller to break the processing into smaller pieces - but it seems like these should almost be combined into a module or class?
The data processing really is specific to this controller and is unlikely to be used elsewhere
Questions
Am I correct in feeling like this controller should not have one large, bloated action? Or is it normal for controllers' actions to become large like this?
Are concerns designed to be used to help reduce this? Or are they more to help with the DRY aspects of shared actions between different controllers?
Would a class or a module be a good solution? Is it typical to create custom classes / methods to help keep controllers lean?
If the class/module approach is a good solution, how does one choose module vs class?
If the class/module approach is a good solution, where should these be housed and how should they be loaded / invoked? ( It seems like they should not be global "helper" functions if they are just specific to one controller )
Depends -- if you have to process that data in the controller, perhaps it's the right way. But as with most things, if you show us the code, we may be able to refactor. You need to be aware of modularity, which means you should split your code as much as possible, to encourage reuse
Concerns are really for providing cross-controller / cross-model modularity. For example, we use friendly_id in several models; we've separated into different concerns, giving us the ability to change the concern once & update all the models
You're looking for class methods
Fat Model Skinny Controller
Although not well documented, one of the core Rails patterns is to keep your controller as lean as possible. To do this, dhh recommends putting lots of your methods into your models (scopes, class methods etc) - allowing you to call them with brevity
This is a general programming pattern
Inherited Resources
One of my favourites - this creates the standard RESTful action interface in your controller, so you don't need to include it yourself:
#app/controllers/posts_controller.rb
class PostsController < InheritedResources::Base
end
This will load index, show, new, create, edit, update, destroy automatically
Callbacks
Finally, you should be aware of callbacks
These allow you to run common code with a single instance method. A good example is find:
#app/controllers/posts_controller.rb
class PostsController < ApplicationController
before_action :load_post, only: [:show, :edit]
private
def load_post
#post = Post.find params[:id]
end
end
Your best option in this case is probably to use form objects. A form object exists simply to abstract away the complex interactions that are occurring in your controller. This results in cleaner more maintainable code, among other great benefits. You can read more and find some excellent examples of the technique at http://pivotallabs.com/form-backing-objects-for-fun-and-profit/ and http://railscasts.com/episodes/416-form-objects (pro), or just search for "rails form objects".
Consider I have a controller with an action which renders a view. The view needs data to render. I know the following ways to prepare and send it to the view:
Using instance variables
class CitiesController < ApplicationController
def index
#cities = Cities.order(:name).limit(10)
end
end
This is the default approach which can be found in Rails documentation, but it has some disadvantages:
It makes the action code fat which becomes responsible not only for controller logic, but also for the data preparation.
Views need to access this data through instance variables – those #-variables break the principle of least astonishment.
Using helper methods
class CitiesController < ApplicationController
helper_method :cities
def index
end
def cities
#cities ||= Cities.order(:name).limit(10)
end
end
That's the way I prefer the most. It keeps action methods clean, so I may implement controller logic there not mixing it with data preparations in one method. Also, there's no need to use mysterious instance variables in views, making them isolated. However:
The data preparations are still in the controller. It becomes unreadable when there are a lot of these helper methods, especially when they are relative to different actions/views.
There's a need of having a unique name for each helper method. Say, I can't have a method called products which will return different data for different actions (of course, I can do it in one method, but it would look ugly).
Using the facade pattern
Partially the problem is solved in this article: https://medium.com/p/d65b86cdb5b1
But I didn't like this approach because it introduces a #magic_facade_object in views.
Using inherited resources
It may look beautiful in examples, but in my opinion when it comes to the real code, controller code becomes a spaghetti-monster very fast. The other thing is that a page view usually needs not only the resource but also other data to render (sidebar blocks, etc.) and I still have to use another way to prepare it. Combining different approaches makes the code even more unreadable. Finally, I don't like to use resource variable, because it makes not very clear what is the view about.
So, here is the question. How do you keep your controllers clean?
How do you keep your controllers clean?
By writing DRY code and sprinkling some gem magic around.
Having a look at your bullet points, I think I have a different opinion on most of the stuff.
#cities = Cities.order(:name).limit(10) is exactly what i think belongs into a rails controller and it does not violate the principle of least surprise, it's kind of the opposite. instance variables are the default way of passing around variables from controllers to views, even though that is a pretty ugly thing to do. it's "the rails way" (TM)!
decent_exposure takes away most of these concerns
please stop applying old-school pattern to rails or ruby code. it's really just useful in large applications where you are struggling to keep sane with the amount of code that's within a single controller method. write clean code, test it thoroughly and you will be fine 80% of the time.
don't use "one size fits all" tools. most often, you need to write more configuration than you would need code to make it work. it's also getting a lot more complex through this kind of things.
I'm working on an app at work. Basic stuff, user signs up (with an associated organization).
Initially I started off with a simple controller -
# Need to check if organization exists already; deny user creation if it does
if #organization.save
#user.save
redirect_to user_dashboard_path...
I soon found myself in a callback soup:
After the organization is validated, we save the user.
When the organization is created, I create another two models, EmailTemplate and PassTemplate (an organization has_one :email_template, has_one :pass_template)
after_create :init_company, :init_email_template, :init_pass_template, :init_form
Each of those callbacks generally calls method on the model, something like:
def init_email_template
self.email_template.create_with_defaults
end
Initially I thought this was quite clever - doing so much behind the scenes, but I've been reading Code Complete by Steve McConnell, and feel this is not simple at all. If I didn't know what was happening already, There's no hint that any time an organization is created it creates 3 associated objects (and some of those objects in turn initialize children objects).
It seems like a bad programming practice, as it obfuscates what's going on.
I thought about moving all of those initalizations to the controller, as an organization is only ever created once:
class OrganizationsController < AC
...
def create
if #organization.save
#organization.create_user
#organization.create_email_template
#organization.create_pass_template
end
That seems like cleaner code, and much easier to follow.
Question 1
*Are there better solutions, or best practices for handling creating associated objects upon creation of the hub object that I'm unaware of?*
Side note - I would have to rewrite a bunch of tests that assume that associations are automatically created via callbacks - I'm okay with that if it's better, easier to understand code.
Question 2
**What about a similar situation with after_save callbacks?**
I have a customer model that checks to see if it has an associated user_account after creation, and if not, creates it. It also creates a Tag model for that user_account once we've created the user_account
class Customer < AR
after_create :find_or_create_user_account
def find_or_create_user_account
if !self.user_account_exists?
#create the user
end
Tag.create(:user_id => self.user_account.id)
end
end
Somewhat simplified, but again, I believe it's not particularly good programming. For one, I'm putting logic to create two different models in a third model. Seems sloppy and again the principle of separating logic. Secondly, the method name does not fully describe what it's doing. Perhaps find_or_create_user_account_and_tag would be a better name, but it also goes against the principle of having the method do one thing- keeping it simple.
After reading about observers and services, my world was thrown for a bit of a loop.
A few months ago I put everything in controllers. It was impossible to test well (which was fine because I didn't test). Now I have skinny controllers, but my models are obese and, I think, unhealthy (not clear, not obvious, harder to read and decipher for another programmer/myself in a few months).
Overall I'm just wondering if there are some good guides, information, or best practices on separation of logic, avoiding callback soup, and where to different sorts of code
Why not the following?
after_create :init_associated_objects
def init_associated_objects
init_company
init_email_template
init_pass_template
init_form
end
My interpretation with "a method should do one thing" isn't strict and that I usually have a method that calls other method (much like the one above). At the end of the day, it's a divide and conquer strategy.
Sometimes I create utility POROs (plain old ruby objects) when it doesn't make sense to have an AR model but a group of functionalities is a class' responsibility. Reports, for instance, are not AR-backed models but it's easier when a report that needs to call multiple models is just instantiated once where the reporting period start and end are instance variables.
A rule of thumb that I follow: if I instantiate the models outside of the whole MVC stack (e.g. Rails console), the things that I expect to happen should stay inside the model.
I don't claim best practices but these have worked for me so far. I'm sure other people would have a better idea on this.
Today, trying to DRY up some code, I extracted some duplicate File.exists? code used by several helper methods into a private method
def template_exists?(*template) and accidently monkey patched this already existing Rails helper method. This was a pretty clear indicator of a code smell, I didn't need need any the inherited methods, yet I inherit them. Besides, what was my refactored method doing in this helper at all?
So, this helper does way too much and hence violates SRP (Single Responsibility Principle). I feel that rails helpers are inherently difficult to keep within SRP. The helper I'm looking at is a superclass helper of other helpers, counting 300+ lines itself. It is part of a very complex form using javascript to master the interaction flow. The methods in the fat helper are short and neat, so it's not that awful, but without a doubt, it needs separation of concerns.
How should I go forth?
Separate the methods into many helpers?
Extracting the code inside the helpers methods into classes and delegate to them? Would you scope these classes (i.e. Mydomain::TemplateFinder)?
Separate the logic into modules and list them as includes at the top?
other approaches?
As I see, no 2 is safer wrt accidential monkeypatching. Maybe a combination?
Code examples and strong opinions appreciated!
Extracting helpers methods into classes (solution n°2)
ok to address this specific way to clean up helpers 1st I dug up this old railscast :
http://railscasts.com/episodes/101-refactoring-out-helper-object
At the time it inspired me to create a little tabbing system (working in one of my apps in conjunction with a state machine) :
module WorkflowHelper
# takes the block
def workflow_for(model, opts={}, &block)
yield Workflow.new(model, opts[:match], self)
return false
end
class Workflow
def initialize(model, current_url, view)
#view = view
#current_url = current_url
#model = model
#links = []
end
def link_to(text, url, opts = {})
#links << url
url = #model.new_record? ? "" : #view.url_for(url)
#view.raw "<li class='#{active_class(url)}'>#{#view.link_to(text, url)}</li>"
end
private
def active_class(url)
'active' if #current_url.gsub(/(edit|new)/, "") == url.gsub(/(edit|new)/, "") ||
( #model.new_record? && #links.size == 1 )
end
end #class Workflow
end
And my views go like this :
-workflow_for #order, :match => request.path do |w|
= w.link_to "✎ Create/Edit an Order", [:edit, :admin, #order]
= w.link_to "√ Decide for Approval/Price", [:approve, :admin, #order]
= w.link_to "✉ Notify User of Approval/Price", [:email, :admin, #order]
= w.link_to "€ Create/Edit Order's Invoice", [:edit, :admin, #order, :invoice]
As you see it's a nice way to encapsulate the logic in a class and have only one method in the helper/view space
You mean seperate large helpers into smaller helpers? Why not. I don't know your code too well, but you might want to consider outsourcing large code chunks into ./lib.
No. ;-) This sounds awfully complex.
Sounds complex too. Same suggestion as in 1.: ./lib. The modules in there are auto-loaded if you access them.
No
My suggestion is: Hesitate from using too many custom structures. If you have large helpers, ok, might be the case. Though I wonder if there is an explanation why that whole helper code is not in the Controller. I use helpers for small and simple methods that are used inside the template. Complex (Ruby-)logic should be put into the Controller. And if you really have such a complex Javascript app, why don't you write this complex stuff in Javascript? If it really has to be called from the template, this is the way to go. And probably makes you website a bit more dynamic and flexible.
Regarding monkey patching and namespace collisions: If you have class name, method names etc. that sound common, check out if they are defined. Google, grep or rails console for them.
Make sure you understand which code belongs to
Controller: Fill variables with stuff, perform user actions (basically the computation behind your page)
Helper: Help doing simple stuff like creating a fancy hyperlink
def my_awesome_hyperlink url, text
"Fancy Link to #{text}"
end
./lib: More complex stuff that is used by more than one Controller and/or also used directly by other components like Cucumber step definitions
inside the Template as Ruby Code: Super easy to read
inside the Template (or ./public) as Javascript code: Matter of taste. But the more dynamic your app, the more likely code belongs in here.
Ok this is a really hard question to answer. Rails kind of leads you down the path of view helpers and really doesn't give you a decent baked-in alternative when you out-grow it.
The fact that helpers are just modules that are included in to the view object doesn't really help with the separation of concerns and coupling. You need to find a way to take that logic out of modules altogether, and find it a home in its own class.
I'd start by reading up on the Presenter pattern, and try to think of how you might be able to apply it as a middle layer between the view and the model. Simplify the view as much as possible, and move the logic to the presenter or the model. Move javascript right out of the view, and instead write unobtrusive javascript in .js files that enhance the functionality of the existing javascript. It definitely does not need to be in the view, and you'll find that helps clean up a lot if stuffing js in your views is what got you in this mess.
Here's some links for reading:
http://blog.jayfields.com/2007/03/rails-presenter-pattern.html
About presenter pattern in rails. is a better way to do it?
http://blog.jayfields.com/2007/01/another-rails-presenter-example.html
http://blog.jayfields.com/2007/09/railsconf-europe-07-presenter-links.html
Don't get too caught up in the specific code examples, rather try to understand what the pattern is trying to accomplish and think how you could apply it to your specific problem. (though I really like the example in the 2nd link above; the stack overflow one).
Does that help?
It is difficult to suggest a clear solution without the code. However since helper methods all live in the same global view instance, name collision is a common problem.
#Slawosz may be a solution but no really fit for the helpers philosophy.
Personally I would suggest to use the cells gem : cells are like component for rails, except lightweight, fast, cacheable and testable.
Also to answer your specific problem they're completely isolated. When your view helpers get to complex they're definitely the solution.
(disclosure I am not the creator of this gem, just happily using it....)
# some view
= render_cell :cart, :display, :user => #current_user
# cells/cart_cell.rb
# DO whatever you like in here
class CartCell < Cell::Rails
include SomeGenericHelper
def display(args)
user = args[:user]
#items = user.items_in_cart
render # renders display.html.haml
end
end
Also you can use a generic helper for dryness here without fearing name clash.
I would create a small library which is responsible to manipulate yours forms.Some well named classes, some inheritance, and as input you pass ie parameters, and as output you can has ie. objects for partials used in this form. Everything will be encapsulated, and it will be easy to test.
Look at AbstractController code, and then Metal to see how smart are rails designed, maybe there You will find inspiration how to solve your problem.
Your approach is correct but I would prefer 3rd point i.e. separate the logic into modules.
Modules open up lots of possibilities, particularly for sharing code among more than one class, because any number of classes can mix in the same module.
The greatest strength of modules is that they help you with program design and flexibility.
Using such kind of approach you can achieve design patterns.