Changing Route from "/:id/model" to "/model" - ruby-on-rails

I want to change my path from root/carts/56 to root/cart.
I applied the logic from this question Rails route to username instead of id, which changes the id of the user to the username in the path. That works because the username can be set to unique.
I want a /cart to lead (obviously) to the one cart the visiter (no users) is working with and get rid of the
:cart/:id. I DO NOT use a user model, otherwise I would just do #user.cart (:user/cart)
So I (understandably so) get this error
Invalid route name, already in use: 'cart'
because this line
match '/:carts/:id' => 'carts#show', :as =>'cart', :via => :get
Relevant routes:
carts GET /carts(.:format) carts#index
POST /carts(.:format) carts#create
new_cart GET /carts/new(.:format) carts#new
edit_cart GET /carts/:id/edit(.:format) carts#edit
cart GET /carts/:id(.:format) carts#show
PATCH /carts/:id(.:format) carts#update
PUT /carts/:id(.:format) carts#update
DELETE /carts/:id(.:format) carts#destroy
UPDATE:
With resource :cart, :only => :show # note 'resource' not 'resources'
I get an improvement, but can I remove the id from the path somehow?
http://localhost:3000/cart?id=52
is what it gives me.
Sorry - the line that gives me the id in the URL is
<li><%= link_to "Cart", cart_path(id: session[:cart_id]) %></li>
Is a singular resource really what I need? I am creating the carts in a session like this
<% if session[:cart_id] == nil %>
<li><%= link_to "Cart", new_cart_path %></li>
<% else %>
The idea there being if they haven't created a cart yet, they will create one when they visit the page.
I actually followed the tutorial for the carts here

In your routes file use
resource :cart, :only => :show # note 'resource' not 'resources'
This will give you a cart_path that you can call. It will hit the show method in the carts_controller. If you need /root/ theres a few ways to add that.
Put this above the user path that's declared in the routes.rb file.
You may need some validation to ensure users don't select names that are reserved.

Related

How do I create a Rails form that submits to a RESTful action?

