How to use form input(s) in calculations? - ruby-on-rails

I am putting together a survey-submitting website, and I am giving visitors the option of specifying the time and date of a particular event they created:
<table>
<tr>
<td><%= text_field(:day, "", placeholder: "DD") %></td>
<td><%= text_field(:month, "", placeholder: "MM") %></td>
<td><%= text_field(:year, "", placeholder: "YYYY") %></td>
<td><%= text_field(:hour, "", placeholder: "HH") %> : <%= text_field(:minute, "", placeholder: "MM") %> </td>
<td><%= radio_button_tag(:ampm, "AM") %></td><td><%= label_tag(:ampm, "AM") %></td>
<td></td>
<td><%= radio_button_tag(:ampm, "PM") %></td><td><%= label_tag(:ampm, "PM") %></td>
</tr>
</table>
My Survey model has a :time_of_event attribute that holds a Time object which will represent the time specified by the user that fills out the form. I intend to make use of Time.parse to create a Time object out of the 'YYYY-MM-DD HH:MM:00' that the user specifies.
I have minimal experience using Rails forms - I can create basic text_field tags, and can save the input in those tags to a particular model's attribute upon submitting the form.
How (if at all) can I go about calculating the input in form fields, and save that calculated result to a model's attribute?
In other words, something that will probably end up looking like:
survey.time_of_event = Time.parse(form_params[:year] + '-' + form_params[:month] ...etc)

Related

How to dynamically generate checkboxes on the view and submit to controller?

I send a collection to my view and iterate over it. Each iteration has a checkbox as well as two text fields. I want to be able to submit selected items, but also submit the values in the text field as an update as well.
<% #lots.each_with_index do |lot, index| %>
<tr>
<td><%= lot.lot_code %></td>
<td ><%= check_box_tag "lots[][lot_id]", lot.id, false, %></td>
<td><%= text_field_tag "lots[][seal_num]", lot.seal_number %></td>
<td><%= text_field_tag "lots[][contr_num]", lot.container_number %></td>
</tr>
<% end %>
My #lots collection has three rows:
{id: 2, container_number: "container#0002", seal_number: "seal#0002"}
{id: 6, container_number: "container#0006", seal_number: "seal#0006"}
{id: 11, container_number: "container#00011", seal_number: "seal#00011"}
(apologies if that is not proper hash syntax)
My problem is that if I check items 1 and 3, the parameter string shows the following:
"lots"=>[{"lot_id"=>"2", "seal_num"=>"seal 0002", "contr_num"=>"container#0002"},
{"seal_num"=>"Seal-006", "contr_num"=>"container #006", "lot_id"=>"11"},
{"seal_num"=>"Seal-0011", "contr_num"=>"container #0011"}]
The problem is that lot_id = 11 should be the 3rd item in the array, not the second. For some reason, because item #2 is not selected, the empty lot_id element is being populated by the next one in the sequence.
How do I make sure the selected IDs are in the same elements as the other attributes? Or how do I make sure the non-selected items don't even end up on the parameter string?
Edit: I have also tried the following:
<% #lots.each_with_index do |lot, index| %>
<tr>
<td><%= lot.lot_code %></td>
<td ><%= check_box_tag "lots[#{index}][lot_id]", lot.id, false, %></td>
<td><%= text_field_tag "lots[#{index}][seal_num]", lot.seal_number %></td>
<td><%= text_field_tag "lots[#{index}][contr_num]", lot.container_number %></td>
</tr>
<% end %>
And I get this on the following parameter string:
lots"=>{"0"=>{"lot_id"=>"2", "seal_num"=>"seal 0002", "contr_num"=>"container#0002"},
"1"=>{"seal_num"=>"Seal-006", "contr_num"=>"container #006"},
"2"=>{"lot_id"=>"19", "seal_num"=>"Seal-0011", "contr_num"=>"container #0011"}}
This maintains the integrity of the rows as desired, but I later get a "TypeError: no implicit conversion of String into Integer" later on in processing.
Edit 2: Realized the solution in the edit created a hash, and my code was looking to access an array. So when the hash was iterated over, I was errantly accessing the key, an integer, rather than the value.

Correct way of conditional rendering within a partial in Rails?

