What is the difference between resources and namespace?
I have a Rack app inside a gem that I want to call from the Rails app.
namespace :app do
get 'go', to: Gem::Controller.new
end
Since I have controller called AppController, can I use this one?
resources :app do
collection do
get 'go', to: Gem::Controller.new
end
end
Which way is better?
As per the Rails guide routing section
Resources:
Resource routing allows you to quickly declare all of the common
routes for a given resourceful controller. Instead of declaring
separate routes for your index, show, new, edit, create, update and
destroy actions, a resourceful route declares them in a single line of
code.
Namespace:
You may wish to organize groups of controllers under a namespace. Most
commonly, you might group a number of administrative controllers under
an Admin:: namespace. You would place these controllers under the
app/controllers/admin directory, and you can group them together in
your router.
Eg:
namespace :admin do
resources :articles, :comments
end
But, I think what you meant was to choose between collection and namespacing.
It's like this, namespacing would be a better option if you are planning to have more routes for that app. Else, you can just use it as a collection.
resources is a shortcut for generating seven routes needed for a REST interface.
so resources :app would generate the following seven routes(patch and put routes are same):
get "apps" => "apps#index", :as => 'apps'
get "apps/:id" => "apps#show", :as => 'app'
get "apps/new" => "apps#new", :as => 'new_app'
post "apps" => "apps#create", :as => 'apps'
get "apps/:id/edit" => "apps#edit", :as => 'edit_app'
patch "apps/:id" => "apps#update", :as => 'app'
put "apps/:id" => "apps#update", :as => 'app'
delete "apps/:id" => "apps#destroy", :as => 'app'
and then it would generate another route because of get 'go', to: Gem::Controller.new:
/apps/go
In case of namespace the apps seven REST routes won't be created but a named route for apps/go would be generated.
Related
I have this in my router.rb:
namespace :me do
namespace :bills do
get :consumption_invoice, :format => :pdf
end
end
and also
resources :groups do
member do
namespace :bills do
get :consumption_invoice, :format => :pdf
end
end
end
The first one gives me:
me_bills_consumption_invoice GET /me/bills/consumption_invoice(.:format) me/bills#consumption_invoice {:format=>:pdf}
consumption_invoice_bills_group GET /groups/:id/bills/consumption_invoice(.:format) bills/groups#consumption_invoice {:format=>:pdf}
In the group, the controller called is bills/groups#consumption_invoice instead of groups/bills#consumption_invoice as I'd expect.
Why?
Thanks
EDIT
After some reflexion, here's what I'd like to achieve:
/me/bills/consumption_invoice => :controller => :bills, :action => :consumption_invoice
# and
/groups/:id/bills/consumption_invoice => :controller => :bills, :action => :consumption_invoice
Idealy, I'd like to have both those rules in the :me namespace and the :groups resource blocks for making it cleaner to read.
And I'd like to be able to add more actions easily:
/me/bills/subscription_invoice => :controller => :bills, :action => :subscription_invoice
which is why I wanted to create a block :bills in it.
I've been trying so many possibilities around, can't I achieve that?
The way paths are constructed is different than the way the controller is determined.
Controllers can be organized under a namespace. The namespace is a folder that controllers can sit in. Although the order of resources and namespaces affects the order of the parts of the path, it won't affect the way that namespaces are treated as a controller grouping. The resource is :groups so the controller is named "groups" and handles actions made against the group model. The namespace is :bills so the controller is contained within a folder called "bills".
In a similar fashion, if you nested two resources like:
resources :groups do
resources :users
end
The path for a user action would be /groups/:id/users but the controller would just be named "users".
If you really want this action to be handled by a bills controller in a groups folder, then you could customize the behavior with something like:
resources :groups do
member do
scope module: 'groups' do
get 'bills/consumption_invoice', :format => :pdf, controller: 'bills'
end
end
end
Additional Info for Edit in the Question
If you just want your two paths to reach the bills#consumption_invoice action and you don't want your bills controller to live in a folder called me, you could consider something like this:
get 'me/bills/consumption_invoice', :format => :pdf, to: 'bills#consumption_invoice'
resources :groups do
member do
get 'bills/consumption_invoice', :format => :pdf, controller: 'bills'
end
end
Rails will then expect that your consumption_invoice view lives in a bills folder.
The Rails Routing from the Outside In (http://guides.rubyonrails.org/routing.html) can provide additional details on all the routing options.
When defining a resources in routes.rb in Rails, I have the following problem: My resource supports the standard CRUD operations and has a custom function/route, which allows filtering. Now this custom routes matches the edit route and jumps in before the actual RESTful route.
Is there a way to prioritize the RESTful routes so that they match first?
resources :items do
get ':category(/:level)', :action => :filter, :on => :collection, :as => 'filter'
end
You should just set a simple get route ( if it is a GET request )
get 'filter', :to => "items#filter"
If you have any problems there are always RoR Guides :)
http://guides.rubyonrails.org/routing.html
I've read around the resources on how routing in Rails 3 works, but am running into some difficulties.
In my app there are Blogs and my routes.rb contains:
resources :blogs
root :to => "home#index"
URLs containing 'blogs' are work fine.
However what I'd like to do is have 'blog' in the URLs. Specifically, /blog/:id (for show) and /blog (for index).
If I add the line:
match 'blog' => 'blogs#index'
Then /blog does show the index, however it breaks my blog edit form as the action URL changes from /blog/:id to /blog.:id
Any ideas on how to use blog instead of blogs, and also allow the blog index to be on /blog? I've tried quite a few things (like resource :blog, and also resources :blogs, :as => 'blog') and not getting anywhere. Assuming there's a way to do this without manually defining each route for show, edit, destroy and index.
You need use the :path option
resources :blogs, :path => 'blog'
Remove your match line, and change your resouces line to:
resources :blogs, :path => 'blog'
Check: http://edgeguides.rubyonrails.org/routing.html#translated-paths
In Rails 2.X we have:
map.resources :posts, :controller => 'posts', :as => 'articles'
This essentially creates an alias for our posts routes. For example, this sends "domain.com/articles/" to the posts controller index action.
In Rails3, however, the :as option behaves differently. For example:
resources :posts, :controller => 'posts', :as => 'articles'
sets a named route rather than an alias, and going to "domain.com/articles/" gives an error:
No route matches {:controller=>"posts"}
How do I get the old (Rails 2) :as behavior using the new (Rails 3) api?
PS: Please don't tell me to simply rename my controller. That's not an option for me.
From some cursory reading of the RoR guide on routing, I think you might need to try:
resources :articles, :controller => "posts"
(http://guides.rubyonrails.org/routing.html#specifying-a-controller-to-use)
You might also need to add :as => "articles", but that named helper might already be set up since you are adding :articles resources.
You can accomplish this same behavior using the path option:
resources :posts, :path => '/articles/'
Now for example /posts/new becomes /articles/new.
I'm getting the following error:
Unknown action
No action responded to show. Actions: activate, destroy, index, org_deals, search, and suspend
Controller:
class Admin::HomepagesController < Admin::ApplicationController
def org_deals
#organization = Organization.find(:all)
end
Routes:
map.root :controller => 'main'
map.admin '/admin', :controller => 'admin/main'
map.namespace :admin do |admin|
admin.resources :organizations, :collection => {:search => :get}, :member => {:suspend => :get, :activate => :get}
To note: This is a controller inside of a controller.
Any idea why this is defaulting to show?
Update:
I updated what the routes syntax is. Read that article, and tried quite a few variations but its still adamantly looking for a show.
Firstly, it looks like your routes file has the wrong syntax. If you are trying to establish routes for nested resources, you'd do it like so:
map.resources :admin
admin.resources :organizations
end
This would give you paths such as:
/admin/
/admin/1
/admin/1/organizations
/admin/1/organizations/1
The mapping from route to controller/action is done via a Rails convention, where HTTP verbs are assigned in ways that are useful for the typical CRUD operations. For example:
/admin/1/organizations/1
would map to several actions in the OrganizationsController, distinguished by the type of verb:
/admin/1/organizations/1 # GET -> :action => :show
/admin/1/organizations/1 # PUT -> :action => :update
/admin/1/organizations/1 # DELETE -> :action => :destroy
"Show" is one of the seven standard resourceful actions that Rails gives you by default. You can exclude "show" with the directive :except => :show, or specify only the resourceful actions you want with :only => :update, for example.
I recommend you look at Rails Routing from the Outside In, which is a great introduction to this topic.
EDIT
I see I ignored the namespacing in my answer, sorry. How about this:
map.namespace(:admin) do |admin|
admin.resources :homepages, :member => { :org_deals => :get }
end
This will generate your org_deals action as a GET with an id parameter (for the organization). You also get a show route, along with the six other resourceful routes. rake routes shows this:
org_deals_admin_homepage GET /admin/homepages/:id/org_deals(.:format) {:controller=>"admin/homepages", :action=>"org_deals"}
Of course your homepages_controller.rb has to live in app/controllers/admin/
EDIT redux
Actually, you want organizations in the path, I'll bet, in which case:
map.namespace(:admin) do |admin|
admin.resources :organizations, :controller => :homepages, :member => { :org_deals => :get }
end
which gives you:
org_deals_admin_organization GET /admin/organizations/:id/org_deals(.:format) {:controller=>"admin/homepages", :action=>"org_deals"}
By specifying admin.resources ... you are telling Rails you want the seven default different routes in your application. If you do not want them, and only want the ones you specify, do not use .resources. Show is called because that's the default route called for a GET request with a path such as /admin/id when you have the default resources.