Rails 3 - Forms, Custom Submit Button based on Action? - ruby-on-rails

I currently have a couple of forms that I'm trying to change the button that submits it based if I'm on the edit or new action. I had two forms created but this smelt bad, and am now just using a single form partial.
At the end of my partial, I have something like this at the end of my forms:
<p>
<% if controller.action_name == 'new' %>
<%= f.submit "Create", :class => "pink_button"%> or
<% elsif controller.action_name == 'edit' %>
<%= f.submit "Update", :class => "pink_button"%> or
<% end %>
<%= link_to "cancel", :back %>
</p>
That way, if I'm creating some new, the button reads "Create", and if it's an update that a user is trying to complete, the button reads "Update". This works great, until the form is submitted and validation fails.
In my controller, I'm catching things that do fail like so:
def update
#list = current_user.lists.find(params[:id])
if #list.update_attributes(params[:list])
redirect_to list_path(#list), :notice => "List '#{#list.name}' updated."
else
render :action => 'edit'
end
end
So the form is simply re-rendered. The problem is, I'm no longer on the edit path. This means, my form button does not show up any longer.
Is there a convention to what I'm trying to do?
Thanks

Yes, this is handled in Rails with i18n by default. The translations are in ActionView, and look like this:
en:
helpers:
select:
# Default value for :prompt => true in FormOptionsHelper
prompt: "Please select"
# Default translation keys for submit FormHelper
submit:
create: 'Create %{model}'
update: 'Update %{model}'
submit: 'Save %{model}'
All you need to do is f.submit (without passing "Create" or "Edit", etc) and the translations will do the rest. You can overwrite these by dropping the above yaml into your local locales.
If you need to set the class you can pass nil, e.g. f.submit nil, :class => 'whatev'

The Rails way is to check if the record is new or not:
#list.new_record? ? "Create" : "Update"

Rails has a method persisted? to determine if an object has persisted.
If you're using erb, do
<%= f.submit (#list.persisted? ? 'Create' : 'Update) %>
If you're using haml, use
= f.submit (#list.persisted? ? 'Create' : 'Update')
For more, see http://apidock.com/rails/ActiveRecord/Persistence/persisted%3F

Related

Select_tag login

I would like to have a drop down menu with a list of all the user names in the db. From there, I would like the user to choose his/her name and be able to click login and be taken to their respective page. At this point, a password is not needed. Currently, I have the following:
controller:
def login
#user = User.new
#users = User.all
# #user = User.find_by_id(:id)
# redirect_to user_path(#user)
end
view:
<%= form_for #user, url: '/login', html: {method: 'get'} do |f| %>
<%= f.label "Name" %>
<br/>
<%= select_tag :user, options_for_select(#users) do |users| %>
<%= link_to users.name, users %>
<% end %>
<br/>
<br/>
<%= f.submit 'Login' %>
<% end %>
I cannot seem to link the user to their path and also, i want to show the users name in the drop down menu. Currently, it shows a hexidecimal pointer.
Thank you in advance.
You shouldn't be making a new User object here: you just want to load one out of the database. What you want to do in the controller is just to set current_user to be one of the existing users, right?
Also you've got the form submitting back to the action which loads the form in, which seems weird. I would make it submit to a new action, like "set_current_user" which is a POST action.
in your login template:
<%= form_tag '/set_current_user' do %>
<%= f.label "Name" %>
<br/>
<%= select_tag "user_id", options_for_select(#users.collect{|user| [user.name, user.id] } %>
<br/>
<br/>
<%= submit_tag 'Login' %>
<% end %>
in the controller (you'll need to amend routes.rb to make the '/set_current_user' go to this action) you then need to set something which will keep the user logged in. The traditional way to do this is via session[:user_id], and to have a method current_user which uses this.
def set_current_user
session[:user_id] = params[:user_id]
redirect_to "/" and return
end
Your initial approach is reminiscent of how this sort of thing is normally handled, wherein you do have a form_for, but it's for a UserSession object rather than a User object.

Get checked status of checkbox in controller

i have a form in my index-view where i create multiple checkboxes. One checkbox for every entry. This looks like this:
index.html.erb
<%= form_for :user, url: usersupdate_path() do |f| %>
<%= render #users %>
<%= f.submit 'test', :class => 'btn btn-primary' %>
<% end %>
_user.html.erb
<%= check_box_tag "checked[#{user.id}]","#{user.id}",true %>
Description:
With the form i want to allow the admin to uncheck users - this users i want to send to the controller and update their attributes.
There are only 2 problems:
1) I have to refresh the site until i can send the form to the controller - i don't know why
2) When i print the array it looks like this:
{"1"=>"1", "2"=>"2", "4"=>"4"}
User 3 was unchecked by me.
What i want is something like this:
{"1"=>"true", "2"=>"true", "3"=>"false", "4"=>"true"}
But how can i send the checked value of the checkbox to the controller?
In my controller i do only this at the moment:
def update
flash[:success] = params[:checked]
redirect_to root_path
end
Thanks
The browser does not serialize an unchecked checkbox when sending form data, so if it is not checked, it never gets sent.
You can generally fix this two ways. Make your action smart enough to see "missing" values as "unchecked", or add a hidden field before each checkbox:
<%= hidden_field_tag "checked[#{user.id}]", "false" %>
<%= check_box_tag "checked[#{user.id}]","#{user.id}", true %>
As for the true-values, the second parameter to check_box_tag is the value you want the checkbox to have, so you can change it to this:
<%= hidden_field_tag "checked[#{user.id}]", "false" %>
<%= check_box_tag "checked[#{user.id}]","true", true %>
And it should do what you want.
Note that if you use FormBuilders they handle this nuance for you.

Detecting multiple submit_tag click in Rails [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Ruby on Rails: How to have multiple submit buttons going to different methods (maybe with with_action?)
In a form I have some submit_tags and on server side I have to detect which one was clicked.
This is that I've tried, not working: on server side I only get an action name in params:
<%= form_tag controller_action_path(:id => #project.id), :method => :post do %>
<% if #project_is_synced %>
<%= submit_tag 'Update synchronization', :name => 'update' %>
<%= submit_tag 'Stop synchronization', :name => 'stop' %>
<% else %>
<%= submit_tag 'Start synchronization', :name => 'start' %>
<% end %>
<% end %>
I have only params[:action] with a current action name which is always the same
The easiest way to debug this is to run it locally and look at the parameters as they come through, or log parameters in your action:
if request.post?
logger.warn "POST #{params}"
end
You have named the submit_tags, so instead of the default name 'commit', each button has a different name, and you'll have to check for params named 'start', 'stop', or 'update'.
Simplest is just to remove the names and check params[:commit] for a varying value, however if you don't want to change the view, use this (replacing the render code obviously):
if params[:start]
render :text => "start"
elsif params[:update]
render :text => "update"
else
render :text => "stop"
end
The comments to the answer in the linked post do deal with this, but I can see why you missed it.

Make Rails wait for form submission before continuing

I have the following form and controller.
<%= form_tag do %>
<div>
<%= label_tag :Old %>
<%= password_field_tag :old_password %>
</div>
<div>
<%= label_tag :New %>
<%= password_field_tag :new_password %>
</div>
<div>
<%= label_tag :Confirm %>
<%= password_field_tag :confirm_password %>
</div>
<div>
<%= submit_tag "Update" %>
</div>
<% end %>
and the controller:
def change
#user = current_user
#op = params[:old_password]
#np = params[:new_password]
#cp = params[:confirm_password]
if #np == #cp
#user.update_with_password(:password => #np, :current_password=>#op)
if #user.save
flash[:notice] = "Password Successfully Changed"
redirect_to home_path
end
else
#user.errors.add("Incorrect confirmation")
end
end
This is all tied to 'password/change' in the config/routes.rb
The problem is that when I go to /password/change I immediately an redirected to home and receive the "password successfully changed" flash notice. What I take from it is that it is not requiring me to click the submit button in order to pass the parameters. How do I make it so that it waits for the submission of the form before continuing through the controller?
The problem is that you need 2 separate methods. One to show the view and one to handle the form post.
Right now the "change" method in your password_controller is handling the form post so you need a method like "index" to show the form
def index
#move your form to /views/password/index.html.erb or specifically render your 'change' view
end
Then in your markup add the action to your form
<%= form_tag('/password/change') do %>
…
Then in your controller you can specify POST only for the change method
class PasswordController < ApplicationController
verify :method => :post, :only => :change
…
UPDATE
Instead of using the verify method (removed in rails 3) you should either set up your route to be restful (Rails Routing from the Outside In) or you can create a specific route for changing the password like so:
match 'password/change' => 'password#change', :via => :post
The best practice will be to separate these two things into different controller methods. One should be used to simply display the view, while the other should be used to handle the POST request. However, if you're dead set on doing it this way, I believe a solution like this will work:
def change
#user = current_user
#op = params[:old_password]
#np = params[:new_password]
#cp = params[:confirm_password]
if #np && #np == #cp # This checks to see if params[:new_password] is nil
#user.update_with_password(:password => #np, :current_password=>#op)
I'd strongly suggest you separate it out though.
When you render password/change from the browser, params is nil, so #np == #cp always evaluates to TRUE, executes the update, saves, and does the redirect — in fact, if you check I would bet the user's password is being set to nil.
You need to make sure the params are not empty before attempting the update.
Does that help point you in the right direction?
side note: from a code readability standpoint I might recommend just using the variables inline, instead of the instance vars, but that's just my opinion :)

2 submit buttons in a form

I have a question about forms. I have a fairly standard form that saves a post (called an eReport in my app) with a title and body. The table also has a "published" field, which is boolean. The saved eReport only shows on the public site if this field is set to true, with false being the default.
Rather than the default check box, I would like to display two buttons at the end of the form: a "Publish Now" button and a "Save as Draft" button. If the user presses the former, the published field would be set to true. If the latter, then false. In PHP, I used to display 2 submit fields with different name values, then handle the input with an if/else statement to determine the proper SQL query to build. In Rails, I'm assuming I would place this logic in the controller, under the appropriate action, but I'm not sure how to manipulate the name or id values of buttons.
For the record, I'm using Formtastic, but if someone could show me how to do this with the default Rails form tags, that's OK too. Here's the code for my form as it stands right now:
<% semantic_form_for #ereport do |form| %>
<% form.inputs do %>
<%= form.input :title %>
<%= form.input :body %>
<% end %>
<% form.buttons do %>
<%= form.commit_button :label => "Publish Now" %>
<%= form.commit_button :label => "Save as Draft" %>
<% end %>
<% end %>
Thanks in advance for the help!
I don't know about formtastic, but with the default rails form builder, you could do it like this:
<%= form.submit "Save with option A", :name => "save_option_a" %>
<%= form.submit "Save with option B", :name => "save_option_b" %>
Then in the controller, you can pick those up in params:
if params[:save_option_a]
# do stuff
end
in addition to #iddlefingers answer, here is a view of the log of the application (striping some useless params due to explanation purposes)
Parameters: {"utf8"=>"✓", ..., "comentar"=>"Confirmar"}
where we can see that comentar is the name of the parameter, and "Confirmar" is it's value, which is the button's text too.
which was obtained by submit_tag "Confirmar", :name => 'comentar'
So in general you could have (if you want to reduce the number of params you are working with) several submit_tag "onevalue", :name => 'SAMEname', submit_tag "othervalue", :name => 'SAMEname'...
and retrieve them in your controller
if params[:SAMEname] == "onevalue"
# do stuff
elsif params[:SAMEname] == "othervalue"
#do different stuff
end
I think you need to use jQuery.
You can bind the button click event and submit the form for specified location.

Resources