Help with checkboxes - ruby-on-rails

When a user submits without any boxes checked. I need my ODM (Mongoid) to update the record appropriately.
Having a bit of trouble with:
<% Notification.all.each do |notification| %>
<li>
<%= check_box_tag 'user[notification_ids][]', notification.id, #user.notifications.include?(notification) %>
<%= label_tag notification.description %>
</li>
<% end %>
The doc suggests that the check_box helper puts in a hidden input. The hidden field has the same name and its attributes mimic an unchecked check box. However, with the above code. I am going through a loop. Which is slightly different.
I tried:
<%= check_box('user_notification_ids_', '', options = {:index => notification.id, :checked => #user.notifications.include?(notification)}, checked_value = "1", unchecked_value = "0") %>
But whenever I submit, I get: illegal ObjectId format
Or should I create the hidden tag for notification_ids manually? Something like:
<%= hidden_field_tag 'user[notification_ids][]', '[]' %>
Looking to hear your feedback

Go with the first loop you included. It looks much simpler and looks like it does the same thing.
If I understand your first sentence correctly, it sounds like you aren't seeing the user's notifications getting updated to none when they uncheck all the check boxes. When there are no check boxes checked, the browser won't send that param back. It simply won't be included in params so when you do something like:
#user.update_attributes(params[:user])
... notifications won't get updated. In your controller, do this to ensure there is something set for params[:user][:notifications]:
params[:user][:notifications] ||= []
This is will set it to an empty array if there if it doesn't exists and/or there's no value there. This ensures that update_attributes will set it to none/empty.

check_box_tag doesn't generate any hidden field. check_box does, but looking at your situation, I think using check_box_tag is more appropriate since the check_box method is mainly used for boolean field. Here is one way to do it.
<%= hidden_field_tag 'user[notification_ids][]' %>
<% Notification.all.each do |notification| %>
<li>
<%= check_box_tag 'user[notification_ids][]', notification.id, #user.notifications.include?(notification) %>
<%= label_tag notification.description %>
</li>
<% end %>
When the form is submitted with the checkboxes for Notification of id 2 and 3 checked, the value for params[:user] is { "notification_ids" => ["", "2", "3"] }. When nothing is checked, params[:user] is {"notification_ids"=>[""]}, which will clear the user's notifications. This works because empty string is ignored by ActiveRecord. From here, we can use the usual #user.update_attributes(params[:user]) to update the User model.

Related

Adding a confirmation checkbox to a form in Rails not tied to some attribute?

Noob question! :)
I have a form, that has basically no point other than call some_action. The reason I use a form for this, is because we have a specific styling for this in our large website.
<%= styled_form_for(#user, :url => some_action_user_path #user)) do |f| %>
<%= f.save_button %>
<% end %>
I thought, since it's a form, I should be able to put a checkbox in there. It should have no other goal than confirming the user wants to do this action indeed. E.g. "Yes, I want to do some_action to the user model".
How would I make a checkbox that does not really change any attribute or affect anything - Other than that it should be checked for the form to submit?
This is probably dead simple, but according to the documentation and various error messages I should provide arguments such an attribute (which I don't want...)
form_for is meant to work on attributes of a model, which is what all the documentation you are reading is telling you. So if your model had a boolean column you could easily attach a check box to it.
If you ever want a form (or specific tag) that does not follow this, you can use the _tag version of these methods. For example, form_tag or, in your particular case, check_box_tag.
Example:
<%= styled_form_for(#user, :url => some_action_user_path #user)) do |f| %>
<%= check_box_tag "do_some_method" %>
<%= f.save_button %>
<% end %>
NOTE: You will only get a param entry for :do_some_method if it is checked off. If you want to get a param regardless, you have to add a hidden_field_tag before it.
<%= hidden_field_tag "do_some_method", "no_dont_do_it" %>
<%= check_box_tag "do_some_method", "yes_do_it" %>
Now if the checkbox is selected you'll get params[:do_some_method] set to "yes_do_it"; if it's not checked off, instead of getting no entry, you'll get params[:do_some_method] set to "no_dont_do_it".

Does select_tag always have to return something?

I have two forms that leads to one controller action:
<%= form_tag some_action_path do %>
<%= slect_tag 'foo[]', options_for_select([
["Nothing", nil],
["wal1", "wal1"],
["wal2", "wal2"]]) %>
<%= submit_tag "Search" %>
<% end %>
<%= form_tag some_action_path do %>
<%= check_box_tag 'foo[]', "wal1" %>
<%= check_box_tag 'foo[]', "wal2" %>
<%= submit_tag "Search" %>
<% end %>
My problem is that when I select "Nothing" in select select_tag I get [""], on the other hand when I submit second form without any check_box selected I get nil. Which gives me a headake in my search function. Because it have to look like this:
def search_action(foo)
if foo.nil?
Obj.all
elsif foo.present? && foo[0].blank?
Obj.all
elsif foo.present? && foo[0].pesent?
Obj.where(foo: foo)
end
end
The function above is irrelewent, I only wanted to show how the difference output between those two forms complicate my search action.
My question:
Is there any way to return nil from "select_tag" form? Or I am stupid to lead two forms to one controller action and one search method, and I should write two actions with two search action that leads to one view. :D
Usually the search functionality is in one form where you have the both options available, but there is nothing wrong with your approach if you want them to be separate searches. Though I would rename the input of either of the forms to not be same as the other forms inputs to differentiate them on controller and then be able to write something like
def search_action(foo)
if form_1_attribute.present?
Obj.where(form_1_attribute: form_1_attribute)
elsif form_2_attribute.present? && form_2_attribute.blank?
Obj.where(form_2_attribute: form_2_attribute)
else
Obj.all
end
end

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.

Rails forms: How to append request params?

I got a list page and I filter items via links with get params (I can choose many links so query would be like "?param1=value1&param2=value2"). But also I have to filter it by text field, so I made a form:
<form>
<%= text_field_tag :zip, params[:zip] %>
<%= submit_tag 'OK', :name => nil %>
</form>
But when I submit it, text field param replaces existing query params. So, how to make text field value add to query, not to replace it?
Since I was just dealing with this problem in Rails 4 I thought I'd share my solution.
My page gets loaded with a sport_id parameter, and when the user specifies a sort-order I wanted it to submit a GET request for page.url/event?sport_id=1&sortby=viewers but it wouldn't preserve the sport_id parameter until I added a hidden field tag in the form like so:
<%= hidden_field_tag :sport_id, params[:sport_id] %>
This solution does submit an empty sport_id parameter if that parameter was not in the original request, but that is easily prevented by encapsulating the hidden field in an <% if params[:sport_id].present? %> condition.
Use hidden_field_tag.
Inside of your form, just set hidden_field_tags for the existing GET params, like so:
<% request.query_parameters.collect do |key, value| %>
<%= hidden_field_tag key, value %>
<% end %>
This will ensure that your existing params persist.
Rails 3?
<%= form_tag your_path(params.except(:controller, :action)), :method => :get do %>
<%= text_field_tag :zip, params[:zip] %>
<%= submit_tag 'OK', :name => nil %>
<% end %>

ruby on rails will paginate between dates

In the application there is a default report the user see's listing all the calls for a certain phone. However, the user can select a date range to sort the list from. Doing that, everything works correctly, but when the user selects the date range and changes to the second page, the date-range is lost and it goes back to the default view for the second page.
In my controller, I'm checking to see if the date_range param is being passed in. If it isn't, I display the entire listing, if it is, I display the records in between the certain date range.
The problem is, when I click on a new page, the new parameter doesn't include the old date-range that it should.
How do I go about doing this, I was thinking of doing some class level variable test but that isn't working out the way I thought. And I'm pretty stuck.
I don't have the code right in front of me, but if I remember correctly it's something like this:
<% form for :date_range do |f| %>
<%= f.calendar_date_select :start %>
<%= f.calendar_date_select :end %>
<%= f.Submit %>
<% end %>
And in the controller, it's something like:
if params[:date_range] == nil
find the complete listings without a date range
else
find the listings that are within the date range
end
The main problem is that you're using a POST request when submitting the form, but will-paginate uses a GET request. You should also use form_tag instead of form_for because form_for will nest the fields in a hash which is not possible with GET.
<% form_tag items_path, :method => 'get' do %>
<%= calendar_date_select_tag :start_date %>
<%= calendar_date_select_tag :end_date %>
<%= submit_tag "Submit", :name => nil %>
<% end %>
Then check params[:start_date] and params[:end_date] directly. You'll need to change items_path to whatever page you want the form to go to.
This is untested but it should get you in the right direction.
You could modify the link_to (assuming that's how you go through pages) so that it passed the date_range param.
= link_to 'Next', #whatever_path, :date_range => #date_range
where #date_range could be set in your controller by capturing your params in an instance variable.. .
But there may be a better solution.

Resources