Rails nested routes not working as expected - ruby-on-rails

I have nested resources in my routes like so. These work perfectly on my other rails 5 app, but not on my rails 6 app. I cannot figure out why it recognizes only the first level of nested stuff.
resources :blogs do
member do
put 'like', to: 'blogs#upvote'
put 'dislike', to: 'blogs#downvote'
end
resources :comments
member do
put 'like', to: 'comments#upvote'
put 'dislike', to: 'comments#downvote'
end
resources :notations
end
Here is what rake routes gives me:
blogs_user GET /users/:id/blogs(.:format) users#blogs
like_blog PUT /blogs/:id/like(.:format) blogs#upvote
dislike_blog PUT /blogs/:id/dislike(.:format) blogs#downvote
blog_comments GET /blogs/:blog_id/comments(.:format) comments#index
POST /blogs/:blog_id/comments(.:format) comments#create
new_blog_comment GET /blogs/:blog_id/comments/new(.:format) comments#new
edit_blog_comment GET /blogs/:blog_id/comments/:id/edit(.:format) comments#edit
blog_comment GET /blogs/:blog_id/comments/:id(.:format) comments#show
PATCH /blogs/:blog_id/comments/:id(.:format) comments#update
PUT /blogs/:blog_id/comments/:id(.:format) comments#update
DELETE /blogs/:blog_id/comments/:id(.:format) comments#destroy
PUT /blogs/:id/like(.:format) comments#upvote
PUT /blogs/:id/dislike(.:format) comments#downvote
notations GET /blogs/:id/notations(.:format) notations#index
POST /blogs/:id/notations(.:format) notations#create
new_notation GET /blogs/:id/notations/new(.:format) notations#new
edit_notation GET /blogs/:id/notations/:id/edit(.:format) notations#edit
notation GET /blogs/:id/notations/:id(.:format) notations#show
PATCH /blogs/:id/notations/:id(.:format) notations#update
PUT /blogs/:id/notations/:id(.:format) notations#update
DELETE /blogs/:id/notations/:id(.:format) notations#destroy
On my other app, for example, it would produce
/blogs/:blog_id/comments/:id/like

I make a copy of your routes and replicated in two apps (Rails 5 and Rails 6) and both produced same routes (without three nested level). If you want the /blogs/:blog_id/comments/:id/like route, you must do a small change.
resources :blogs do
member do
put 'like', to: 'blogs#upvote'
put 'dislike', to: 'blogs#downvote'
end
resources :comments do
member do
put 'like', to: 'comments#upvote'
put 'dislike', to: 'comments#downvote'
end
end
resources :notations
end

You are missing the "do" "end" block syntax
resources :blogs do
member do
put 'like', to: 'blogs#upvote'
put 'dislike', to: 'blogs#downvote'
end
resources :comments do # here
member do
put 'like', to: 'comments#upvote'
put 'dislike', to: 'comments#downvote'
end
resources :notations
end # and here
end
Anyway, more than two levels of nesting is discouraged by the rails guidelines.

Related

Ruby on Rails - routing to a new page

