I noticed a bug with my view where my form could not be submitted after the initial submission to generate a PDF, and during research saw that form_with was the recommended way to build forms going forward with rails. I updated my form, and everything seems to be working the way it's supposed to, but now the PDF doesn't download as before and just seems to render the string in a response without generating the file. Using Wicked-PDF and Rails 5.2.1. Sorry if I'm missing something super obvious!
Using form_tag (pdf downloads as expected):
form in view:
<%= form_tag("download_pdf", format: :pdf, method: "get") do %>
<div class="input-group mb-3">
<%= collection_select(:location, :id, Location.all, :id, :name, {:include_blank => 'Filter by location'}, {:id => 'qr_code_loc_select', :selected_value => '', :name => 'location', :style=> 'width: 17em', :autocomplete => 'off'}) %>
</div>
<div class="input-group mb-3">
<%= collection_select(:name, :id, DeviceType.all, :id, :name, {:include_blank => 'Filter by device type'}, {:id => 'qr_device_type_select', :selected_value => '', :name => "device_type", :style=> 'width: 17em', :autocomplete => 'off'}) %>
</div>
<div class="input-group mb-3">
<input type="number" name="width" class="form-control label_size_input" id="label_width" step="0.001" placeholder="Label Width" autocomplete ='off' aria-describedby="basic-addon3">
<div class="input-group-append">
<span class="input-group-text">inches</span>
</div>
</div>
<div class="input-group mb-3">
<input type="number" name="height" class="form-control label_size_input" id="label_height" step="0.001" placeholder="Label Height" autocomplete ='off' aria-describedby="basic-addon3">
<div class="input-group-append">
<span class="input-group-text">inches</span>
</div>
</div>
<%= label_tag "qr_col", "Columns:", class:"ml-2 text-light" %>
<div class="input-group mb-3">
<%= select_tag "qr_col", options_for_select(["1","2", "3", "4", "5"], "3"), {:autocomplete => 'off'}%>
</div>
<%= label_tag "paper_size", "Paper Size:", class:"ml-2 text-light" %>
<div class="input-group mb-3">
<%= select_tag "paper_size", options_for_select(#paper_size, "A4"), {:autocomplete => 'off'}%>
</div>
<div class="btn-group mb-3" role="group" aria-label="pdf_export_button" id="pdf_export">
<%= hidden_field_tag :column_number %>
<%= hidden_field_tag :label_size %>
<%= hidden_field_tag :format, "pdf" %>
<%= submit_tag("Create PDF Document", {:class=> "btn btn-secondary"}) %>
<% end %>
</div>
in controller:
def download_pdf
#columns = params[:column_number].to_i
#height = params[:height]
#width = params[:width]
#paper_size = params[:paper_size]
#type = params[:device_type]
#location = params[:location]
if #type.blank?
if #location.blank?
#devices = Device.all
else
#devices = get_devices_by_location(#location)
end
else
if #location.blank?
#devices = Device.where('device_type_id=?', #type)
else
#devices = get_devices_by_type_and_location(#type, #location)
end
end
pdf_string = render_to_string(
template: "qr_codes/show.html.erb",
layout: "layouts/pdf_layout.pdf.erb",
viewport_size: '1280x1024',
page_size: #paper_size
)
respond_to do |format|
format.pdf do
pdf = WickedPdf.new.pdf_from_string(pdf_string)
send_data pdf, :filename => "report.pdf", :type => "application/pdf"
end
end
end
in console:
Started GET "/qr_codes/download_pdf?utf8=%E2%9C%93&location=&device_type=&width=&height=&qr_col=3&paper_size=A4&column_number=3&label_size=&format=pdf&commit=Create+PDF+Document" for 127.0.0.1 at 2018-11-14 20:03:51 -0500
Processing by QrCodesController#download_pdf as PDF
Parameters: {"utf8"=>"✓", "location"=>"", "device_type"=>"", "width"=>"", "height"=>"", "qr_col"=>"3", "paper_size"=>"A4", "column_number"=>"3", "label_size"=>"", "commit"=>"Create PDF Document"}
Rendering qr_codes/show.html.erb within layouts/pdf_layout.pdf.erb
(0.4ms) SELECT COUNT(*) FROM "devices"
Device Load (0.6ms) SELECT "devices".* FROM "devices"
Rendered qr_codes/show.html.erb within layouts/pdf_layout.pdf.erb (778.0ms)
"***************[\"/Users/joe/.rbenv/versions/2.5.0/bin/wkhtmltopdf\", \"-q\", \"file:////var/folders/pf/kl12j8g91w5bj7ssc_0fdv3c0000gn/T/wicked_pdf20181114-912-1opkhpt.html\", \"/var/folders/pf/kl12j8g91w5bj7ssc_0fdv3c0000gn/T/wicked_pdf_generated_file20181114-912-m57i12.pdf\"]***************"
Rendering text template
Rendered text template (0.1ms)
Sent data report.pdf (1.7ms)
Completed 200 OK in 3077ms (Views: 1.2ms | ActiveRecord: 1.0ms)
Using form_with (pdf does not generate as expected and only has an unformatted string in response):
form in view:
<%= form_with url: download_pdf_path(format: :pdf), method: "get" do |f| %>
<div class="input-group mb-3">
<%= f.collection_select(:id, Location.all, :id, :name, {:include_blank => 'Filter by location'}, {:id => 'qr_code_loc_select', :selected_value => '', :name => 'location', :style=> 'width: 17em', :autocomplete => 'off'}) %>
</div>
<div class="input-group mb-3">
<%= f.collection_select(:id, DeviceType.all, :id, :name, {:include_blank => 'Filter by device type'}, {:id => 'qr_device_type_select', :selected_value => '', :name => "device_type", :style=> 'width: 17em', :autocomplete => 'off'}) %>
</div>
<div class="input-group mb-3">
<%= f.number_field nil, {:name => "width", :id => "label_width", :class => "form-control label_size_input", :step => "0.001", :placeholder => "Label Width", :autocomplete => 'off'} %>
<div class="input-group-append">
<span class="input-group-text">inches</span>
</div>
</div>
<div class="input-group mb-3">
<%= f.number_field nil, {:name => "height", :id => "label_height", :class => "form-control label_size_input", :step => "0.001", :placeholder => "Label Height", :autocomplete => 'off'} %>
<div class="input-group-append">
<span class="input-group-text">inches</span>
</div>
</div>
<%= label_tag "qr_col", "Columns:", class:"ml-2 text-light" %>
<div class="input-group mb-3">
<%= f.select "column_number", options_for_select(["1","2", "3", "4", "5"], "3"), {:autocomplete => 'off'}, :id => "qr_col"%>
</div>
<%= label_tag "paper_size", "Paper Size:", class:"ml-2 text-light" %>
<div class="input-group mb-3">
<%= f.select "paper_size", options_for_select(#paper_size, "A4"), {:autocomplete => 'off'}%>
</div>
<div class="btn-group mb-3" role="group" aria-label="pdf_export_button" id="pdf_export">
<%= f.hidden_field :label_size %>
<%= f.submit("Create PDF Document", {:class=> "btn btn-secondary", :data => { turbolinks: false }}) %>
</div>
<% end %>
controller:
def download_pdf
#columns = params[:column_number].to_i
#height = params[:height]
#width = params[:width]
#paper_size = params[:paper_size]
#type = params[:device_type]
#location = params[:location]
if #type.blank?
if #location.blank?
#devices = Device.all
else
#devices = get_devices_by_location(#location)
end
else
if #location.blank?
#devices = Device.where('device_type_id=?', #type)
else
#devices = get_devices_by_type_and_location(#type, #location)
end
end
respond_to do |format|
format.pdf do
pdf = WickedPdf.new.pdf_from_string(
render_to_string(
template: 'qr_codes/show.html.erb',
layout: 'layouts/pdf_layout.pdf.erb',
page_size: #paper_size
),
)
send_data pdf, :filename =>'PDF Report-' + Time.now.strftime('%v %H:%M:%S').to_s, disposition: 'attachment', :type => "application/pdf"
end
end
end
in console:
Started GET "/qr_codes/download_pdf_path?utf8=%E2%9C%93&location=&device_type=&width=&height=&column_number=3&paper_size=A4&label_size=&format=pdf&commit=Create%20PDF%20Document" for 127.0.0.1 at 2018-11-14 20:01:04 -0500
Processing by QrCodesController#download_pdf as PDF
Parameters: {"utf8"=>"✓", "location"=>"", "device_type"=>"", "width"=>"", "height"=>"", "column_number"=>"3", "paper_size"=>"A4", "label_size"=>"", "commit"=>"Create PDF Document"}
Rendering qr_codes/show.html.erb within layouts/pdf_layout.pdf.erb
(0.3ms) SELECT COUNT(*) FROM "devices"
Device Load (1.2ms) SELECT "devices".* FROM "devices"
Rendered qr_codes/show.html.erb within layouts/pdf_layout.pdf.erb (453.5ms)
"***************[\"/Users/joe/.rbenv/versions/2.5.0/bin/wkhtmltopdf\", \"-q\", \"file:////var/folders/pf/kl12j8g91w5bj7ssc_0fdv3c0000gn/T/wicked_pdf20181114-912-1ym4a9q.html\", \"/var/folders/pf/kl12j8g91w5bj7ssc_0fdv3c0000gn/T/wicked_pdf_generated_file20181114-912-edkha0.pdf\"]***************"
Rendering text template
Rendered text template (0.1ms)
Sent data PDF Report-14-NOV-2018 20:01:07 (1.6ms)
Completed 200 OK in 2682ms (Views: 1.1ms | ActiveRecord: 1.5ms)
IT WAS SOMETHING DUMB--decided to turn my attention to the form_with documentation and found out that remote: true is set by default. If you set this to local: true, the issue is resolved. Hope that helps someone else!
I want to use simple-form and bootstrap to generate a horizontal form with 2 rows. The first row should have two inputs side by side - one for first name with one label and the second row should have an input for email. My problem is that that label for the first row is not getting the control-label class that is required for the horizontal form to render correctly. However, all the proper classes are being applied to the email field.
Below is my code:
= simple_form_for #order, :url => '/product/process_order', :html => {:class => 'form-horizontal'} do |f|
.form-inputs
.control-group
= f.label :first, "Full and last name"
.controls
= f.input_field :first, :class => "span2", :placeholder => 'First'
= f.input_field :last, :class => "span3" , :placeholder => 'Last'
= f.input :email, :placeholder => 'you#example.com'
Which generates:
<form accept-charset="UTF-8" action="/product/process_order" class="simple_form form-horizontal" id="new_order" method="post" novalidate="novalidate">
<div class="form-inputs">
<div class="control-group">
<label for="order_first">Full and last name</label>
<div class="controls">
<input class="string required span2" id="order_first" name="order[first]" placeholder="First" size="50" type="text">
<input class="string required span3" id="order_last" name="order[last]" placeholder="Last" size="50" type="text">
</div>
</div>
<div class="control-group email required">
<label class="email required control-label" for="order_email">
<abbr title="required">*</abbr> Email
</label>
<div class="controls"><input class="string email required" id="order_email" name="order[email]" placeholder="you#example.com" size="50" type="email"></div>
</div>
</div>
</form>
In your config/initializers/simple_form.rb file, find the label class line and set it to:
config.label_class = 'control-label'
Also, if you are using bootstrap, you can do a few other things in this file. This might also help you:
SimpleForm.setup do |config|
config.wrappers :my_wrapper, :class => 'control-group',
:hint_class => :field_with_hint, :error_class => :field_with_errors do |b|
b.use :html5
b.use :placeholder
b.optional :maxlength
b.optional :pattern
b.optional :min_max
b.optional :readonly
## Inputs
b.use :label
b.wrapper :my_wrapper, :tag => 'div', :class => 'controls' do |ba|
ba.use :input
ba.use :error, :wrap_with => { :tag => 'span', :class => 'label label-important' }
ba.use :hint, :wrap_with => { :tag => 'p', :class => 'help-block' }
end
end
config.default_wrapper = :my_wrapper
config.boolean_style = :nested
config.button_class = 'btn'
config.error_notification_tag = :div
config.error_notification_class = 'alert alert-error'
config.label_class = 'control-label'
config.form_class = 'form-horizontal'
config.generate_additional_classes_for = [:wrapper, :label, :input]
config.browser_validations = true
end
According to this you have to do something along the lines of this:
f.label :first, label: 'Full and last name'
I'm working on Rails 3 app. Here a view displays all the excel files uploaded by user. A button to execute all the checkbox selected files was already present with delete for each file separately. Now I'm supposed to add a 'delete' button to delete the selected files. I've added the button n modified the function called by this form jus to display "in execute" and "in delete" for now to check if the second 'delete' button is functioanal. But every time delete is clicked it prints "in execute" only in cmd. I guess the AJAX related code written in the view 'list' is the problem.
Pls help!! Tell me why is it going to execute always?
The related code is here:
PS: I hav used if params[:commit]="Delete" & if params[:delete_button] also in controller.rb to but didnt help
list.html.erb (the view that displays all files)
<% if #files.length > 0 %>
<h2 id='comments'>Uploaded Excel Files are as listed below for Edit/Delete/Execution</h2>
<div id='checkone' class='hide'>Please check atleast one excel file to execute</div>
<% ajax_str = "new Ajax.Request('/account/execute_testcases', {asynchronous:true, evalScripts:true, onComplete:function(request){adjust_sidebar();Element.show('msg');Element.hide('waitid');Element.hide('disableexecuteid');Element.show('executeid');}, onLoading:function(request){Element.show('waitid');Element.hide('msg');Element.hide('executeid');Element.show('disableexecuteid');}, parameters:Form.serialize(this)}); return false;".html_safe %>
<%= form_for 'file_names', :url => {:controller => 'account', :action => 'execute_testcases'}, :remote => true, :html => {:name => 'frmExecute', :onsubmit => ajax_str }, :id =>'execute_tc' do |f| %>
<table>
<% if #file_count > 1 && #error_in_all_files == false %>
<tr>
<td>
<input type='checkbox' name='chkAll' onclick='checkAll();'>
<span class='text'>Check All/Decheck All</span>
</td>
</tr>
<% end %>
</table>
<table class='upload'>
<% for a in #files %>
<tr>
<td>
<% file_id = a.id.to_i %>
<% if(#excel_errors[file_id].nil? || #excel_errors[file_id].empty?) && a.file_type.to_i != 1 %>
<input type='checkbox' name = "excelfile[]" value="<%= a.excel_filename %>,<%= a.excel_filename_with_timestamp %>">
<% else %>
<input type='checkbox' name = "excelfile[]" value="<%= a.excel_filename %>,<%= a.excel_filename_with_timestamp %>" disabled=true>
<% end %>
<a href="open_excel_file/<%= a.id %>" title='Click to open' class='nodecoration'><%= a.excel_filename %></a>
</td>
<td>
<%= link_to(image_tag("/images/b_edit.png", :border => 0, :title => 'Edit'), :action => 'upload_file', :file_id => a.id) %>
</td>
<td>
<img src='/images/b_drop.png' border=0 title='Delete' onclick="return confirm('This will delete the related reports too. Are you sure to delete?');">
</td>
<td>
<%
if !#excel_errors[file_id].nil? && !#excel_errors[file_id].empty?
#joined_excel_errors = #excel_errors[file_id].join(', ')
%>
Error
<% end %>
</td>
</tr>
<tr id="excel_error_<%=file_id %>" style='display:none;'>
<td colspan=4>
<% if !#excel_errors[file_id].nil? && !#excel_errors[file_id].empty? %>
<div class="padder">
<% for error_value in #excel_errors[file_id] %>
<font color='maroon'><%= error_value %></font><br>
<% end %>
</div>
<% end %>
</td>
</tr>
<% end %>
<tr><td> </td></tr>
<tr>
<td>
<% if #error_in_all_files == false %>
<span class='executebutton' id='executeid'>
<%= f.submit "Execute", name: 'execute_button', :onclick =>"return checkSelected();" %>
</span>
<span class='deletebutton' id='deleteid'>
<%= f.submit "Delete", name: 'delete_button', :onclick =>"return checkSelected();" %>
</span>
<% end %>
<span id='disableexecuteid' class='executebutton' style='display:none;'>
<input type='submit' value="Execute" disabled="disabled">
</span>
<span id='waitid' style="display:none;" class='text'>
<br>Executing Test Cases...Please wait...<%= image_tag("/images/wait26trans.gif", :border => 0) %>
</span>
<span id='msg' style="display:none;" class='text'>
<br><br> Click here to <%= link_to 'View Test Results', {:controller => 'account', :action => 'recent_test_results'}, :class => 'brownlink' %>
</span>
</td>
</tr>
</table>
<span id='subject_list'>
</span>
<% end %>
<% else %>
No test case sheets found!
<br><br>
<%= link_to '>> Upload File', {:controller => 'account', :action => 'upload_file'}, :class => 'brownlink' %>
<% end %>
<% for i in 1..10 %>
<div> </div>
<% end %>
controller.rb
def execute_testcases
if !params[:execute_button].nil?
puts "in execute"
# file_names = []
# originalfile_filewithtime = []
# original_file_map = {}
# originalfile_filewithtime = params[:excelfile]
......
# SOME CODE HERE
......
# render :update do |page|
# page.replace_html :subject_list, :partial => 'show_output', :locals => {:new_file_map => #new_file_map}
# page.visual_effect :highlight, 'subject_list', :duration => 2
# flash[:display]=#execmsg
#end
# puts #execmsg
elsif !params[:delete_button].nil?
puts "in delete"
end
end
I realised it had to do something with the Form.serialize(this) of AJAX which serialises everything. ie It calls the function of first button in the view irrespective of no of submit buttons present
I have two models, contest and submission. submission belongs_to contest and contest has_many submissions.
In the index action for submissions I have a search:
def index
contest_id = params[:contest_id]
#contest = Contest.find(contest_id)
if params[:search].blank?
#submissions = Submission.paginate(:per_page => 10, :page => params[:page])
else
#submissions = Submission.search(params[:search]).paginate(:per_page => 10, :page => params[:page])
end
#search = params[:search]
end
I think the right way to pass it in is through the search form in the submissions>index view:
<div class ="span12 row">
<%= form_tag submissions_path, :method => 'get', :class => "form-search pull-right" do %>
<%= text_field_tag :search, params[:search], :class => 'input-xlarge', :placeholder => 'Search by member, title or description' %>
<%= submit_tag "Search", :title => nil, :class => 'btn btn-primary' %>
<% end %>
</div>
And I have been able to come close using this:
<%= hidden_field :contest_id, #contest.id %>
In the form, but it's returning this in the url:
http://localhost:3000/submissions?utf8=%E2%9C%93&search=test&contest_id%5B%5D=&commit=Search
And an error:
Couldn't find Contest with id=
I've also tried this:
<%= hidden_field(:contest_id, :value => #contest.id ) %>
But it's returning similar url and error.
Right now, I'm stuck. If you have any idea, please let me know.
[edit - added html]
Before search:
<div class ="span12 row">
<form accept-charset="UTF-8" action="/submissions" class="form-search pull-right" method="get"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /></div>
<input class="input-xlarge" id="search" name="search" placeholder="Search by member, title or description" type="text" />
<input id="contest_id_5" name="contest_id[5]" type="hidden" />
<input class="btn btn-primary" name="commit" type="submit" value="Search" />
</form>
</div>
Here's what works from other links going to submissions:
From the submission show page:
<%= link_to 'Browse All Submissions', submissions_path(:contest_id => #contest.id), :class => 'btn btn-mini pull-right' %>`
and from the contest show page:
<%= link_to 'Browse All Submissions', submissions_path(:contest_id => #contest.id), :class => 'btn btn-mini pull-right' %>
Both of these pass the url "contest_id=5" which is what the controller needs to find a contest. The issue I'm having with search is finding the right syntax to get contest_id=5 to appear without the mumbo jumbo mucking it up.
This turned out to be an easy solution. Insert a hidden_field_tag in the search form:
<%= hidden_field_tag 'contest_id', #contest.id %>
This will pass the correct value into params:
http://localhost:3000/submissions?utf8=%E2%9C%93&search=new&contest_id=5&commit=Search
I have some troubles with :reject_if. I don't know why the following code doesn't work.
View - _form.html.erb:
<%= f.fields_for :questions do |builder| %>
<div class="nested-field">
<%= builder.label :id, "Question" %><br />
<%= builder.collection_select(:id, Question.all(:order => 'question'), :id, :question, { :prompt => 'Select Question' } ) %>
</div>
<div class="nested-field">
<%= builder.label :test1 %><br />
<%= builder.text_field :test1 %>
</div>
<div class="nested-field">
<%= builder.label :test2 %><br />
<%= builder.text_field :test2 %>
</div>
<div class="nested-field">
<%= builder.label :description %><br />
<%= builder.text_field :description %>
</div>
<br /><br /><br />
<hr />
<% end %>
Model - questionary.rb:
has_many :questions, :dependent => :destroy
accepts_nested_attributes_for :questions, :reject_if => lambda { |a| a[:id].blank? }, :allow_destroy => true
Thank you very much!
Instead of
:reject_if => lambda { |a| a[:id].blank? }
try
:reject_if => lambda { |a| a['id'].blank? }
(note the string 'id') and to follow the API exactly, use proc
:reject_if => proc { |a| a['id'].blank? }
I had a look at the API for accepts_nested_attributes_for, and found there that the documentation states:
:reject_if
Allows you to specify a Proc or a Symbol pointing to a method that checks whether a record should be built for a certain attribute hash.
Have you tried to replace the lambda with proc? The syntax here seems to be special, so the lambda may be just ignored.