With Rails 5, how do I create a form that submits to a RESTful action?
In my routes file I have:
resources :people do
collection do
get 'image/:id', :to => "people#image", :as => 'image'
get 'ranks', :to => "people#ranks", :as => 'ranks'
get 'search/:search(.:format)', to: 'people#search'
end
end
So I'm wondering how to construct a form that submits to the "search" action.
I tried the following:
<%= form_tag(people_search_path) do %>
<%= text_field_tag :search %>
<%= submit_tag 'Search' %>
<% end %>
But this results in the following error:
undefined local variable or method `people_search_path' for #<#<Class:0x00007ff2afc59168>:0x00007ff2afc50f68>
If you do rake routes, you'll see that your search path has no name:
image_people GET /people/image/:id(.:format) people#image
ranks_people GET /people/ranks(.:format) people#ranks
GET /people/search/:search(.:format) people#search
people GET /people(.:format) people#index
POST /people(.:format) people#create
new_person GET /people/new(.:format) people#new
edit_person GET /people/:id/edit(.:format) people#edit
person GET /people/:id(.:format) people#show
PATCH /people/:id(.:format) people#update
PUT /people/:id(.:format) people#update
DELETE /people/:id(.:format) people#destroy
If, instead, you do:
resources :people do
collection do
get 'image/:id', :to => "people#image", :as => 'image'
get 'ranks', :to => "people#ranks", :as => 'ranks'
get 'search/:search(.:format)', to: 'people#search', as: :search
end
end
You'll see your path now has a name:
image_people GET /people/image/:id(.:format) people#image
ranks_people GET /people/ranks(.:format) people#ranks
search_people GET /people/search/:search(.:format) people#search
people GET /people(.:format) people#index
POST /people(.:format) people#create
new_person GET /people/new(.:format) people#new
edit_person GET /people/:id/edit(.:format) people#edit
person GET /people/:id(.:format) people#show
PATCH /people/:id(.:format) people#update
PUT /people/:id(.:format) people#update
DELETE /people/:id(.:format) people#destroy
Which you can use as search_people_path.
BTW, I believe that (.:format) bit is unnecessary and you can simply do:
post 'search/:search', to: 'people#search', as: :search
If I were you, however, I would do:
resources :people do
collection do
get 'image/:id', :to => "people#image", :as => 'image'
get 'ranks', :to => "people#ranks", :as => 'ranks'
get :search, to: 'people#search', as: :search
end
end
Which will give you:
image_people GET /people/image/:id(.:format) people#image
ranks_people GET /people/ranks(.:format) people#ranks
search_people GET /people/search(.:format) people#search
people GET /people(.:format) people#index
POST /people(.:format) people#create
new_person GET /people/new(.:format) people#new
edit_person GET /people/:id/edit(.:format) people#edit
person GET /people/:id(.:format) people#show
PATCH /people/:id(.:format) people#update
PUT /people/:id(.:format) people#update
DELETE /people/:id(.:format) people#destroy
Then, I would update your form as Anees Muhammed suggests (I used :terms instead of :search):
<%= form_tag search_people_path, method: :get do %>
<%= text_field_tag :terms %>
<%= submit_tag 'Search' %>
<% end %>
Then, when you submit, you should get something like:
Started GET "/people/search?terms=foo" for ::1 at 2018-01-29 13:49:40 -0800
Processing by People#search as HTML
Parameters: {"utf8"=>"✓", "terms"=>"foo", "commit"=>"Search"}
And you can access your terms by doing params[:terms].
There is, BTW, nothing "non-RESTful" about this. It is, IMO, completely consistent the Guide for adding RESTful actions.
You should use search_people_path instead of people_search_path. But I don't think that change will take you to what you are trying to achieve. Since your route is get 'search/:search(.:format)', to: 'people#search' rails will expect you to provide a value for the keyword :search to build a url like /people/search/yoursearchterm with something like search_people_path(yoursearchterm). For your functionality to work, change the form to
<%= form_tag search_people_path, method: :get do %>
<%= text_field_tag :search %>
<%= submit_tag 'Search' %>
<% end %>
and then in your controller
def search
params[:search]
end
Also the routes to
get 'search', to: 'people#search'
Updated
Since you are trying to submit the form directly to a rest route like search/:search, I believe there is no direct rails way to achieve the same because that's how forms work. But if all you want is just a rest route like yourwebsite.com/search/yoursearchterm when you submit the form, there are some workarounds to achieve this. Either you have to write a piece of js on submitting the form and forward the request to your route with the input value or you can perform a redirect in the controller to the route, like this.
Routes:
resources :people do
collection do
get 'search', to: 'people#search_people'
get 'search/:search', to: 'people#search'
end
end
So, first the form will be submitted to search_people action and then redirect to search with params. In controller
def search_people
redirect_to search_people_path(params[:search])
end
This will then give you a url yoursite.com/people/search/searchterm and then in your search action, you can use the search params.
Hope this helps.

Rails model_path routing error, no route matching "model.2"; should be "model/2"

There seems to be something wrong with my routing paths. Normally I should be able to do something like <%= link_to Profile, user_path(#user||current_user) %> and I move on with my day. For whatever reason I'm failing to understand my user_path is not returning /user/:id like I would expect it to do. Instead it is returning /user.:id
To test this, I loaded a partial with the following code.
app/view/users/_test.html.rb
<%= #user %><br>
<%= #user.id %><br>
<%= link_to user_path(#user), user_path(#user) %><br>
<%= new_user_path %><br>
<%= edit_user_path(#user) %><br>
<%= url_for(#user) %>
This returned
localhost:3000/test
#<User:0x007fb6cd341f08>
1
/user.1
/users/new
/users/1/edit
/user.1
I can't figure out what is causing this to happen. The edit_user_path(#user) works perfectly, but the show doesn't. I have read the Rails Routing Guide from top to bottom about three times and I can't figure it out. The closest I found to my problem was on an old Rails 3.1 gem problem with Devise, but I'm not even using the Devise gem (maybe I should be?).
Why is my route failing? I'm not really looking for a workaround (though I suppose I'd rather have a workaround than no solution), I want to understand why this is happening and fix it. What's going on?
My routes are pretty vanilla, nothing special going on there, but just in case the problem is there and I missed it, here it is.
config/routes.rb
Rails.application.routes.draw do
root 'static#home'
%w( 404 406 422 500 503 ).each do |code|
get code, :to => "errors#show", :code => code
end
#USER PAGES
get '/test' => 'users#test'
get '/signup' => 'users#new'
post '/user' => 'users#create'
get '/user/list' => 'users#index'
post '/user/' => 'users#update'
get '/user/:id' => 'users#show'
get 'profile', to: 'users#show'
resources :users
end
I'd suggest updating your routes as follows:
config/routes.rb
Rails.application.routes.draw do
root 'static#home'
%w( 404 406 422 500 503 ).each do |code|
get code, :to => "errors#show", :code => code
end
#USER PAGES
get '/test' => 'users#test'
get 'profile', to: 'users#show', as: :user_profile
resources :users
end
...as resources :users creates all of the routes I've removed.
The duplicates may have been overwriting a default path, causing the behaviour you're seeing - if you pass an object to a url helper that doesn't expect a parameter, you see the behaviour you're getting (i.e. doesnt_have_an_id_path(#object) => /doesnt_have_an_id.1).
I've also added a name to the user profile path to avoid this clashing. See if this works (perhaps one step at a time to get the cause and effect) - otherwise, try temporarily removing the profile route.
Re that path, you may have a problem in that the users#show action will expect an :id parameter, yet that route doesn't allow for one. This might be causing the current problem, though if not, may cause issues down the line.
Hope that fixes it - shout if you've any questions / feedback when you've tried it out.
In your case the two conflicting routes are:
post '/user/' => 'users#update'
get '/user/:id' => 'users#show'
You are trying to use user_path helper method, thus you need to have user named route.
If you run rake routes for these two routes you will see this:
Prefix Verb URI Pattern Controller#Action
user POST /user(.:format) users#create
GET /user/:id(.:format) users#show
The Prefix column shows you the named routes which are defined for your application. In this case Rails auto-generated named route user for POST /user endpoint. That means user_path will return /user instead of /user/:id as you expected. Rails generate routes like these when it sees a route definition without parameters. For example if you have get /user/some/more in your routes, Rails will auto-generate named route user_some_more for you and they you will be able to use user_some_more_path helper.
In order to fix your particular case you can stop rails from generating route for POST endpoint by doing this: post '/user/', as: nil and give GET endpoint a name you want: get '/user/:id', as: 'user'. Then you will be able to use user_path(user) to generate paths of format /user/:id.

Rails set show action rooting as post request

In my rails app i have such route for carts controller:
resources :carts
so in layout, according to my logic i have:
= link_to "Моя корзина", #cart
and in browser i see for example:
******:3000/carts/112
Could i however do nested rails route show as post-like request? so i will have:
******:3000/carts/
also rake routes:
arts GET /carts(.:format) carts#index
POST /carts(.:format) carts#create
new_cart GET /carts/new(.:format) carts#new
edit_cart GET /carts/:id/edit(.:format) carts#edit
cart GET /carts/:id(.:format) carts#show
PUT /carts/:id(.:format) carts#update
DELETE /carts/:id(.:format) carts#destroy
cart POST /carts/:id(.:format) carts#show
I now how to write it for my own methods... But how to be with build-in show?
i need to change show route, so that id for show is sending not as get-param by url, but as post-param in request...
you could add routes like this (routes.rb)
Ex:
resources :carts do
member do
post :add
end
end
more about rails routes
The resources method simply puts in a bunch of predefined routes, as described here.
Specifically, it is adding the equivalent of
get '/carts/:id' => 'carts_controller#show'
post '/carts' => 'carts_controller#create'
...
If you want to use a different set of routes, don't use resources, and just define your own routes instead.
Also, you can't hide the cart id from the user this way. If the request contains the ID, it means that the user can see it. He might have to view it with Firebug or by looking at the page source instead of his address bar, but it's still not secret or protected in any way.
Just run rake routes in your console and see the routes you have.
Also you can read more about RESTful routes at http://guides.rubyonrails.org/routing.html#crud-verbs-and-actions

Pass value to controller from link name Rails

I have a list of names, that contain this:
<td><%= product.date %></td>
and it is in my index page. (It is the list of my applications)
I want to assign a custom link to that, and pass THAT value to the controller:
I tried this:
<td><%= link_to product.date, {:controller => "product", :action => "sort_by_date", <how do I pass the 'product.date' string?> }%></td>
I read the rails route guide but I couldn't find help
Thanks
what rakes routes returns:
products GET /products(.:format) products#index
POST /products(.:format) products#create
new_product GET /products/new(.:format) products#new
edit_product GET /products/:id/edit(.:format) products#edit
product GET /products/:id(.:format) products#show
PUT /products/:id(.:format) products#update
DELETE /products/:id(.:format) products#destroy
root /
products#home.html
use like below
<%= link_to product.date, {:controller => "product", :action => "sort_by_date", :product_date => product.date %>
and in your controller you should get the date in params[:product_date]
You can also use resource helper function to pass custom parameters like below.
<%= link_to product.date, products_path(:product_date => product.date)
This method will route to the ProductsController#index with a params[:product_date]
Edit:
I just tried with following
resources :products do
collection do
get 'sort_by_date' => 'products#sort_by_date'
end
end
The rake routes are as following
sort_by_date_products GET /products/sort_by_date(.:format) products#sort_by_date
To generate the URL it will be better to use the resource helper function like below
sort_by_date_products_path(:product_date => '1/1/2012')
This will generate a url like /product/sort_by_date?product_date=1/1/2012 which will call the sort_by_date method of ProductsController and also have params[:product_date] available.
Lets check if its work...

ruby on rails no route matches action :delete

I'm setting up friendships within a RoR website. The model for it is user_id, friend_id, and pending (boolean). I followed the RailsCast on friendships for the most part, but making some changes to it too. What I have so far is that when you go to a user's page you can click Request Friendship and the code uses:
user_friendships_path(current_user, :friend_id => #user), :method => :post
This calls the create method in the Friendships controller. It automatically sets pending to true. What I want now is to have a link to Accept it which would just turn pending to false. So I am trying to set it up like
(<%= link_to "Accept", user_friendship_path(:user_id => current_user.id, :friend_id => friendship.user.id, :pending => 'false'), :method => :put %>)
I don't actually want to go to the edit page, because it just needs to set that boolean to false, so I want to call the update directly. But when I run this page, I get the error:
No route matches {:action=>"destroy", :controller=>"friendships", :user_id=>1, :friend_id=>2, :pending=>"false"}
I don't understand why. I'm not calling the destroy (that would be with :method => :delete), and there actually is a destroy method within the Friendship controller.
The resources are set up like:
resources :users do
resources :friendships
end
And the paths from running "rake routes" are:
user_friendships GET /users/:user_id/friendships(.:format) {:action=>"index", :controller=>"friendships"}
user_friendships POST /users/:user_id/friendships(.:format) {:action=>"create", :controller=>"friendships"}
new_user_friendship GET /users/:user_id/friendships/new(.:format) {:action=>"new", :controller=>"friendships"}
edit_user_friendship GET /users/:user_id/friendships/:id/edit(.:format) {:action=>"edit", :controller=>"friendships"}
user_friendship GET /users/:user_id/friendships/:id(.:format) {:action=>"show", :controller=>"friendships"}
user_friendship PUT /users/:user_id/friendships/:id(.:format) {:action=>"update", :controller=>"friendships"}
user_friendship DELETE /users/:user_id/friendships/:id(.:format) {:action=>"destroy", :controller=>"friendships"}
Any help would be greatly appreciated. Please let me know if you require more information.
Thanks.
The path that exists according to rake routes is
user_friendship PUT /users/:user_id/friendships/:id(.:format) {:action=>"update", :controller=>"friendships"}
The method you are using is put, but you aren't supplying ':id'.
There are two solutions depending on what you are trying to do:
Change the method to get - that will point you to the new action
Add :id to your URL builder - that will point you to the update action
Your code is leaning towards the second, but I think if you want to create a new friendship, the first would be better.
I'm baffled as to why the URL helper is mapping to a destroy action. However there is a simpler problem: user_friendship_path expects params :user_id and :id, not :friend_id.

Resources