Ruby on Rails: How to Have Multiple Submit Buttons Going to Different Methods (Maybe with With_Action)

When I click submit button in my form, create action is supposed to work but it is rather processed by new action

It is really weird that it works in the first case and not in the second.

Try this,

<%= simple_form_for @task, url: tasks_path, method: :post, html: {class: 'form-horizontal'}, wrapper: :horizontal_input_group do |f| %>

this will force the form to submit to tasks_path with post method which goes to the create action. Let me know if it works

Also, this is your create method

        def create 
@task = current_user.client_relationships.build(task_params)
if @task.save
flash[:success] = "Micropost created!"
redirect_to @current_user
else
render 'new'
end
end

A couple of issues.

1) redirect_to @current_user does not mean anything, right ? should be like user_path(@current_user)

2) you should always do redirect_to and return so that the code block after redirection will not be called. In your case, its ok since the rest is in a else block

3) It could be that task.save fails and new is rendered. use a debugger and check if comes to first line of create

Submit same form to different actions

In this case creating a Cat and updating a Dog were related enough that it makes sense to handle both in the CatsController with a case statement and use a :name attribute on on the submit button.

For example:

app/views/cats/new.html.erb:

<%= form_tag(cats_path, multipart: true, role: "form") do %>
<%= button_tag 'Cat', name: 'route_to[cat]'%>
<%= button_tag 'Dog', name: 'route_to[dog]' %>
<% end %>

app/controllers/cats_controller.rb:

def create
case route_to params
when :cat
# create a cat
when :dog
# update a dog
end
end
.
.
.
private

def route_to params
params[:route_to].keys.first.to_sym
end

Submitting a form with a param to new controller action

In Rails you don't create resources by posting to the new route- you post to the collection route eg. /books. The new action is just used to create a page with a form on it.

Its still really puzzling why new_book_path would return /bookd/new but the error is actually correct. new_book_path responds to GET - not POST. This is explained in Rails Routing from the Outside.

If you actually just use:

table.table.table-striped
thead
tr
th Name
tbody
- @books.each do |book|
tr
td = book.name

= simple_form_for(@book || Book.new) do |f|
.form-inputs
= f.input :name # book_name is a typo?

It will correctly create a form with action="/books" method="POST".

I have no idea what your trying to do with this mess:

= form_with url: new_book_path do |f|
.form-inputs
= f.label 'Add Book'
= f.text_field :book_name
.form-actions
= f.submit

= simple_form_for(@book) do |f|
.form-inputs
= f.input :book_name

But none of the HTML specifications allow nested <form> elements and the results can be wildly unpredictable. For example a submit button may submit the inner form or the outer form.

How to get form submit button to do update action as opposed to create action

Generally you don't need template for edit form if nothing special.

Just use create form and use form_for @instance.

form_for will judge the instance and arrange form path automatically. If the instance is not persisted, it will point to #create. If the instance is a persisted object in db, it will point to #udpate automatically.

multiple controllers in one view (ruby on rails MVC)


  1. Technically, this terminology is somewhat confusing. By default each method in a controller corresponds to a similarly-named view file, so it may be better to word the question as "Is it good practice to render a view that is not the default view?" And the answer is, of course, it depends. It is a technique commonly used to DRY up controller code and if there are advantages to be gained by it, in your application, I would certainly use it. In fact, the controller code generated by the default resource scaffolding in Rails uses it in the create and update methods. I think you could make the argument that anything in Rails core is, if not a best-practice, at least within the limits of sanity.

  2. With that being said, there may be opportunities for improvement. A common way to handle the same thing would be to route your create and update requests to the same controller action and use the same controller view. If that is not feasible, at least be assured that you will not need to redefine the variables. From the official documentation:

Using render with :action is a frequent source of confusion for Rails
newcomers. The specified action is used to determine which view to
render, but Rails does not run any of the code for that action in the
controller. Any instance variables that you require in the view must
be set up in the current action before calling render.

  1. You shouldn't need to do that... Not in this situation, or any other one that I can think of. Any time you see something super hackey like that in Rails is a sign that something probably isn't quite right, and that there are probably better ways to handle the same thing.

Bonus: If you need to go somewhere that already is in charge of setting itself up, and you don't need access to any of the in scope variables, a redirect is probably a better choice. That way, you don't need to re-describe your controller logic in multiple places. Here is an example from your posted code:

    # inefficient and not DRY
@user = User.find(current_user)
@microposts = @user.microposts.paginate(page: params[:page])
render 'users/show'

# does the same thing as above (in this case)
redirect_to users_path

In Rails when a resource create action fails and calls render :new, why must the URL change to the resource's index url?

It actually is sending you to the create path. It's in the create action, the path for which is /books, using HTTP method POST. This looks the same as the index path /books, but the index path is using HTTP method GET. The rails routing code takes the method into account when determining which action to call. After validation fails, you're still in the create action, but you're rendering the new view. It's a bit confusing, but a line like render :new doesn't actually invoke the new action at all; it's still running the create action and it tells Rails to render the new view.

RoR: button click action call

In light of the other answers not working, here is what I propose:

#config/routes.rb
resources :logins, only: [:index, :create] do
collection do
get :buttons
end
end

#view
<%= link_to "Submit", logins_buttons_path # -> whatever the path helper is %>

I have used link_to because this answer recommends button_to for POST requests. This should work for you, but it's non-conventional, so you'll be best describing how you want it it work


Update

I am glad this worked for you

Several things which probably contributed to its functionality:

  1. Conventional routes
  2. Using link_to

When using routing in Rails, it's basically middleware which defines how your app will "catch" incoming requests. When you browse to domain.com/route, Rails takes the /route & the HTTP verb part of the URL & loads the corresponding controller / action to help it load up.

When defining your routes, you therefore need to be extremely careful about which routes you define, and how you define them. The best way is to use Rails conventions (which essentially means using inbuilt helpers) such as resources :controller

--

We also used the link_to in place of button_to

button_to creates a small form on your page, which then sends a request to your assigned route. This form is typically POST, but can be assigned GET. In light of your new comment, you'll probably want to read up on the button_to documentation to get it formatted correctly



Related Topics



Leave a reply



Submit