Inherited Resources always had a hate/love history with Rails Edge. Just after DHH posted about respond_with, it was already there in Inherited Resources. This initial implementation provided a nice test suite and several use cases for a improved Rails’ implementation, based in Responders, which encapsulates all the behavior in one class, and can be added, modified or updated.
After that, Inherited Resources was outdated and envy. It needed to be updated and it was: responders has been available in Inherited Resources for more than four months, and consequently in Rails 2.3.
Everything looked great until we started to develop a fresh Rails 3 application. The main purpose of this fresh application is to be a sample of Rails 3 features, including generators and responders. Based on that, it doesn’t make sense to use a tool like Inherited Resources, since it would abstract almost all controllers away and the application would no longer fit as an example.
So we were there, building an application based on scaffold, and as we saw duplicated code we started to realize Inherited Resources contains a lot of tools that could be used outside its context. And this is what is happening right now, two new gems are being launched: Responders and HasScope.
Responders
Responders is a repository of Rails 3 responders, mainly based on this post on Ruby on Rails weblog. And as a proof of concept, we wrote two Responders: FlashResponder and HttpCacheResponder.
FlashResponder uses I18n to automatically look up flash messages for you, even allowing you to set generic messages. In other words, your old create action:
1 2 3 4 5 | def create @post = Post.new(params[:post]) flash[:notice] = "Post was successfully created" if @post.save respond_with(@post) end |
Can now be written as:
1 2 3 4 5 | def create @post = Post.new(params[:post]) @post.save respond_with(@post) end |
Your locale just needs to have the following configuration:
flash:
actions:
create:
notice: "{resource_name} was successfully created"
update:
notice: "{resource_name} was successfully updated"
destroy:
notice: "{resource_name} was successfully destroyed"
alert: "{resource_name} could not be destroyed"If you want to change a message, let’s say, the success message when creating a post, there are several ways to achieve that. You can give :notice to respond_with or even update your I18n under the key: “flash.posts.create.notice”.
For us it came as a nice tool to provide I18n by default in our controllers and decouple messages from code.
The HttpCacheResponder automatically adds a Last-Modified header to API requests without any extra configuration. This allows clients to easily query the server if a resource changed and also replies with 304 (Not Modified) status.
As usual, the code for both implementations came from Inherited Resources. And since it contains a Rails 3.0 Responders shim, those responders can already be used in Inherited Resources and they are!
In other words, Inherited Resources code got simplified and such features can now be used by any Rails 3 application without a need to load all Inherited Resources stack. Besides, as more Responders appears, they can be added to Responders repository and be used in Inherited Resources easily.
HasScope
The other tool extracted from Inherited Resources is HasScope.
Let’s suppose that we have a ProjectsController and at some point you want to add some filters on the index action like showing just featured projects, selecting projects by methodology or even let the user choose how many projects he can see per page. The first thing to do? Add named scopes to your model:
1 2 3 4 5 | class Project < ActiveRecord::Base named_scope :featured, :conditions => { :featured => true } named_scope :by_methodology, proc {|methodology| { :conditions => { :methodology => methodology } } } named_scope :limit, proc{|limit| :limit => limit.to_i } end |
The next step would be to add a lot of code in your controllers that check which named scopes you should call, based on the parameters sent right? Well, not anymore. Your controller can be as simple as:
1 2 3 4 5 6 7 8 9 | class ProjectsController < ApplicationController has_scope :featured, :type => :boolean has_scope :by_methodology has_scope :limit, :default => 10, :only => :index def index @projects = apply_scopes(Project).all end end |
Then for each request:
/projects #=> acts like a normal request, but returning only 10 projects /projects?featured=true #=> calls the featured named scope and bring 10 featured projects /projects?featured=true&by_methodology=agile&limit=20 #=> brings 20 featured projects with methodology agile
If you configure your routes, you could even have pretty urls with it:
/projects/agile/featured #=> brings 10 featured projects with methodology agile
All in all, you can now call has_scope in any controller and in case you are using it inside an Inherited Resources controller, everything gets handled automatically, so enjoy!
So Inherited Resources finally reaches 1.0
After this refactoring and a complete clean up of Inherited Resources issues, it finally reaches 1.0! When you install it, responders and has_scope gems should be installed as well. Responders is always loaded, since it’s a dependency, but if you want to use has_scope you will need to add it to your environment as well.
After you install the gem, the upgrade process in any application can be handled in three steps:
1) Add config.gem “has_scope” to your “config/environment.rb”.
2) Configure which flash keys are used by your application. At first, Inherited Resources used :notice and :error. Then we changed to :success and :failure, but just after this DHH established :notice and :alert as Rails default.
From 1.0 on, Inherited Resources will be using :notice and :alert, but it allows you to change it:
InheritedResources.flash_keys = [ :success, :failure ]
3) Finally, you may need to do a final change in your application due to how responders work. The default way a resource tells a responder if it was created/updated/destroyed with success or not, is through errors. If the errors are empty, it assumes it succeeded, otherwise it failed.
This will be true in all create/update scenarios, but not in destroy. In other words, if you have a code with similar structure in your model (please don’t!):
def before_destroy if some_condition_is_not_valid? false else true end end
It won’t work anymore. You need to add an error to your model to really invalidate it:
def before_destroy if some_condition_is_not_valid? errors.add(fault_attribute, :invalid) false else true end end
Now you should be ready to go. Enjoy!
Tags: inherited_resources, plugins, rails, responders, respond_with
Posted in English | View Comments
Well, we are in business for almost one year and we are happy to say that quite a lot of applications were already delivered. In each one of them, we were definitely learning and moving toward the Plataforma way of doing things.
So I want to talk the way we treat Rails controllers at Plataforma. With love, of course, but we are going to go deeper than that, specifically in three steps:
1) Using InheritedResources to dry up controllers
2) Splitting your controllers by scope with nested controllers
3) Creating acts_as_* and filters to contain common logic and configuration among controllers
Step 1: Using InheritedResources to dry up controllers
InheritedResources is a tool that allows drying up your controllers, by removing the common logic and taking care of stuff like relationships.
For instance, imagine that you have an Article model which belongs to user. If you want to show all the articles for an specific user, your routes definition and controller are just the following:
# config/routes.rb map.resources :users do |u| u.resources :articles end # app/controllers/articles_controller.rb class ArticlesController < InheritedResources::Base belongs_to :users end
It supports nested and/or polymorphic relationships, I18n and other stuff like named scopes.
Almost all of our controllers inherit from InheritedResources::Base and the first step is as simple as that.
Step 2: Splitting your controllers by scope with nested controllers
Sometime ago, Matt Jankowski from Thoughtbot wrote an excellent blog post on how they deal with scoped controllers, like in the scenario above where we want to show all the articles which belongs to an specific user.
Matt tell us that instead of having an ArticlesController, we should have a Users::ArticlesController, so ArticlesController is available if you want to show all the articles in the application.
Since we read this post, we started to use this setup on our applications as well. However, InheritedResources does not play nice with it by default and let’s check why. Our ArticlesController should be renamed to Users::ArticlesController and be rewritten as:
class Users::ArticlesController < InheritedResources::Base belongs_to :users end
The problem is, according to the namespace Users, InheritedResources appends to all named routes the prefix “users”. But since Articles belongs to :user, it also appends “user”. So the resource_url method will actually call “users_user_article_url”, which is not defined. The fix is simple:
class Users::ArticlesController < InheritedResources::Base defaults :route_prefix => nil belongs_to :users end
Matt’s post contains a lot of tips about using nested controllers and it’s a must-read.
Step 3: Creating acts_as_* and filters to contain common logic and configuration among controllers
As your application grow, you will start to notice that your controllers will have a lot of configuration values and methods for specific scopes. Let’s consider that in our application an user can only see his articles and we are going to retrieve the user from session. So instead of having a route “/users/:user_id/articles/:id” like above, we should just have “/articles/:id” and our controller will be similar to:
class Users::ArticlesController < InheritedResources::Base before_filter :find_user_from_session layout "users" defaults :route_prefix => nil protected # Get the articles scoped to the current user def begin_of_association_chain @current_user end # Simple method to retrieve an user from session def find_user_from_session @current_user ||= User.find(session[:user_id]) end end
With time, we will notice that several controllers use this same pattern, and we need to refactor it. Our first thought would be move part of the logic to ApplicationController, but our ApplicationController will only grow and grow as you add roles (like Admin) to your application.
A better approach would be to move this specific logic to a controller named Users::ApplicationController inside “app/controllers/users/application_controller.rb”:
class Users::ApplicationController < ApplicationController before_filter :find_user_from_session layout "users" protected def begin_of_association_chain @current_user end def find_user_from_session @current_user ||= User.find(session[:user_id]) end end
Now we can inherit from it and get InheritedResources methods by calling inherit_resources in our controller:
class Users::ArticlesController < Users::ApplicationController inherit_resources # the same as inheriting from InheritedResources::Base defaults :route_prefix => nil end
But we are not very happy with this pattern, because we still need to call defaults and set some configuration values (which can be quite a few depending on your application).
What we do instead is create some macros inside a module called Filters. So we create a file at “app/controllers/users/filters.rb” with the following:
module Users::Filters def acts_as_user(options={}) before_filter :find_user_from_session layout "users" defaults options.reverse_merge(:route_prefix => nil) include ControllerMethods end module ControllerMethods protected def begin_of_association_chain @current_user end def find_user_from_session @current_user ||= User.find(session[:user_id]) end end end
And extend this module in our ApplicationController:
class ApplicationController < ActionController::Base extend Users::Filters end
And we can use it simply as:
class Users::ArticlesController < InheritedResources::Base acts_as_user end
The main advantage here is that we have more control of our controller configuration through a single interface. If we need to configure a singleton controller or ensure that most controllers have pagination, we can simply do:
module Users::Filters def acts_as_user(options={}) before_filter :find_user_from_session layout "users" has_scope :paginate, :only => :index unless options.delete(:paginate) == false defaults options.reverse_merge(:route_prefix => nil) include ControllerMethods end
And invoke it as:
acts_as_user :paginate => false acts_as_user :singleton => true acts_as_user :paginate => false, :singleton => true
Wrapping up
As you add more roles to your application, you create more filter. Remember that the important here is to keep your code DRY and is NOT reduce the lines of code. So just place inside those acts_as_* helpers configuration which is common to almost all (if not all) controllers. There is some convention over configuration here, so be sure that the whole team working in the project agrees with them as well. In other words: use it with caution, because we certainly do.
This pattern holds almost all controllers in the last applications we built and we are quite happy with it. Be sure to grab our blog feed (see our sidebar), because we will continue writing about the Plataforma way in next posts!
Tags: filters, inherited_resources, the plataforma way
Posted in English | View Comments
First, what is Inherited Resources?
Inherited Resources is a gem/plugin that allows you to speed up development by making your controllers inherit all restful actions so you just have to focus on what is important. A Rails scaffold controller which responds to html, xml and json is as simple as:
1 2 3 | class ProjectsController < InheritedResources::Base respond_to :html, :xml, :json end |
However all actions are still customizable! For example, you can change the behavior of the create action on success just doing:
1 2 3 4 5 6 7 8 9 | class ProjectsController < InheritedResouces::Base respond_to :html, :xml, :json def create create! do |success, failure| success.html { redirect_to edit_project_url(@project) } end end end |
It also supports I18n (all flash messages are set with I18n), belongs to association (like a task belongs to project), nested belongs to (task belongs to project which belongs to company), polymorphic belongs to (comments belong to task or file or message) and optional belongs to (the same as previously, but you can request the resource with or without parents).
As you noticed, besides simplifying your controllers, InheritedResouces makes easy to reproduce your models behavior and relationship in controllers. And right now, it’s also scopes and responder fluent!
has_scope: named_scope twin brother
Let’s suppose that we have a ProjectsController and at some point you want to add some filters on the index action like showing just featured projects, selecting projects by methodology or even let the user choose how many projects he can see per page. The first thing to do? Add named scopes to your model:
1 2 3 4 5 | class Project < ActiveRecord::Base named_scope :featured, :conditions => { :featured => true } named_scope :by_methodology, proc {|methodology| { :conditions => { :methodology => methodology } } } named_scope :limit, proc{|limit| :limit => limit.to_i } end |
The next step would be to add a lot of code in your controllers that check which named scopes you should call, based on the parameters sent right? Well, not anymore. Your controller can be as simple as:
1 2 3 4 5 | class ProjectsController < InheritedResources::Base has_scope :featured, :boolean => true has_scope :by_methodology has_scope :limit, :default => 10, :only => :index end |
Then for each request:
/projects #=> acts like a normal request, but returning only 10 projects /projects?featured=true #=> calls the featured named scope and bring 10 featured projects /projects?featured=true&by_methodology=agile&limit=20 #=> brings 20 featured projects with methodology agile
If you configure your routes, you could even have pretty urls with it:
/projects/agile/featured #=> brings 10 featured projects with methodology agile
Yay!
Responder
A couple weeks ago, we wrote about ActionController::Responder. But you don’t have to wait Rails 3 to be released to play with it, you can start now by using Inherited Resources.
Quick redirect
After using Inherited Resouces, I realized that most of the times I overwrite a create, update or destroy actions is to change the redirect destination. In our ProjectsController above, if we want to redirect to the edit page after create, we would have to do:
1 2 3 4 5 6 7 8 9 | class ProjectsController < InheritedResouces::Base respond_to :html, :xml, :json def create create! do |success, failure| success.html { redirect_to edit_project_url(@project) } end end end |
It wouldn’t be cool if it have a shortcut? Now it has:
1 2 3 4 5 6 7 | class ProjectsController < InheritedResouces::Base respond_to :html, :xml, :json def create create! { edit_project_url(@project) } end end |
That simple, just give the url as a proc and since the proc does not expect any parameters, it assumes that you want to overwrite the redirect url.
Finally some DSL?
Last weeks, there was a discussion on Boston.rb group about different resource controllers gems. Reading some of the feedback there, I’ve decided to stab a DSL to Inherited Resources. It will mainly remove the duplication when you have to give a block, the previous example above could be written as:
1 2 3 4 5 6 7 | class ProjectsController < InheritedResouces::Base respond_to :html, :xml, :json create! do |success, failure| success.html { redirect_to edit_project_url(@project) } end end |
Or even in the compact form:
1 2 3 4 | class ProjectsController < InheritedResouces::Base respond_to :html, :xml, :json create! { redirect_to edit_project_url(@project) } end |
Those changes were not applied yet, it depends mainly on you. If you like or not, let us know in the comments!
Tags: inherited_resources, plugins, rails
Posted in English | View Comments

All
English only
Em português apenas