3

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 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?

bodacious
  • 6,608
  • 9
  • 45
  • 74

3 Answers3

0

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.

Community
  • 1
  • 1
Michael De Silva
  • 3,808
  • 1
  • 20
  • 24
  • Thanks Mike but that's not quite what I'm looking for. I want my routes to refer to the controller name, but to be smart enough to know that I'm referring to the controller within the same nesting (eg. /app1/users_controller.rb is in the same nesting as /app1/sessions_controller.rb – bodacious Jun 20 '11 at 13:00
  • What about namespacing then? Each app would be uniquely namespaced... Hmm. – Michael De Silva Jun 22 '11 at 07:51
  • Each app is namespaced - that's the problem... I'm creating too many routes which is slowing down my development env – bodacious Jun 22 '11 at 08:30
  • Running out of ideas, but you might need to consider taking the route of Engines, as [discussed here](http://www.builtfromsource.com/2010/12/13/mountable-engines-in-rails-3-1-beta-getting-started/) ... and look to setup an OAuth provider to coalesce logins across the various apps. Hope you figure this out though! – Michael De Silva Jun 22 '11 at 12:32
  • Regarding that OAuth suggestion, it's [fully documented here](http://blog.joshsoftware.com/2010/12/16/multiple-applications-with-devise-omniauth-and-single-sign-on/). Essentially you dictate which 'app' a user is associated with by updating their session - at least this way the routes shouldn't linearly scale by app count. – Michael De Silva Jun 22 '11 at 12:41
0

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.

Msencenb
  • 5,675
  • 11
  • 52
  • 84
  • The web application serves more than one similar website (a lot like StackExchange). They are similar but not always _the same_ I stuck all of the shared behaviour into a module and include that in the controllers - I then override the defaults if necessary – bodacious Jun 20 '11 at 16:26
  • Fair enough. My answer definitely doesn't apply then – Msencenb Jun 20 '11 at 17:49
0

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
bodacious
  • 6,608
  • 9
  • 45
  • 74