rails, adding a parameter to new route - ruby-on-rails

The new action normally doesn't require parameters, since it creates a new resource from scratch.
In my application whenever i create a certain type of resource say a book i need to provide a template, that is the id of another book. So my new route always has a parameter.
I don't know how to represent this fact into routes.rb file.
Since i don't even know whether it is feasible, just in the case it isn't, then i will create a new_wp, a "new with parameter" action.
I tried to add it to my
resources :books, :only => [:edit, :update, :show, :new] do
member do
get 'new_wp/:template_id', :action => 'new_wp'
end
end
but rake routes say that it isn't quite what i want:
GET /books/:id/new_wp/:template_id(.:format) books#new_wp
that is, it has two params.

I do this often, the easiest way, I believe is to just adjust the path_names. That way your route names don't get messed up. Let me explain.
Scenario 1 - Standard Rails
Code
resources :books
Output
books GET /books(.:format) books#index
POST /books(.:format) books#create
new_book GET /books/new(.:format) books#new
edit_book GET /books/:id/edit(.:format) books#edit
book GET /books/:id(.:format) books#show
PATCH /books/:id(.:format) books#update
PUT /books/:id(.:format) books#update
DELETE /books/:id(.:format) books#destroy
Scenario 2 - Chris Heald Version
Code
resources :books do
get "new/:template_id", to: "books#new_wp", on: :collection
end
# You can also do, same result with clearer intention
# resources :books do
# get ":template_id", to: "books#new_wp", on: :new
# end
Output
GET /books/new/:template_id(.:format) books#new_wp
books GET /books(.:format) books#index
POST /books(.:format) books#create
new_book GET /books/new(.:format) books#new
edit_book GET /books/:id/edit(.:format) books#edit
book GET /books/:id(.:format) books#show
PATCH /books/:id(.:format) books#update
PUT /books/:id(.:format) books#update
DELETE /books/:id(.:format) books#destroy
Scenario 3 - My preferred and noted by steakchaser above
Code
resources :books, path_names: {new: 'new/:template_id' }
Output
books GET /books(.:format) books#index
POST /books(.:format) books#create
new_book GET /books/new/:template_id(.:format) books#new
edit_book GET /books/:id/edit(.:format) books#edit
book GET /books/:id(.:format) books#show
PATCH /books/:id(.:format) books#update
PUT /books/:id(.:format) books#update
DELETE /books/:id(.:format) books#destroy
You will notice that in scenario 2 you are missing a path name, which means you would want to add an as: :new which would generate new_new_book. Fixing this you can change from get ":template_id" ... to get path: ":template_id"... which will generate new_book
My preference is scenario 3 if all you want to do is pass arguments for new. If you want to change the action then you would want to consider using scenario 2 but exclude :new from the resource or in your case don't add :new to the only: argument.

Try:
resource ...
get "new/:template_id", :to => "Books#new_wp", :on => :collection
end
# GET /books/new/:template_id(.:format) Books#new_wp

Related

Creating a link to a rails route

