High CPU Usage when generating PDFs in Rails with Wicked_PDF gem - ruby-on-rails

I'm trying to generate a PDF file with Rails, but when I do I notice my system CPU starts to max out. Initially, it will go from ~2.5% then increase to ~65%-$80% for a steady period of time and then finally max out almost prior to displaying them PDF in my iframe on my page. Here are some messages I get when monitoring the memory usage on my system:
Warning or critical alerts (lasts 9 entries)
2017-06-09 14:58:07 (0:00:04) - CRITICAL on CPU_SYSTEM (100.0)
2017-06-09 14:58:04 (0:00:13) - CRITICAL on CPU_USER (Min:72.8 Mean:83.3 Max:93.7)
2017-06-09 14:47:39 (0:00:06) - CRITICAL on CPU_USER (93.0)
2017-06-09 14:47:29 (0:00:04) - WARNING on CPU_SYSTEM (74.7)
2017-06-09 14:36:48 (0:00:04) - CRITICAL on CPU_SYSTEM (100.0)
2017-06-09 14:36:45 (0:00:10) - CRITICAL on CPU_IOWAIT (Min:78.6 Mean:85.7 Max:97.4)
2017-06-09 14:18:06 (0:00:04) - CRITICAL on CPU_SYSTEM (94.3)
2017-06-09 14:18:06 (0:00:07) - CRITICAL on CPU_USER (91.0)
2017-06-09 15:01:14 2017-06-09 14:17:44 (0:00:04) - WARNING on CPU_SYSTEM (73.8)
The gems I have installed for my PDF generation are wicked_pdf (1.0.6) and wkhtmltopdf-binary-edge (0.12.4.0). And the process with code for each are as follows:
controllers/concerns/pdf_player_reports.rb
def director_report_pdf
#players = Player.where(id: params["player_ids"]
respond_to do |format|
format.html
format.pdf do
render pdf: "#{params['pdf_title']}",
template: 'players/director_summary_report.pdf.erb',
layout: 'print',
show_as_html: params.key?('debug'),
window_status: 'Loading...',
disable_internal_links: true,
disable_external_links: true,
dpi: 75,
disable_javascript: true,
:margin => {:top => 7, :bottom => 7, :left => 6, :right => 0},
encoding: 'utf8'
end
end
players/director_summary_report.pdf.erb
<div class="document" style="margin-top: -63px;">
<% #players.each do |player| %>
<% reports = player.reports.order(created_at: :desc) %>
<% if player.is_college_player? %>
<%= render partial: 'college_director_report.html.erb', player: player %>
<% else %>
<%= render partial: 'pro_director_report.html.erb', player: player %>
<% end %>
<%= "<div class='page-break'></div>".html_safe %>
<% end %>
</div>
college_director_report.html.erb
<%= wicked_pdf_stylesheet_link_tag "application", media: "all" %>
<%= wicked_pdf_javascript_include_tag "application" %>
<% provide(:title, "#{player.football_name}") %>
<% self.formats = [:html, :pdf, :css, :coffee, :scss] %>
<style>
thead { display: table-row-group; page-break-inside: avoid }
tfoot { display: table-row-group; }
/*thead:before, thead:after { display: none; }*/
table { page-break-inside: avoid; }
tr { page-break-inside: avoid; }
.page-break {
display:block; clear:both; page-break-after:always;
}
.keep-together { page-break-before: always !important; }
.table-striped>tbody>tr:nth-child(odd)>td,
tr.found{
background-color:#e2e0e0 !important;
}
</style>
<div class="row">
<div class="col-xs-6">
<span>DIRECTOR SUMMARY</span>
</div>
<div class="col-xs-6 text-right">
<%= "#{player.full_name} / #{player.school.short_name}".upcase %>
<h1><%= "#{player.full_name(true)} (#{player.school.code})".upcase %></h1>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<%= render 'directors_report_player_header', player: player %>
<%= render 'directors_report_workouts', player: player %>
<%= render 'directors_report_grades', player: player %>
<%= render 'legacy_directors_report_contacts', player: player %>
</div>
</div>
directors_report_player_header.html.erb
<table class="table table-condensed table-bordered">
<thead>
<tr>
<th>Name</th>
<th>School</th>
<th>#</th>
<th>Position</th>
</tr>
</thead>
<tbody>
<tr>
<td><%= player.full_name(true) %></td>
<td><%= player.school.short_name %></td>
<td><%= player.jersey %></td>
<td><%= player.position.abbreviation %></td>
</tr>
</tbody>
</table>
UPDATE
I ran an example PDF generator using the following and the CPU% is what ends up maxing out as shown below...
<table class="table table-condensed">
<thead>
<th>Number</th>
</thead>
<tbody>
<% (1..60000).each do |number| %>
<tr>
<td><%= number %></td>
</tr>
<% end %>
</tbody>
</table>

