How to prevent pluralization of a model in Rails? - ruby-on-rails-3

I have model called Search and a resource named :search. I'd like to name my controller SearchController, rather than SearchesController. But when I initialize an instance of Search, Rails assumes its route has to be "/searches".
Is there anything I can do to stop this?

This should work:
resources :search, :as => :searches
Route urls start with /search, point to search controller and use default naming convention:
searches GET /search(.:format) {:controller=>"search", :action=>"index"}
POST /search(.:format) {:controller=>"search", :action=>"create"}
new_search GET /search/new(.:format) {:controller=>"search", :action=>"new"}
edit_search GET /search/:id/edit(.:format) {:controller=>"search", :action=>"edit"}
search GET /search/:id(.:format) {:controller=>"search", :action=>"show"}
PUT /search/:id(.:format) {:controller=>"search", :action=>"update"}
DELETE /search/:id(.:format) {:controller=>"search", :action=>"destroy"}
The reason for error is that when form has only access to model instance it tries to find a route helper based on pluralized model name. In this case it tried to use searches_path. Things should work if we keep the default route names and change only urls and controller.
Relevant documentation (under "Relying on named routes")

Related

Rails routes, kind of synonym routes

Statement
Imagine we have an inventory app, there it is a Movement model, it represent any movement like products purchase or products sale. So we have default REST routes.
movements GET /movements(.:format) {:action=>"index", :controller=>"movements"}
POST /movements(.:format) {:action=>"create", :controller=>"movements"}
new_movement GET /movements/new(.:format) {:action=>"new", :controller=>"movements"}
edit_movement GET /movements/:id/edit(.:format) {:action=>"edit", :controller=>"movements"}
movement GET /movements/:id(.:format) {:action=>"show", :controller=>"movements"}
PUT /movements/:id(.:format) {:action=>"update", :controller=>"movements"}
DELETE /movements/:id(.:format) {:action=>"destroy", :controller=>"movements"}
For mnemonic proposes, we want to have some descriptive routes, like:
new_purchase /purchase/new(.:format) {:controller=>"movements", :action=>"new_purchase"}
edit_purchase /purchase/:id/edit(.:format) {:controller=>"movements", :action=>"edit_purchase"}
If you can see purchase's are same model likemovement's, actually are processed by MovementsController, but there with have different flow and treatment, this specified by create_purchase instead of create.
Questions
How should I add restful routes for purchase's? Taking care of specify HTTP methods like GET, POST, PUT, DELETE, etc.
How should I write form_for tags? Using movement model we can write: <%= form_for(#movement) do |f| %> but how is to call purchase paths for create or update methods?
How should I specify validation rules for purchase's? I have specified some rules on Movement model, but they are not applied for purchase's when a form is submitted.
You could use some thing like this in your routes file
match '/purchase/new(.:format)' => 'movements#new_purchase' :via => :get
match '/purchase/:id/edit(.:format)' => 'movements#edit_purchase' :via => :post
and you can mention others like delete, put in :via
for more info look at this link
If you want to change create to create_purchases go to the movements controller and change the definition names.
for the second question you could do something like this
form_tag(:controller => "controller_name", :action => "action_name", :method => "get")
I don't think that you should be looking for a way to RESTfully build routes for a model that handles an object in two separate ways. That sounds to me like you're really looking for two objects. You can create a Purchase model that inherits its properties from a parent Movement model.
Alternatively, you could assume that they are the same object and handle them the same way with semantic paths that make sense. That said, what you're looking for may be a path alteration for the default RESTful routes of the Movement controller actions. Also, a typical rails convention is to use plural path routes, which makes semantic sense for index pages and identifying objects that are a subset of a table of objects in a database, so I'm using purchases instead of purchase.
resources :movements, :path => "/purchases"
will produce
movements GET /purchases(.:format) {:action=>"index", :controller=>"movements"}
POST /purchases(.:format) {:action=>"create", :controller=>"movements"}
new_movement GET /purchases/new(.:format) {:action=>"new", :controller=>"movements"}
edit_movement GET /purchases/:id/edit(.:format) {:action=>"edit", :controller=>"movements"}
movement GET /purchases/:id(.:format) {:action=>"show", :controller=>"movements"}
PUT /purchases/:id(.:format) {:action=>"update", :controller=>"movements"}
DELETE /purchases/:id(.:format) {:action=>"destroy", :controller=>"movements"}
Using this model, the form_for helper method can still be used just like you would normally. Assuming #movement is properly defined, the path with the purchases root will be called properly.

Nested Routing for Single Table Inheritance model rails 3.1

I created a Single table inheritance model in my model file and am having difficulty with the routing. When I use :as in my resource, it renames my named path.
Model file:
class Account < ActiveRecord::Base
belongs_to :user
end
class AdvertiserAccount < Account
end
class PublisherAccount < Account
end
Routes.rb
resources :advertiser_accounts, :as => "accounts" do
resources :campaigns
end
I used :as in my routes because it is a single table inheritance and I want to pass the account_id and not the advertiser_account_id. My link is http://127.0.0.1:3000/advertiser_accounts/1/campaigns
/advertiser_accounts/:account_id/campaigns/:id(.:format)
However, using :as renames my named path from advertiser_account_campaigns to account_campaigns. My route looks like
account_campaigns GET /advertiser_accounts/:account_id/campaigns(.:format) campaigns#index
So when I create a new item using form_for, I would get "undefined method `advertiser_account_campaigns_path'"
Edited: current hacked solution
A hack around way that I am using is to duplicate the code in the routes file. Anyone have suggestions?
resources :advertiser_accounts, :as => "accounts" do
resources :campaigns
end
resources :advertiser_accounts do
resources :campaigns
end
If you run "rake routes" with your setup you'll see this:
account_campaigns GET /advertiser_accounts/:account_id/campaigns(.:format) campaigns#index
POST /advertiser_accounts/:account_id/campaigns(.:format) campaigns#create
new_account_campaign GET /advertiser_accounts/:account_id/campaigns/new(.:format) campaigns#new
edit_account_campaign GET /advertiser_accounts/:account_id/campaigns/:id/edit(.:format) campaigns#edit
account_campaign GET /advertiser_accounts/:account_id/campaigns/:id(.:format) campaigns#show
PUT /advertiser_accounts/:account_id/campaigns/:id(.:format) campaigns#update
DELETE /advertiser_accounts/:account_id/campaigns/:id(.:format) campaigns#destroy
accounts GET /advertiser_accounts(.:format) advertiser_accounts#index
POST /advertiser_accounts(.:format) advertiser_accounts#create
new_account GET /advertiser_accounts/new(.:format) advertiser_accounts#new
edit_account GET /advertiser_accounts/:id/edit(.:format) advertiser_accounts#edit
account GET /advertiser_accounts/:id(.:format) advertiser_accounts#show
PUT /advertiser_accounts/:id(.:format) advertiser_accounts#update
DELETE /advertiser_accounts/:id(.:format) advertiser_accounts#destroy
So you should use "account_campaingns_path" in this setup, the ":as" actually changes the calls in the code not the paths in the url. If you want to change the paths you should use ":path =>" rather than ":as =>".
The Rails guide on routing also shows some examples with ":as" and ":path" and the resulting paths and helpers, you'll need to search a bit because think they only use in in examples explaining other cases.
Edit: rereading your question, I think you may also want to look at member routes, I'm not sure if that's what you want to mean with it being a single inheritance and not wanting to pass the advertiser_account's ':account_id'?

Nested resource in Rails3, no route match

I have a nested route in rails 3 mapped as
resources :maps do
resource :versions
member do
post 'share'
get 'share'
end
end
but when i try to connect to http://localhost:3000/maps/35/versions/2 i obtains
No route matches "/maps/35/versions/2"
and in rake routes
GET /maps/:map_id/versions/:id(.:format) {:controller=>"versions", :action=>"show"}
or similar (with :id) is missing
other routes with versions works correctly
what's wrong?
EDIT 2:
This is the full rake routes output
maps_public GET /maps/public(.:format) {:controller=>"maps", :action=>"public"}
map_versions POST /maps/:map_id/versions(.:format) {:controller=>"versions", :action=>"create"}
new_map_versions GET /maps/:map_id/versions/new(.:format) {:controller=>"versions", :action=>"new"}
edit_map_versions GET /maps/:map_id/versions/edit(.:format) {:controller=>"versions", :action=>"edit"}
GET /maps/:map_id/versions(.:format) {:controller=>"versions", :action=>"show"}
PUT /maps/:map_id/versions(.:format) {:controller=>"versions", :action=>"update"}
DELETE /maps/:map_id/versions(.:format) {:controller=>"versions", :action=>"destroy"}
share_map POST /maps/:id/share(.:format) {:controller=>"maps", :action=>"share"}
GET /maps/:id/share(.:format) {:controller=>"maps", :action=>"share"}
maps GET /maps(.:format) {:controller=>"maps", :action=>"index"}
POST /maps(.:format) {:controller=>"maps", :action=>"create"}
new_map GET /maps/new(.:format) {:controller=>"maps", :action=>"new"}
edit_map GET /maps/:id/edit(.:format) {:controller=>"maps", :action=>"edit"}
map GET /maps/:id(.:format) {:controller=>"maps", :action=>"show"}
PUT /maps/:id(.:format) {:controller=>"maps", :action=>"update"}
DELETE /maps/:id(.:format) {:controller=>"maps", :action=>"destroy"}
It has to be resources :versions. Note the missing "s" in your case.
In addition to #Femaref's answer, the url you need to access is /maps/35/versions/2. If you want the singular (singleton) resource, then you'd do:
resources :maps do
resource :version
end
And then hit /maps/35/version (doesn't take an id). Which, if you have multiple versions for each map, you probably don't want to do.

URL helper for a post route in a resource

I have a resourceful route, with a post route nested within it:
resources :groups, :only => [:index, :show] do
post 'send_audit_reminder', :on => :member
end
If I run rake routes, this route shows up just fine:
send_audit_reminder_group POST /groups/:id/send_audit_reminder(.:format)
{:controller=>"groups", :action=>"send_audit_reminder"}
However, I can't seem to figure out how to refer to the send_audit_reminder URL for a given route. I've tried send_audit_reminder_group_path(#group) and send_audit_reminder_url(#group), which both give me the following error:
No route matches {:controller=>"groups", :action=>"send_audit_reminder"}
As you can see from rake routes, there is indeed a route that matches those parameters, and there is also a matching method on the controller.
How can I find the path or URL for this route? I would like not to hard code it, since our apps are deployed to subdirectories on the same virtual host, so a hard-coded absolute path won't work.
And where would I look for documentation or information on this in the future? Since these path and URL helper methods are generated from my routes, I obviously can't look for documentation, and while rake routes tells me that the route is there, it doesn't appear to be there when I try and get the URL.
It might be that you're missing the placeholders and it can't route because of that. The following should work based on your definition:
send_audit_reminder_group_path(group)
Any time you see identifiers like :id or :group_id in your route, you must supply them unless they are in brackets, which declares them as optional, as is the case here with :format. The arguments need to be supplied in the same order they are declared. For this:
/example/:user_id/groups/:id
The arguments to this route would be user_id and id and both must be supplied. Generally with routes you can either use a literal number or string, or a model that supports to_param as all ActiveRecord::Base-derived ones do.
This all stems from declaring with :member, meaning it is specific to a particular record, and not :collection where that is omitted. The Rails Routing Guide explains more.

Replacing default routes for a resource in Rails 3

I have a resource defined like so:
resources :referrals, :except => [:show, :edit, :destroy]
and I'd like to replace (not just add a named route) a default route that Rails produces, specifically the one for the update action.
Here is my rake routes:
referrals GET /referrals(.:format) {:action=>"index", :controller=>"referrals"}
POST /referrals(.:format) {:action=>"create", :controller=>"referrals"}
new_referral GET /referrals/new(.:format) {:action=>"new", :controller=>"referrals"}
referral PUT /referrals/:id(.:format) {:action=>"update", :controller=>"referrals"}
share /share(.:format) {:controller=>"referrals", :action=>"new"}
special /special(.:format) {:controller=>"referrals", :action=>"index"}
thanks /thanks(.:format) {:controller=>"pages", :action=>"thanks"}
/:shortlink(.:format) {:controller=>"referrals", :action=>"update"}
/:linktext(.:format) {:controller=>"referrals", :action=>"update"}
root /(.:format) {:controller=>"pages", :action=>"home"}
I'd like either the
/:shortlink(.:format)
or
/:linktext(.:format)
to hit the update action, but not the
/referrals/:id(.:format)
This is to implement a form of non-password "security". When the PUT goes to the update action, I want certain things to happen, but I don't want to require authorization to do this, and I don't want to allow easy guessing of the url based on controller name and simple low-numbered ids.
How can I fully replace the default route given by rails?
resources :referrals, :except => [:show, :edit, :destroy, :update]
match "/whatever_you_want/:variable_here" => "referrals#updated", :as=> the_link, :via=> :put
then in your controller you will access the param with
params[:variable_here]
here the param is whatever you want to compare against in the db, and the path will be create like this:
the_link_path or the_link_url
the :via part will constrain the path per HTTP method so only put request will match
more info here
http://guides.rubyonrails.org/routing.html