Rails Routing Error - No route matches - ruby-on-rails

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

Related

Is it possible to change params through web?

I am coding a website, that have no legit option for editing users.
Once created, nothing can be changed.
And here is my question:
Is it possible to change users data (for example by sending patch requests) without using edit form (because I did not create one), by 3rd party (a.k.a. not host)?
As Rails 5 requires, I am using strong params (sending user name and password when creating user by signup form).
#routes
Prefix Verb URI Pattern Controller#Action
root GET / sessions#new
signup GET /signup(.:format) users#new
POST /signup(.:format) users#create
login GET /login(.:format) sessions#new
POST /login(.:format) sessions#create
logout DELETE /logout(.:format) sessions#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
Should also mention that there is no update method, but I am using
resources :users
For third party access to your db you probably need an API.
Simplified example:
You app's URL is https://myapp.example.com/.
config/routes.rb:
namespace :api do
namespace :v1 do
resources :users, only: [:update]
end
end
rake routes:
Prefix Verb URI Pattern Controller#Action
api_v1_user PATCH /api/v1/users/:id(.:format) api/v1/users#update
PUT /api/v1/users/:id(.:format) api/v1/users#update
app/controllers/api/v1/base_controller.rb:
class Api::V1::BaseController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
protect_from_forgery with: :null_session
end
app/controllers/api/v1/users_controller.rb:
class Api::V1::UsersController < Api::V1::BaseController
def update
# check params, maybe look for some security tokens
user = User.find(params[:id])
if user
user.update_attribute(:name, params[:name])
render plain: "success" and return
else
render plain: "failure" and return
end
end
end
Then request like this
curl -X PATCH https://myapp.example.com/api/v1/users/1?name=new_name
would change users' with id = 1 name by "new_name".
For proper API desing you may check http://jsonapi.org/.

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)

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).

NoMethodError new to Rails

Ive been following some rails guides and im trying to now implement something on my own for a project im doing and have hit a snag at the first hurdle
I get this error when trying to load the page
ActionController::UrlGenerationError in StepOne#login
Showing /Users/rogan/Sites/authImp/app/views/step_one/login.html.erb where line #3 raised:
No route matches {:action=>"show", :controller=>"step_one"} missing required keys: [:id]
Extracted source (around line #3):
<%= form_for url: step_one_path do %>
form stuff...
then my step_one_controller.rb
class StepOneController < ApplicationController
def new
end
def create
user = User.authenticate(params[:email], params[:password])
if user
pincode = generatePin
puts "one use pin.#{pincode}"
redirect_to "step_two"
else
flash.now.alert = "Invalid email or password"
render "new"
end
end
end
this was adapter from a login system i saw in a guide that used SessionsController.rb and form_for url: sessions_path
but my simple changes seem to have broke it, i've looked at my routes as well and they all seem to be in order
edit: heres is my routes
edit edit: changed everything to step_one and to removed the 's' as suggested, I now get
NoMethodError in StepOne#login
undefined method `model_name' for Hash:Class
<%= form_for url: step_one_path do %>
so from one problem to another!
AuthImp::Application.routes.draw do
resources :users
resources :sessions
resource :step_one
get "users/:id" => "users#show"
get "sign_up" => "users#new"
get "log_in" => "step_one#login"
get "step_two" => "sessions#new"
get "log_out" => "sessions#destroy", :as => "log_out"
then my rake routes is as follows
root to: "welcome#index"
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
sessions GET /sessions(.:format) sessions#index
POST /sessions(.:format) sessions#create
new_session GET /sessions/new(.:format) sessions#new
edit_session GET /sessions/:id/edit(.:format) sessions#edit
session GET /sessions/:id(.:format) sessions#show
PATCH /sessions/:id(.:format) sessions#update
PUT /sessions/:id(.:format) sessions#update
DELETE /sessions/:id(.:format) sessions#destroy
step_one POST /step_one(.:format) step_ones#create
new_step_one GET /step_one/new(.:format) step_ones#new
edit_step_one GET /step_one/edit(.:format) step_ones#edit
GET /step_one(.:format) step_ones#show
PATCH /step_one(.:format) step_ones#update
PUT /step_one(.:format) step_ones#update
DELETE /step_one(.:format) step_ones#destroy
GET /users/:id(.:format) users#show
sign_up GET /sign_up(.:format) users#new
log_in GET /log_in(.:format) step_one#login
step_two GET /step_two(.:format) sessions#new
log_out GET /log_out(.:format) sessions#destroy
root GET / welcome#index
your problem is in the naming I think, resources :step_one assumes that you define the StepOnesController (plural), not StepOneController
So, you should either rename your controller or use resource :step_one route (without the s at the end)
It looks like Rails is expecting you to pass in an id to your step_one_path, so the form_for should look like this:
<%= form_for url: step_one_path(#user.id) do %>
Where #user.id would be the id of the user that the form is associated with. Hope that helps. If not, please include your routes.rb file.
<%= form_tag step_one_path do |f| %>
was the form tag necessary, i was going about it wrong
thanks for all the help

Resources