Ruby on Rails - Path variable without using resources route - ruby-on-rails

I have a controller, let's just call it FruitsController, that grabs all of the fruit and sends it to the index view. In the view, I want to show links to the individual pages for those fruits. I'm using the format:
<% #fruits.each do |fruit| %>
<%= link_to fruit.name, fruit_path(fruit) %>
<% end %>
And this works great when I have the route resources :fruits, but I don't want routes for deleting, saving, and updating, so I don't want to use resources. But when I just do individual routes for showing all and individual fruits, I get the error fruit_path function is not defined, and when I use the function fruits_path it works but it just appends a period to the path like /fruits.1. How can I use the fruit_path function without using resources? Thanks.

There are a number of ways you could do this; in your config/routes.rb, any of the following should work:
resources :fruits, only: :show
resources :fruits, except: [:index, :edit, :destroy, :update] # etc
get 'fruits/:id', to: 'fruits#show', as: :fruit
scope controller: :fruits do
get 'fruits/:id' => :show, as: :fruit
end

You're not limited to just resources, you can customize and create your own routes, for example:
get '/:username/photos', to: 'users#show', as: 'collage'
to: means controller/action, in this case users is the controller and show is the action.
as: creates a path for you 'collage_path'
you can find good info regarding routing =>http://guides.rubyonrails.org/routing.html

Related

How should I set up this form to submit to the correct path?

