ruby on rails form not doing correct action - ruby-on-rails

I'm trying to edit a form, the route is controller/id/action for edit so for example
people/124321/edit
I'm trying to make this form submit to the update action using this code:
<% form_for :probe, #probe, :action => "update" do |f| %>
...
...
...
<%= submit_tag 'Submit' %>
<% end %>
When I click submit, it gives me an error stating
Unknown Action.
No action responded to (id).
Edit
The only thing in my routes specified for probes is map.resources :probes
RoR just did the people/124321/edit by itself when I generated the controller.
Rake routes shows this
probes GET /probes(.:format) {:controller=>"probes", :action=>"index"}
POST /probes(.:format) {:controller=>"probes", :action=>"create"}
new_probe GET /probes/new(.:format) {:controller=>"probes", :action=>"new"}
edit_probe GET /probes/:id/edit(.:format) {:controller=>"probes",action=>"edit"}
GET /probes/:id(.:format) {:controller=>"probes", :action=>"show"}
PUT /probes/:id(.:format) {:controller=>"probes", :action=>"update"}
DELETE /probes/:id(.:format) {:controller=>"probes", :action=>"destroy"}
Edit 2 Probe Controller
def edit
#probe = Probe.find(params[:id])
end
def update
#probe = Probe.find(params[:id])
debugger
if #probe.update_attributes(params[:probe])
flash[:notice] = "Successfully updated probe."
redirect_to probes_path
else
render :action => 'edit'
end
end

It's hard to say exactly since you have posted very little supporting details for your question, but my guess is that your routes file is set up such that the precedence of something matching :controller/:action/:id comes before the route you're aiming for, :controller/:id/:action.
Routes are evaluated top-down, first match wins.
I'll echo John's answer, too. You shouldn't need to specify :action => 'update', and in fact these days I usually extract the form out of both new.html.erb and edit.html.erb into a partial _form.html.erb. form_for will figure out if the object is a new record and POST to either the create or update action, as appropriate.
I have seen some situations in the past where route changes reloaded in development mode confuse the routing code, which is usually fixed by restarting the server.
rake routes is also a good debugging tool. Check the page source to see what Rails has used for the form's action attribute, then scan down the output of rake routes to see where the request will end up.

