It is common in Rails 3.0 applications that you want to provide default views for a group of controllers. Let’s say you have a bunch of controllers inside the
Admin namespace and you would like each action to fallback to a default template. So if you are rendering the index action for
Admin::PostsController and “app/views/admin/posts/index.html.*” is not available, it should then render “app/views/admin/defaults/index.html”.
There are several ways to implement this feature at the controller level. It mainly relies on trying to render the original template and then rescue
ActionView::MissingTemplate. If this error is rescued, you then render the default one. However, there is a considerable performance overhead in this approach as it needs to pass through the rendering and template lookup stack twice.
Luckily, since Rails 3.0, we have a new abstraction called resolvers that holds the logic to find a template. I explain comprehensively how resolvers work and their API in my book Crafting Rails Applications. So here I would just show the basics to get this functionality working.
First, we need to define a
DefaultResolver, it could be done inside the lib directory:
class MyResolver < ::ActionView::FileSystemResolver def initialize super("app/views") end def find_templates(name, prefix, partial, details) super(name, "admin/defaults", partial, details) end end
Our new resolver simply inherits from
ActionView::FileSystemResolver and does two changes: Overrides the
initialize method so the view path defaults to “app/views” inside our application and overrides
find_templates method receives the template name, a prefix (i.e. the controller path), a boolean marking if the template is a partial or not and a hash of details. In the example above, we simply ignore the prefix given and hardcode it to “admin/defaults”.
Now, assuming that all controllers inside the Admin namespace inherit from an
Admin::ApplicationController, we can add default views to all of them by adding the following line:
class Admin::ApplicationController < ActionController::Base append_view_path MyResolver.new end
And we are done! The
view_paths holds a list of paths and/or resolvers that the controller will look for templates until one is found. If none is found, an
ActionView::MissingTemplate is raised. Since we used
append_view_paths, our resolver was added after the “app/views” path, used by default in all controllers.
As you may have guessed, resolvers are a powerful abstraction that allows you to retrieve templates from anywhere, including the database, which is the example given in Crafting Rails Applications.
Finally, template inheritance was a feature recently added to Rails master (upcoming Rails 3.1), so you won’t need to create your custom resolver as above. There is a good wrap up about this feature in Rails Edge.
Rails 3 was released this week but the minds of the Rails Core team members are already focused on the 3.1 release for quite some time. DHH was the first one to give a hint on what we would like to see in Rails 3.1 in his RailsConf talk and, as Ruby Summer of Code is close to its end, we are able to see the work of several students getting solid enough to be an important part of Rails 3.1 release.
In between all this work, I was invited to participate in three important conferences in the following months and lately I’ve prepared enough material to give a talk entitled “Rails 2.3, 3.0 and 3.1: Past, Present and Future“!
In this talk I plan to discuss many of the conceptual changes done in Rails 3 and how these changes were given life in the Rails source code, comparing, as much as possible, with Rails 2.3. After the current and past scenarios are throughly discussed, I will show how much of the work done in Rails 3 can still be improved and how several Ruby Summer of Code Projects are helping us to achieve it. And if you ever wondered how much Merb affected the Rails community, you will have a few surprises while watching this talk!
The three different conferences I mentioned above will be held in Ukraine, Brasil and Sweden. But I’m not sure if there will be anyone recording them, so I’d suggest you not to miss any of them.
Here they are…
1) RubyConfUA (Ukraine): 16th and 17th October
If you have never been to Kyiv before (just like me), here’s a great opportunity to visit it for the first time! It will be two days of deep immersion into Ruby with nice city visits during the night!
Other active developers in the community as Oleg Andreev and Piotr Sarnacki will be present as well. By the way, RubyConf Ukraine is still accepting both sponsors and talk proposals! We are waiting for you!
2) RubyConf (Brasil): 26th and 27th October
Right after RubyConf Ukraine, I’ll be flying back to Brasil to present a portuguese version of this talk. RubyConf Brasil is the former “Rails Summit Latin America” (which has been the largest Ruby and Rails conference in Latin America for the last two years). And this year it won’t be different. Several Ruby and Rails developers (like Yehuda Katz, Charles Nutter, Evan Phoenix and many others) have confirmed their presence. If you get the chance, don’t miss it!
3) Oredev (Sweden): 8th to 12th November
And finally, my last stop will be in Sweden at the developer conference held in Malmö. This will be different from the previous two, since it is not focused in Ruby nor Rails. It’s a multitrack conference that hosts different technologies (by the way, the keynotes and tutorials programme is very interesting!). Since I’m expecting several non-Rails developers in the audience, I will slightly change my talk to focus more on the conceptual side and less on technical discussions. Also, I’ll be hosting a a workshop about Rails 3, where I’ll demonstrate a few of @plataformatec’s open source projects.
If you are coming to any of these events, please let me know in the comments!