I have products that have many variants. When I edit and submit the variant I need it to stay connected to the product. So the URl would be localhost/products/1/variants/3/. The way it is right now it is submitting to localhost/variants/3 and errors out because it cannot find the product?
<%= form_with(model: variant, local: true) do |form| %>
Edit. Routes:
resources :variants
resources :products do
resources :option_values
resources :option_value_variants
resources :variants do
collection do
post :update_positions
end
end
end
When you edit and submit the variant, you don't need to create a nested route. The product_id will already be saved with the variant (from when it was created). So need to use a nested route - you only need nested routes for new and create actions, that is called "shallow nesting". Because only in those two actions you don't have access to the product id in any other way than through the url (params).
The error in your code likely comes from the fact that you created a nested route but you are not giving the product instance to the form:
%= form_with(model: [#product, #variant], local: true) do |form| %>
But as stated above, no need for that here, just change your routes accordingly.
After updating the question:
So for shallow routing your routes should look like this:
resources :variants, only: [:index, :show, :edit, :update, :destroy]
resources :products do
...
resources :variants, only [:create, :new] do
collection do
post :update_positions
end
end
end
Only create and new need to be nested, for the other routes you don't need it.

change routes URL from a random :id to :username in rails

I want to change my routes.rb file in a way so that it changes my current urls
localhost:3000/amitian/1
to localhost:3000/username
I will provide my routes.rb file for reference
Rails.application.routes.draw do
devise_for :amitians
root 'home#index'
resources :amitians do
member do
get :following, :followers
end
end
resources :confessions do
member do
get 'like' , to: 'confessions#upvote'
get 'dislike' , to: 'confessions#downvote'
end
resources :confessioncomments
end
resources :relationships, only: [:create, :destroy]
end
As Gregg mentioned, you can change the name of the parameter using:
resources :amitians, param: :username
But you're essentially just renaming a variable. Whether you expect an id or a username is determined in the controller action amitians#show:
#amitian = Amitian.find(param[:id]) # Treat :id as id
#amitian = Amitian.find_by_username(param[:id]) # Treat :id as username
Now, if you want to specifically route to /:username rather than /amitians/:username, you'll have to override that resource route:
resources :amitians, except: [:show] do
member do
get :following, :followers
end
end
get '/:username', to: 'amitians#show'
However, I would recommend against that. Having a parameter directly off root will cause lots of confusion for you when users type in the incorrect url and get a user page instead of a 404 error. Or even worse, what if a user chooses the username 'login' or 'register'? Either your register page would be unreachable or else that user's page would be.
I should also point out that rails convenience methods such as resources, Amitian.find, url_for #amitian, link_to #amitian etc. all use the REST standard which uses numerical IDs.
If you want to use a username instead of IDs, you'll have to stop relying on these methods and change your controllers and views, in addition to your routes file.
In rails 4 you can do the following in the route
resources :amitians, param: :username

Adding member or alias to existing path in Rails 3

For the jobs -> apply action I want to "alias" the "create" action.
In rake routes it would look something like this:
https://gist.github.com/YOUConsulting/19b404759757898a6f4f#file-rake_routes-rb
I've tried to do it like this but I think this is not exactly what I'm looking for:
resources :jobs, :only => [:show, :index, :create] do
resources :apply, :only => [:index, :create] do
member do
post :completed
end
end
resources :share, :only => [:index, :create]
end
In human words:
When the user submits the page located at "/jobs/<job_id_here>/apply" (the index view) the result page (the create view) should be "/jobs/<job_id_here>/apply/completed" instead of "/jobs/<job_id_here>/apply/" .
Reason:
When we track users via Google Analytics we can't see if they submitted the form successfully since there is no difference between "/apply" and "/apply" .
Hm, what about using a named route as path
Add a line at the end of your routes.rb
post '/jobs/:job_id/apply/completed', to: apply#create as: apply_job
And then in your new.html.haml
form_for :job, apply_job_path
This should call the create action of your apply controller.
Instead of apply you can use of course any name you want.

how to fill twice id from routes rails

i try to fill twice id in url, but when i send params twice id just one id fill the url id.
My route :
namespace :admin do
resources :stores
get "/:id/new_items"=> 'stores#new_items', as: :store_new_items
post "/:id/create_items"=> 'stores#create_items', as: :store_create_items
get "/:id/show_items/:id"=> 'stores#show_items', as: :store_show_items
get "/:id/items/:id/new_items_sub" => 'stores#new_items_sub', as: :store_new_items_sub
post "/:id/items/:id/create_items_sub" => 'stores#create_items_sub', as: :store_create_items_sub
get "/:id/items/:id/show_items_sub/:id" => 'stores#show_items_sub', as: :store_show_items_sub
end
my view :
<%= link_to "add new items", admin_store_new_items_sub_path(#store.id, #items.id), :class=> "btn" %>
i hope my url like this :
http://localhost:3000/admin/#{store.id}/items/#{items.id}/new_items_sub
but i get same id like this :
http://localhost:3000/admin/#{store.id}/items/#{store.id}/new_items_sub
please tell me when i'm wrong? thanks
you have to create neseted routes for that .have a look at
http://guides.rubyonrails.org/routing.html#nested-resources
for example
resources :publishers do
resources :magazines do
resources :photos
end
end
will accept routes /publishers/1/magazines/2/photos/3
Your params should be unique, so you can't pass more than one different :id params. Instead. you can do something like:
get '/:store_id/show_items/:id', as: :store_show_items
and in view:
<%= link_to 'show items', store_show_items_path(#store.id, #item.id) %>
Also, you should read more about Resources and Nested Resources in Rails, there's probably no need to complicate your life by creating each route independently.
You could refactor this to use nested routes like this (you may have to change controller method names):
namespace :admin do
resources :stores do
resources :items, :only => [:new, :create, :show] do
resources :subs, :only => [:new, :create, :show]
end
end
end
This would give you a few url helpers like this: new_store_item_sub_path(#store.id, #item.id) for the new action and store_item_sub_path(#store.id, #item.id, #sub.id) for the show action.
Run rake routes to see what helpers and routes you have access to.
Have a look here to find out more about nested routes.
Your code can be DRYed up significantly. Hopefully this works; might need some tweaking:
namespace :admin do
resources :stores do
member do
get :new_items, as: :store_new_items
post :create_items, as: :store_create_items
end
get "show_items/:id"=> 'stores#show_items', as: :store_show_items
resources :items do
get :new_items_stub => 'stores#new_items_sub', as: :store_new_items_sub
post :create_items_stub => 'stores#create_items_sub', as: :store_create_items_sub
get "show_items_sub/:id" => 'stores#show_items_sub', as: :store_show_items_sub
end
end
end
Uses Member Routes (see 2.10) & Nested Resources
Nested Resources
The crux of your issue is that you're trying to pass the :id param twice
Fortunately, Rails has a solution to this, in the form of Nested Resources. These work by taking the "parent" id and prepending a singular prefix, such as :store_id, allowing you to use the :id param for another set of methods

Custom rails routing helper method

I am having issues getting my helper method names to work properly, any suggestions would be great:
#config/routes.rb
resources :junkie, only: [:show, :index, :destroy], as: :junkie do
get :merge, on: :collection
end
So I was having issues because I the singular form of junkies is junky, but when I make this change and look at the routes it changes the #merge helper to:
merge_junkie_index GET /junkies/merge(.:format) junkies#merge
Is there any way to change this to just merge_junkie? I tried removing it from the resource black and using the match syntax: get "junkies/merge" => "junkies#merge", as: :junkie but for some odd reason this directed me to the show method even though the route was right.
The solution is a ugly one but it works, since the show route is the only one that is affected by the as: :junkie you can break it out put the merge route in a separate block. The ordering of the resource also matters for some reason, if you do not put the merge first, it will interpret the url /junkie/merge/ as a id and hit the show action. So it should look like this in your routes file:
resources :junkies, only: [:index] do
get :merge, on: :collection
end
resources :junkies, only: [:show, :destroy], as: :junkie

Resources