Unable to route to a method in my controller - ruby-on-rails

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)

Related

Scoped routes creating a routing issue

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.

User Resources Expanded

In order to more clearly understand exactly what "resources" is doing in the Ruby on Rails routes.rb file, I want to write under it the exact code it is replacing.
When I run rake routes I get this:
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
Can someone help me fill in the blanks below so I can understand this more clearly:
resources 'users'
# get 'users' => 'users#index"
# post ...
# get ...
# get ...
# patch ...
# put ...
# delete ...
The equivalent code could be expressed as:
get 'users', to: 'users#index'
post 'users', to: 'users#create'
get 'users/new', to: 'users#new', as: 'new_user'
get 'users/:id/edit', to: 'users#edit', as: 'edit_user'
get 'users/:id', to: 'users#show', as: 'user'
patch 'users/:id', to: 'users#update'
put 'users/:id', to: 'users#update'
delete 'users/:id', to: 'users#destroy'
Brad werths answer is what you need.
To give you some more context, you also need to appreciate how the resourceful routing system works in Rails...
Resource routing allows you to quickly declare all of the common routes for a given resourceful controller. Instead of declaring separate routes for your index, show, new, edit, create, update and destroy actions, a resourceful route declares them in a single line of code.
Basically, each time you call resources, you're telling rails to build a set of routes for a controller designed around the "resourceful" principle.
"Resourceful" actions through the Internet are defined by wikipedia as follows:
HTTP functions as a request-response protocol in the client-server computing model. A web browser, for example, may be the client and an application running on a computer hosting a web site may be the server. The client submits an HTTP request message to the server. The server, which provides resources such as HTML files and other content, or performs other functions on behalf of the client, returns a response message to the client. The response contains completion status information about the request and may also contain requested content in its message body.
All of this make sense when you understand that Ruby/Rails is object orientated. This means everything you do in your application has to resolve around the initialization & maintenance of "objects".
Objects are basically your models - they are created, edited and destroyed (CRUD -- create read update destroy) with your controller actions. Therefore, to give you a set of standardized routes, you'll be able to use the following:
If you want to see your routes like how brad has outlined, you'll want to run rake routes
--
Good resource here: https://softwareengineering.stackexchange.com/questions/120716/difference-between-rest-and-crud

Why does my controller keep routing my link_to toward "show" action? Rails 4

So I am pretty stumped. I am new to Ruby on Rails (I am using Rails 4) and I have been trying to figure out for the last two days why my link_to tag keeps routing my login action to show instead. I removed the show action from my controller and even deleted show.html.erb and yet Rails remains persistent in trying to route it to a show action that no longer exists.
I removed all my redirect_to functions, and the link_to I create takes me to the correct page localhost:8000/users/login but now displays the error Unknown Action: The action 'show' could not be found for UsersController.
I have read up other SO questions that were similar, and some suggest that it may be an issue with jquery_ujs, which I removed from my file to see if it was the problem, but I still ended up with the same result.
The files in my views directory are as follows:
views
users
new.html.erb
login.html.erb
Here's what my code looks like:
The link_to in users/new (new.html.erb)
<li><%= link_to "Login", users_login_path %></li>
routes.rb
resources :users
root 'users#new'
get 'users/create'
get 'users/login'
users_controller.rb
class UsersController < ApplicationController
def new
end
def create
#user = User.create(:username => params[:username], :password => params[:password])
#user.save
#users = User.all
end
def login
#message = "Success"
end
end #end class
login.html.erb (Just testing an output here to see if it ever gets to this page)
<h3><%= #message %></h3>
Output of rake routes command
Prefix Verb URI Pattern Controller#Action
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
root GET / users#new
users_create GET /users/create(.:format) users#create
users_login GET /users/login(.:format) users#login
I figured out what the problem was:
I needed to remove resources :users from the routes.rb file.
Everything is working as expected now. After doing a little bit of research it seems that the problem with having resources :users in there is that when browsers try to access the page they try to perform a command by using an HTTP method, which is either GET, POST, PUT, DELETE, or PATCH.
When the page looks for an incoming command which in this case was GET /users/login, it tries to map it to a controller action. If the first matching route is resources :users, it will send it to the show action.
It seems that this is due to the default CRUD system Rails uses where each HTTP method represents a CRUD action (correct me if I am wrong):
GET is show
POST is create
DELETE is destroy
PATCH is update
I got most of this research from Rails Routing from the Outside In, Section 2.1.

