Rails route alias for a nested route with specific id - ruby-on-rails

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 }

Related

Routing Error: No route matches [POST] "/topics/post_up_vote_path(post)"

I'm working on an assignment for school and I'm receiving a routing error that I don't understand.. I'm trying to integrate a voting feature to allow users to up vote or down vote on various posts on the site. However, I keep getting the following error:
Routing Error
No route matches [POST] "/topics/post_up_vote_path(post)"
I recently updated my routes.rb file to look like this to implement shallow nesting:
Rails.application.routes.draw do
devise_for :users
resources :users, only: [:update]
resources :topics do
resources :posts, except: [:index]
end
resources :posts, only: [] do
resources :comments, only: [:create, :destroy]
post '/up-vote' => 'votes#up_vote', as: :up_vote
post '/down-vote' => 'votes#down_vote', as: :down_vote
end
get 'about' => 'welcome#about'
root to: 'welcome#index'
end
Now my routes for up_votes and down_votes look like this:
post_up_vote_path POST /posts/:post_id/up-vote(.:format) votes#up_vote
post_down_vote_path POST /posts/:post_id/down-vote(.:format) votes#down_vote
From the error I receive above it looks like my app is searching for /topics/post_up_vote_path(post) when it should be searching for /posts/:post_id/up-vote . I'm a bit stuck at this point, not sure how to get things to route correctly..
Here's the relevant GitHub branch associated with this project for further reference to other files:
https://github.com/jlquaccia/Bloccit/tree/checkpoint-49-voting
In your voter partial (app/views/votes/_voter.html.erb) you pass the string 'post_up_vote_path(post)' as the url argument for link_to. You just need to get rid of the quotes, so change the link_to to this:
link_to " ", post_up_vote_path(post), class: 'glyphicon glyphicon-chevron-up', method: :post
You will have to do the same with the down vote link.

Can I get a controller to show up in the url under a different name?

I have a controller called "Pages". Can I make it show up in the url bar under a different name? For example, when I render the 'show' template, it shows up under this url: localhost:3000/pages/:id. Could I make it show up as localhost:3000/people/:id? I only care about the 'show' url; the other urls aren't that important.
routes.rb
get "pages/results"
get "pages/index" => "pages#index", as: "index_page"
resources :pages do
resources :categories
end
Add this your routes:
get '/people/:id', to: 'pages#show'
And remove the old show route from the resource:
resources :pages, only: [:index, :new, :create, :edit, :update, :delete] do
resources :categories
end
See: Rails guides about rounting
You could use like this:
get '/pages/:id' => "pages#show", path: 'people/:id'
This way you can access particular show page in the browser.
Hope this helps you.

Ruby on Rails attribute routing using resources

I'm working on a preservation project where I have models for Institutions, Objects, and Files and I'm using resources in my routes file to help manage all of that. The problem I'm having is that resources uses the :id generated by Ruby on Rails for all of its routes and I would like to use a different attribute. This is particularly important for academic preservation and URL consistency. For example, I would like my show URL for an institution to read institutions/:identifier as opposed to institutions/:id, where :identifier is the attribute I have created. The problem is, I haven't been able to find any information on how to do this aside from just matching individual routes to the new ones I want which seems like a cheap hack at best and breaks a lot of my code.
This is my current routes file:
Fluctus::Application.routes.draw do
#match "institutions/", to: 'institutions#index', via: [:get]
#match "institutions/", to: 'institutions#create', via: [:post]
#match "institutions/:identifier", to: 'institutions#show', via: [:get]
#match "institutions/:identifier", to: 'institutions#update', via: [:patch]
#match "institutions/:identifier", to: 'institutions#update', via: [:put]
#match "institutions/:identifier", to: 'institutions#destroy', via: [:delete]
#match "institutions/:identifier/edit", to: 'institutions#edit', via: [:get]
#match "institutions/:identifier/events", to: 'events#index', via: [:get]
#match "institutions/new", to: 'institutions#new', via: [:get]
#
#match "objects/institution_identifier", to: 'intellectual_objects#index', via: [:get], as: "intellectual_objects_path"
#match "objects/institution_identifier", to: 'intellectual_objects#create', via: [:post]
resources :institutions do
resources :intellectual_objects, only: [:index, :create], path: 'objects'
resources :events, only: [:index]
end
resources :intellectual_objects, only: [:show, :edit, :update, :destroy], path: 'objects' do
resources :generic_files, only: :create, path: 'files'
patch "files/:id", to: 'generic_files#update', constraints: {id: /.*/}, trailing_slash: true, format: 'json'
resources :events, only: [:create, :index]
end
devise_for :users
resources :users do
patch 'update_password', on: :collection
get 'edit_password', on: :member
patch 'generate_api_key', on: :member
end
resources :generic_files, only: [:show, :destroy], path: 'files' do
resources :events, only: [:create]
end
Blacklight.add_routes(self)
mount Hydra::RoleManagement::Engine => '/'
authenticated :user do
root to: "institutions#show", as: 'authenticated_root'
# Rails 4 users must specify the 'as' option to give it a unique name
# root :to => "main#dashboard", :as => "authenticated_root"
end
root :to => "catalog#index"
end
You can see where I have attempted to match individual routes without much luck. I've also looked into FriendlyID without any luck so far. If anyone has any ideas it would be greatly appreciated. Thank you!
Unless I'm missing something here, you should just be able to stick the string you want to use into the URL where the id whould be. For example, /objects/show/1 would become /objects/show/some_string. Then in your controller you can find the object using the id parameter:
def show
#object = Object.where(:some_attribute => params[:id]).first
end

How can I specify two actions mapped to the DELETE verb in a rails resource?

I have an api tokens controller based on Matteo Melanis blog post. I'd like to add two custom actions register and unregister to the controller, and so the route that looked like this
namespace :api do
namespace :v1 do
resources :tokens,:only => [:create, :destroy]
end
end
has now become this
namespace :api do
namespace :v1 do
resources :tokens do
put 'register', on: :member, as: :register
delete 'unregister', on: :member, as: :unregister
end
end
end
This is the only way I've found that doesn't let unregister suppress the CRUD destroy action, associated with the DELETE verb. I tried to do
resources :tokens, :only => [:create, :destroy, :register, :unregister] do
in the above code, as well as defining resources :tokens,:only => [:create, :destroy] in parallel to the block. Yet, I either get the undesirable all CRUD + custom actions, or one of the custom actions overriding a CRUD action.
In short, I'd like to end up with
register_api_v1_token PUT /api/v1/tokens/:id/register(.:format) api/v1/tokens#register
unregister_api_v1_token DELETE /api/v1/tokens/:id/unregister(.:format) api/v1/tokens#unregister
api_v1_tokens GET /api/v1/tokens(.:format) api/v1/tokens#index
POST /api/v1/tokens(.:format) api/v1/tokens#create
DELETE /api/v1/tokens/:id(.:format) api/v1/tokens#destroy
Is this possible, and if yes: how can I make it so?
This should work:
resources :tokens, only: [:create, :destroy] do
member do
put 'register'
delete 'unregister'
end
end

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