Rails: Why am I getting "No route matches"? - ruby-on-rails

Snippet from routes.rb:
resources :templates do
post :add_rates
resources :rates
delete :remove_rate
end
Now I try to use the "add_rates" path in my form.
Tried both:
<%= form_for(#template.template_id, :html => {:class=>"form-horizontal"},:url=> { :action=>:add_rates}) do |f| %>
and:
<%= form_tag(:template_add_rates) do %>
But I'm always getting: No route matches {:action=>"add_rates", :controller=>"templates"}
Any help would be appreciated.

You're doing it wrong:
form_for [#template, :add_rates], html: { class: "form-horizontal } do
or
form_for #template, url: template_add_rates_path(#template), html: {class: "form-horizontal" } do
The template, and its ID, and the action you want (add_rates) all have to be passed in as the same parameter. You can't give it the template ID as the first argument, and then try to tack additional URL parameters onto it. Additionally, in both cases, you're missing key parts of the URL. In the first one, you're just giving it an ID, and :add_rates; Rails can't take an arbitrary number and know that it's a template ID that you're giving it. In the second case, you're giving it :template_add_rates; how is Rails supposed to know which template you're trying to add rates to, without a template ID? You need to give it all three pieces of the route you're trying to match: /templates/:template_id/add_rates.
There are also a bunch of other weird issues/errors with the code you've posted:
#template.template_id should be #template.id, unless you've explicitly deviated from Rails' conventions, which you should almost never do.
Your routes are pretty weird. You shouldn't be adding a add_rate route, you should be using the routes provided by your nested resources :rates line.
Your routes should look like this:
resources :templates do
resources :rates
end
This gives you routes like POST /templates/:template_id/rates for creating rates (instead of your add_rate route), and DELETE /templates/:template_id/rates/:rate_id for deleting rates (instead of your remove_rate route).

Related

Failed to try to use 2 ids on nestes routes in rails

I'm trying to pass 2 ids to the controller within the update action, but it does not stop, I do not recognize the first id, student_id. This is the definition of the route within routes.rb
post 'registers/students/:student_id/notes/:note_id/edit', to: 'registers/students/notes#update', as: :update_registers_student_note
While this is the part of the form_for, using the corresponding helper
<%= form_for #note, url: update_registers_student_note_path(:student_id,:note_id), method: :post do |f| %>
My question is how can I correctly pass the 2 ids of the corresponding resources, since the form only recognizes me note_id, and not student_id
Thank you
The helper should works. You also can use update_registers_student_note_path(student_id: 1, note_id: 12).
But I suggest you to use nested resources in your routes instead.
You can write somethings like that:
namespace :registers do
resources :students do
resources :notes
end
end
The new url helper will be registers_student_note_path(<note_id>, student_id: <student_id>) with method PATCH.
yes, you did put a right thing for url_helpers. You can try to open rails console and try it with these command
include Rails.application.routes.url_helpers
update_registers_student_note_path(1,2)
you will see => "/registers/students/1/notes/2/edit"

rails named route puts '.' instead of '/' in URL on updating [duplicate]

This question already has an answer here:
Rails dot instead of slash in URL
(1 answer)
Closed 5 years ago.
Update #3 ... fixed! Solution was moving the new name space code (get 'dash', to: 'dashes#show') to the bottom of the routes.rb file just above the root "campaigns#index" entry.
Update #2 ... it's not a pluralization as it's called singularly, shown below & removing the named route automatically corrects all issues.
Update #1 ... found reason why no one had listed period in place of slash in URL ... it's unix nouns, not english ... IE: if you search for 'dot' in place of '.', then you get all sorts of answers.
I'm flumoxed by this one ... made my first named route the other day, everything looked great until suddenly it appears that the edit page when called from the named route doesn't update properly, with error ...
No route matches [PATCH] "/dash.6"
Removal of the named route takes me back to normal routes & all options working. I can't find a mention of routing which uses '.' instead of '\', so I'm lost. My route file below & then the route results from rails server ...
Rails.application.routes.draw do
devise_for :users, controllers: { sessions: 'users/registrations' }
# map.login '/login', :controller => 'sessions', :action => 'new' ## 3rd try
# get '/dash', :controller => 'dashes', :action => 'show' ## 2nd try
# get 'dash', to: 'dashes#show' ## Original named route
resources :dashes
resources :campaigns
resources :players
resources :countries
root "campaigns#index"
# yank later
resources :neighborhoods
end
Rails results on server ...
Paths Matching (dashes):
dashes_path GET /dashes(.:format)
dashes#index
POST /dashes(.:format)
dashes#create
Paths Containing (dashes):
dashes_path GET /dashes(.:format)
dashes#index
POST /dashes(.:format)
dashes#create
new_dash_path GET /dashes/new(.:format)
dashes#new
edit_dash_path GET /dashes/:id/edit(.:format)
dashes#edit
GET /dashes/:id(.:format)
dashes#show
PATCH /dashes/:id(.:format)
dashes#update
PUT /dashes/:id(.:format)
dashes#update
DELETE /dashes/:id(.:format)
dashes#destroy
My form is standard rails generated & works whenever I remove the named route ... edit.html.haml renders the _form partial ...
%h1 Editing dash
= render 'form'
= link_to 'Show', #dash
\|
= link_to 'Back', dashes_path
_form.html.haml
= simple_form_for(#dash) do |f|
= f.error_notification
.form-inputs
= f.input :name
= f.association :user
= f.association :dashcampaigns
= f.association :dashplayers
.form-actions
= f.button :submit
As described in this question, typically the issue is when you confuse between collection (plural) and member (singular) controller actions.
A collection controller action is an action that does not have an ID since it does not manipulate an existing resource (dash) or since it works on a group of resources. The RESTful collection actions are: index, new, and create. Each of them has a helper method and a "verb" (method):
index: url: dashes_path, method: :get (method get is default)
create: url: dashes_path, method: :post
new: url: new_dash_path, method: :get
Note how both index and create share the same plural URL helper method dashes_path. Only the method option differentiates between them.
A member controller action is an action that has an ID of the resource it is manipulating (one particular dash). The RESTful collection actions are:
edit: url: edit_dash_path(#dash), method: :get
show: url: dash_path(#dash), method: :get
update: url: dash_path(#dash), method: :patch
destroy: url: dash_path(#dash), method: :destroy
See how except edit, all other actions use the same singular URL helper method dash_path(#dash).
You can find further details on this in the guides.
Now, the "dot instead of slash" symptom is when you mistakenly try to point to a member action in a way that should be used for collection actions. So if you try to do dashes_path(#dash) - there is no such thing. The only parameter dashes_path accepts is format, which is added to the URL in the end after a dot, that's why you're seeing a weird URL such as /dash.6.
Rails form builder form_for and extensions such as simple_form_for need to decide whether to point the form action at the #create collection action (when rendering the #new collection action) or #update member action (when rendering the #edit member action). They do so "magically" by taking a look at the object you give them when you do simple_form_for(#dash). If #dash.new_object? is true, they point the form action to #create, if it's false they point it to #update.
In your case when you used it "out of the box" it was all good. It started acting up on you when you added this line to your routes.rb:
get 'dash', to: 'dashes#show'
By default show is a member action, not a collection action. It must receive an ID. I think that this is why Simple Form is acting up on you. Instead of that alias, try this one:
get 'dash/:id', to: 'dashes#show'
Let us know if this fixes the issue.
And in general, I recommend to "work with" the RESTful routing rather then "working against" them. It is very rare to need to add named routes in routes.rb. There are exceptions, but I don't think it is justified in your case to deviate from conventions and try to use dash/1 rather than dashes/1. "Working with" Rails will get you the productivity boost it is known for, not "working against" it by trying to force it for relatively small details like this one.

route is redirecting to wrong path

This is what my routes currently look like:
which gives
On my homepage I have a create vacancy button
<%= link_to "plaats", new_employer_vacancy_path(:employer_id)%>
Which should be linked to the line from the first image
get '/employers/:employer_id/vacancies/new', to: 'vacancies#new', as: 'new_employer_vacancy'
In the vacancies_controller#new - create I have:
def new
#vacancy = Vacancy.new
#employervacancy = Employervacancy.new
end
def create
#vacancy = Vacancy.create(vacancy_params)
createEmployervacancy
redirect_to employer_vacancy_path(current_employer, #vacancy)
end
def createEmployervacancy
#employer = current_employer
Employervacancy.create(vacancy_id: #vacancy.id, employer_id: #employer.id)
end
But whenever I click the button I get redirected to some other method in my vacancies_controller that is totally irrelevant.
How is this even possible? Don't I clearly define that when that path is clicked he should go to vacancies#new? and not to vacancies#show_specific_employer_vacancies?
EDIT
After following the answers I am indeed being linked to the correct route.
First, it gave me this error.
After trying to pass the current_employer.id instead of #employer like suggested I got following error:
For your routes, you'd better to change into nested route for easily maintaining routes.
Remove these codes:
get '/employers/:employer_id/vacancies/:id', to:"vacancies#show_specific_employer_vacancies", as: "employer_vacancy"
get '/employers/:employer_id/vacancies/edit/:id' ...
get '/employers/:employer_id/vacancies/index' ...
get '/employers/:employer_id/vacancies/new' ...
path '/employers/:employer_id/vacancies/:id' ...
change into:
resources :employers do
resources :vacancies
end
Try to use basic routes here because you use standard simple form url. For example:
<%= simple_form_for(#employee, #vacancy) %>
The simple_form_for will generate url well if you use nested routes above.
Finally, in your link you have to add #employer_id
<%= link_to "plaats", new_employer_vacancy_path(:employer_id => #employer_id)%>
I hope this help you
Your router cannot tell the difference between your employer_vacancy and new_emplyer_vacancy routes because the :id parameter accepts anything. Because of this, when you point your browser to "/employers/5/vacancies/new", the route is taking your employer_vacancy route and assigning {:employer_id => 5, :id => "new"} instead of going to your new_employer_vacancy route (because routes are first-come-first-serve).
To correct this, add a constraint to your first route to ensure that only numbers (and not the string "new") is accepted into the employer_vacancy route:
get '/employers/:employer_id/vacancies/:id',
to: 'vacancies#show_specific_emplyer_vacancies',
as: 'employer_vacancy',
constraints: { id: /\d+/ } # <- This line
As Wes Foster said rails router is trying to find a first match.
It means that given a path /employers/999/vacancies/new your router looks through the routes and when it sees get '/employers/:employer_id/vacancies/:id he thinks that this route matches. So :employer_id is 999 and :id is new.
I'd suggest to put the route with :id at the end of employers routes:
...
get '/employers/:employer_id/vacancies/new'
...
get '/employers/:employer_id/vacancies/:id'
Btw this is better than adding a constraint because:
It is easier
It doesn't pollute routes file
Later you may want to change ids to be hashed or alphabetic and then you'd have to change the constraint

Submitting a form with GET method which doesn't match route

I want to filter results by category and I'd like to use the GET method instead of POST. However, I am doing something wrong that I can't figure out: the form's action does not match the defined route, so it triggers a different method.
Here's the form:
<div>
<%= form_tag '/expenses/search', method: 'get' do %>
<%= select_tag 'category_name', options_from_collection_for_select(Category.order(:name), :name, :name) %>
<%= submit_tag 'search' %>
<% end %>
</div>
Sending this form produces an URL like the following:
http://localhost:3000/expenses/search?utf8=%E2%9C%93&category_name=Alcohol&commit=Search
However the route is defined like this:
resources :expenses
get 'expenses/search/:category_name', to: 'gastos#search_by_category'
This means the URL where the form is submitted isn't the one I'm trying to submit it to. It's matched with the one corresponding to the show method, as you can imagine.
How can I submit the form to the matching URL? What is the usual way to deal with this situation?
You didn't set your route properly as it has unrecognized :category_name segment. Your route should be defined like this:
get 'expenses/search', to: 'gastos#search_by_category`
If your route is nested on expenses I recommend to use block function
resources :expenses do
collection do
match 'search', to: 'gastos#search_by_category`, via: :get
end
end
Is a good practice to use rials routes helper, try to avoid put routes with plain text, in your case will be:
<%= form_tag search_expenses_path, method: 'get' do %>
<%= select_tag 'category_name', options_from_collection_for_select(Category.order(:name), :name, :name) %>
<%= submit_tag 'search' %>
<% end %>
Furthermore, don't confuse 'query params' with 'url params'
http//www.host.com/profile/12?type='json'
In this example '12' is a url param and is expresed with :(nameofparam) in routes files but 'type' is a query param that are not expresed on rails routes.
It's supposed to work like that, since it's client-side.
You see, parameters are sent by the browser, that (in general) has no understanding of how your site routing works inside. Submitting a form, in general, requires an URL (to submit params to) and a set of parameters, which in case with GET typically* gets passed as a query string.
The browser will eventually hit the exact route that is specified in form's URL and supply all the form's parameters in a query string appended to the end in usual format:
...?category=stuff
You simply cannot expect the browser to hit a different route (which query string is not part of) with one form just because it has a different value in one of the <input>s.
* I've never actually seen this done differently, but I didn't find a firm requirement of this either.
Do you really want pretty search links that badly?
You could try to circumvent this by placing a "prettifying redirection" – direct search queries to that action, but do not perform search there: instead use the received parameters to construct a route and redirect your user to it.
def search_redirect
redirect_to whatever_search_path(category: params[:category])
end
That would trigger the route helper to build the pretty adress that conforms to the defined routes.
Too hacky?
Well, you could go with submitting a form through JavaScript and alter the parameters and URL request in any way you want. But this is still hacky and I wouldn't do either. Query string in search requests looks perfectly fine to me.

Making a controller exist on as a sub-controller, how to fix form routes in rails

I have a ChaptersController that does not have a direct route (i.e. site/chapters/:id) but only exists as a sub route for a BooksController (i.e. site/books/:id/chapters/:id). however, when I try to go to books/:id/chapters/new , I get the following routing error:
Showing .../app/views/chapters/_form.html.erb where line #1 raised:
No route matches {:controller=>"chapters"}
how can I fix this?
It seems like you are using nested routes in this manner:
resources :books do
resources :chapters
end
in which case you should have the named routes 'book_chapter' and 'book_chapters'. You can check this by running rake routes.
In your _form.html.erb partial you need to change this line:
<%= form_for(#chapter) do |f|%>
You need to specify the target URL of the form explicitly, and probably also handle different URLs for create and update scenarios. Try something like this:
<%= form_for(#chapter, :url => (#chapter.new_record? ? book_chapters_path(#book) : book_chapter_path(#book, #chapter) )) do |f| %>
I suppose there is wrong path in /app/views/chapters/_form.html.erb
Check what url is in tag. I suppose you forgot to change it to nested in books.
You may as well paste _form.html.erb here, so i will point it out :)

Resources