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.
Related
In case you were unaware, this is a beginner's question.
Having learned a bit of Ruby, I have ventured onto Rails, but have run into a brick wall when it comes to organizing methods. I'm building something which is supposed to take the data/parameters you get when someone creates something, but instead of showing it like you would a tweet or blog post, I want to use them as variables in some mathematical calculations, the results of which I then want to show.
Now, in Ruby, I would make a method for each little math operation, to make sure they (the methods) have a single responsibility each. In Rails, though, what am I supposed to do? In case you don't understand my problem, I think it has to do with my lack of understanding of instances in Rails. Instances in Ruby can call upon the methods I make, but where do I call upon my methods (actions?) in Rails?
You should follow the MVC paradigm:
The controller should receive the parameters that the user gave via some html form.
Then that controller should instantiate an object that is doing the math calculation and then the controller should render a view to present the results to the user.
The place where the controller and the views are stored is already decided by the framework:
controllers are in app/controllers and the views in app/views/<controller_name>
Now the question is where you put the class that performs the calculations.
You might think about the app/models folder, but that one is typically for the models that inherit from ActiveRecord::Base, ie, all those that are persisted in the database.
Normally the kind of class that you are implementing lives in the lib folder.
For example, you might have the following structure:
app/controllers/calculations_controller.rb
def perform_calculations
math_calculator = MathCalculator.new params[:operation]
#result = math_calculator.calculate
end
lib/math_calculator.rb
class MathCalculator
def calculate
# whatever you need to do here
end
end
app/views/calculations/perform_calculations.html.erb
<%= #result %>
There's nothing official, I think its helping you
http://www.caliban.org/ruby/rubyguide.shtml
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".
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.
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).
I'm really enjoying Rails (even though I'm generally RESTless), and I enjoy Ruby being very OO. Still, the tendency to make huge ActiveRecord subclasses and huge controllers is quite natural (even if you do use a controller per resource). If you were to create deeper object worlds, where would you put the classes (and modules, I suppose)? I'm asking about views (in the Helpers themselves?), controllers and models.
Lib is okay, and I've found some solutions to get it to reload in a dev environment, but I'd like to know if there's a better way to do this stuff. I'm really just concerned about classes growing too large. Also, what about Engines and how do they fit in?
Because Rails provides structure in terms of MVC, it's natural to end up using only the model, view, and controller containers that are provided for you. The typical idiom for beginners (and even some intermediate programmers) is to cram all logic in the app into the model (database class), controller, or view.
At some point, someone points out the "fat-model, skinny-controller" paradigm, and intermediate developers hastily excise everything from their controllers and throw it into the model, which starts to become a new trash can for application logic.
Skinny controllers are, in fact, a good idea, but the corollary--putting everything in the model, isn't really the best plan.
In Ruby, you have a couple of good options for making things more modular. A fairly popular answer is to just use modules (usually stashed in lib) that hold groups of methods, and then include the modules into the appropriate classes. This helps in cases where you have categories of functionality that you wish to reuse in multiple classes, but where the functionality is still notionally attached to the classes.
Remember, when you include a module into a class, the methods become instance methods of the class, so you still end up with a class containing a ton of methods, they're just organized nicely into multiple files.
This solution can work well in some cases--in other cases, you're going to want to think about using classes in your code that are not models, views or controllers.
A good way to think about it is the "single responsibility principle," which says that a class should be responsible for a single (or small number) of things. Your models are responsible for persisting data from your application to the database. Your controllers are responsible for receiving a request and returning a viable response.
If you have concepts that don't fit neatly into those boxes (persistence, request/response management), you probably want to think about how you would model the idea in question. You can store non-model classes in app/classes, or anywhere else, and add that directory to your load path by doing:
config.load_paths << File.join(Rails.root, "app", "classes")
If you're using passenger or JRuby, you probably also want to add your path to the eager load paths:
config.eager_load_paths << File.join(Rails.root, "app", "classes")
The bottom-line is that once you get to a point in Rails where you find yourself asking this question, it's time to beef up your Ruby chops and start modeling classes that aren't just the MVC classes that Rails gives you by default.
Update: This answer applies to Rails 2.x and higher.
Update: The use of Concerns have been confirmed as the new default in Rails 4.
It really depends on the nature of the module itself.
I usually place controller/model extensions in a /concerns folder within app.
# concerns/authentication.rb
module Authentication
...
end
# controllers/application_controller.rb
class ApplicationController
include Authentication
end
# concerns/configurable.rb
module Configurable
...
end
class Model
include Indexable
end
# controllers/foo_controller.rb
class FooController < ApplicationController
include Indexable
end
# controllers/bar_controller.rb
class BarController < ApplicationController
include Indexable
end
/lib is my preferred choice for general purpose libraries. I always have a project namespace in lib where I put all application-specific libraries.
/lib/myapp.rb
module MyApp
VERSION = ...
end
/lib/myapp/CacheKey.rb
/lib/myapp/somecustomlib.rb
Ruby/Rails core extensions usually take place in config initializers so that libraries are only loaded once on Rails boostrap.
/config/initializer/config.rb
/config/initializer/core_ext/string.rb
/config/initializer/core_ext/array.rb
For reusable code fragments, I often create (micro)plugins so that I can reuse them in other projects.
Helper files usually holds helper methods and sometimes classes when the object is intended to be used by helpers (for instance Form Builders).
This is a really general overview. Please provide more details about specific examples if you want to get more customized suggestions. :)
... the tendency to make huge
ActiveRecord subclasses and huge
controllers is quite natural ...
"huge" is a worrisome word... ;-)
How are your controllers becoming huge? That's something you should look at: ideally, controllers should be thin. Picking a rule-of-thumb out of thin air, I'd suggest that if you regularly have more than, say, 5 or 6 lines of code per controller method (action), then your controllers are probably too fat. Is there duplication that could move into a helper function or a filter? Is there business logic that could be pushed down into the models?
How do your models get to be huge? Should you be looking at ways to reduce the number of responsibilities in each class? Are there any common behaviours you can extract into mixins? Or areas of functionality you can delegate to helper classes?
EDIT: Trying to expand a bit, hopefully not distorting anything too badly...
Helpers: live in app/helpers and are mostly used to make views simpler. They're either controller-specific (also available to all views for that controller) or generally available (module ApplicationHelper in application_helper.rb).
Filters: Say you have the same line of code in several actions (quite often, retrieval of an object using params[:id] or similar). That duplication can be abstracted first to a separate method and then out of the actions entirely by declaring a filter in the class definition, such as before_filter :get_object. See Section 6 in the ActionController Rails Guide Let declarative programming be your friend.
Refactoring models is a bit more of a religious thing. Disciples of Uncle Bob will suggest, for example, that you follow the Five Commandments of SOLID. Joel & Jeff may recommend a more, er, "pragmatic" approach, although they did appear to be a little more reconciled subsequently. Finding one or more methods within a class that operate on a clearly-defined subset of its attributes is one way to try identifying classes that might be refactored out of your ActiveRecord-derived model.
Rails models don't have to be subclasses of ActiveRecord::Base, by the way. Or to put it another way, a model doesn't have to be an analogue of a table, or even related to anything stored at all. Even better, as long as you name your file in app/models according to Rails' conventions (call #underscore on the class name to find out what Rails will look for), Rails will find it without any requires being necessary.
Here's an excellent blog post about refactoring the fat models that seem to arise from the "thin controller" philosphy:
http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/
Basic message is "Don’t Extract Mixins from Fat Models", use service classes instead, the author provides 7 patterns to do so