2 buttons, 1 form - ruby-on-rails

I have a simple form that looks like so
<% remote_form_for post, :url => post_path(post), :method => :put do |f| -%>
<%= f.submit "Approve" %>
<%= f.submit "Deny" %>
<% end -%>
Which renders
<input type="submit" value="Approve" name="commit"/>
<input type="submit" value="Deny" name="commit"/>
In my controller I have the following logic
#post.approved = params[:commit] == 'Approve' ? true : false
So problem is that if the user clicks the "Approve" button or the "Deny" button the parameter that is sent is that :commit => "Approve".
Does anybody know of a bug relating to this or another (simple) way to perform the same functionality?
Thanks.

JS lib (Prototype I guess) doesn't know what button was pressed. It just serializes the form field values for the Ajax request. When using normal form POST, browsers attach right value to the commit param.
You can add hidden form field (eg action). Then add JS code to set required value of the hidden field when appropriate button is pressed (and before the Ajax request is sent).

Another option is to override the "name" parameter of the second button.
<%= f.submit "Deny", :name => "commit_deny" %>

I think Submit is unique per form (HTML thing) so yopu have two options:
Use 2 forms whith 1 submit each, that lead to the same action (CSS it to you liking)
Use 2 button-type controls (i.e. not submits) and submit with both onClick events (javascript needed)

Related

Rails verify if an image is clicked before sending the form

I am new to Rails and am trying to create a form that submit a value to the database depends on the image clicked.
I have five images and a submit button. I am thinking of turning the five images into button class so that whenever it is clicked, it will run an action in the Article Controller and pass the value.
For example if the first image is clicked, it will run the action #article.title="First image is clicked" and the submit button will run the Create action of #article.save.
I tried:
<%= button_to "Submit Score", { :controller => "articles", :action => "submitScore"} %>
but for some reasons when I press the image it tries to run the Create action in the Article Controller and tries to save it as well. I know that because I have some data validation and restricted the #article.title cannot be blank and when I press the image button it says title cannot be blank.
What is the best way to do this?
button_to generates an entire form tag. Try using button tags with value attributes contained within a form tag helper:
<%= form_for #article, articles_path do |f| %>
<%= f.text_field :title %> <!-- or hidden field? -->
<button type="submit" name="article[score]" value="1">
<%= image_tag 'foobar.gif' %>
</button>
<% end %>
instead of the button_to helper.
Overlay a checkbox on each image. Make the label for the checkbox encompass the image so when the image is clicked the checkbox is checked. (Use radio buttons if you want the user to select only one image)
Then when the form is submitted to the controller, the controller can check the params to see what image(s) were selected and do whatever it needs to do.

Add multiple "types" to a submit button in RoR