Rails 5.2.3
In my routes.rb, I have:
get '/books/:author', to: 'books#index'
get '/books/:author/show', to: 'books#show'
post '/books/:author/create', to: 'books#create'
Which, when running rake: routes, gives me:
GET /books/:author(.:format) books#index
GET /books/:author/show(.:format) books#show
POST /books/:author(.:format) books#create
When a route helper is not provided by rake: routes, can I assume that when I create a link to it in a view, I can use use the model name, like: books_path or books_url? something like:
= link_to books_path(:author => #author), :method => :post
I tried it, but I am getting an error message:
undefined method books_path
So, I am either doing something wrong in routes.rb, or I am not referencing it correctly?
You are creating an unnamed route. I think what you want in your particular situation is:
resources :books, only: [:index, :show, :create], param: :author
That will give:
Prefix Verb URI Pattern Controller#Action
books GET /books(.:format) books#index
POST /books(.:format) books#create
book GET /books/:author(.:format) books#show
This does not seem RESTful to me though. I think what you really want is a nested resource between books and authors. Check out the Rails guides on routing for more information: https://guides.rubyonrails.org/routing.html
Just to pile on, I suggest you use nested routes:
resources :authors do
resources :books, shallow: true
end
resources :books, only: [:index, :create, :new]
Which will give you (amongst other things):
author_books GET /authors/:author_id/books(.:format) books#index
POST /authors/:author_id/books(.:format) books#create
new_author_book GET /authors/:author_id/books/new(.:format) books#new
edit_book GET /books/:id/edit(.:format) books#edit
book GET /books/:id(.:format) books#show
PATCH /books/:id(.:format) books#update
PUT /books/:id(.:format) books#update
DELETE /books/:id(.:format) books#destroy
authors GET /authors(.:format) authors#index
POST /authors(.:format) authors#create
new_author GET /authors/new(.:format) authors#new
edit_author GET /authors/:id/edit(.:format) authors#edit
author GET /authors/:id(.:format) authors#show
PATCH /authors/:id(.:format) authors#update
PUT /authors/:id(.:format) authors#update
DELETE /authors/:id(.:format) authors#destroy
books GET /books(.:format) books#index
POST /books(.:format) books#create
new_book GET /books/new(.:format) books#new
That ought to give you everything you need to manage authors and books.
I don't get how post '/books/:author/create', to: 'books#create' gives you POST /books/:author(.:format) books#create.
If you want to name your custom routes add the name with the :as option: get 'something', to: 'controller#action', as: 'something' to get "something_path" as a valid helper.
Note that you are going away from RESTful routes, if you want rails to do the things it usually do (like the named routes helpers) you should stick with it's conventions: https://guides.rubyonrails.org/routing.html
It's books_author_path, most likely.
Just remember what you're doing is not good practice at all. (It's actually beyond terrible for a coc framework like Ruby).
First of all, nested new routes are fine but nested create routes are generally considered bad.
Second, why is books/author_id/create creating a book?
It should be authors/author_id/books/new to books/create
Go into your console and type in "rails routes" and it'll tell you what all the helper urls are

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

No route matches {:controller=>"comments", :action=>"create"} - It does

