Skip to content

Instantly share code, notes, and snippets.

@kevcha
Last active July 6, 2019 03:33
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save kevcha/c5aebe73849bb56a94ed to your computer and use it in GitHub Desktop.
Save kevcha/c5aebe73849bb56a94ed to your computer and use it in GitHub Desktop.
Rails 4 view resolvers

The problem

Using multiple namespaces will require to have also namespaces views. For exemple, if you have an Admin namespace, with a Admin::ProjectsController with a show action that also exists in non namespaced ProjecsController, you cannot render views/projects/show.html.erv from Admin::ProjecsController.

What we want to do

The researched behavior is to try to render the views/admin/projects/show.html.erb, and, if it doesn't exist, fallback to views/projects/show.html.erb

The solution

Use a ViewResolver in /whateveryouwant. I choosed to put it in lib/resolvers/admin_views_resolver.rb :

class Resolvers::AdminViewsResolver < ::ActionView::FileSystemResolver
  def initialize
    super('app/views')
  end

  def find_templates(name, prefix, partial, details)
    prefix = prefix.sub(/^admin\//, '')
    super(name, prefix, partial, details)
  end
end

Then make it autoload in application/config.rb :

# Add lib directory in autoload_paths
config.autoload_paths << File.join(config.root, 'lib')

And finally, instanciate it in our(s) controller(s) :

class Admin::BaseController < ApplicationController
  append_view_path Resolvers::AdminViewsResolver.new
end

What's happening here ?

We're telling to Rails to use a this view resolver for our Admin::BaseController, which is the parent controller for all our controllers under Admin namespace. This will not break anything, because we call super('app/views') in the initialize function of the resolver. So, Rails will try to find the views/admin/projects/show.html.erb, but then, only if there is no such view, will call the find_templates method from the resolver, which trim admin from prefix variable (the prefix variable contains the original path to the template).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment