Rails choosing wrong route when looping through a nested resource - ruby-on-rails

I've got two resources, Clients and Projects.
In routes.rb:
resources :clients do
resources :projects
end
rake routes gives me this the route prefix client_project for the projects#show action
In my view, I call:
<% #client.projects.each do |project| %>
<%= link_to project.name, project %>
<% end %>
and Rails keeps throwing an error: undefined method project_path, which tells me for some reason the view is trying to call project_path and not client_project_path. I've tried rebooting my server (even rebooting my computer), and can't seem to find why it won't call the route properly. I recently refactored my routes (which caused this break). Am I missing something here? This exact pattern works in every other model in my app, only the refactored route doesn't.

I've never had success getting nested routes to work by simply passing the object in question as the url parameter of link_to... Plus (and maybe it's just me) I like my templates to be a bit more "explicit" than that.
A couple things you could do:
<%= link_to project.name, url_for([#client, project]) %>
or
<%= link_to project.name, client_project_path(#client, project) %>

If projects is a nested route it won't have a project_path route unless you explicitly define one. The Project URLs require a Client. Check this out http://guides.rubyonrails.org/routing.html#nested-resources

Related

How do rails forms work without a model?

I am trying to challenge my learning by creating a simple project using rails forms, however I have gotten really stuck and can't find any information that seems to help online.
What I am trying to do:
I want to create a rails application with no model (so no persistence of data). Simply put I want a user to enter a Soundcloud URL which then gets transferred to the controller where I can do more logic. Essentially I am really trying to understand the connection between the Rails form and the controller in rails. I have spent all day reading about HTML forms, as well as googling this exact question without really fully getting it.
I understand there are different form helpers, but what I cannot seem to understand is how to use these without a model. My biggest hang up right now is I cannot get the form values transferred to the controller. I thought I understood RESTful routes, PUT/GET etc.. but this has made me super frustrated that I cannot seem to get my head around this. Any advice is super appreciated.
The code:
Below is the specific code I am struggling with, currently when I get submit the form it crashes giving me an error based on routes, and that's where I am stuck.
Problem code is found in the _form.html.erb file in views:
<%= form_tag '/show' do %>
<%= label_tag(:soundcloud_url, "Please enter a valid Soundcloud Artist URL:") %>
<%= text_field_tag(:soundcloud_url) %>
<%= submit_tag("Let's go!") %>
<% end %>
Routes.rb:
Rails.application.routes.draw do
resources :soundcloud_query
root 'soundcloud_query#index'
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
Error:
Routing Error
No route matches [POST] "/show"
rake routes output:
Prefix Verb URI Pattern Controller#Action
soundcloud_query_index GET /soundcloud_query(.:format) soundcloud_query#index
POST /soundcloud_query(.:format) soundcloud_query#create
new_soundcloud_query GET /soundcloud_query/new(.:format) soundcloud_query#new
edit_soundcloud_query GET /soundcloud_query/:id/edit(.:format) soundcloud_query#edit
soundcloud_query GET /soundcloud_query/:id(.:format) soundcloud_query#show
PATCH /soundcloud_query/:id(.:format) soundcloud_query#update
PUT /soundcloud_query/:id(.:format) soundcloud_query#update
DELETE /soundcloud_query/:id(.:format) soundcloud_query#destroy
root GET / soundcloud_query#index
Github link:
https://github.com/gaelant/simple_soundcloud_app/commit/09c4c4df524bb721a0f472b4378cd8c1ff18177f
Note: I understand this is a basic question but I have just gotten really confused with this. I know the way the code above is written is not correct, but I have tried so many different things and I just don't understand what is going on, or if this is even possible without a model.
Your /show form action points to nowhere. rails routes shows you which url is valid and to which controller#action each of them lead.
The correct form action would be
<%= form_tag '/soundcloud_query' do %>
<%= label_tag(:soundcloud_url, "Please enter a valid Soundcloud Artist URL:") %>
<%= text_field_tag(:soundcloud_url) %>
<%= submit_tag("Let's go!") %>
<% end %>
A far more better way is to use the url_helpers available through your defined ressource in Routes.rb
Doing so your form action would look like this
<%= form_tag soundcloud_query_index_path do %>
<%= label_tag(:soundcloud_url, "Please enter a valid Soundcloud Artist URL:") %>
<%= text_field_tag(:soundcloud_url) %>
<%= submit_tag("Let's go!") %>
<% end %>
The hardcoded and the url_helper based solution will route your request to a controller class named SoundcloudQuery where the action create will be called. Inside this action you have to put all needed logic.
It's also possible do define that /show should point to a specifc controller and action. This would look like this.
post '/show', to: 'mycontroller#myaction', as: 'mypathnameforhelper'
A much more better explanation with many examples about routes and how to use them can be found in this quite good guide.
Rails Routing from the Outside In
Hint: You should stay close to the ROR naming conventions. Controllers should have pluralized names. So you should define your routes like this:
Rails.application.routes.draw do
ressources :soundcloud_queries
root 'soundcloud_queries#index'
end
and then rename your controller class and file accordingly into SoundcloudQueries and soundcloud_queries.rb. But this is not mandatory.
I think in this case you should not use the url in the form_tag but the controller action.
Let's say you've got a view called my_form.html.erb and a submit_form method in your soundcloud_controller.rb
def submit_form
params[:soundcloud_url] your logic
end
I'd set up the routes like this:
get 'soundcloud_query' => 'soundcloud_query#my_form' // didn't want to use 'resources' but it doesn't matter
post 'soundcloud_query' => 'soundcloud_query#submit_form'
The form would then look like:
<%= form_for :this_doesnt_matter, action: :submit_form do |f| %>
<%= f.text_field :soundcloud_url %>
<%= f.submit %>
<% end %>

Undefined method in controller (Routing)

I'm new at rails and I'm currently working on an already existing application that handles butons like so:
<%= link_to 'Edit', edit_answer_path(ans) %>
That links to the file /answers/edit.html.erb but now I need to make a button that links to the file /answers/comment.html.erb how do I go about doing this?
I already tried with
<%= link_to 'Comment', comment_answer_path(ans) %>
but I get the error "Undefined method 'comment_answer_path'" even after adding this lines to answers_controller :
def comment
ans = Answer.find(params[:id])
end
You need to add a route to your config/routes.rb and then restart the server. Something like
resources :answers do
member do
get 'comment'
end
end
will create the comment_answer_path helper for you as well.
It depends on how you've set up the routes in routes.rb.
You can use rake routes to see the list of all paths and their alias.

Rails: Why am I getting "No route matches"?

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

rails link path and routing error when model singular and plural name are the same (e.g. equipment, species)

<%= link_to t('.new', :default => t("helpers.links.new")), new_equipment_path, :class => 'btn btn-primary' %>
I have the above code in a view, but am getting the following error when clicking the link: No route matches {:action=>"show", :controller=>"equipment"}
My routes file contains:
resources :equipment
resources :workouts
match ':controller(/:action(/:id))(.:format)'
Why is it trying to access the show action?
Here are the entries from my routes:
equipment_index GET /equipment(.:format) equipment#index
POST /equipment(.:format) equipment#create
new_equipment GET /equipment/new(.:format) equipment#new
edit_equipment GET /equipment/:id/edit(.:format) equipment#edit
equipment GET /equipment/:id(.:format) equipment#show
PUT /equipment/:id(.:format) equipment#update
DELETE /equipment/:id(.:format) equipment#destroy
This issue has cropped up before and is related to how rails scaffolding generates the new.html.erb file for models that have names like 'equipment' which are both singular and plural.
If you inspect the form_for in the new.html.erb file you'll see equipment_path in the link_to at the bottom. For these models with singular==plural names that refers to a route that is actually for the show action, hence your error message.
The advice is often along the lines of 'avoid model names like this if you can' or it involves a bit of messing around with the config/initializers/inflections.rb file to force a plural version of the model name. Of course then you end up with an app with very odd sounding references to models: 'equipments' isn't very nice to work with (and someone later on will 'fix' it, messing things up again).
To keep the model name grammatically correct, you need to fix the form_for i.e.:
<% form_for(#equipment, :url=> {:action=>'create'}) do |f| %>
and the link_to:
<%= link_to 'Back', equipment_index_path %>
Have you tried adding an 's' to equiment in your routes.rb?
resources :equipments
Since equipment is considered an uncountable noun, you should be able to solve this using inflections.
The rails documentation on inflections actually uses equipment as part of its' example.
Add the following to your config/initializers/inflections.rb.
ActiveSupport::Inflector.inflections do |inflect|
inflect.uncountable 'equipment'
end
Additional information: Uncountable Nouns in Rails 3 Resource Routing

Rails routing name convention

For some reason the conventional path names for a particular controller are not working? (Rails 3.1)
I created a controller using ryan bates nifty scaffold. Just a controller, no underlying model.
in the controller I have
class ProjectTemplatesController < ApplicationController
# a bunch of stuff
def new
#project = Project.new
end
#more stuff
end
in my view (app/views/project_templates/index.html.erb) I have:
<p><%= link_to "New Project Templates", new_project_templates_path %></p>
however I get the error
undefined local variable or method `new_project_templates_path' for #<#<Class:0x2ab9c24>:0x2ab80e0>
in my routes.rb file I declared the controller as a resource like all the others
resources :project_templates
If I change the link to use
<%= link_to "New Project Templates", {:controller=>"project_templates, :action=>"new"} %>
then it works perfectly?! Why doesnt the naming convension of action_controller_path work in this case?
A simple addendum to the previous posts noting the possibility to run rake routes. If on a POSIX system, run the result through grep or some other text filter.
rake routes | grep project
or
bundle exec rake routes | grep project
Generated routes can get to be very plentiful in large projets so I suggest becoming a command line tools guru in order to efficiently data crunch.
You can find all of the routes and their names on the command line with rake routes.
Rails knows about the pluralization you are using so it could be magically removing it and naming the route new_project_template_path without the 's'?
If you are using resources :project_templates, you could safely to do something like this:
link_to "All Project Templates", :project_templates
link_to "New Project Template", [:new, :project_template]
link_to "Edit Project Template", [:edit, #project_template]
link_to "Show Project Template", #project_template
link_to "Delete Project Template", #project_template, :method => :delete
form_for ProjectTemplate.new do |f|
form_for #projectTemplate do |f|
This way, you don't have to remember the plural or singular problem.
One more thing is that you actually could wrap them all in [] so that you don't worry about them.
link_to "All PT", [:project_templates]
link_to "Show PT", [#project_template]

Resources