Can anyone think of a way to create smart or dynamic routes in Rails?
Given that I have controllers:
app/controllers/app1/users_controller.rb app/controllers/app2/users_controller.rb
I have in my routes file:
["app1", "app2"].each do |n| constraints(:host => "#{n}.com") do scope({:as => vn, :module => vn}) do resources :users end end end
This gives me routes like so:
GET app1_users_path (app1.com/users) { :controller => "app1/users", :action => "index" } GET app2_users_path (app2.com/users) { :controller => "app2/users", :action => "index" }
I do this for every path, for every "app" in my application.
The problem is, as 开发者_C百科the no. of both apps and paths grows, so does the no. of paths
n = no_of_paths a = no_of_apps (n * a) = "LOADS"
Can anyone think of a way I can set the "module" part of my routes (the controller prefix) as a wildcard so I only have to name each route once?
Something like:
match ":controller/:action(/:id)" => ":host/:controller#:action"
maybe?
That's exactly it; it's called a catch-all route. See more here. You should however note that as of less than a week ago there has much discussion about catch-all routes, and you can read up on it here.
Do note the quote below is referencing Rails 3.1 - made by Ryan Bigg (aka Radar).
The catch-all route at the bottom of config/routes.rb is now commented out because having it there by default is not only unnecessary, but also really dangerous. If that link exists, then I would be able to give you an innocent looking URL (such as one provided by bit.ly) that linked to /admin/users/1/destroy, or whatever. Can you see the problem here? By having this commented out, only the routes that you've explicitly defined are going to be available. Most applications don't need the catch-all anyway.
Is there a reason why you want more than one users_controller? As it stands it seems like each app has a nested resource of users. This means that you should be able to have a url/route that looks like this:
GET /app/1
This is very much the same as a "Show" controller you get from the scaffold generator. This corresponds to an app with an id of 1 in your database (You might want to hash the id instead of just the straight id to prevent tampering). From here in your controller you can do something like this to pull up all the users that correspond to that app (assuming you have associations set up).
@users = Users.find_all_by_app_id(params[:id])
And then you can deal with them in the view.
I've solved this...
Essentially, I was asking the wrong question.
My application serves more than one website so I thought it was prudent to create a controller (and therefore a route) for each "vertical" (site within my app).
The shared behaviour in these controllers went into a module which I included in each controller. ie:
# vertical1/users_controller.rb
class Vertical1::UsersController < ApplicationController
include UsersControllerTemplate
end
# vertical2/users_controller.rb
class Vertical2::UsersController < ApplicationController
include UsersControllerTemplate
end
# lib/users_controller_template.rb
module UsersContrllerTemplate
def index() end
end
In practise, I found that 95% of the time I stuck with the shared behaviour. Having separate controllers and routes was overkill.
Working fine (and faster) now with one instance for most controllers and one or two name-spaced controllers where I need to customise the behaviour.
I've also decided to inherit custom controllers from the default behaviour (rather than include modules):
# vertical1/users_controller.rb
class Vertical1::UsersController < UsersController
# change some stuff here
end
精彩评论