self.prepend_view_path - am I missing something

I have an app that varies its content based upon the domain from which it is being accessed. Some of the domain characteristics are supported in the model but it is easier varying static text in the views and then sharing the form templates via partials etc.

Rails 2.3.10 and looking at the documentation at http://rubydoc.info/docs/rails/2.3.8/ActionController/Base#prepend_view_path-instance_method

application_controller.rb

before_filter :domain_lookup, :set_view_paths

  protected

  def set_view_paths     self.prepend_view_path "app/views/#{controller_name}/ #{@domain.policy.policy_type}"   end

according to the documentation this should add this path to the front of the search order for this request only (as opposed to the similar class method which prepends for all future requests)

I would expect the template to be rendered for the controller from app/ views/quote/type1/new.html.erb if it exists, if it does not exist it will fall back to app/views/quote/new.html.erb

When I GET http://domain1:3000/quote/new it always renders app/views/ quote/new.html.erb and in the log I can see

Processing QuoteController#new (for 192.168.1.24 at 2011-02-21 18:47:52) [GET]   Domain Load (0.2ms) SELECT * FROM "domains" WHERE ("domains"."host" = 'example.com') LIMIT 1   Policy Load (0.2ms) SELECT * FROM "policies" WHERE ("policies"."id" = 6) Rendering template within layouts/application Rendering quote/new

which is incorrect.

In my development environment I also render a debug partial and in it I have

<p><%= self.view_paths %></p>

which renders the pathset object.

views/quote/pumpapp/views

Has anyone got this working? I was thinking of over-riding render but am wary of any side effects.

Thanks.

O.

Tada. Spending a bit of time in debugger and going through the Rails code here is where it all happens:

http://rubydoc.info/docs/rails/2.3.8/ActionView/PathSet#find_template-instance_method

So it goes hunting for load_path + template_path on line 60 where load_path is iterated over view_path that I set in the application controller and template path is "controller/action"

In an nutshell the view path is just the set of "roots" from which the template_path (i.e. controller/action) is loaded as the template.

All I needed to do is change my directory structure for this:

application_controller.rb

  before_filter :domain_lookup, :set_view_paths

  protected

  def set_view_paths     self.prepend_view_path ["app/views/variants/ #{@domain.policy.policy_type}"]   end

and set out my view directories as follows:

app/views/controller_name becomes the fall-back or default set of views if the variant of the view does not exist app/views/variants/policy_type/controller_name is where you put all of the variants of the view for the specific variant.

This approach does have a nice side-effct of allowing all of the references to partials from within the view of also being loaded in the same fashion. For example, if I want a variant of a form for one of the domains, all I need to do is put the modified version of the form partial in the appropriate directory and all the relative paths to partials can remain the same. As they say. Neat.

All in all this is a nice technique for using the same application to serve multiple variants (skins) based on domain or sub-domain name.

I did find similar postings trying to do the same thing. Either I and they misread the documentation or it is not very clear how view_paths evaluate to the actual filename. I'll look into putting in an amendment to the documentation.

O.

> def set_view_paths > self.prepend_view_path "app/views/#{controller_name}/ > #...@domain.policy.policy_type}" > end

Above worked in development but not in testing unless you provide an absolute path for integration testing.

  def set_view_paths     self.prepend_view_path ["#{RAILS_ROOT}/app/views/variants/ #{@domain.policy.policy_type}"]   end