Rails 2 Namespace and Shallow Routes Issue - ruby-on-rails

I've written the admin area of a particular rails app and now I'm ready to set it as own section within the website.
Therefore, it will be /admin
However, I didn't want to have it as /admin within the route itself I wanted to have something less common, so I added a couple of hyphens before and after it.
So the route is /-admin-/ and the namespace is Admin.
After setting this up using :path_prefix => "/-admin-", I have the following code block:
map.namespace "/-admin-/", :name_prefix => "", :path_prefix => "/-admin-" do |admin|
This works for all but shallow routes, instead, in the rake routes output the output is:
new_page GET /-admin-/areas/:area_id/pages/new(.:format) {:action=>"new", :controller=>"admin/pages"}
edit_admin_page GET /admin/pages/:id/edit(.:format) {:action=>"edit", :controller=>"admin/pages"}
admin_page GET /admin/pages/:id(.:format) {:action=>"show", :controller=>"admin/pages"}
PUT /admin/pages/:id(.:format) {:action=>"update", :controller=>"admin/pages"}
DELETE /admin/pages/:id(.:format) {:action=>"destroy", :controller=>"admin/pages"}
areas GET /-admin-/areas(.:format) {:action=>"index", :controller=>"admin/areas"}
POST /-admin-/areas(.:format) {:action=>"create", :controller=>"admin/areas"}
new_area GET /-admin-/areas/new(.:format) {:action=>"new", :controller=>"admin/areas"}
Notice how the shallow-routed routes are prefixed as /admin/ and not as /-admin-/ (as are their parent routes).
Any ideas on how to get around this? Is this a bug in rails or do I need to work around it? I tried adding the :path_prefix to each nested route but it doesn't do anything?
Any ideas?

I'm not sure about your rationale on not using /admin - security through obscurity isn't really security - you should be using something like authlogic to keep out unauthorised users.
Try the following to namespace your admin controllers:
map.namespace :admin, :path_prefix => "-admin-" do |admin|
admin.resources :users
admin.resources :pages
end
A sample generated route:
admin_users GET /-admin-/users(.:format) {:controller=>"admin/users", :action=>"index"}

There is no way to get around this. Turns out that all versions of Rails will break down the URL and its resource names to their lowest points when they're set to shallow. The only solution to this is to set all of your resource routes manually without using map.resources.

Related

Routing resource does not handle "new" as expected

I have a simple rails application in which I'm trying to add a very simple type of record ("client_types") to a database.
I have a route in routes.rb which reads:
resources :client_types
And as I understand it, should be a proxy to all of the conventional routes for my client_types resource.
So when I browse to the following URL http://localhost:3000/client_types/new, I get the following routing error at runtime:
No route matches {:action=>"show", :controller=>"client_types"}
Notice the action in question here is show, not new (and I have a method for both of these in my controller).
So... I added the following route below the resources route above, and viola, it works:
match 'client_types/new' => 'client_types#new', :as => :client_type
So what am I missing? My assumption was that resources :client_types in my routing file would have added a route matching the one I explicitly added later.
rake routes reveals the following:
client_types GET /client_types(.:format) {:action=>"index", :controller=>"client_types"}
POST /client_types(.:format) {:action=>"create", :controller=>"client_types"}
new_client_type GET /client_types/new(.:format) {:action=>"new", :controller=>"client_types"}
edit_client_type GET /client_types/:id/edit(.:format) {:action=>"edit", :controller=>"client_types"}
client_type GET /client_types/:id(.:format) {:action=>"show", :controller=>"client_types"}
PUT /client_types/:id(.:format) {:action=>"update", :controller=>"client_types"}
DELETE /client_types/:id(.:format) {:action=>"destroy", :controller=>"client_types"}
client_type /client_types/new(.:format) {:controller=>"client_types", :action=>"new"}
This is now working. I had an issue in one of my views and this error message was a red herring.

Rails 3 routing and namespaces