If you're using RESTful resources, then you should just be able to do this:
<% form_for(#probe) do |f| %>
.
.
.
<%= f.submit 'Submit' %>
<% end %>
Rails can work out whether you're creating a new record or updating an existing one. See Binding a Form to an Object for further details.
Also, note the use of f.submit in my example. The *_tag helpers go together, so you wouldn't usually see a form_for helper with a submit_tag.

"Unknown Action. No action responded to (id)." sounds like a routing problem.
Have you removed or commented out the default routes in your routes.rb file?
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
If the default routes are being run it could be swapping the id for the action?

Related

No route matches [POST] "/articles/new" - Why?

I made the following introduction:
http://guides.rubyonrails.org/getting_started.html
And after that, I wanted to create a new field (like title) and got the error notification:
Here is my code:
routes.rb
Rails.application.routes.draw do
get 'welcome/index'
resources :articles do
resources :comments
resources :description
root 'welcome#index'
# For details on the DSL available within this file, see guides.rubyonrails.org/routing.html
end
end
I know that this question has been asked a lot but their solutions didn't helped me.
What should I do?
Regards
The problem is in your new.html.erb form, you are missing url: articles_path, if you don't specify it, the form will be sent to the same action (i.e. new). So, since submitting the form uses POST (by default) method, you get:
No route matches [POST] “/articles/new”
You need to change your form_for and specify the url, like this:
<%= form_for :article, url: articles_path do |f| %>
From the same link your provided:
There's one problem with this form though. If you inspect the HTML
that is generated, by viewing the source of the page, you will see
that the action attribute for the form is pointing at /articles/new1.
This is a problem because this route goes to the very page that you're
on right at the moment, and that route should only be used to display
the form for a new article.
1 My emphasis.
By default rails new resource route has a GET HTTP verb, not POST. Unless you specified otherwise.
Seems like you are using new_article_path or articles/new in the form
<%= form_for :article, url: new_articles_path do |f| %>
Change it to
<%= form_for :article, url: articles_path do |f| %>

When the form is submitted with an error, the rendered url changes in Rails 4

I have created a user signup page. When the user submits the form incorrectly, when displaying a validation error, it does not render on the same URL.
The signup form is located at this url:
http://localhost:3000/signup
I have added the following routes for the signup page:
resources :users
match '/signup', to: 'users#new', via: 'get'
When I submit the form, the model validation shows up but the url redirects to:
http://localhost:3000/users
I want the user to remain at the same url after submitting the form.
http://localhost:3000/signup
This is my controller code:
def new
#user = User.new
end
def create
#user = User.new(user_params) # Not the final implementation!
if #user.save
# Handle a successful save.
else
render 'new'
end
end
This is the beginning tag of my form:
<%= form_for #user, url: {action: "create"} do |f| %>
I'm working with Rails 5, but I suspect it's not too different conceptually.
In routes.rb:
get 'signup', to: 'users#new'
post 'signup', to: 'users#create'
resources :users
and in your form helper:
<%= form_for #user, url: signup_path do |f| %>
Essentially, the reason why it's not working as described in your original post is because when the form posts (rails 4.2 form helpers), it's tied to url: {action: "create"}, which by default, according to the routes automatically generated for resources :users, is post '/users', to: 'users#create (rails 4.2 routing guide). And by searching top down in routes.rb, it'll see this first and you end up with http://localhost:3000/users.
So, the changes I propose, should bind the form to post to the signup path instead which, in routes.rb, is seen as the second route entry.
I believe that #Jaskaran's question is in regards to question 2 found at the bottom of Michael Hartle's Ruby on Rails Tutorial, section 7.3.3, so I will be answering in reference to that question:
How does the URL on the unsubmitted signup form (Figure 7.12) compare to the URL for a submitted signup form (Figure 7.18)? Why don’t they match?
To answer this question, we need to understand how routing works in a Rails application. Let's walk through what happens when you visit each page and make a submission.
Your main page (home.html.erb) contains a link to your signup page (new.html.erb). That link looks like this:
<%= link_to "Sign up now!", signup_path, class: "btn btn-lg btn-primary" %>
The signup_path is the part we are most interested in. signup_path is a route helper and essentially tells Rails that when someone clicks on that link, Rails should behave as if they just went to your /signup page. This is why the first URL you see (before submitting the form) shows http://localhost:3000/signup.
Now let's take a look at what happens when your form is submitted. According to the new.html.erb file, the form is contained within this Ruby code:
<%= form_for(#user) do |f| %>
. . .
<% end %>
You may remember from 7.2.2 that that Ruby code is actually rendered in HTML as:
<form class="new_user" id="new_user" action="/users" accept-charset="UTF-8" method="post">
. . .
</form>
What that is saying is that when the form is submitted, it will make a POST request to /users - and that's the URL that you are seeing in your browser.
We can better understand why this is if we first stop to think - where does /users route to? You can quickly check your routes by typing bundle exec rake routes in your console. You should see it listed there:
Prefix Verb URI Pattern Controller#Action
users GET /users(.:format) users#index
POST /users(.:format) users#create
So any POST requests to /users will be routed to the create method of our users_controller.rb. If you're wondering why that is, it is because we added this line to our routes.rb file:
resources :users
More details on that line can be found here.

Controller/Action not found although physically present?

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.

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.

Rails routing error with nested resources

In my application, I have a RecipesController and a CommentsController. All comments belong to a recipe, and can be voted up. Here's a snippet from my routes.rb:
resources :recipes do
member do
put 'vote_up'
post 'comment'
end
resources :comments do
member do
put 'vote_up'
end
end
end
If I run rake routes, I find the following route in the output:
vote_up_recipe_comment PUT /recipes/:recipe_id/comments/:id/vote_up(.:format) {:action=>"vote_up", :controller=>"comments"}
The CommentsController has a method called vote_up.
Also, linking to the route works (from my view)
<%= link_to 'Vote up', vote_up_recipe_comment_path(#recipe, comment), :method => 'put' %> <br />
However, clicking on that link gives me the following error:
Routing Error
No route matches "/recipes/7/comments/4/vote_up"
What am I missing? I'm not sure how to debug this, because as far as I can see the route should match.
I think that you get this error message because the request is made via HTTP GET method, not PUT.
In order to create links that use POST/PUT/DELETE method, your application should correctly load a Javascript Rails adapter.
Check that your app has jQuery (http://github.com/rails/jquery-ujs) or Prototype JS adapter and that your layout correctly loads it.
try the following tweak: send the put method as a symbol
<%= link_to 'Vote up', vote_up_recipe_comment_path(#recipe, comment), :method => :put %>

Resources