I have a submit button on a form that is an image, and I want it to clear the form once it is clicked.
To make the submit button an image, I use the following code:
<%= f.submit "2", :type => :image, :src => "/assets/down.png" %>
To make the button clear the form, I use the following code
<%= f.submit "2", :type => :reset %>
But I have tried and failed to add two "types" to the form
Any Ideas?
You should use javascript here (to submit your form after pressing on your image (or as you want -- reset it).
$('#form').trigger("reset");
This isn't possible.
By default, the form_for submit must and will be an HTML tag <input type="submit" />. Without the type attribute being set to "submit", the tag wouldn't actually be a submit button and would certainly not be able to submit the form without some sort of client-side intercession (e.g., Javascript).
CORRECTION:
The OP is correct that "image" is indeed a valid type attribute for an image button.

Erroneous value for commit options in params hash

I'm using a submit_tag form helper in one of my apps. The value of this submit button should change dynamically. The two possible values for this submit button are Save and Update. So, in the view, I have done something like the following:
<% temp = 0 %>
<% text = '' %>
<% temp = ActivityLog.find_by_sql("SELECT COUNT(id) AS cnt FROM logs WHERE id > 0")%>
<% text = temp[0][:count].to_i > 0 ? 'Update' : 'Save' %>
<!-- other html contents -->
<%= submit_tag text, :id=>"submitBtn"+i.to_s, :onclick=>"submit_button_clicked(this)"%>
Now, when I run the view inside a browser, I can see the desired effect. But the rails controller receives the erroneous value for the commit options in the params hash.
For instance, when the value of text is evaluated to Save, I get the following in the Firebug:
<input type="submit" value="Save" style="" onclick="submit_button_clicked(this)" name="commit" id="submitBtn3">
But raise params.inspect in the associated controller shows the follwing:
{"commit"=>"Update",
"authenticity_token"=>"",
"time"=>{"292"=>"3.0",
"2"=>"1.0",
"456"=>"4.0"},
"date"=>"2011-09-20"}
See, although the value of the Submit button is shown as Save in the HTML, the rails controller shows the value of commit as Update. What's wrong in here?
If you are using Rails helpers, it provides a simple way to choose text on button with according to type of form:
<%= form_for #activity do |f| %>
<%= f.label :title %>:
<%= f.text_field :title %><br />
<%= f.submit %>
<% end %>
When no value is given, it checks if the object is a new resource or not to create the proper label. In the example above, if #activity is a new record, it will use "Create Activity" as submit button label, otherwise, it uses "Update Activity".
P.S. please do not use SQL in your views

Easy way to turn a Rails form into an AJAX form?

I have the following form in my Rails application:
<% form_tag password_resets_path, :id => 'recoverPasswordForm' do %>
<label for="passwordRecoveryEmailAddress">Email Address:</label>
<%= text_field_tag "passwordRecoveryEmailAddress" %>
<%= submit_tag 'Recover' %>
<br />
<div id="forgotPasswordLoginLinkContainer">
<a id="forgotPasswordLoginLink" href="/login">Login Instead</a>
</div>
<% end %>
When this form is submitted, the page must reload. I would like to easily turn this form into an AJAX form, such that the form submits via AJAX, and a page reload does not happen.
I could do this easily using jQuery, hooking into the .submit() function. But, I am curious: does Rails provide some easy way to turn any given form into an AJAX form? Or, what's the simplest (yet elegant) way possible? Maybe something like
<% form_tag password_resets_path, :id => 'recoverPasswordForm', :ajax => true do %>
I'm using Rails 2.
Yes, and you were close with your guess. Rails 3 allows you to do form_tag ..., :remote => true to let the form use AJAX if Javascript is available.
See http://railsapi.com/doc/rails-v3.0.0/classes/ActionView/Helpers/FormTagHelper.html#M002483

How do I create multiple submit buttons for the same form in Rails?

I need to have multiple submit buttons.
I have a form which creates an instance of Contact_Call.
One button creates it as normal.
The other button creates it but needs to have a different :attribute value from the default, and it also needs to set the attribute on a different, but related model used in the controller.
How do I do that? I can't change the route, so is there a way to send a different variable that gets picked up by [:params]?
And if I do then, what do I do in the controller, set up a case statement?
You can create multiple submit buttons and provide a different value to each:
<% form_for(something) do |f| %>
..
<%= f.submit 'A' %>
<%= f.submit 'B' %>
..
<% end %>
This will output:
<input type="submit" value="A" id=".." name="commit" />
<input type="submit" value="B" id=".." name="commit" />
Inside your controller, the submitted button's value will be identified by the parameter commit. Check the value to do the required processing:
def <controller action>
if params[:commit] == 'A'
# A was pressed
elsif params[:commit] == 'B'
# B was pressed
end
end
However, remember that this tightly couples your view to the controller which may not be very desirable.
There is also another approach, using the formaction attribute on the submit button:
<% form_for(something) do |f| %>
...
<%= f.submit "Create" %>
<%= f.submit "Special Action", formaction: special_action_path %>
<% end %>
The code stays clean, as the standard create button doesn't need any change, you only insert a routing path for the special button:
formaction:
The URI of a program that processes the information submitted by the input element, if it is a submit button or image. If specified, it overrides the action attribute of the element's form owner.
Source: MDN
You can alternatively recognized which button was pressed changing its attribute name.
<% form_for(something) do |f| %>
..
<%= f.submit 'A', name: 'a_button' %>
<%= f.submit 'B', name: 'b_button' %>
..
<% end %>
It's a little bit uncomfortable because you have to check for params keys presence instead of simply check params[:commit] value: you will receive params[:a_button] or params[:b_button] depending on which one was pressed.
Similar solution to one suggested by #vss123 without using any gems:
resources :plan do
post :save, constraints: lambda {|req| req.params.key?(:propose)}, action: :propose
post :save, constraints: lambda {|req| req.params.key?(:finalize)}, action: :finalize
end
Notice that I avoid using value and use input name instead since submit button value is often internationalized / translated. Also, I'd avoid using this too much since it will quickly clutter your routes file.
We solved using advanced constraints in rails.
The idea is to have the same path (and hence the same named route & action) but with constraints routing to different actions.
resources :plan do
post :save, constraints: CommitParamRouting.new("Propose"), action: :propose
post :save, constraints: CommitParamRouting.new("Finalize"), action: :finalize
end
CommitParamRouting is a simple class that has a method matches? which returns true if the commit param matches the given instance attr. value.
This available as a gem commit_param_matching.
An old question, but since I've been dealing with the same situation, I thought I'd post my solution. I'm using controller constants to avoid introducing a discrepancy between the controller logic and the view button.
class SearchController < ApplicationController
SEARCH_TYPES = {
:searchABC => "Search ABCs",
:search123 => "Search 123s"
}
def search
[...]
if params[:commit] == SEARCH_TYPES[:searchABC]
[...]
elsif params[:commit] == SEARCH_TYPES[:search123]
[...]
else
flash[:error] = "Search type not found!"]
[...]
end
end
[...]
end
And then in the view:
<% form_for(something) do |f| %>
[...]
<%= f.submit SearchController::SEARCH_TYPES[:searchABC] %>
<%= f.submit SearchController::SEARCH_TYPES[:search123] %>
[...]
<% end %>
This way the text only lives in one place - as a constant in the controller. I haven't tried to figure out how to i18n this yet, however.
I have a variable number of submit buttons on my form thanks to nested_form_fields, so just using the name wasn't enough for me. I ended up including a hidden input field in the form and using Javascript to populate it when one of the form submit buttons was pressed.

Resources