I want to have a namespaced controller called 'portal'.
in this will be nested resources such as companies and products.
I'd like routes like :
/portal/:company_id/product/:id to work
I can get
/portal/company/:company_id/product/:id to work but would like to eliminate the 'company' in the url
Hope that is clear. Please keep in mind that I need the namespaced module portal to exist.
I think you could use scope to achieve what you want. Perhaps like this:
namespace "portal" do
scope ":company_id" do
resources :products
end
end
That will generate the following routes:
portal_products GET /portal/:company_id/products(.:format) {:action=>"index", :controller=>"portal/products"}
POST /portal/:company_id/products(.:format) {:action=>"create", :controller=>"portal/products"}
new_portal_product GET /portal/:company_id/products/new(.:format) {:action=>"new", :controller=>"portal/products"}
edit_portal_product GET /portal/:company_id/products/:id/edit(.:format) {:action=>"edit", :controller=>"portal/products"}
portal_product GET /portal/:company_id/products/:id(.:format) {:action=>"show", :controller=>"portal/products"}
PUT /portal/:company_id/products/:id(.:format) {:action=>"update", :controller=>"portal/products"}
DELETE /portal/:company_id/products/:id(.:format) {:action=>"destroy", :controller=>"portal/products"}
Edit: Accidentally used resource instead of resources. Fixed now.
You can customize the routes to nearly whatever you want if you spell them out directly, like this:
match '/portal/:company_id/product/:id', :to => 'companies_products#show'
The :to part specifies the controller and action to use, something that should match what you have in your routes now. If you're not sure what that is, rake routes will tell you its specific interpretation.

scope equivalent in rails 2.3.x?

Is there a way to generate a group of routes under an admin scope without having to create a new physical directory (like namespace requires you to).
I know that in Rails 3 there is a scope method on the route mapper, and this appears to do what I want, but apparently it doesn't exist in Rails 2.3.x
My goal is to have a route like this: "/admin/products" map to "app/controllers/products_controller, not "app/controllers/admin/products_controller".
Is there any way to accomplish this in Rails 2.3.x?
Sure, you need to use :name_prefix and :path_prefix to get to what you want:
ActionController::Routing::Routes.draw do |map|
map.with_options :name_prefix => 'admin_', :path_prefix => 'admin' do |admin|
admin.resources :products
end
end
Will yield routes:
admin_products GET /admin/products(.:format) {:controller=>"products", :action=>"index"}
POST /admin/products(.:format) {:controller=>"products", :action=>"create"}
new_admin_product GET /admin/products/new(.:format) {:controller=>"products", :action=>"new"}
edit_admin_product GET /admin/products/:id/edit(.:format) {:controller=>"products", :action=>"edit"}
admin_product GET /admin/products/:id(.:format) {:controller=>"products", :action=>"show"}
PUT /admin/products/:id(.:format) {:controller=>"products", :action=>"update"}
DELETE /admin/products/:id(.:format) {:controller=>"products", :action=>"destroy"}
It appears to be not well documented, but namespace is actually a very simple wrapper for with_options. It sets the :path_prefix, :name_prefix, and :namespace options, of which I believe you only want the first, so:
map.with_options :path_prefix => 'admin/' do |admin|
admin.connect ':controller/:action'
end
I'm going through this from reading the code. It looks like :name_prefix is used to give named routes a prefix, and :namespace is used to actually look in subdirectories.

difference between scope and namespace of ruby-on-rails 3 routing