Rails undefined method `user_index_path`

I'm new to Ruby and Rails and working my way through the Rails Tutorial. Early on, I realized that I accidentally created my model as Users rather than User, so I've been going with that ever since.
It hasn't been an issue until I tried to implement the sign up page, and now whether going to pages or running the test visit signup_path for the sign up page, I keep getting the following error:
undefined method `users_index_path' for #<#<Class:0x007f9e3e1d91b8>:0x007f9e3e1d1ff8>
I can't figure out what's going wrong here. When I run rake routes I get the following:
~/Coding/rails_projects/sample_app (sign-up*) ☔ rake routes
Prefix Verb URI Pattern Controller#Action
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
root GET / static_pages#home
help GET /help(.:format) static_pages#help
about GET /about(.:format) static_pages#about
contact GET /contact(.:format) static_pages#contact
signup GET /signup(.:format) users#new
From that output, it looks to me like there should be a method users_index_path.
If it helps, my Users controller is the following:
class UsersController < ApplicationController
def new
#user = Users.new
end
def show
#user = Users.find(params[:id])
end
end
Using Rails 4.0.5.
Output from a page giving me the error:
Please keep in mind users_index_path is being called by Rails and not by me.
with
users GET /users(.:format) users#index
POST /users(.:format) users#create
you'll have a users_path method that will generate the /users path. That path will lead to either the index action (with a GET request) or the create action (with a POST request).
Under the hood, form_for #user will call the users_path method and set things up to fire a POST on submit (when #user is a new record). The URL helper method is calculated dynamically from the class name. This is ok if you're using Rails' defaults, but if you've defined custom routes you'll need to specify the URL explicitly.
With this out of the way, let's look at your problem.
A model with a plural name, e.g. class Users, will confuse rails.
When you pass #user to form_for, Rails will look at the class name, notice that it's a plural word, and try its best to deal with the ambiguity.
Normally it would be user_path for singular routes (show, update, delete) and users_path for the plural ones (index, create). Here, however, users_path must be used for the singular routes, and Rails will fallback to use users_index_path for index and create.
This would be all right.... but you have defined the routes using the default statement, probably with something like
resources :users
Which is correct, but not compatible with your model name.
Either rename your routes (bad) or rename your model (good).

Rails Routing Error - No route matches

I've been through the Rails Guide and additional docs to better understand routing, but I'm at a loss for why the following won't work.
Routing Error
No route matches {:action=>"preferences", :controller=>"users"}
I've added the following additional methods (they aren't complete yet) to my users_controller:
def preferences
#user = User.find(params[:id])
end
def update_pref
#user = User.find(params[:id])
if #user.save
redirect_to edit_user_registration_path, :notice => 'Updated Preferences.'
else
flash.alert = 'Unable to update preferences.'
render :edit
end
end
My routes.rb contains,
resources :users do
member do
get 'preferences'
put 'update_pref'
end
end
And when I run rake:routes, I get,
preferences_user GET /users/:id/preferences(.:format) users#preferences
update_pref_user PUT /users/:id/update_pref(.:format) users#update_pref
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
Any and all advice is greatly appreciated. Thanks for your time.
resources :users do
member do
get 'preferences' # comment or remove
put 'update_pref'
end
end
one way
get '/preferences' => 'users#preferences'
now you can use:
preferences_path
the way you put it in member it expects an id:
preferences_user_path(user)
another way
resources :users do
collection do
get 'preferences'
end
end
and you'll have users/preferences available without needing to pass user object.
You need to assign the user object to the url.
like user
preferences_user_path(#user)
This will create an url like users/1/preferences
Please visit documentation http://guides.rubyonrails.org/v3.2.13/routing.html#adding-more-restful-actions

Resources