I would like to create a new route that leads to the url '../coins/:id/events/pending-events' however my new route is leading to '..coins/:coin_id/events/:event_id/pending-events' when I do this. What am I doing wrong here and how can I fix this?
routes.rb
resources :coins do
...
resources :events do
get 'pending-events', to: 'events#pending'
member do
put "like", to: "events#upvote"
put "dislike", to: "events#downvote"
end
end
...
end
event_controller.rb
...
def pending
#events = Event.where(coin_id: #coin.id).order("created_at DESC")
end
...
Just add on: :collection to your route e.g:
resources :coins do
...
resources :events do
get 'pending-events', to: 'events#pending', on: :collection
member do
put "like", to: "events#upvote"
put "dislike", to: "events#downvote"
end
end
...
end
More info: https://guides.rubyonrails.org/routing.html#adding-collection-routes
I suggest you do:
resources :coins do
resources :events do
collection do
get :pending
end
member do
put "like", to: "events#upvote"
put "dislike", to: "events#downvote"
end
end
end
Which will give you:
pending_coin_events GET /coins/:coin_id/events/pending(.:format) events#pending
like_coin_event PUT /coins/:coin_id/events/:id/like(.:format) events#upvote
dislike_coin_event PUT /coins/:coin_id/events/:id/dislike(.:format) events#downvote
coin_events GET /coins/:coin_id/events(.:format) events#index
POST /coins/:coin_id/events(.:format) events#create
new_coin_event GET /coins/:coin_id/events/new(.:format) events#new
edit_coin_event GET /coins/:coin_id/events/:id/edit(.:format) events#edit
coin_event GET /coins/:coin_id/events/:id(.:format) events#show
PATCH /coins/:coin_id/events/:id(.:format) events#update
PUT /coins/:coin_id/events/:id(.:format) events#update
DELETE /coins/:coin_id/events/:id(.:format) events#destroy
coins GET /coins(.:format) coins#index
POST /coins(.:format) coins#create
new_coin GET /coins/new(.:format) coins#new
edit_coin GET /coins/:id/edit(.:format) coins#edit
coin GET /coins/:id(.:format) coins#show
PATCH /coins/:id(.:format) coins#update
PUT /coins/:id(.:format) coins#update
DELETE /coins/:id(.:format) coins#destroy
No need to specify to: and pending_coin_events_path reads nicely.
Personally, I would do:
resources :coins do
resources :events do
collection do
get :pending
end
member do
put :upvote
put :downvote
end
end
end
Which will give you:
pending_coin_events GET /coins/:coin_id/events/pending(.:format) events#pending
upvote_coin_event PUT /coins/:coin_id/events/:id/upvote(.:format) events#upvote
downvote_coin_event PUT /coins/:coin_id/events/:id/downvote(.:format) events#downvote
coin_events GET /coins/:coin_id/events(.:format) events#index
POST /coins/:coin_id/events(.:format) events#create
new_coin_event GET /coins/:coin_id/events/new(.:format) events#new
edit_coin_event GET /coins/:coin_id/events/:id/edit(.:format) events#edit
coin_event GET /coins/:coin_id/events/:id(.:format) events#show
PATCH /coins/:coin_id/events/:id(.:format) events#update
PUT /coins/:coin_id/events/:id(.:format) events#update
DELETE /coins/:coin_id/events/:id(.:format) events#destroy
coins GET /coins(.:format) coins#index
POST /coins(.:format) coins#create
new_coin GET /coins/new(.:format) coins#new
edit_coin GET /coins/:id/edit(.:format) coins#edit
coin GET /coins/:id(.:format) coins#show
PATCH /coins/:id(.:format) coins#update
PUT /coins/:id(.:format) coins#update
DELETE /coins/:id(.:format) coins#destroy
I like that better because:
You're doing less typing
Your action and paths are parallel
Symbols are (IMO) prettier and subject to fewer typos
But, that's just me.

Rails adding a random path to URLs

So when the link to my website is clicked (not typed), rails app adds paths to url like
http://www.drolle.co/NgOLZ/posts/187
the "NgOLZ" is added and it's unique every time.
I have no idea why. Here's my code:
# Define root URL
root 'pages#index'
resources :posts do
resources :comments do
member do
put "like", to: "comments#upvote"
put "dislike", to: "comments#downvote"
end
resources :replies do
member do
put "like", to: "replies#upvote"
put "dislike", to: "replies#downvote"
end
end
end
member do
put "like", to: "posts#upvote"
put "dislike", to: "posts#downvote"
put "report", to: "posts#report"
end
end
And in the logs
ActionController::RoutingError: No route matches [GET] "/NgOLZ/posts/187"
the extra letters are added even with http://drolle.co
I did have an error with a missing nodejs module so I added universalify, may be this has to do with it? I don't really know.
Thanks for helping.

Nested routes without resources

I have an application with an object, movies, that doesn't use some of the standard RESTful routes. I don't want the 'new' route to lead anywhere.
The problem is I have 'movies' with a nested resource 'reviews'
resources :movies do
resources :reviews
end
I want this style of routing:
get '/movies', to: "movies#index"
But with nested routes. Is this possible? I'm sure there's answer to this somewhere on this site, but I can't find it.
You can simply do:
resources :movies, :only => [:index] do
resources :reviews
end
Which will give you:
movie_reviews GET /movies/:movie_id/reviews(.:format) reviews#index
POST /movies/:movie_id/reviews(.:format) reviews#create
new_movie_review GET /movies/:movie_id/reviews/new(.:format) reviews#new
edit_movie_review GET /movies/:movie_id/reviews/:id/edit(.:format) reviews#edit
movie_review GET /movies/:movie_id/reviews/:id(.:format) reviews#show
PATCH /movies/:movie_id/reviews/:id(.:format) reviews#update
PUT /movies/:movie_id/reviews/:id(.:format) reviews#update
DELETE /movies/:movie_id/reviews/:id(.:format) reviews#destroy
movies GET /movies(.:format) movies#index

How do you create links in Rails using link.to