Edit: I've seen a number of these but couldn't find an answer to this so I'm attempting to document it as best I can and asking this question.
I have a model-less rails app (calling an API) with a nested comments resource. I am able to post a comment against a story if I go directly to the comments#new or comments#index action and accordingly post to the comments#create action.
However I'd like very much to be able to post a comment on the same page as the #show action of the parent resource: (opusses#show)
I've tried using the rails url_helper path from rake routes as opuss_comments_path and explicitly stating the controller and action. In both cases I still get this message:
No route matches {:controller=>"comments", :action=>"create"}
Here is my routes db:
resources :users
resources :sessions, only: [:new, :create, :destroy]
resources :osessions, only: [:new, :create, :destroy]
resources :authors do
member do
get :following
get :followed
post :follow
end
end
resources :opusses do
resources :comments
member do
get :like
get :authorfeed
post :repost
end
end
And my Rake Routes:
DELETE /authors/:id(.:format) authors#destroy
opuss_comments GET /opusses/:opuss_id/comments(.:format) comments#index
POST /opusses/:opuss_id/comments(.:format) comments#create
new_opuss_comment GET /opusses/:opuss_id/comments/new(.:format) comments#new
edit_opuss_comment GET /opusses/:opuss_id/comments/:id/edit(.:format) comments#edit
opuss_comment GET /opusses/:opuss_id/comments/:id(.:format) comments#show
PUT /opusses/:opuss_id/comments/:id(.:format) comments#update
DELETE /opusses/:opuss_id/comments/:id(.:format) comments#destroy
&&
like_opuss GET /opusses/:id/like(.:format) opusses#like
authorfeed_opuss GET /opusses/:id/authorfeed(.:format) opusses#authorfeed
repost_opuss POST /opusses/:id/repost(.:format) opusses#repost
opusses GET /opusses(.:format) opusses#index
POST /opusses(.:format) opusses#create
new_opuss GET /opusses/new(.:format) opusses#new
edit_opuss GET /opusses/:id/edit(.:format) opusses#edit
opuss GET /opusses/:id(.:format) opusses#show
PUT /opusses/:id(.:format) opusses#update
DELETE /opusses/:id(.:format) opusses#destroy
When I call the code below from comments#index page it works perfectly. However it's quite common to post to another form from a different controller and when I call this code from the opusses#show page it fails with the error above.
On the off chance it had to do with the URL helper, I tried specifying the controller and action explicitly and that still didn't work - generated the same error.
Classic newbie mistake, but for others benefit =>
I had rake routes and I had the path correct, what I wasn't doing was submitting a the id of the parent resource. So POST to the path and include the object in question. In my case this mean opuss_comments_path(#opuss["xyz"]) where xyz was the id of my object.
opuss_comments GET /opusses/:opuss_id/comments(.:format) comments#index
POST /opusses/:opuss_id/comments(.:format) comments#create
Ah.. learning. :)
Based on your routes, You shouldn't have to use a url helper. but you do have to make sure that you have a handle on the Opuss object in the controller. so do something like this ;
#opuss = Opuss.find(params[:id]) #or your equivalent finder code
#comment = #opuss.comments.build
and then in your view;
<%= form_for([#opuss, #comment]) do |f| %>
.... rest of form
<% end %>

Rails routing error: No route matches [POST] "/students/1"

I'm getting a routing error: No route matches [POST] "/students/1" that I can't figure out. Here are the details.
view code:
<% #students.each do |student| %>
.
.
<td><%= link_to 'Show', student %></td>
<td><%= link_to 'Edit', edit_student_path(student) %></td>
<td><%= link_to 'Select Subjects', select_path(student) %></td> # error occurs here
In my students controller:
def select
.
.
end
routes.rb:
HomeSchool::Application.routes.draw do
resources :notes
resources :assignments
resources :subjects do
resources :assignments, :only => [:create, :index, :new]
end
resources :students
resources :resources
match "students/:id/select" => "students#select", :as => :select
root :to => 'students#index'
end
The output from rake routes is:
GET /students/:id/select(.:format) students/:id#select
notes GET /notes(.:format) notes#index
POST /notes(.:format) notes#create
new_note GET /notes/new(.:format) notes#new
edit_note GET /notes/:id/edit(.:format) notes#edit
note GET /notes/:id(.:format) notes#show
PUT /notes/:id(.:format) notes#update
DELETE /notes/:id(.:format) notes#destroy
assignments GET /assignments(.:format) assignments#index
POST /assignments(.:format) assignments#create
new_assignment GET /assignments/new(.:format) assignments#new
edit_assignment GET /assignments/:id/edit(.:format) assignments#edit
assignment GET /assignments/:id(.:format) assignments#show
PUT /assignments/:id(.:format) assignments#update
DELETE /assignments/:id(.:format) assignments#destroy
subject_assignments GET /subjects/:subject_id/assignments(.:format) assignments#index
POST /subjects/:subject_id/assignments(.:format) assignments#create
new_subject_assignment GET /subjects/:subject_id/assignments/new(.:format) assignments#new
subjects GET /subjects(.:format) subjects#index
POST /subjects(.:format) subjects#create
new_subject GET /subjects/new(.:format) subjects#new
edit_subject GET /subjects/:id/edit(.:format) subjects#edit
subject GET /subjects/:id(.:format) subjects#show
PUT /subjects/:id(.:format) subjects#update
DELETE /subjects/:id(.:format) subjects#destroy
students GET /students(.:format) students#index
POST /students(.:format) students#create
new_student GET /students/new(.:format) students#new
edit_student GET /students/:id/edit(.:format) students#edit
student GET /students/:id(.:format) students#show
PUT /students/:id(.:format) students#update
DELETE /students/:id(.:format) students#destroy
resources GET /resources(.:format) resources#index
POST /resources(.:format) resources#create
new_resource GET /resources/new(.:format) resources#new
edit_resource GET /resources/:id/edit(.:format) resources#edit
resource GET /resources/:id(.:format) resources#show
PUT /resources/:id(.:format) resources#update
DELETE /resources/:id(.:format) resources#destroy
select /students/:id/select(.:format) students#select
root / students#index
Any suggestions? I'm having a really hard time grasping exactly how routing in rails is supposed to work and I have yet to find any kind of treatise on it but I'm pretty sure that having no method listed for my select route is at least part of my problem.
Thanks,
Lon
Try removing the match in your routes.rb file and change your students resource to this:
resources :students do
member do
get 'select'
end
end
Also update your view to call select_student_path(student).
This happens because of your routes.rb file. It doesn't have a callback for post method in "/students/new"
To correct this.
Go to routes.rb and add post 'students/new' to: 'students#new' before end.
and check rails routes. you will find a routing path there for the post.

Resources