Have you ever felt like your controller was getting a lot of private methods to maintain its code clean? Better yet, have you ever felt that those chunks of code could be used elsewhere in your application, helping keep your code DRY?
I was hit by this thoughts a while back when i was starting developing with rails and the method i used back then seems to be pretty straightforward to me, even now (one year later). The principle is simple: Take reusable chunks of your code that can be used on different controllers, glue them up in a helper module and include that module on every controller that uses the code.
I usually split the methods into subjects, like UserSharedHelper for user-related methods, PurchaseSharedHelper for purchase-related methods and so on…
Let’s see an example of this practice in action:
module UserSharedHelper # Require an user to be logged in. def require_current_user # if there is a current_user, then the user is logged in and # the action can proceed return true if current_user.present? # if the method hasn't returned, there is no user logged in! # flash a warning and redirect the user to the log in page flash[:warning] = "You must log in before proceeding!" redirect_to new_user_session_path end end class StoreCheckoutsController < ApplicationController include UserSharedHelper # require users to be logged in on actions under this controller before_filter :require_current_user def new; end [...] end
It’s pretty simple and helps you to keep your code DRY. There are some drawbacks though that need to be considered:
- The controller scope gets methods from the SharedHelper, which may lead to method conflicts;
- As your SharedHelpers grow larger, you gotta be careful with injecting a lot of unnecessary code into your controllers;
- Methods from the SharedHelper make their way into the view, which may lead to further conflicts.
Being used with careful, i don’t see a reason not to use it. What about you? How do you keep your controllers DRY? Comment below!
Guillermo commented with a pretty straightforward way to make this approach even better:
Defining the module:
And in the controller: