Scoped routes creating a routing issue - ruby-on-rails

Im trying to learn to dry up my code a bit but have come across a issue,
Im scoping my routes with controller and path options
scope path: '/administrators', controller: :administrators do
get 'unverified' => :unverified
patch 'verify/:id' => :verify
get 'reported' => :reported
get 'ban_user' => :ban_user
patch 'execute_ban/:id' => :execute_ban
end
So this is what ive done so far, all the get links are working correctly...
but this is making the patch 'execute_ban/:id' => :execute_ban become a extension of ban user like this: (also the same with verify)
verified GET /administrators/unverified(.:format) administrators#unverifie
PATCH /administrators/verify/:id(.:format) administrators#verify
reported GET /administrators/reported(.:format) administrators#reported
ban_user GET /administrators/ban_user(.:format) administrators#ban_user
PATCH /administrators/execute_ban/:id(.:format) administrators#execute_ban
now ive changed my link_to route = link_to 'ban', ban_user_path(x.id), method: :patch
but its throwing an routing error saying no path matches.
Is there something im missing, any insight would aooreciated as always.
Thanks

Why not go for a more restful design that centers around the resource being modified?
Rails.application.routes.draw do
resources :users do
get :unverified, on: :collection
get :reported, on: :collection
get :ban
patch :ban, action: 'execute_ban'
end
end
You don't need different paths for the form and acting on a resource - use the HTTP verb instead.
Prefix Verb URI Pattern Controller#Action
unverified_users GET /users/unverified(.:format) users#unverified
reported_users GET /users/reported(.:format) users#reported
user_ban GET /users/:user_id/ban(.:format) users#ban
PATCH /users/:user_id/ban(.:format) users#execute_ban
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
If you are adding a separate controller just for authorization purposes it's an anti-pattern of sorts since you are just adding more complexity for something that should be handled by Pundit/CanCanCan.

Related

Unable to route to a method in my controller

I’m using Rails 4.2.5. I’m trying to set up my controller so that when a logged in user visits /users/edit, they see my form where they can edit some of their profiles. So in config/routes.rb I have
resources :users
…
get "users/edit" => "users#edit"
then in “app/controllers/users_controller.rb” I have
def edit
#user = User.find(session["user_id"])
render 'edit'
end
but when I visit “http://localhost:3000/users/edit” in a browser, I get the error
The action 'show' could not be found for UsersController
It is true I have no “show” method in my controller, but that is not where I want the user to go. I want them going to the edit method.
You are trying to go to the show action with this link:
http://localhost:3000/users/edit
You have this route for the show action:
GET /users/:id(.:format) users#show
(:id) is (edit)
Because you have defined first RESTful route:
resources :users
Which includes all routes listed below:
users_path GET /users(.:format) users#index
POST /users(.:format) users#create
new_user_path GET /users/new(.:format) users#new
edit_user_path GET /users/:id/edit(.:format) users#edit
user_path GET /users/:id(.:format) users#show
PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
and then
get "users/edit" => "users#edit"
Rails always finds first match. In this case show action of RESTFul routes will be applied:
GET /users/:id(.:format) users#show
and the other route will be ignored.
Solution: Change the order of the routes. That way edit route will be applied first.
The problem is that you're mixing a resource route with your own edit method, and "Rails routes are matched in the order they are specified" so it's matching the resources show route users/:id and stopping there.
You need to move your edit route above the resource.
Alternatively, read the linked guide and see if you can add edit as a collection route to the resource, and except the resources edit method. You may also need to except the show method, but it's worth having a play and seeing what you come up with. Routing is an important aspect and worth time to understand.
remove get "users/edit" => "users#edit" from your routes, change to resources :users, only: [:edit] (or more if actions you need them), remove the render 'edit' from your controller (default action).
Visit http://localhost:3000/users/1/edit to see the edit page for user_id 1 (there can't be an edit page for all users, you have to specify the id)

Rails4 Should I prevent multiple URIs indicate the same action?

Suppose you have UsersController and routes are configured in config/routes.rb as the followings.
root 'users#index' # root should list all users
resources :users
Then rake routes shows
Prefix Verb URI Pattern Controller#Action
root GET / users#index
users GET /users(.:format) users#index
users POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
There are a couple of URIs indicating same users#index action.
Should I prevent this kind of URI duplication or should I let them alone for me to follow Rails' default convention?
There are a couple of URIs indicating same users#index action. There are a couple of URIs indicating same users#index action.
Well, that's what you've specified by creating the users resource and then pointing the root path to users#index. If you don't want this behavior, you can remove the default index action from the resource.
resources :users, except: [:index]
Note that with this place, you can no longer refer to the index path via the traditional URL helpers. Personally I wouldn't be concerned with this and just let the URL duplication exist.
For root it's okay--this is typical and it's just redirecting to the users resource.

Restricting Rails routes to actions

Lets say I have an UsersController that contains an action #new. In my routes file I map with the following:
match 'signup', to: 'users#new'
This action can now be accessed by both /signup and /users/new. How do I restrict it to only the custom route.
I apologize if this has been answered, but am new to this. I've searched, but haven't found the answer. Possibly due to my not knowing how to concisely phrase this.
You can exempt the new route from the users resource, and replace it with your custom route:
resources :users, except: [:new]
get 'signup', to: 'users#new', as: "new_user"
Resulting in:
users GET /users(.:format) users#index
POST /users(.:format) users#create
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
new_user GET /signup(.:format) users#new

Setting up devise+omniauth in rails, keep getting a routing error after 'login'

So I've been working on a fairly simple rails 4 app and I've reached the point where I need to add user authentication. In particular, I want to use Google Apps (and only google apps) authentication via a combination of devise and omniauth. Now, devise has a tutorial that supposedly tells you how to set something like that up. After installing devise and making the suggested changes in the tutorial, everything seemed great. I clicked my sign-in link and was properly sent off to google for authentication. However, after I supply my credentials I'm immediately greeted with a routing error:
uninitialized constant Users
Which is confusing. From what I understand, that means that the controller is missing... but I definitely have users_controller.rb and it's where it should be. Barring that, I have no clue.
Here's my route.rb for reference:
resources :instances, :users
devise_for :users, :controllers => { :omniauth_callbacks => 'users/omniauth_callbacks' }
# authentication routes
devise_scope :user do
get 'sign_in', :to => 'devise/sessions#new', :as => :new_user_session
get 'sign_out', :to => 'devise/sessions#destroy', :as => :destroy_user_session
end
root to: 'instances#index'
And here's the result of rake routes:
Prefix Verb URI Pattern Controller#Action
instances GET /instances(.:format) instances#index
POST /instances(.:format) instances#create
new_instance GET /instances/new(.:format) instances#new
edit_instance GET /instances/:id/edit(.:format) instances#edit
instance GET /instances/:id(.:format) instances#show
PATCH /instances/:id(.:format) instances#update
PUT /instances/:id(.:format) instances#update
DELETE /instances/:id(.:format) instances#destroy
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
user_omniauth_authorize GET|POST /users/auth/:provider(.:format) users/omniauth_callbacks#passthru {:provider=>/google_apps/}
user_omniauth_callback GET|POST /users/auth/:action/callback(.:format) users/omniauth_callbacks#(?-mix:google_apps)
new_user_session GET /sign_in(.:format) devise/sessions#new
destroy_user_session GET /sign_out(.:format) devise/sessions#destroy
root GET / instances#index
Also of note is that I'm running rails 4 and devise 3.0.0.rc (because it's rails 4 compatible)
Let me know if there's anything else you need, pretty much everything else that is relevant is in the tutorial thing though.
You're problem lies here: :omniauth_callbacks => 'users/omniauth_callbacks'
'users/omniauth_callbacks' translates to Users::OmniauthCallbacksController. While your application does have a User model and a UserController, you haven't declared a constant which defines a Users namespace.
You'll need to add a controller in that namespace to handle the callback:
# app/controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
# action names should match the names of the providers
def facebook; end
def twitter; end
def github; end
...
end

why no path names for custom routes in Rails

In my rails app following in routes.rb
resources :users
leads to following output for 'rake routes'
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
user GET /users/:id(.:format) users#show
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
& following in routes.rb (for my custom controller 'home')
match '/new_user' => 'home#new_user', via: [:get]
match '/users/:id/edit' => 'home#edit_user', via: [:get]
match '/users/:id' => 'home#show_user', via: [:get]
match '/users/:id' => 'home#create_user', via: [:post]
leads to following output for 'rake routes'
GET /new_user(.:format) home#new_user
GET /users/:id/edit(.:format) home#edit_user
GET /users/:id(.:format) home#show_user
POST /users/:id(.:format) home#create_user
why there are no path names for second case? like in first case ('new_user', 'edit_user')
is there any way to have path names for second case? as i want to use these path names in my views
There are no path names because you haven't specified path names. If you're supplying custom routes instead of using resources, you need to use :as to provide a pathname:
match '/new_user' => 'home#new_user', via: :get, as: :new_user
You should also just use get instead of match... via: :get:
get '/new_user' => 'home#new_user', as: :new_user
However, given your set of routes, your better bet is to continue using resources, but to supply a limited list of actions via :only and a custom controller via :controller:
resources :users, only: %w(new edit show create), controller: "home"

Resources