Controller/Action not found although physically present? - ruby-on-rails

My attempt to make a new-action which gives the user a form and a create-action to process it fails with the error message `.
View: app/views/studios/new.html.erb:
<%= form_for #studio, url: {action: 'create'} do |f| %>
<%= f.text_field :name %>
<%= f.submit 'Create' %>
<% end %>
Controller: app/controllers/studio_controller.rb:
def new
#studio = Studio.new
respond_to do |format|
format.html
format.json { render json: #studio }
end
end
def create
# TODO
end
Route: config/routes.rb
get 'studios/new' => 'studios#new', :as => 'new_studio'
On attempting to visit http://localhost:3000/studios/new, I am presented with the error
No route matches {:action=>"create", :controller=>"studios"}
As you can see, the create-action is present in the studios-controller. Why is it failing?

It's failing because you don't have route defined for the create action. You have a get action defined for the new action only.
Update your routes file to add a post route to the create action as:
post 'studios/create' => 'studios#create'
Or, you could choose to use resourceful routing and update your routes file as:
resources :studios, only: [ :new, :create ]
This will define the new and create route for your studio resource. To see the generated routes you can run rake routes.

The rails form helper, given the instance variable #studio, asks for the instance variable via the new action, and, upon clicking save, calls the create action to validate and save this new instance. It's failing because rails cannot find the action to submit the object to.
Try adding resources :studios for RESTful routes in config/routes.rb (index, new, create, show, edit, update, destroy) automagically routing to actions with the same name in the app/controllers/studio_controller.rb
Try visiting the docs for form helpers here: http://guides.rubyonrails.org/form_helpers.html#binding-a-form-to-an-object for a more in depth explaination.

Related

How to add params id in rails link_to

I have a Job model that contains a Company_id as a foreign key. On the company show page, I want to use a link_to tag that links to the Job new page so I can create a new job with the company_id using simple_form.
<%= link_to "Create Job", new_company_job_path %>
I get this error "No route matches {:action=>"new", :controller=>"jobs", :id=>"13"}, missing required keys: [:company_id]"
This is my nested route
resources :companies do
resources :jobs, only: [:new, :create, :update, :destroy]
end
From rails routes, this is the route to the job new page
new_company_job GET /companies/:company_id/jobs/new(.:format) jobs#new
This is the simple-form in the job_new page
<%= simple_form_for (#job) do |f| %> etc
I would like know how I can include the company_id in to the link_to tag in order to use simple_form in the job new_page to create a new job.
Rails routes can take arguments; if you ever want to explicitly pass a parameter to a route you can do so just like you would pass an argument to any other method:
<%= link_to "Create Job", new_company_job_path(company_id: #company.id) %>
*note: this assumes you have defined #company somewhere on this view.
In the case of general resource routes, Rails is smart enough to insert these params in the right place. It's worth noting though that if a param is not defined on the route in routes.rb Rails will tack on these passed parameters to the end of the route as query strings.
For example, if you have a route like
get 'landing_pages/page' => '#landing_pages#page'
and you called:
<%= link_to "Go to your landing page", landing_pages_page_path(brand: 'Apple') %>
The route will become /landing_page/page?brand=Apple
For further reference: http://guides.rubyonrails.org/routing.html

Rendering 'new' leads to a different url

When handling validation errors in a User form on my rails project, I have the instruction render 'new' if the user is not valid.
However, when this occurs, the url in the search bar changes.
Originally, it's https://localhost:3000/signup but when the user submit the forms and the render 'new' occurs, the URL becomes https://localhost:3000/users
Why is that?
Here's my routes.rb
Rails.application.routes.draw do
# Resources
resources :users, only: [ :new, :create ]
# Application root
root 'static_pages#home'
# Static pages
get '/help', to: 'static_pages#help'
get '/contact', to: 'static_pages#contact'
# Users
get '/signup', to: 'users#new'
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
Thanks,
In the Rails REST conventions you use different URI's to display the form to create a resource and for the forms action attribute which you POST to.
Lets say you have:
resources :pets
This gives us:
GET /pets/new => pets#new
POST /pets => pets#create
We then have a typical form:
# posts to /pets
<%= form_for(#pet) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.submit %>
<% end %>
And a run of the mill controller:
class PetsController < ApplicationController
def new
#pet = Pet.new
end
def create
#pet = Pet.new(pet_params)
if #pet.save
redirect_to #pet
else
render :new
end
end
# ...
end
So when the user visits /pets/new and fills in the form the browser url should read /pets if the form is invalid. This is the intended behavior - posting to a different URL avoids a myriad of cache and history related issues.
From a restful standpoint its also correct - you're no longer viewing the new action - you're viewing the results of attempting to create a resource. The former is idempotent - the latter is not.
You need to recognize that the line render :new is short for render template: 'pets/new'. It does not redirect and it does not call the new action in the controller. It simply renders the template and returns it as the response to the current request.
The reason this is happening is because of the way Rails handles routes. Most likely, the form on your signup page has something like:
<?= form_for #user do |f| ?>
If you look at the generated HTML you'll notice that the form is POSTing to the url '/users'. So when the signup form is submitted, the app is going to redirect you to /users.
This is the normal behavior in Rails. (see Rails Guides)
If you want the URL to look like /signup you can add a named route for it:
# Users
get '/signup', to: 'lead_magnets#new'
post '/signup', to: 'lead_magnets#create'
Then in your signup form you'll need to explicitly reference the new signup path:
<?= form_for #user, url: signup_path do |f| ?>
The generated HTML should look like
<form class="new_user" id="new_user" action="/signup" method="post">
You need to add
post '/signup', to: 'users#new'
Did you try to include recognize path?
Rails.application.routes.recognize_path
The reason for this is because when you submit your form, you're submitting it to some action from your new view. The action that the form submits to has a path, and you can see what the path is by typing:
rake routes
in your console and searching for the create action. When your validation fails in the create action, you call render 'new'.
When you render a template, the url of the page being rendered will be the url / path of the controller action that rendered the template.
In your case, whatever action you have that calls render 'new' will be the one determing the url once your template is rendered.

Rails run :get route within /new and /edit _form

I have a _form for new and edit for a #Giveaway object. Within this form I have a field for a random winner.
I want to populate this field by calling the method giveaways#random_winner with <%= button_to "Randomly Pick Winner!", {:action => 'choose_winner'}, :method => :get %>, but I am getting this error No route matches {:action=>"choose_winner", :controller=>"giveaways"} when loading /giveaways/new.
Here is my controller:
def choose_winner
random_winner = SubscriberUser.where(user_id: current_user.id).pluck(:subscriber_id).sample(1)
session[:random_winner] = random_winner
redirect_to :back
end
Here are the routes that I have tried. I'm not very good at non-scaffold routes yet:
resources :giveaways do
member do
get 'choose_winner' => 'giveaways#choose_winner'
#tried get :choose_winner, as: :choose_winner
#tried get 'new/choose_winner'
#tried get 'choose_winner'
#tried get 'choose_winner', to: 'giveaways#choose_winner', as: 'choose_winner'
end
end
Question -- Why is the page not loading when I have defined the controller and action in the route? Will I have to reload the page when I do run that route... is there a better way to get at this data?
Your routes.rb is close
resources :giveaways do
member do
get :choose_winner
end
end
And then I would use a Rails route helper so you don't have to worry about setting the action/controller yourself.
<%= button_to "Randomly Pick Winner", choose_winner_giveaway_path(#giveaway), method: :get %>

Rails - custom action in controller - how to reference in view?

I'm using a custom action to get the id of a project into the session, so that only relevant info for that project is shown in other areas. I've made a custom action in the projects controller, and am having trouble getting a link to work in the view to call that action. I just get an error saying "Couldn't find project without ID". I'm new to rails - I know it's probably an easy question, but help would be much appreciated, thanks!
View Code:
<%= link_to 'Select Project', :action => :select_project %>
Controller Code:
def select_project
#project = Project.find(params[:id])
session[:project_id] = #project.id
end
Routes:
resources :projects do
collection do
get :select_project
end
end
Alternative routes code:
resources :projects do
put 'select_project', on: :member
end
This is untested but I believe it is what you are looking for:
Routes:
resources :projects do
member do
post :set_current
end
end
this should create the following:
Endpoint: /projects/:id/set_current POST
Helper: set_current_project_path
Controller
def set_current
project = Project.find(params[:id])
session[:project_id] = project.id
redirect_to projects_path, :notice => "Current project set to #{project.name}"
end
Views
# index / erb tags excluded for simplicity
#projects.each do |project|
link_to 'Select Project', set_current_project_path(project), :method => :post
end
# show
<%= link_to 'Select Project', set_current_project_path(#project), :method => :post %>
See:
http://guides.rubyonrails.org/routing.html#adding-more-restful-actions
http://guides.rubyonrails.org/routing.html#crud-verbs-and-actions
Note also the use of 'post' instead of 'get', since we are changing the state of an object (session)
it is preferred to use a post not a get, otherwise users might pull up an old get request in the address bar
of their browser and set their session to a project unknowingly.
like varatis said - use rake routes or CONTROLLER=projects rake routes to help with determining what your route/path helpers look like and what http verbs they are expecting
And is there a reason why it's project not #project in the controller
The #project creates an instance variable; in a rails controller instance variables are made available to the views. This set_current action will never render a view, so no reason to make an instance variable out of it.
How come you have to set it to member and not collection in the routes
any action where you want to reference params[:id] should be a member route, an alternative would be to leave it as a collection route and pass params[:project_id] and pass that in all of your link_to calls, but in this case member makes more sense.
I believe resources :projects is a short cut for this break down
member do
get :show
get :edit
put :update
delete :destroy
end
collection do
get :index
get :new
post :create
end
hopefully that clarifies your questions some?
I think the route generated would be select_project_projects_path.
Link:
<%= link_to 'Select Project', select_project_projects_path %>
For future reference, run rake routes to see the automatic route helpers generated by Rails.

Unknown action No action responded to delete. Actions: add, edit, and index

When I am on the index page and click on the delete link to destroy the post i get that error:
Unknown action
No action responded to delete. Actions: add, edit, and index
The edit link next to delete works with out a problem I do not understand why delete won't work. This is what is in my controller car_controller.rb
def delete
#car = Car.find(params[:id])
flash[:notice] = "Question #{#car.name} deleted!"
#car.destroy
redirect_to :controller => :car, :action => :index
end
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
map.root :controller => "main"
map.root :controller => "car"
end
Isn't the action for delete actually destroy?
If you look at a controller that was generated as part of scaffold, you should see what the delete action maps to...
Rails provides the 7 classical RESTful actions out of the box when you generate the controller and each one has the actual URL + method commented above the action method...
# DELETE /subject_families/1
# DELETE /subject_families/1.xml
def destroy
...
end
I hope this helps...
Make sure your request is using the correct HTTP verb. Rails' default for REST resources is to use HTTP DELETE on the destroy action. Are you using GET (a simple link) or POST instead of DELETE?
I recommend checking your routes - run rake routes - to confirm what Rails is expecting. If you are using Rails' resources route generator, then I would expect your view template to contain something like this:
<%= form_for #car, :html => { :method => :delete } do |f| %>
<%= submit_tag 'Delete Car' %>
<% end %>

Resources