I have a group model which has_many article model. And I want to use the following url pattern "{group_id}/{article_id}".
so I wrote these route codes:
resource :groups do
resource :articles
end
match ':group_id/:id(.:format)', :to => 'articles#show', :as => :article
match ':id', :to => 'groups#show', :as => :group
But rails fail to generate correct url for group records and article records. How can I replace the automatic generated article_path and group_path to match my routes?
You're running into problems because you aren't watching out for pluralization. When you define a singular resource route, Rails doesn't treat it as a collection where you would refer to each member with an id. You instead want a plural resources for both groups and articles:
resources :groups do
resources :articles
end
Generates the following routes:
group_articles GET /groups/:group_id/articles(.:format) {:action=>"index", :controller=>"articles"}
POST /groups/:group_id/articles(.:format) {:action=>"create", :controller=>"articles"}
new_group_article GET /groups/:group_id/articles/new(.:format) {:action=>"new", :controller=>"articles"}
edit_group_article GET /groups/:group_id/articles/:id/edit(.:format) {:action=>"edit", :controller=>"articles"}
group_article GET /groups/:group_id/articles/:id(.:format) {:action=>"show", :controller=>"articles"}
PUT /groups/:group_id/articles/:id(.:format) {:action=>"update", :controller=>"articles"}
DELETE /groups/:group_id/articles/:id(.:format) {:action=>"destroy", :controller=>"articles"}
groups GET /groups(.:format) {:action=>"index", :controller=>"groups"}
POST /groups(.:format) {:action=>"create", :controller=>"groups"}
new_group GET /groups/new(.:format) {:action=>"new", :controller=>"groups"}
edit_group GET /groups/:id/edit(.:format) {:action=>"edit", :controller=>"groups"}
group GET /groups/:id(.:format) {:action=>"show", :controller=>"groups"}
PUT /groups/:id(.:format) {:action=>"update", :controller=>"groups"}
DELETE /groups/:id(.:format) {:action=>"destroy", :controller=>"groups"}
If you want to leave off the groups and articles segments you can pass :path => '' to each of the resources definitions, but you are going to have to tread carefully because any request to http://example.com/1/2 will map to an article under groups and be uninformative to end users and bots alike.
Related
I'm using rspec-rails (2.8.1) and rails 3.1.3.
I'm trying to test routes for my Admin::ZonesController. I have verified the route exists in both the browser and by running rake routes. I am not using ActiveRecord (if that matters). When I run the routing spec, it tells me:
ActionController::RoutingError: No route matches "/admin/zones/new"
Here is the test (spec/routing/admin/zones_routing_spec.rb):
require 'spec_helper'
describe "routing to zones" do
it "routes /admin/zones/new to admin/zones#new" do
{ :get => "/admin/zones/new" }.should route_to(
:controller => "admin/zones",
:action => "new"
)
end
end
Here is the controller action whose route I am trying to test (admin/zones#new):
class Admin::ZonesController < Admin::BaseController
before_filter :instantiate_variables
def new
#zone = Zone.new
#campaign = Campaign.new
#rules = [Rule.new]
end
end
Running rake routes gives me this:
POST /hooks/:resource(.:format) {:controller=>"hooks", :action=>"create"}
POST /services/:service/:method(.:format) {:controller=>"services", :action=>"create"}
admin_zones GET /admin/zones(.:format) {:action=>"index", :controller=>"admin/zones"}
POST /admin/zones(.:format) {:action=>"create", :controller=>"admin/zones"}
new_admin_zone GET /admin/zones/new(.:format) {:action=>"new", :controller=>"admin/zones"}
edit_admin_zone GET /admin/zones/:id/edit(.:format) {:action=>"edit", :controller=>"admin/zones"}
admin_zone GET /admin/zones/:id(.:format) {:action=>"show", :controller=>"admin/zones"}
PUT /admin/zones/:id(.:format) {:action=>"update", :controller=>"admin/zones"}
DELETE /admin/zones/:id(.:format) {:action=>"destroy", :controller=>"admin/zones"}
admin_widgets GET /admin/widgets(.:format) {:action=>"index", :controller=>"admin/widgets"}
POST /admin/widgets(.:format) {:action=>"create", :controller=>"admin/widgets"}
new_admin_widget GET /admin/widgets/new(.:format) {:action=>"new", :controller=>"admin/widgets"}
edit_admin_widget GET /admin/widgets/:id/edit(.:format) {:action=>"edit", :controller=>"admin/widgets"}
admin_widget GET /admin/widgets/:id(.:format) {:action=>"show", :controller=>"admin/widgets"}
PUT /admin/widgets/:id(.:format) {:action=>"update", :controller=>"admin/widgets"}
DELETE /admin/widgets/:id(.:format) {:action=>"destroy", :controller=>"admin/widgets"}
zones GET /zones(.:format) {:action=>"index", :controller=>"zones"}
POST /zones(.:format) {:action=>"create", :controller=>"zones"}
new_zone GET /zones/new(.:format) {:action=>"new", :controller=>"zones"}
edit_zone GET /zones/:id/edit(.:format) {:action=>"edit", :controller=>"zones"}
zone GET /zones/:id(.:format) {:action=>"show", :controller=>"zones"}
PUT /zones/:id(.:format) {:action=>"update", :controller=>"zones"}
DELETE /zones/:id(.:format) {:action=>"destroy", :controller=>"zones"}
root / {:controller=>"admin/zones", :action=>"new"}
My routes.rb looks like this:
D2CModularPlatform::Application.routes.draw do
post "/hooks/:resource" => "hooks#create"
post "/services/:service/:method" => "services#create"
namespace :admin do
resources :zones
resources :widgets
end
resources :zones
root :to => "admin/zones#new"
end
My controllers dir looks like this:
controllers
admin
base_controller
widgets_controller
zones_controller
application_controller
hooks_controller
services_controller
zones_controller
My spec/routing dir looks like this:
spec/routing
admin
zones_routing_spec
hooks_routing_spec
services_routing_spec
zones_routing_spec
I am using Ruby on Rails 3.0.7 and I am trying to set correctly (and as well as possible) my router.
In the routes.rb file I have:
namespace :articles do
resources :categories
end
resources :articles
In order to work as expected, I must state the namespace before the resources :articles statement so that the router intercepts requests and direct these to the namespace related to articles. Otherwise (if the resources :articles is stated before of the namespace), as it is possible deduct from the above code, all requests like
<my_site>/articles/1
<my_site>/articles/new
<my_site>/articles/1/edit
...
are intercepted so that the articles namespace will be "hardly" reached. For example, if you make a request like <my_site>/articles/categories it will generate an error as the following:
ActiveRecord::RecordNotFound
Couldn't find Article with ID=categories
So, how can I handle this situation and how can I improve the router code? What do you advice about?
Running the command rake routes in my console I get this (as it is ordered):
articles_categories GET /articles/categories(.:format)
{:action=>"index", :controller=>"articles/categories"}
POST /articles/categories(.:format)
{:action=>"create", :controller=>"articles/categories"}
new_articles_category GET /articles/categories/new(.:format)
{:action=>"new", :controller=>"articles/categories"}
edit_articles_category GET /articles/categories/:id/edit(.:format)
{:action=>"edit", :controller=>"articles/categories"}
articles_category GET /articles/categories/:id(.:format)
{:action=>"show", :controller=>"articles/categories"}
PUT /articles/categories/:id(.:format)
{:action=>"update", :controller=>"articles/categories"}
DELETE /articles/categories/:id(.:format)
{:action=>"destroy", :controller=>"articles/categories"}
articles GET /articles(.:format)
{:action=>"index", :controller=>"articles"}
POST /articles(.:format)
{:action=>"create", :controller=>"articles"}
new_article GET /articles/new(.:format)
{:action=>"new", :controller=>"articles"}
edit_article GET /articles/:id/edit(.:format)
{:action=>"edit", :controller=>"articles"}
article GET /articles/:id(.:format)
{:action=>"show", :controller=>"articles"}
PUT /articles/:id(.:format)
{:action=>"update", :controller=>"articles"}
DELETE /articles/:id(.:format)
{:action=>"destroy", :controller=>"articles"}
Check this rails documentation about controller namespaces. It says you need to namespace your categories controller like Articles::CategoriesController and you need to place your categories controller under app/controllers/articles directory.
I think I have a handle on nested routes (great url helpers, and access and much more) and nested resources in forms with accepts_nested_attributes_for but what do I use in routes as I see both:
resources :schools do
resources :documents
end
and also
resources :schools :has_many => :documents
end
please can you tell me the difference between these.
Obviously has_many is for a one-to-many relationship. does it produce path helpers and require correct routing and for the do block what relationship does that imply, none? just path helpers (/schools/documents) and what if I want multiple resources (other than books, say documents) under schools, the first way I can add it into the do-end block but what about the second way, just two lines, one for each has_many?
Though I've read the guides and api's I don't quite get the difference/usage here and anyone that can provide a clear explanation of the distinction between the two (in the form 'a does x whereas b does y' would be great) would be much appreciated :)
Oh and of course how they relate to having the has_many in the model - so I guess these relationships can be in the model with has_many, the controller (mostly thru usage of paths) and in the view (through forms with nested attributes).
They both do the same thing, its up to you to choose which one
I prefer the do block format as its easier to read
btw with the has_many format you could do :has_many => [:docs, :otherthings] for multiple nested routes
I think the has_many syntax was something added to Rails 2 as a shorthand for those that didn't like the block syntax. You can see a blog post about it here. I just tried it and it seems that Rails 3 ignores the has_many option. So the output for me was:
resources :schools do
resources :documents
end
created the routes:
school_documents GET /schools/:school_id/documents(.:format) {:action=>"index", :controller=>"documents"}
POST /schools/:school_id/documents(.:format) {:action=>"create", :controller=>"documents"}
new_school_document GET /schools/:school_id/documents/new(.:format) {:action=>"new", :controller=>"documents"}
edit_school_document GET /schools/:school_id/documents/:id/edit(.:format) {:action=>"edit", :controller=>"documents"}
school_document GET /schools/:school_id/documents/:id(.:format) {:action=>"show", :controller=>"documents"}
PUT /schools/:school_id/documents/:id(.:format) {:action=>"update", :controller=>"documents"}
DELETE /schools/:school_id/documents/:id(.:format) {:action=>"destroy", :controller=>"documents"}
schools GET /schools(.:format) {:action=>"index", :controller=>"schools"}
POST /schools(.:format) {:action=>"create", :controller=>"schools"}
new_school GET /schools/new(.:format) {:action=>"new", :controller=>"schools"}
edit_school GET /schools/:id/edit(.:format) {:action=>"edit", :controller=>"schools"}
school GET /schools/:id(.:format) {:action=>"show", :controller=>"schools"}
PUT /schools/:id(.:format) {:action=>"update", :controller=>"schools"}
DELETE /schools/:id(.:format) {:action=>"destroy", :controller=>"schools"}
while
resources :schools :has_many => :documents
created the routes:
schools GET /schools(.:format) {:action=>"index", :controller=>"schools"}
POST /schools(.:format) {:action=>"create", :controller=>"schools"}
new_school GET /schools/new(.:format) {:action=>"new", :controller=>"schools"}
edit_school GET /schools/:id/edit(.:format) {:action=>"edit", :controller=>"schools"}
school GET /schools/:id(.:format) {:action=>"show", :controller=>"schools"}
PUT /schools/:id(.:format) {:action=>"update", :controller=>"schools"}
DELETE /schools/:id(.:format) {:action=>"destroy", :controller=>"schools"}
I think the real answer to your question is that those are/were supposed to do the same thing, just with different syntax.
I have the following in my routing config:
resources :users do
resources :apps, :controller => :user_apps
end
rake routes includes the following:
user_apps GET /users/:user_id/apps(.:format) {:action=>"index", :controller=>"user_apps"}
user_apps POST /users/:user_id/apps(.:format) {:action=>"create", :controller=>"user_apps"}
new_user_app GET /users/:user_id/apps/new(.:format) {:action=>"new", :controller=>"user_apps"}
edit_user_app GET /users/:user_id/apps/:id/edit(.:format) {:action=>"edit", :controller=>"user_apps"}
user_app GET /users/:user_id/apps/:id(.:format) {:action=>"show", :controller=>"user_apps"}
user_app PUT /users/:user_id/apps/:id(.:format) {:action=>"update", :controller=>"user_apps"}
user_app DELETE /users/:user_id/apps/:id(.:format) {:action=>"destroy", :controller=>"user_apps"}
However, when I try to access eg user_apps_path(1,2) I get /users/1/apps.2 rather than /users/1/apps/2.
Where am I going wrong?
I'm using rails 3.
The correct route is user_app_path(1,2) The pluralized version goes to the index action, making the second argument the format / extension of the request.
Is it possible to have a variable namespace? I have restful resources like the following:
resources :articles
resources :persons
But I need to scope these inside a variable namespace, such that it responds to URLs of the form:
':edition/:controller/:action/:id'
for example:
/foobar/article/edit/123 or /bazbam/person/edit/345
for each of the resources. Is this possible with the resources method, or must I hand-craft these? I will not know the possible values for :edition ahead of time; these get looked up in a before_filter in my ApplicationController.
Is this all I need to do?
scope ':edition' do
resources :articles
resources :matches
resources :teams
end
UPDATE: When using the scope directive above, I get routes like I want:
articles GET /:edition/articles(.:format) {:action=>"index", :controller=>"articles"}
POST /:edition/articles(.:format) {:action=>"create", :controller=>"articles"}
new_article GET /:edition/articles/new(.:format) {:action=>"new", :controller=>"articles"}
edit_article GET /:edition/articles/:id/edit(.:format) {:action=>"edit", :controller=>"articles"}
article GET /:edition/articles/:id(.:format) {:action=>"show", :controller=>"articles"}
PUT /:edition/articles/:id(.:format) {:action=>"update", :controller=>"articles"}
DELETE /:edition/articles/:id(.:format) {:action=>"destroy", :controller=>"articles"}
matches GET /:edition/matches(.:format) {:action=>"index", :controller=>"matches"}
POST /:edition/matches(.:format) {:action=>"create", :controller=>"matches"}
new_match GET /:edition/matches/new(.:format) {:action=>"new", :controller=>"matches"}
edit_match GET /:edition/matches/:id/edit(.:format) {:action=>"edit", :controller=>"matches"}
match GET /:edition/matches/:id(.:format) {:action=>"show", :controller=>"matches"}
PUT /:edition/matches/:id(.:format) {:action=>"update", :controller=>"matches"}
DELETE /:edition/matches/:id(.:format) {:action=>"destroy", :controller=>"matches"}
teams GET /:edition/teams(.:format) {:action=>"index", :controller=>"teams"}
POST /:edition/teams(.:format) {:action=>"create", :controller=>"teams"}
new_team GET /:edition/teams/new(.:format) {:action=>"new", :controller=>"teams"}
edit_team GET /:edition/teams/:id/edit(.:format) {:action=>"edit", :controller=>"teams"}
team GET /:edition/teams/:id(.:format) {:action=>"show", :controller=>"teams"}
PUT /:edition/teams/:id(.:format) {:action=>"update", :controller=>"teams"}
DELETE /:edition/teams/:id(.:format) {:action=>"destroy", :controller=>"teams"}
I'm now able to reference :edition in my ApplicationController:
class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :authenticate_user!
before_filter :get_edition
def get_edition
#edition = Edition.first(:conditions => { :FriendlyName => params[:edition] } )
end
end
Now I just want to make sure this is the best way to accomplish this.
Actually, you can just do the following :
my_var = "persons"
resources my_var.to_sym
The to_sym method on a string changes it to a symbol
If you don't know the possible values for edition - then you can't use namespaces which seem like they might have solved this issue.
That said, I'd just handcraft them - your case here seems like the ideal case foregoing resources and going straight to a handcrafted path.