Hi im doing a kind of blog to learn Rails, using the Getting started tutorials like these
http://guides.rubyonrails.org/getting_started.html
http://guides.rubyonrails.org/routing.html
I have manage to do the posts sections and i also do a admin/posts section, this is the problem now..
Ths system is "conflicting" and admin goes to domain.com/posts instead of admin/posts.
I think the problem is the way i build the links..
In the tutorial to link a item yo do
<h2><%= link_to post.title, post %></h2>
I have tried
<h2><%= link_to post.title, admin_post_path %></h2>
And similars but i get
undefined local variable or method `admin_post_path' for #<#<Class:0x007fe3e990ef28>:0x007fe3e6e3b508>
How does this works i mean i have done rake routes and i see there the routes, but i cant use them
new_user_session GET /users/sign_in(.:format) devise/sessions#new
user_session POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
user_password POST /users/password(.:format) devise/passwords#create
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
PUT /users/password(.:format) devise/passwords#update
cancel_user_registration GET /users/cancel(.:format) registrations#cancel
user_registration POST /users(.:format) registrations#create
new_user_registration GET /users/sign_up(.:format) registrations#new
edit_user_registration GET /users/edit(.:format) registrations#edit
PUT /users(.:format) registrations#update
DELETE /users(.:format) registrations#destroy
users GET /admin/users(.:format) admin/users#index
POST /admin/users(.:format) admin/users#create
new_user GET /admin/users/new(.:format) admin/users#new
edit_user GET /admin/users/:id/edit(.:format) admin/users#edit
user GET /admin/users/:id(.:format) admin/users#show
PUT /admin/users/:id(.:format) admin/users#update
DELETE /admin/users/:id(.:format) admin/users#destroy
posts GET /admin/posts(.:format) admin/posts#index
POST /admin/posts(.:format) admin/posts#create
new_post GET /admin/posts/new(.:format) admin/posts#new
edit_post GET /admin/posts/:id/edit(.:format) admin/posts#edit
post GET /admin/posts/:id(.:format) admin/posts#show
PUT /admin/posts/:id(.:format) admin/posts#update
DELETE /admin/posts/:id(.:format) admin/posts#destroy
players GET /players(.:format) players#index
POST /players(.:format) players#create
new_player GET /players/new(.:format) players#new
edit_player GET /players/:id/edit(.:format) players#edit
player GET /players/:id(.:format) players#show
PUT /players/:id(.:format) players#update
DELETE /players/:id(.:format) players#destroy
player_steps GET /player_steps(.:format) player_steps#index
POST /player_steps(.:format) player_steps#create
new_player_step GET /player_steps/new(.:format) player_steps#new
edit_player_step GET /player_steps/:id/edit(.:format) player_steps#edit
player_step GET /player_steps/:id(.:format) player_steps#show
PUT /player_steps/:id(.:format) player_steps#update
DELETE /player_steps/:id(.:format) player_steps#destroy
coach_steps GET /coach_steps(.:format) coach_steps#index
POST /coach_steps(.:format) coach_steps#create
new_coach_step GET /coach_steps/new(.:format) coach_steps#new
edit_coach_step GET /coach_steps/:id/edit(.:format) coach_steps#edit
coach_step GET /coach_steps/:id(.:format) coach_steps#show
PUT /coach_steps/:id(.:format) coach_steps#update
DELETE /coach_steps/:id(.:format) coach_steps#destroy
candidates GET /candidates(.:format) candidates#index
POST /candidates(.:format) candidates#create
new_candidate GET /candidates/new(.:format) candidates#new
edit_candidate GET /candidates/:id/edit(.:format) candidates#edit
candidate GET /candidates/:id(.:format) candidates#show
PUT /candidates/:id(.:format) candidates#update
DELETE /candidates/:id(.:format) candidates#destroy
payment_notifications GET /payment_notifications(.:format) payment_notifications#show
post GET /posts/:id(.:format) posts#show
posts GET /posts(.:format) posts#index
admin_posts_path GET /admin/posts(.:format) admin/posts#index
admin_posts_path POST /admin/posts(.:format) admin/posts#index
admin_post_path GET /admin/posts/:id(.:format) admin/posts#show
new_admin_post_path GET /admin/posts/new(.:format) admin/posts#new
/*a(.:format) errors#routing
choose GET /user_type(.:format) home#user_type
root / devise/sessions#new
Also tried this
<h2><%= link_to post.title, url_for([#post]) %></h2>
this throw:::: Nil location provided. Can't build URI.
=( any documentation on doing this, ?? do you know where i can find it
Routes.rb
Consult::Application.routes.draw do
devise_for :users, :controllers => { :registrations => "registrations" }
scope "/admin" do
resources :users, :controller => 'admin/users'
resources :posts, :controller => 'admin/posts'
end
resources :players
resources :player_steps
resources :coach_steps
resources :candidates
resource :payment_notifications, :only => :show
#match 'candidates' => 'candidates#index'
#resources :posts
get '/posts/:id', to: 'posts#show', as: 'post'
get '/posts/', to: 'posts#index', as: 'posts'
get '/admin/posts/', to: 'admin/posts#index', as: 'admin_posts_path'
post '/admin/posts/', to: 'admin/posts#index', as: 'admin_posts_path'
get '/admin/posts/:id', to: 'admin/posts#show', as: 'admin_post_path'
get '/admin/posts/new', to: 'admin/posts#new', as: 'new_admin_post_path'
match '*a', :to => 'errors#routing'
# The priority is based upon order of creation:
# first created -> highest priority.
# Sample of regular route:
# match 'products/:id' => 'catalog#view'
# Keep in mind you can assign values other than :controller and :action
# Sample of named route:
# match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase
# This route can be invoked with purchase_url(:id => product.id)
# Sample resource route (maps HTTP verbs to controller actions automatically):
# resources :products
# Sample resource route with options:
# resources :products do
# member do
# get 'short'
# post 'toggle'
# end
#
# collection do
# get 'sold'
# end
# end
# Sample resource route with sub-resources:
# resources :products do
# resources :comments, :sales
# resource :seller
# end
# Sample resource route with more complex sub-resources
# resources :products do
# resources :comments
# resources :sales do
# get 'recent', :on => :collection
# end
# end
# Sample resource route within a namespace:
# namespace :admin do
# # Directs /admin/products/* to Admin::ProductsController
# # (app/controllers/admin/products_controller.rb)
# resources :products
# end
# You can have the root of your site routed with "root"
# just remember to delete public/index.html.
#root :to => "devise/sessions#new"
get 'user_type', to: 'home#user_type', as: :choose
devise_scope :user do
root :to => "devise/sessions#new"
end
# See how all your routes lay out with "rake routes"
# This is a legacy wild controller route that's not recommended for RESTful applications.
# Note: This route will make all actions in every controller accessible via GET requests.
# match ':controller(/:action(/:id))(.:format)'
end
Try using namespace, as opposed to the scope, as the namespace is much better for nesting. your routes file should look something like this.
namespace :admin do
resources :users
resources :posts
end
resources :players
resources :player_steps
resources :coach_steps
resources :candidates
resource :payment_notifications, :only => :show
#match 'candidates' => 'candidates#index'
resources :posts
you can remove
get '/posts/:id', to: 'posts#show', as: 'post'
get '/posts/', to: 'posts#index', as: 'posts'
get '/admin/posts/', to: 'admin/posts#index', as: 'admin_posts_path'
post '/admin/posts/', to: 'admin/posts#index', as: 'admin_posts_path'
get '/admin/posts/:id', to: 'admin/posts#show', as: 'admin_post_path'
get '/admin/posts/new', to: 'admin/posts#new', as: 'new_admin_post_path'
as the namespace and the resources handle their generation
full routes file should be
Consult::Application.routes.draw do
devise_for :users, :controllers => { :registrations => "registrations" }
namespace :admin do
resources :users
resources :posts
end
resources :players
resources :player_steps
resources :coach_steps
resources :candidates
resources :posts
resource :payment_notifications, :only => :show
get 'user_type', to: 'home#user_type', as: :choose
devise_scope :user do
root :to => "devise/sessions#new"
end
end

How to re-name routes?

I have nested routes on my site for Sections and Pages.
resources :sections do
resources :pages
end
This is a sample URL:
sitename.com/sections/5/pages/22
I don't like the name 'sections', and would prefer 'chapters'.
sitename.com/chapters/5/pages/22
I assume re-naming the model would be to complicated, so how can I just re-name the route easily?
Pass your desired URL segment name as the value to the path argument:
resources :sections, :path => :chapters do
resources :pages
end
This results the the following routes:
section_pages GET /chapters/:section_id/pages(.:format) pages#index
POST /chapters/:section_id/pages(.:format) pages#create
new_section_page GET /chapters/:section_id/pages/new(.:format) pages#new
edit_section_page GET /chapters/:section_id/pages/:id/edit(.:format) pages#edit
section_page GET /chapters/:section_id/pages/:id(.:format) pages#show
PUT /chapters/:section_id/pages/:id(.:format) pages#update
DELETE /chapters/:section_id/pages/:id(.:format) pages#destroy
sections GET /chapters(.:format) sections#index
POST /chapters(.:format) sections#create
new_section GET /chapters/new(.:format) sections#new
edit_section GET /chapters/:id/edit(.:format) sections#edit
section GET /chapters/:id(.:format) sections#show
PUT /chapters/:id(.:format) sections#update
DELETE /chapters/:id(.:format) sections#destroy

Resources