How to reference this path name in Rails 3.2? - ruby-on-rails

I have the following routes.rb
resource :user, :only => [ :edit, :update ] do
collection do
get :tax_info
get :payment_info
put :payment_info
and would like to reference the get payment_info via an rspec matcher like this:
expect(response).to redirect_to(user_payment_info)
What would be the proper way to reference that path? I have tried user_payment_info and edit_user_payment_info?
Edit #1
Show output of rake routes on this controller

You're missing the _path portion that rails generates for all routes. Your rspec matcher should look like this:
expect(response).to redirect_to(user_payment_info_path)
The information returned when running rake routes will look similar to this:
GET /users/:id(.:format) user#show
tax_info_user GET /user/tax_info(.:format) users#tax_info
payment_info_user GET /user/payment_info(.:format) users#payment_info
PUT /user/payment_info(.:format) users#payment_info
edit_user GET /user/edit(.:format) users#edit
user PATCH /user(.:format) users#update
PUT /user(.:format) users#update
You can see on the left hand side there is a column that denotes the prefix for the url and path helpers that rails is going to generate. You can see this defined in the Rails 3.2 routing documentation.

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)

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

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

Can I change the default parameter ':id' generated by routes in Rails 3?

I have checked a lot of similar questions out there. Mostly the answers are showing override to_param method. But that's not what I want.
Let's say resources: users
rake routes
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)
Then back to my UsersController, I can get the id param from params[:id]. But this is not I want, I want it to be params[:user_id] . It's impossible according to the routes above.Because there is no :user_id parameter from the route. Is there any way that can help?
In general, Rails makes your life easy if you agree to go along with its conventions, and hard otherwise. So I'd recommend leaving this one alone.
But if you really want the param to be :user_id - say for readability reasons or something - you can just "alias" it in a before_filter:
params[:user_id] = params[:id]
Hope that helps!
You might be able to do something to the default with :path_prefix, I'll have a play and update if I find a way.
You can do this manually though if needed by defining individual matches in your routes instead of using the resource generator:
match 'users/:user_id/edit' => 'users#edit'
This will resolve the url /users/1/edit like so:
Started GET "/users/1/edit"
Processing by UsersController#edit as HTML
Parameters: {"user_id"=>"1"}

Diagnosing a 404 error in Rails

I am trying to make a POST request to /api/kpi?data=some+stuff:
curl -i http://127.0.0.1:9010/api/create_kpi -F data="some stuff"
but I'm getting a 404.
My routes are:
# config/routes.rb
namespace :api do
resource :kpi, :except => [:edit, :destroy]
end
Which should hit my controller
# app/controllers/api/kpi_controller.rb
class Api::KpiController < ApplicationController
def create
temp = Kpi.new(params[:data])
end
end
So I am guessing the paths are not correct. Right? I am having a hard time understanding whether my route is incorrect, or the controller, or the call.
When you get a 404, check your routes. It usually means there is no route to the controller to reach. Routes are what makes the link between URLs and controllers. If your controller was getting hit, it'd either work or give you a runtime error.
Inspect your routes by running rake routes. It's a very helpful tool. It should give you something like 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
You can see that it gives you the mapping of what [method, URL] request will hit which [controller, action]. For example, here, POST /users will trigger action create of UsersController.
Given a controller/resource name, Rails will, by convention, go looking for the plural of that name. For example, given resources :user, Rails will go looking for UsersController in file app/controllers/users_controller.rb. (Path/file names have to match the name!)
#yfedblum talks about the use of singular and plural in Rails into more detail.

Resources