How to add extra parameter to resources in routes - ruby-on-rails

I want member routes generating by resources to contain additional parameter.
Something like:
resources :users
with folowing routes:
users/:id/:another_param
users/:id/:another_param/edit
Any ideas ?

resources method doesn't allow you to do that. But you can do something similar using the path option and including extra parameters:
resources :users, path: "users/:another_param"
That will generate urls like this:
users/:another_param/:id
users/:another_param/:id/edit
In this case you will need to send :another_param value to routing helpers manually:
edit_user_path(#user, another_param: "another_value")
# => "/users/another_value/#{#user.id}/edit"
Passing :another_param value is not required if a default value has been set:
resources :users, path: "users/:another_param", defaults: {another_param: "default_value"}
edit_user_path(#user) # => "/users/default_value/#{#user.id}/edit"
Or you can even make the extra parameter not mandatory in the path:
resources :users, path: "users/(:another_param)"
edit_user_path(#user) # => "/users/#{#user.id}/edit"
edit_user_path(#user, another_param: "another_value")
# => "/users/another_value/#{#user.id}/edit"
# The same can be achieved by setting default value as empty string:
resources :users, path: "users/:another_param", defaults: {another_param: ""}
If you need extra parameters for particular actions, it can be done this way:
resources :users, only: [:index, :new, :create]
# adding extra parameter for member actions only
resources :users, path: "users/:another_param/", only: [:show, :edit, :update, :destroy]

you could do something more explicit like
get 'my_controller/my_action/:params_01/:params_02', :controller => 'my_controller', :action => 'my_action'

resources :users, path: 'user' do
collection do
get ':id/:some_param', action: :action_name
get ':id/:some_param/edit', action: :custom_edit
end
end

Related

Rails route alias for a nested route with specific id

I am trying to make some alias for my rails route like this 'events/8/event_participants/new' to /business-meet/registration,
My routes are written like this:
resources :events, only: [], shallow: true do
resources :event_participants, only: [:new, :create, :edit, :update] do
post :complete, on: :collection
member do
get :invite, :add_people, :accept_invitation, :invitation_success, :reserved
put :refer
end
end
end
I want the alias for the specific event id 8, I tried with redirect, but it actually redirect to the the route, so the whole route is visible in the browser, I want the to keep visible /business-meet/registration routes to my browser.
You can use a match method in your route.
match '/business-meet/registration', to: 'event_participants#new', via: :get, defaults: { event_id: 8 }

Rails - Deploying to Heroku with duplicate routes

I'm deploying my Rails app that uses the clearance gem to Heroku. Everything works fine in development but I'm running into trouble with the gem generated routes I get.
When attempting to deploy to Heroku, I get the error...
ArgumentError: Invalid route name, already in use: 'sign_in'
You may have defined two routes with the same name using the `:as` option, or you may be overriding a route already defined by a resource with the same naming. For the latter, you can restrict the routes created with `resources` as explained here:
remote: http://guides.rubyonrails.org/routing.html#restricting-the-routes-created
I'm not seeing where to restrict the duplicates or where they would be generated with any of my resources:
Please see routes.rb file below
Routes.rb
Rails.application.routes.draw do
resources :passwords, controller: "clearance/passwords", only: [:create, :new]
resource :session, controller: "clearance/sessions", only: [:create]
resources :users, controller: "clearance/users", only: [:create] do
resource :password,
controller: "clearance/passwords",
only: [:create, :edit, :update]
end
get "/sign_in" => "clearance/sessions#new", as: "sign_in"
delete "/sign_out" => "clearance/sessions#destroy", as: "sign_out"
get "/sign_up" => "clearance/users#new", as: "sign_up"
get 'newSignUp', to: 'signups#new'
post 'newSignUp', to: 'signups#create'
get 'newTrip', to: 'trips#new'
post 'newTrip', to: 'trips#create'
get 'trips/:id/send_itinerary' => 'trips#send_itinerary', as: :trips_send_itinerary
root 'static_pages#home'
get 'static_pages/home'
get 'static_pages/help'
get 'static_pages/about'
get 'static_pages/contact'
resources :signups
resources :tripitems
resources :trips
end
This issue has to do with the clearance gem.
I am not totally familiar with the gem, so as per usual, I checked out the github and found the following:
# config/routes.rb
if Clearance.configuration.routes_enabled?
Rails.application.routes.draw do
resources :passwords,
controller: 'clearance/passwords',
only: [:create, :new]
resource :session,
controller: 'clearance/sessions',
only: [:create]
resources :users,
controller: 'clearance/users',
only: Clearance.configuration.user_actions do
resource :password,
controller: 'clearance/passwords',
only: [:create, :edit, :update]
end
get '/sign_in' => 'clearance/sessions#new', as: 'sign_in'
delete '/sign_out' => 'clearance/sessions#destroy', as: 'sign_out'
if Clearance.configuration.allow_sign_up?
get '/sign_up' => 'clearance/users#new', as: 'sign_up'
end
end
end
This is basically creating the same routes for you, only if the config routes_enabled? is true.
You need to configure clearance as follows to handle the routes yourself:
config.routes = false
After looking at the gems GitHub, it looks like I raked the routes earlier and even though config.routes was set to false in the initializer, there was a conflict generate in the generated resources in production.
I wound up deleting the raked routes and making config.routes=true.

Add custom new routes to rails resources

I my routes file, I have defined a resource
namespace :admin do
resources :invoices, only: [:index, :new]
end
Then I've got a route rule with corresponding path helper new_admin_invoice_path
new_admin_invoice GET /admin/invoices/new(.:format) admin/invoices#new
But how can I add two more new rules, so thуe look like
new_admin_incoming_invoice GET /admin/invoices/new/incoming(.:format) admin/invoices#new {:type=>:incoming}
new_admin_outgoing_invoice GET /admin/invoices/new/outgoing(.:format) admin/invoices#new {:type=>:outgoing}
I tried add them manually
resources :invoices, only: [:index, :new] do
get 'new/incoming', on: :collection, action: :new, type: :incoming
get 'new/outgoing', on: :collection, action: :new, type: :outgoing
end
But got wrong result
new_incoming_admin_invoices GET /admin/invoices/new/incoming(.:format) admin/invoices#new {:type=>:incoming}
new_outgoing_admin_invoices GET /admin/invoices/new/outgoing(.:format) admin/invoices#new {:type=>:outgoing}
How can I get exactly that routes with path helpers what I need?
Here is the easy rails way from official guide
resources :invoices, only: [:index] do
get 'incoming', on: :new, type: :incoming, action: :new
end
Results to
incoming_new_admin_invoice GET /admin/invoices/new/incoming(.:format) admin/invoices#new {:type=>:incoming}
Try by using a scope like this:
scope "/admin" do resources :invoices end

How to rename index path in routes file?

How to rename index path only?
routes.rb
resources :tasks, :except => [:create] do
collection do
..............
end
member do
.............
end
end
instead of /tasks in URL I need /trigger or even /tasks/trigger will do, im on rails3.
I tried
1.
collection do
'/', to: 'tasks#trigger'
end
and
2.
resources :tasks, :except => [:create] do
get '/task', to: 'task#trigger', as: task_index
end
both throw up errors.
any ideas?
For URL like '/trigger' add to routes.rb:
get 'trigger' => 'tasks#index'
For URL like '/tasks/trigger' modify routes.rb:
resources :tasks, :except => [:create] do
collection do
get 'trigger' => 'tasks#index'
end
end
If your index method in task's controller named as 'trigger, 'tasks#index' is replaced by 'tasks#trigger'
If you want to make your own index route then you need to do two things
1- you need to disable index path created by resources
2- Define your own path whatever you want.
As per your requirement you want to make index route as '/trigger'.
Following is the solution.
get 'trigger' => 'tasks#index'
resources :tasks, :except => [:create, :index] do
collection do
..............
end
member do
.............
end
end
Just restraint index route from being generated in your resources call:
resources :tasks, :except => [:create, :index]
And then do your own custom route. For '/trigger':
get 'trigger', to: 'task#trigger', as: 'trigger

Rails routes: GET without param :id

I'm developing a REST API based on rails. To use this API, you MUST be logged in. Regarding that, I'd like to create a method me in my user controller that will return a JSON of the logged in user infos.
So, I don't need an :id to be passed in the URL. I just want to call http://example.com/api/users/me
So I tried this:
namespace :api, defaults: { format: 'json' } do
scope module: :v1, constraints: ApiConstraints.new(version: 1, default: true) do
resources :tokens, :only => [:create, :destroy]
resources :users, :only => [:index, :update] do
# I tried this
match 'me', :via => :get
# => api_user_me GET /api/users/:user_id/me(.:format) api/v1/users#me {:format=>"json"}
# Then I tried this
member do
get 'me'
end
# => me_api_user GET /api/users/:id/me(.:format) api/v1/users#me {:format=>"json"}
end
end
end
As you can see, my route waits for an id, but I'd like to get something like devise has. Something based on current_user id. Example below:
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
In this example you can edit the current user password without passing the id as a param.
I could use a collection instead of a member, but that's a dirty bypass.
The way to go is to use singular resources:
So, instead of resources use resource:
Sometimes, you have a resource that clients always look up without referencing an ID. For example, you would like /profile to always show the profile of the currently logged in user. In this case, you can use a singular resource to map /profile (rather than /profile/:id) to the show action [...]
So, in your case:
resource :user do
get :me, on: :member
end
# => me_api_user GET /api/users/me(.:format) api/v1/users#me {:format=>"json"}
Resource routes are designed to work this way. If you want something different, design it yourself, like this.
match 'users/me' => 'users#me', :via => :get
Put it outside of your resources :users block
You can use
resources :users, only: [:index, :update] do
get :me, on: :collection
end
or
resources :users, only: [:index, :update] do
collection do
get :me
end
end
"A member route will require an ID, because it acts on a member. A collection route doesn't because it acts on a collection of objects. Preview is an example of a member route, because it acts on (and displays) a single object. Search is an example of a collection route, because it acts on (and displays) a collection of objects." (from here)
Maybe I am missing something, but why don't you use:
get 'me', on: :collection
resources :users, only: [:index, :update] do
collection do
get :me, action: 'show'
end
end
specifying the action is optional. you can skip action here and name your controller action as me.
This gives same result as Arjan's in simpler way
get 'users/me', to: 'users#me'
When you create a route nested within a resource, you can mention, whether it is member action or a collection action.
namespace :api, defaults: { format: 'json' } do
scope module: :v1, constraints: ApiConstraints.new(version: 1, default: true) do
resources :tokens, :only => [:create, :destroy]
resources :users, :only => [:index, :update] do
# I tried this
match 'me', :via => :get, :collection => true
...
...

Resources