How can I add a view path to Rails's partial rendering lookup?
Asked Answered
W

1

23

I'd like to have the following directory structure:

views/
  app1/
    users/_user.html.erb
    users/index.html.erb

  app2/
    users/index.html.erb

  shared/
    users/_user.html.erb
    users/index.html.erb

In my view, I'd call

# app1/users/index.html
<%= render :partial => "user" %>
# => /app1/users/_user.html.erb


# app2/users/index.html
<%= render :partial => "user" %>
# => /shared/users/_user.html.erb

So basically, how do I tell Rails to check in the /app2/users dir then the shared dir before it raises it's missing template error?

Update


I got around this (as suggested by Senthil, using File.exist?

Here's my solution - feedback and suggestions welcome

# application_helper.rb

# Checks for a partial in views/[vertical] before checking in views/shared
def partial_or_default(path_name, options={}, &block)
  path_components         = path_name.split("/")
  file_name               = path_components.pop
  vertical_file_path      = File.join(vertical}, path_components, file_name)
  shared_file_path        = File.join("shared", path_components, file_name)
  full_vertical_file_path = File.join("#{Rails.root}/app/views/", "_#{vertical_file_path}.html.erb")
  attempt_file_path       = File.exist?(full_vertical_file_path) ? vertical_file_path : shared_file_path
  render({:partial => attempt_file_path}.merge(options), &block)
end
Whangee answered 21/5, 2011 at 12:7 Comment(1)
Any reason you can't use File.exists? to check if file exits and render the appropriate file?Ornithomancy
D
71

There's already something built into rails that facilitates this type of "theming" for you. It's called prepend_view_path.

http://api.rubyonrails.org/classes/ActionView/ViewPaths/ClassMethods.html#method-i-prepend_view_path

There's also append_view_path for adding paths to the end of the lookup stack.

I have this successfully working in production:

 class ApplicationController < ActionController::Base
   before_filter :prepend_view_paths

   def prepend_view_paths
     prepend_view_path "app/views/#{current_app_code}"
   end
 end

Now every controller will first look in "views/app1" (or whatever your dynamic name turns out to be) for the views corresponding to the action being called.

It's also smart enough to check all the defined paths for the file you're looking for, so it rolls back to the default location if one isn't found.

Defiance answered 21/5, 2011 at 15:39 Comment(5)
This is really awesome! I wish we've got this implementation... btw this have just been described in railscasts.269 (but your answer tells everything already)Abstriction
Correct URL is: api.rubyonrails.org/classes/ActionController/Base.html#M000267Pict
Old, but there is there is a class method for this instead of doing this with a filterBuckles
The class method Carson is talking about is AbstractController.prepend_view_pathFaunus
You can also use self.class.prepend_view_path in your controller actions.Lusitania

© 2022 - 2024 — McMap. All rights reserved.