Rails 3.1 Custom Controllers and Views w/ Default
- I'm building an app that lets users create their own website (e.g., mywebsite.alexlod.com)
- Each website owner is affiliated with me, so I'll trust them to write their own rails code
- Each website should have default controllers and views, except when one of these owners creates their own
Here's how I envision controllers working:
I'm thinking that what's in app/controllers/ will be the default, but when a file is specified in a <subdomain> top-level directory, that file will take precedence over the default.
Let me give an example. Let's say one of my website owners (foo.alexlod.com) wants to tweak app/controllers/photos_controller.rb. They should be able to create foo/controllers/photos_controller.rb whereby their controller is used instead of the default. I'm thinking the correct approach here has something to do with routes and the load path, but I'm new to Rails and Ruby and could use some guidance.
As for views, I would like them to work much the same. When a view or partial is defined in <subdomain>/views/, that view is used instead of the default located in app/views/.
I realize my plan here violates the default rails directory structure. But this approach has gotta be more simple than the alternative - case statements in each controller action. Unless there's an even better alternative?
I believe engines may be the way to go for what you want. That link is a little old but still should be applicable with Rails 3.1. Each subdomain's controllers and views can be placed in their respective engine folder.
Now, you just need to figure out which engine to load per request. That's the part I think may be the deterrent to your idea -- you don't want to be loading and unloading code all the time in production.
You may want to opt for a templating language like Liquid, in that case. That, however, gives a lot less control to the users.
I may have a partial answer for you as it sounds like you want to do something very similar to what I am doing for the mobile version of my site. After I identify that a user is mobile I add a mobile directory to the path to override any views that I have optimized for mobile. If the view doesn't exist in the mobile directory it defaults to the default view.
Here is what I did for views:
before_filter :prepend_view_path_if_subdomain def prepend_view_path_if_subdomain unless pSubdomains.blank? subdomain = request.subdomain.first #This will add the subdomain view directory to the view path before the default #Rails view directory and any views here will be picked up and rendered. prepend_view_path 'app/' + subdomain + '/views' end end
Doing the same thing for controllers, however, is a little trickier due to routing. There is no prepend_controller_path method that is equivalent to prepend_view_path. Honestly I'm not sure how to approach this, you could use your case statement approach or possibly dynamically forward on the request to the subdomain controller (it if exists). I think it might be possible to add a before_filter to your controllers that evaluates each request much like I show above with views and then determines which controller should be used.
I also stumbled across this question: Rails 3.1 load controller from different path based on subdomain, not sure if it helps you or not.