I can't understand what the difference is between a namespace and a scope in the routing of ruby-on-rails 3.
Could someone please explain?
namespace "admin" do
resources :posts, :comments
end
scope :module => "admin" do
resources :posts, :comments
end
The difference lies in the paths generated.
The paths are admin_posts_path and admin_comments_path for the namespace, while they are just posts_path and comments_path for the scope.
You can get the same result as a namespace by passing the :name_prefix option to scope.
examples always help me, so here is an example:
namespace :blog do
resources :contexts
end
will give us the following routes:
blog_contexts GET /blog/contexts(.:format) {:action=>"index", :controller=>"blog/contexts"}
POST /blog/contexts(.:format) {:action=>"create", :controller=>"blog/contexts"}
new_blog_context GET /blog/contexts/new(.:format) {:action=>"new", :controller=>"blog/contexts"}
edit_blog_context GET /blog/contexts/:id/edit(.:format) {:action=>"edit", :controller=>"blog/contexts"}
blog_context GET /blog/contexts/:id(.:format) {:action=>"show", :controller=>"blog/contexts"}
PUT /blog/contexts/:id(.:format) {:action=>"update", :controller=>"blog/contexts"}
DELETE /blog/contexts/:id(.:format) {:action=>"destroy", :controller=>"blog/contexts"}
Using scope...
scope :module => 'blog' do
resources :contexts
end
Will give us:
contexts GET /contexts(.:format) {:action=>"index", :controller=>"blog/contexts"}
POST /contexts(.:format) {:action=>"create", :controller=>"blog/contexts"}
new_context GET /contexts/new(.:format) {:action=>"new", :controller=>"blog/contexts"}
edit_context GET /contexts/:id/edit(.:format) {:action=>"edit", :controller=>"blog/contexts"}
context GET /contexts/:id(.:format) {:action=>"show", :controller=>"blog/contexts"}
PUT /contexts/:id(.:format) {:action=>"update", :controller=>"blog/contexts"}
DELETE /contexts/:id(.:format) {:action=>"destroy", :controller=>"blog/contexts"}
Here is some good reading on the subject: http://edgeguides.rubyonrails.org/routing.html#controller-namespaces-and-routing
from the rails guide
"The namespace scope will automatically add :as as well as :module and :path prefixes."
so
namespace "admin" do
resources :contexts
end
is the same as
scope "/admin", as: "admin", module: "admin" do
resources :contexts
end
Both scope and namespace are scoping a set of routes to the given default options.
Except that there are no default options for scope, and for namespace
:path, :as, :module, :shallow_path and :shallow_prefix options all default to the name of the namespace.
Available options for both scope and namespace correspond to those of match.
scope is bit complex, but provides more options to fine-tune exactly what you want to do.
scope supports three options: module, path and as. If you see scope with all it options, it will be exactly same as namespace.
In other words, routes generated by
namespace :admin do
resources :posts
end
is same as
scope module: 'admin', path: 'admin', as: 'admin' do
resources :posts
end
In other words, we can say that there are no default options for scope as compared to namespace. namespace add all these options by default. Thus using scope, we can more fine tune the routes as required.
If you take a deep look into scope and namespace default behaviour, you will find that scope by default supports only :path option, where as namespace supports three options module, path and as by default.
For more info, please refer a doc namespace-and-routing.

Default segment name in rails resources routing

I want to create a route in my rails application along the lines of
/panda/blog
/tiger/blog
/dog/blog
where panda, tiger, and dog are all permalinks (for an animal class)
The normal way of doing this
map.resources :animals do |animal|
animal.resource :blog
end
would create routes along the lines of
/animals/panda/blog
/animals/tiger/blog
/animals/dog/blog
But i do not want the first segment, as it will always be the same.
I know I could do this by manual routing, but I want to know how to do using rails resources, as having animals and blogs is a requirement for me.
In rails 3.x, you can add path => "" to any resource or resources call to remove the first segment from the generated path.
resources :animals, :path => ""
$ rake routes
animals GET / {:action=>"index", :controller=>"animals"}
POST / {:action=>"create", :controller=>"animals"}
new_animal GET /new(.:format) {:action=>"new", :controller=>"animals"}
edit_animal GET /:id/edit(.:format) {:action=>"edit", :controller=>"animals"}
animal GET /:id(.:format) {:action=>"show", :controller=>"animals"}
PUT /:id(.:format) {:action=>"update", :controller=>"animals"}
DELETE /:id(.:format) {:action=>"destroy", :controller=>"animals"}
You can use this plugin:
http://github.com/caring/default_routing/tree/master

Resources