I have created a partial for a LineItem that, in my case, emits a <tr> with a couple of <td>s. This works just fine and dandy.
What I'd want to do then, is use the same partial in different places. The original view has plenty of room, so displaying every cell is ok. But another (a sidebar), has much less space, and I'd only want to display two of the 5 cells.
So the question, then, is what is the correct way of implementing this? I'd like for the "full" version to be the default unless otherwise specified, and only use the limited version if a parameter is passed.
Currently I'd probably use the feature of passing locals to a partial and check if a parameter limited is defined, and if so, skip the last N cells. Am I on a right track, and if so, what kind of a variable should I use (can I use symbols for this)?
Current _line_item.html.erb (that I'm somewhat unhappy with)
<tr>
<td><%= line_item.quantity %>×</td>
<td><%= line_item.product.title %></td>
<td class="item_price"><%= number_to_currency(line_item.total_price, unit: '€') %></td>
<% unless defined? limited %>
<td class="remove_item"><%= button_to 'Remove', line_item, method: :delete %></td>
<% end %>
</tr>
Edit: Added current version.
Yes, you are on the right track. You can do something like
<%= render 'partial_name', limited: true %>
and then in the partial:
<% limited ||= false %> # More explicit as to what default value is
<tr>
<td><%= line_item.quantity %>×</td>
<td><%= line_item.product.title %></td>
<td class="item_price"><%= number_to_currency(line_item.total_price, unit: '€') %></td>
<% unless limited %>
<td class="remove_item"><%= button_to 'Remove', line_item, method: :delete %></td>
<% end %>
</tr>

Update a time field dynamically when checking a checkbox in Rails & dynamically updating the DB without using a Submit button

I'm trying to do the following:
1) When a checkbox gets checked, I want the Time of Arrival box to be updated with the time when the checkbox got checked dynamically.
I don't want to be pressing a submit button or anything of that sort, it should be dynamic, via AJAX i guess.
My current code looks like this:
<table border="1">
<tr>
<td><b>Present</b></td>
<td><b>Student ID</b></td>
<td><b>First Name</b></td>
<td><b>Last Name</b></td>
<td><b>Time of Arrival</b></td>
</tr>
<% #register.student_registers.each do |student_register| %>
<tr>
<td><%= check_box_tag "student_registers_ids[#{student_register.id}]", student_register.id, student_register.present?%></td>
<td><%= student_register.student.university_id%></td>
<td><%= student_register.student.first_name.titlecase%></td>
<td><%= student_register.student.last_name.titlecase%></td>
<td><%= student_register.time_of_arrival %></td>
</tr>
<% end %>
</table>
2) The other thing I want to do is to update the record in the database, as soon as the Present checkbox gets checked, without having to press a Submit button. This will be done in the model#show page, not the model#edit page.
Any suggestions?
EDIT:
I changed the code around, but it still isn't working...
<table border="1">
<tr>
<td><b>Present</b></td>
<td><b>Student ID</b></td>
<td><b>First Name</b></td>
<td><b>Last Name</b></td>
<td><b>Time of Arrival</b></td>
</tr>
<% form_tag :remote => true %>
<% #register.student_registers.each do |student_register| %>
<tr>
<td><%= check_box_tag "student_registers_ids[#{student_register.id}]",
student_register.id, student_register.present?,
:disabled => false,
:onclick => 'popup ' %></td>
<td><%= label_tag 'UniversityId', student_register.student.university_id%></td>
<td><%= label_tag 'FirstName', student_register.student.first_name.titlecase%></td>
<td><%= label_tag 'LastName', student_register.student.last_name.titlecase%></td>
<td><%= label_tag student_register.time_of_arrival, nil, :class => 'TimeOfArrival'%> </td>
</tr>
<% end %>
</table>
<%= submit_tag "Save", :confirm => "You sure", :onclick => 'alert("Test")'%>
Please, anybody help....
Here's what I would do:
Designate a common CSS class for all the checkbox inputs (to be used as a jQuery selector later).
Create an empty <span>...</span> element with an id that encodes the student id (e.g., 'toa_1234') in the "Time of arrival" cell.
Use jQuery .change() and $.ajax() to send the message to the server.
Create a corresponding controller or action to process the AJAX POST and return the recorded (server-side) time.
On AJAX success, display the recorded server time and disable the checkbox (so it can't be clicked again).
HTML/ERB:
<td><%= check_box_tag "student_registers_ids[#{student_register.id}]",
student_register.id, false,
:class => 'student_present' %></td>
<td><%= student_register.student.university_id%></td>
<td><%= student_register.student.first_name.titlecase%></td>
<td><%= student_register.student.last_name.titlecase%></td>
<td><%= content_tag :span, student_register.time_of_arrival,
:id => "toa_#{student_register.student.id}" %></td>
JS/CoffeeScript:
$ ->
$('input[type="checkbox"].student_present').change (e) ->
checkbox = $(this)
student_id = checkbox.val()
$.ajax
url: '/register/present'
method: 'POST'
dataType: 'json'
data:
student_id: student_id
success: (data) ->
$("span#toa_#{student_id}").html(data['toa'])
checkbox.attr 'disabled', true
Controller/action:
def present
student_id = params['student_id']
# TODO: mark student present and save in database
recorded_toa = Time.now # TODO replace with actual time
render json: { student_id: student_id, toa: recorded_toa.strftime('%I:%M %P') }
end

Rails - add a dropdown selection to index with db update on change

I've added dropdown selections to forms before, but am having trouble getting them to work in the index view. I've read the API on this and can't get anything to work.
Basically, I've got a list of all tasks in the index view. I set the default in the db to 'No' in a migration. I want to be able to loop through all the tasks and have a dropdown selection appear with the options no, yes and partly. Then I want to be able to have the db update that task's field with the selection when it is made.
I can't get the dropdown to work - whenever I try using task.select, it says that select is a private method. I apologise, I'm fairly new to rails - any help anyone could give would be fantastic! How do I get the dropdown to work and how do I ensure that the db gets updated when the value is changed?
Thanks!
View code (here's what I have so far) - tasks/index:
<table class="table table-striped table-bordered">
<tr>
<th>Name</th>
<th>Category</th>
<th>Notes</th>
<th>Completed?</th>
<th></th>
<th></th>
<th></th>
</tr>
<% #tasks.each do |task| %>
<tr>
<td><%= task.name %></td>
<td><%= task.category %></td>
<td><%= task.notes %></td>
<td><%= task.select :complete, ['No','Yes','Partly'], :selected => 'No' %></td>
<td><%= link_to 'Show', task %></td>
<td><%= link_to 'Edit', edit_task_path(task) %></td>
<td><%= link_to 'Delete', task, confirm: 'Are you sure?', method: :delete %></td>
</tr>
<% end %>
</table>
UPDATE:
After more research, I've changed the line of code:
<td><%= task.select :complete, ['No','Yes','Partly'], :selected => 'No' %></td>
to:
<% form_for task do |f| %>
<td><%= select :task, :complete, [ ["Yes",2], ["Partly",1], ["No",0]] %></td>
<% end %>
This has stopped throwing up errors when I try and load the page, however, there is nothing where the 'form' should be - and nothing in the source code, these lines are skipped. How can I get this form to appear and how can I get it to change the database when the selection is changed? Thanks!
Suppose that Post::CATEGORIES = ["No", "Yes", "Partly"]
It depends on how you store task.category in your DB.
If it is an integer in (0, 1, 2)
form_for task do |f|
f.select :category, Post::CATEGORIES.map { |c| [c, Post::CATEGORIES.index(c)] }, :selected => task.category, :include_blank => true
end
If it is a string in ("No", "Yes", "Partly")
form_for task do |f|
f.select :category, Post::CATEGORIES, :selected => task.category, :include_blank => true
end
To be able to make a change to your models, you'll of course need to submit the form somehow. You could use one form for all the records with:
One submit button: you'll need to change the form and your update controller to receive multiple tasks
A form per task with multiple submit buttons: your user will need to submit each time he changes the category
Submit using AJAX each time the user changes the category.
Good luck
I think what you're looking for is a form_for and then a f.select. You need to create the form first and then f.select is the drop down. Something like this:
form_for task do |f|
f.select("task", "category", Post::CATEGORIES, {:include_blank => true})
end
replace Post::CATEGORIES with the list of options for the dropdown

How do I output name instead of ID?

Rails newbie here! I have a has_many_and_belongs_to_many relationship between items and builds.
In the code provided below, the ID of the items are being displayed instead of the name of the item with that ID. How do I display the name of the item?
<% current_user.builds.each do |build| %>
<tr>
<td><%= build.hero.name%></td>
<td><%= build.user.email%></td>
<td><%= build.name %></td>
<td><%= build.starting_items %></td>
<td><%= build.early_items %></td>
<td><%= build.core_items %></td>
<td><%= build.situational_items %></td>
</tr>
<% end %>
If you mapped association (has_one) in model with Hero and User, then probably you can use following code:
build.hero.field_name # Where field_name is column name from Hero Model
Please let me know if this will work for you or not.

Resources