Putting this in a controller seems ill-advised because the minute you deploy this the request will take a significant time to generate and block other incoming requests for other pages.
You should separate this into two concerns. One job that generates the HTML, which could be this controller, and then a background task to convert that HTML into PDF format.
In your controller, trigger a job using DelayedJob or similar and then render a page that polls for the job having completed.
Then in your background job you're dealing with just the task of rendering the HTML to PDF, rather than being within a web request. Something along these lines:
class RendersReportPdf
def self.call player_ids
html = ReportsController.render :director_report_pdf, assigns: { players: Player.where(id: player_ids }
pdf = WickedPdf.new.pdf_from_string html
temp = Tempfile.new("#{Time.now.to_i}.pdf")
temp.write(pdf)
temp.close
temp.path
# Probably upload this to S3 or similar at this point
# Notify the user that it's now available somehow
end
end
If you do this, then you can rule out that the issue is with running WickedPDF from within your controller action, but also you're making sure your site will stay up if you have long-running requests.

So I wanted to post my solution for future visitors, but it's based off of #stef's solution - so thanks stef!
controllers/concerns/players_controller.rb
def generate_report_pdf
players = print_settings(params)
pdf_title = "#{params['pdf_title']} - #{Time.now.strftime("%c")}"
GeneratePdfJob.perform_later(players.pluck(:id), pdf_title, current_user.code, params["format"])
end
app/jobs/generate_pdf_job.rb
def perform(*args)
player_ids = args[0]
pdf_title = args[1]
user_code = args[2]
report_type = args[3]
generate_pdf_document(player_ids, pdf_title, user_code, report_type)
end
def generate_pdf_document(ids, pdf_title, user_code, report_type)
# select the proper template by the report type specified
case report_type
when "Labels"
html = ApplicationController.new.render_to_string(
template: 'players/board_labels.pdf.erb',
locals: { player_ids: ids },
margin: { top: 6, bottom: 0, left: 32, right: 32 }
)
when "Reports"
# ...
end
end
def save_to_pdf(html, pdf_title, user_code)
pdf = WickedPdf.new.pdf_from_string(
html,
pdf: "#{pdf_title}",
layout: 'print',
disable_internal_links: true,
disable_external_links: true,
disable_javascript: true,
encoding: 'utf-8'
)
pdf_name = "#{pdf_title}.pdf"
pdf_dir = Rails.root.join('public','uploads','reports',"#{user_code}")
pdf_path = Rails.root.join(pdf_dir,pdf_name)
# create the folder if it doesn't exist
FileUtils.mkdir_p(pdf_dir) unless File.directory?(pdf_dir)
# create a new file
File.open(pdf_path,'wb') do |file|
file.binmode
file << pdf.force_encoding("UTF-8")
end
end
With this way I then use an ajax call to keep checking the user's specified directory for new files, and I update the partial that lists out the files in the directory. The only thing I don't like is now I have to have a table list of the user's files. I'd rather just have the file get delivered to the client's browser for download instead - but have yet figured out how to get that to work.

Related

Filterrific gem for two tables

I am using filterrific gem to add filters in my app. I have parents table and children table. On the children_list page which displays list of all the children with their firstname and their parent's firstname. The issue I am facing is in the search query I want to add the parent.firstname search as well for filterrific. I tried adding a join as below:-
num_or_conds = 2
joins(child: :parent).where(
terms.map { |term|
"(LOWER(children.firstname) LIKE ?) OR (LOWER(parents.firstname) LIKE ?) "
But this didnt do the job. Any idea how this can be achieved.
parent.rb
has_many :children
child.rb
belongs_to :parent
filterrific(
available_filters: [
:search_query,
:with_clinic_date
]
)
scope :search_query, lambda { |query|
return nil if query.blank?
terms = query.downcase.split(/\s+/)
terms = terms.map { |e|
(e.gsub('*', '%') + '%').gsub(/%+/, '%')
}
num_or_conds = 2
where(
terms.map { |term|
"(LOWER(children.firstname) LIKE ?) OR (LOWER(parents.firstname) LIKE ?)"
}.join(' AND '),
*terms.map { |e| [e] * num_or_conds }.flatten
)
}
scope :with_clinic_date, lambda { |ref_date|
where('children.clinic_date = ?', ref_date)
}
end
_children.html.erb
<h1>Children</h1>
<div class="table-responsive">
<table class="table table-bordered">
<thead>
<tr>
<th>Parent First Name</th>
<th>Child firstname</th>
</tr>
</thead>
<tbody>
<% #children.each do |child| %>
<tr>
<td><%=child.parent.firstname %></td>
<td><%=child.firstname %></td>
</tr>
<% end %>
</tbody>
</table>
</div>
</div>
children-list.html.erb
<%= form_for_filterrific #filterrific do |f| %>
<div class="row">
<div class="col-sm-3">
Search
<%= f.text_field(
:search_query,
class: 'filterrific-periodically-observed form-control'
) %>
</div>
<div class="col-sm-3">
Request Date
<%= f.date_field(:with_clinic_date, class: 'js-datepicker form-control') %>
</div>
<div class="col-sm-3">
<br>
<%= link_to(
'Reset filters',
reset_filterrific_url,
) %>
</div>
</div>
<%= render_filterrific_spinner %>
<% end %>
<%= render( partial: 'children/children_list') %>
children.js.erb
<% js = escape_javascript(
render(partial: 'children/children_list')
) %>
$("#filterrific_results").html("<%= js %>");
AFAIK, you can't filter two separate classes on the same page. It will use the last defined filterrific instance. When I ran into this problem, I used remote forms with custom action/routes
# routes.rb
resources :parent do
get :filter_parents
resources: children do
get :filter_children
end
end
And then the controllers..
# parents_controller.rb
def index
parents_filter # this would be a helper method running your filter queries
end
def filter_parents
parents_filter # this would be a helper method running your filter queries
end
The children's controller would look similar, just different named helper method/custom action.
And then use a partial for the table. Target the table's container, and use a filter_parents.js.erb and filter_childrens.js.erb file
$('#parents-table').html('<%= escape_javascript render 'path/to/partial'%>')
// same in childrens.js.erb, just target the appropriate table

undefined method `each' for nil:NilClass on an erb array iteration

Im currently working in an Rails 5 application where you can search for a first name or last name and records of the customers of that account would be displayed. However I am getting a Nil object return from search algorithm.
customers_controller:
class CustomersController < ApplicationController
def index
if params[:keywords].present?
#keywords = params[:keywords]
customer_search_term = CustomerSearchTerm.new(#keywords)
#customer = Customer.where(
customer_search_term.where_clause,
customer_search_term.where_args).
order(customer_search_term.order)
else
#customers = []
end
end
end
As you can see if there is no records found is suppose to return an empty array but is returning a Nil object.
customers/index.html.erb
[![<header>
<h1 class="h2">Customer Search</h1>
</header>
<section class="search-form">
<%= form_for :customers, method: :get do |f| %>
<div class="input-group input-group-lg">
<%= label_tag :keywords, nil, class: "sr-only" %>
<%= text_field_tag :keywords, nil,
placeholder: "First Name, Last Name or Email Address",
class: "form-control input-lg" %>
<span class="input-group-btn">
<%= submit_tag "Find Customers", class: "btn btn-primary btn-lg" %>
</span>
</div>
<% end %>
</section>
<section class="search-results">
<header>
<h1 class="h3">Results</h1>
</header>
<table class="table table-striped">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
<th>Joined</th>
</tr>
</thead>
<tbody>
<% #customers.each do |customer| %>
<tr>
<td><%= customer.first_name %></td>
<td><%= customer.last_name %></td>
<td><%= customer.email %></td>
<td><%= l customer.created_at.to_date %></td>
</tr>
<% end %>
</tbody>
</table>
</section>][1]][1]
The first thing you should understand is that instance variables return nil if they haven't been set. If you say #fake_var == nil it will be true if you never defined #fake_var before this. You can contrast this with regular local variables, which will raise a NoMethodError if you try and use them before they're defined. For example, puts(fake_var) will raise a NoMethodError for fake_var.
Now look at your template. No matter what it will loop over #customers. If #customers has not been set, you'll see a NoMethodError because you can't call each on nil.
Finally, look at your controller action:
def index
if params[:keywords].present?
#keywords = params[:keywords]
customer_search_term = CustomerSearchTerm.new(#keywords)
#customer = Customer.where(
customer_search_term.where_clause,
customer_search_term.where_args).
order(customer_search_term.order)
else
#customers = []
end
end
Specifically the case when params[:keywords].present?. You never set #customers in this case so it will be nil when the template tries to access it.
I think if you simply replaced #customer = with #customers = it would solve your problem.
you can force it to return array using #to_a which converts nil to empty array
def index
return [] unless params[:keywords]
#keywords = params[:keywords]
customer_search_term = CustomerSearchTerm.new(#keywords)
#customer = Customer.where(
customer_search_term.where_clause,
customer_search_term.where_args).
order(customer_search_term.order
).to_a
end
https://apidock.com/ruby/Array/to_a

Ruby on Rails select2 AJAX/JQuery - passing a parameter to controller not working

I'm trying to make a Job descriptions (JD) page to compare between a choose JDs.
My main page will have a field to select some jobs, and a button/link to show the selected jobs details in a table below the selection field using select2 with RoR, as in the image
Job descriptions Viewer .
My issue is that I cannot pass the selected Jobs IDs to the controller, and I get this message:
Completed 406 Not Acceptable in 20ms (ActiveRecord: 0.0ms)
ActionController::UnknownFormat (ActionController::UnknownFormat):
app/controllers/job_descriptions_controller.rb:81:in `updateJobs'
My controller method :
def updateJobs
#selected = JobDescription.where(id: params[:selectJdField2])
respond_to do |format|
format.js
format.html
end
end
The main View (jdComparison.html.erb) will render two partials
<h1>Listing Job Descriptions</h1>
<%= render 'sidebar' %>
<div class="clearfix"></div>
<div>
<%= render partial: 'item_list', locals: { job_desc: #job_descriptions} %>
</div>
The _sidebar.html.erb partial has selet2 field and a link to refresh the Jds that called "Find Link":
<div class="col-sm-8">
list of JDs:
<%= select_tag "selectJdField", options_from_collection_for_select(#job_descriptions, :id, :job_title), { :multiple => true } %>
</div>
<%= link_to "Find Link", updateJobs_path(#job_descriptions), :remote => true %>
<script>
$(document).ready(function() { $("#selectJdField").select2(); });
</script>
The _item_list.html.erb partial will view all JDs have been chosen in the select2 field:
<div>
<table>
<thead>
<tr>
<th>Job title</th>
<th>Department</th>
</tr>
</thead>
<tbody>
<% job_desc.each do |job_description| %>
<tr>
<td><%= job_description.job_title %></td>
<td><%= job_description.department %></td>
</tr>
<% end %>
</tbody>
</table>
</div>
updateJobs.js.erb, should refresh the JDs list when I click the "Find Link" button (I think my first issue is here)
$("#div_id").html("<%= escape_javascript(render partial: 'item_list', locals: { job_desc: #selected}) %>")
The JS file (I think my second issue is here):
$ ->
updateLists = () ->
$.ajax
url:'updateJobs'
type: 'post'
dataType: 'html'
format: 'js'
data: {
selectJdField2 : $('#selectJdField').val()
}
The routes:
get 'updateJobs' => 'job_descriptions#updateJobs'
post 'updateJobs' => 'job_descriptions#updateJobs'
When I replace the controller method with this:
def updateJobs
#selected = JobDescription.where(id: 1)
end
it will give me the details of JD number 1 after clicking the Find Link. Kindly, I need your help..
This what I've done to make it works:
I have relapsed the "Find Link" with a normal button:
<button id="btnFind">Find</button>
I added "id" to the first div in _item_list.html.erb partial
<div id = "div_id">
In js file:
$ ->
$(document).on 'change', '#selectJdField', (evt) ->
updateLists()
$(document).on 'click', "#btnFind", (evt) ->
updateLists()
updateLists = () ->
$.ajax '/updateJobs',
type: 'GET'
dataType: 'script'
data: {
selectJdField2 : $('#selectJdField').val()
}
and I didn't need (post 'updateJobs') in the routes file.. Now, everything work fine...Thank you "Venkat Ch"

Enable pagination with deferLoading

I am working in a Rails application and using the deferLoading: true option on jQuery DataTables in order pass the loading of the first DataTables to the Rails controller.
I have the datatable loading how I want it, loading the initial table in the controller gets rid of the Ajax delay when the initial html loads, however, the Datatable info section won't display the pagination results.
Code and images are shown below.
Again everything works except the pagination at the bottom of the table, I just cant get it to apply the same details as the Ajax calls to the datatable. Any ideas or direction on this issue would be greatly appreciated!
index.html.erb:
<div class="row">
<div class="col-xs-12 table-wrapper">
<div class="inner-wrapper">
<p class="quick-app">
<a class="custom-btn accent-inverse-btn add-user" href="<%= calculator_path%>">Quick Application</a>
</p>
<table class="table table-striped table-scroll cms-table-width dataTable" id="customer_deals_datatable" data-source="<%= dealer_customer_deals_url(:include_archived => params[:include_archived].present?) %>" >
<div>
<thead>
<tr>
<th>ID/Calculator</th>
<th>Applicant/Co-Applicant</th>
<th>Year</th>
<th>Model</th>
<th>App Status</th>
<th>Tier Number</th>
<th>Docs Status</th>
<th>Submitted On</th>
<th>Days Remaining</th>
<th>Chrome Decision</th>
<th>Updated At</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<% #datatable.data.each do |datum| %>
<tr>
<% datum[0] = datum[0].join('') %>
<%= (datum.map {|content| "<td>#{content}</td>"}.join('')).html_safe %>
</tr>
<% end %>
</tbody>
</div>
</table>
</div>
</div> <!-- </div>#content -->
</div>
controller
def index
respond_to do |format|
format.html do
params.merge!({"iDisplayLength"=>"10","iSortCol_0"=>"10","sSortDir_0"=>"desc"})
#datatable = CustomerDeals::CustomerDealsDataTable.new(view_context, #dealer)
end
format.json { render json: CustomerDeals::CustomerDealsDataTable.new(view_context, #dealer) }
end
end
here is a portion of the code from the datatable class in the project:
module CustomerDeals
class CustomerDealsDataTable
def fetch_deal_searches
return #deal_searches if #deal_searches.present?
deal_searches = CustomerDeals::CustomerDealSearch.where(dealership_id: #dealer )
if is_submitted_on_sort?
deal_searches = deal_searches.where('deal_dated_calculator_value != ?', 'calculator')
end
if params[:sSearch].present?
deal_searches = deal_searches.containing(params[:sSearch])
end
deal_searches = deal_searches.order(order_query)
#deal_searches = deal_searches
end
def is_submitted_on_sort?
SORT_COLUMNS[params[:iSortCol_0].to_i] == 'deal_submitted_on'
end
def lookup_sort_column
SORT_COLUMNS[params[:iSortCol_0].to_i]
end
def order_query
"#{lookup_sort_column} #{params[:sSortDir_0]}"
end
def paged_deal_searches
fetch_deal_searches.page(current_page_number).per(params[:iDisplayLength])
end
def current_page_number
params[:iDisplayLength].to_i == 0 ? 1 : params[:iDisplayStart].to_i/params[:iDisplayLength].to_i + 1
end
end
end
You're on the right track, deferLoading also can be assigned integer or array of two integers to specify how many records there are in the table for pagination to work.
From the manual:
deferLoading is used to indicate that deferred loading is required, but it is also used to tell DataTables how many records there are in the full table (allowing the information element and pagination to be displayed correctly).
In the case where a filtering is applied to the table on initial load, this can be indicated by giving the parameter as an array, where the first element is the number of records available after filtering and the second element is the number of records without filtering (allowing the table information element to be shown correctly).
Examples:
57 records available in the table, no filtering applied:
$('#example').dataTable( {
"serverSide": true,
"ajax": "scripts/server_processing.php",
"deferLoading": 57
} );
57 records after filtering, 100 without filtering (an initial filter applied):
$('#example').dataTable( {
"serverSide": true,
"ajax": "scripts/server_processing.php",
"deferLoading": [ 57, 100 ],
"search": {
"search": "my_filter"
}
} );

time_select blank field saves a default time when form is submitted

Im having trouble understanding my options for time_select. My goal is to have only user created time selections render in my show action after form submission.
What is happening however is a default time of 12:00 AM being rendered for all time_select fields not touched by a user. I am looking for a way to either stop default time values from saving (which if I had to guess, isn't possible), or create a conditional that would allow me to prevent default time values from rendering.
I have looked over the following with no success so far:
Nil value on datetime_select?
Optional time_select with allow_blank defaults to 00:00
Rails time_select set default
Rails 3: How to prevent my validations to pass a "nil time" from time_select dropdowns?
http://api.rubyonrails.org/classes/ActionView/Helpers/DateHelper.html#method-i-time_select
Here is my code:
_form.html.erb (only the snippet that I am having trouble with for brevity)
<td>
<span style="display: block; width: auto; margin-left: 4%">
<%= f.time_select :med1_time_of_day1, { include_blank: true, twelve_hour: true, minute_step: 15, ampm: true }, style: "width: 45%;" %>
</span>
<span style="display: block; width: auto; margin-left: 4%">
<%= f.time_select :med1_time_of_day2, { include_blank: true, twelve_hour: true, minute_step: 15, ampm: true }, style: "width: 45%;" %>
</span>
<span style="display: block; width: auto; margin-left: 4%">
<%= f.time_select :med1_time_of_day3, { include_blank: true, twelve_hour: true, minute_step: 15, ampm: true }, style: "width: 45%;" %>
</span>
<span style="display: block; width: auto; margin-left: 4%">
<%= f.time_select :med1_time_of_day4, { include_blank: true, twelve_hour: true, minute_step: 15, ampm: true }, style: "width: 45%;" %>
</span>
</td>
<td>
show.html.erb
<table class="table table-bordered table-striped">
<thead>
<th>Medication Name & Instructions for Use</th>
<th>Time of Day</th>
<th>
Day(s) of the Month Medication was Taken
</th>
</thead>
<tbody>
<td>
<%= #med_record_form.med1_name %>
<%= #med_record_form.med1_instruct %>
</td>
<td>
<% unless #med_record_form.med1_time_of_day1.nil? %>
<%= #med_record_form.med1_time_of_day1.strftime("%I:%M %p") %>
<br />
<% end %>
<% unless #med_record_form.med1_time_of_day2.nil? %>
<%= #med_record_form.med1_time_of_day2.strftime("%I:%M %p") %>
<br />
<% end %>
<% unless #med_record_form.med1_time_of_day3.nil? %>
<%= #med_record_form.med1_time_of_day3.strftime("%I:%M %p") %>
<br/>
<% end %>
<% unless #med_record_form.med1_time_of_day4.nil? %>
<%= #med_record_form.med1_time_of_day4.strftime("%I:%M %p") %>
<br />
<% end %>
</td>
</tbody>
</table>
Note: I've also tried replacing #instance_var.nil? with
#instance_var.blank? and #instance_var.empty? without success.
And just in case the controller is needed...
med_record_forms_controller.rb
class MedRecordFormsController < ApplicationController
before_filter :get_resident
def index
#med_record_form = #resident.med_record_forms
end
def new
#med_record_form = #resident.med_record_forms.build
end
def create
#med_record_form = #resident.med_record_forms.build(params[:med_record_form])
if #med_record_form.save
redirect_to [#resident, #med_record_form] #, flash_class[:success] = "Form was created!"
else
render 'new' #, flash[:error] = "There was a problem with the form"
end
end
def show
#med_record_form = #resident.med_record_forms.find(params[:id])
end
def update
#med_record_form = #resident.med_record_forms.find(params[:id])
if #med_record_form.update_attributes(params[:med_record_form])
flash[:success] = "Form updated"
redirect_to controller: 'residents', action: 'show', id: params[:id]
else
render 'edit', flash[:error] = "Unable to update form"
end
end
def edit
#med_record_form = #resident.med_record_forms.find(params[:id])
end
def destroy
#med_record_form = #resident.med_record_forms.find(params[:id])
#med_record_form.destroy
flash[:notice] = "You sure?"
redirect_to resident_med_record_forms_path
end
private
# get_resident converts the resident_id given by the routing
# into an #resident object, for use in this controller & coresponding views
def get_resident
#resident = Resident.find(params[:resident_id])
end
end
This question is similar to this: Optional time_select with allow_blank defaults to 00:00
I found the default for time_select sets the time parts blank but there is a hidden date component that is not set to blank. You can see this when you look at the parameters:
"my_time(1i)"=>"1", "my_time(2i)"=>"1", "my_time(3i)"=>"1", "my_time(4i)"=>"", "my_time(5i)"=>""
You will need to set the time to nil in your controller like this:
def create
#med_record_form = #resident.med_record_forms.build(params[:med_record_form])
#med_record_form.med1_time_of_day1 = nil if params[:med_record_form]["med1_time_of_day1(4i)"].blank? &&
params[:med_record_form]["med1_time_of_day1(5i)"].blank?
if #med_record_form.save
redirect_to [#resident, #med_record_form] #, flash_class[:success] = "Form was created!"
else
render 'new' #, flash[:error] = "There was a problem with the form"
end
end

Resources