I have the following form setup:
= simple_form_for(#job, url: job_payment_path, html: { id: 'payment-processor-form' }) do |j|
div[class='row']
div[class='col-md-12']
div[class='panel panel-default']
div[class='panel-heading']
h3[class='panel-title']
|Total Cost
div[class='panel-body']
h2[class='job-cost' data-initial = "#{job_base_price}"]
= number_to_currency(job_base_price)
div[class='panel-heading']
h3[class='panel-title']
|Have a coupon?
div[class='panel-body']
div[class='row-inline']
div[class='row-block row-block-one']
= j.simple_fields_for :coupon_attributes, #job.coupon do |c|
= c.input_field :code, maxlength: 50, id: 'coupon-code', class: 'form-control', data: { 'initial' => 0 }, include_blank: false
div[class='row-block']
button[type='button' class='btn btn-primary' id='coupon-verify' ]
|Verify
p[class='help-hint']
= t('simple_form.hints.coupon.code')
div[class='row']
div[class='col-md-12']
= j.button :button, type: 'button', class: 'btn-primary text-uppercase', id: 'purchase-job' do
= job_posting_button_step_label
When this form submits, I am seeing the following attributes:
This is not right.
I would expect the coupon code to be nil, not "".
Am I missing something here?
I see two things:
first:
:include_blank is an option for select fields, it skips the generation of a blank option tag at the beginning. code is an input field. If you want to force an input value, try required: true.
second:
form values are sent to the server as application/x-www-form-urlencoded. Empty imput fields are sent as i.e. job[coupon_attributes][code]=. There is no distinction between an empty string and no value.
The convention in Rails is to interpret all input values as string (and typecast later when assigning values to models). So an empty value is always returned as ''.
Related
In my Rails 7 app, I am using Stimulus and need to add data attributes to a form select to link it to a JavaScript controller. I am also trying to format the field (not the options) with a class.
Here is the form select element:
<%= f.select(:repeat, Batch.repeats, {class: "class_name"}, { data: { batch_repeat_target: "input", action: "change->batch-repeat#toggle" }}) %>
The above code results in the data attributes being applied to the select field, but leaving the class out.
I also tried to flip the class and the data attributes, as follows:
<%= f.select(:repeat, Batch.repeats, { data: { batch_repeat_target: "input", action: "change->batch-repeat#toggle" }}, { class: "class_name" }) %>
The result was the opposite of the first approach: this time, the field was styled per the class, but the data attributes were not associated with the select element.
Per this question, I became aware that:
select helper takes two options hashes, one for select, and the
second for html options. So all you need is to give default empty
options as first param after list of items and then add your class to
html_options.
From there, I thought that I needed to include both the class and the data attributes in the first option hash, and leave the second one empty, along the following lines:
<%= f.select(:repeat, Batch.repeats, { { class: "class_name" }, { data: { batch_repeat_target: "input", action: "change->batch-repeat#toggle" }}}, {}) %>
However, the above revised code resulted in an ActionView::SyntaxErrorInTemplate in BatchesController#new error.
In yet another attempt, I tried to shuffle things around, leaving the first option hash empty and including both the class and the data attributes in the second one, as follows:
<%= f.select(:repeat, Batch.repeats, {}, { { class: "class_name" }, { data: { batch_repeat_target: "input", action: "change->batch-repeat#toggle" }}}) %>
That revision also resulted in an ActionView::SyntaxErrorInTemplate in BatchesController#new error.
The question referenced above is more than 11 years old and: is there a different convention now, particularly in Rails 7, with regards to form select elements? How can I both include a class and data attributes here?
A hash looks like this: { key1: value1, key2: value2 }
So, take your attempted code: { { class: "class_name" } } - the inner hash there is { class: "class_name" } so let's assign that to a variable: value1 = { class: "class_name" } and then let's use that variable in your attempted code: { value1 }
See how that's not a hash, there's no key for the value. A hash must always have keys and values. This is why you're getting the syntax errors in your second two examples.
So let me go through your other two attempts:
<%= f.select(:repeat, Batch.repeats, {class: "class_name"}, { data: { batch_repeat_target: "input", action: "change->batch-repeat#toggle" }}) %>
So here, :repeat is the first argument, Batch.repeats is the second, the third argument (which is supposed to be the select options) is the hash with a single key/value pair: { class: "class_name" }, and the fourth argument (which is supposed to be the html options) is the hash with a single key/value pair: { data: { the: data, hash: here }
Your second attempt:
<%= f.select(:repeat, Batch.repeats, { data: { batch_repeat_target: "input", action: "change->batch-repeat#toggle" }}, { class: "class_name" }) %>
First two arguments the same, the third argument (the select options) is now the hash with the :data key/value, and the fourth argument (the html options) is now the hash with the single :class key/value.
What you want to do is provide an empty hash for the third argument (the select options), and then a hash with TWO key/value pairs for the fourth argument (the html options):
{ class: "class_name", data: { the: data, hash: here } }
(Note, I intentionally didn't feed you the full answer, because I feel that you're the sort of person who will benefit from discovering it on your own, but say so if I've misjudged, happy to edit this answer if you need it)
I created a rails (v5) form with multiple select and collection_select elements.
Then I use Select2-rails (v4.0.3) to allow a nice selection looking like tags.
The search-options are pulled by ajax.
It works fine until one presses the submit-button with missing required fields.
Valid field-content has now been deleted from the field.
Let me give some example-code:
controller:
...
def form
if params[:form_request].nil?
#form_request = FormRequest.new
else
#form_request = FormRequest.new(params[:form_request])
end
end
def request_form
#form_request = FormRequest.new(params[:form_request])
if #form_request.valid?
render :summary
else
render :form
end
end
...
form:
...
<%= bootstrap_form_for(#form_request, url: '/form/request_form') do |f| %>
<%= f.select :field, [], {label: 'Field label'} %>
<%= f.submit "Submit form" %>
<% end %>
:field is for sure a writable field in the model (and data is set fine)
coffee-script:
Query ->
$("#form_request_from").select2({
ajax: {
url: func =(params) ->
filter = params.term
return "/data.json?filter=" + filter;
,
dataType: 'json',
processResults: processData
},
theme: 'bootstrap',
placeholder: 'Enter data here'
});
processData = (data) ->
mapdata = $.map(data, func =(obj) ->
obj.id = obj.id;
obj.text = obj.name;
return obj;
);
return { results: mapdata };
I am thinking of a lot of possibilities, but at the end I am not sure where the field-data comes from. It is inside the object, but it isn't written to the resulting HTML in any way.
And even if the id would be written as a selected option,
the select2 script would need to know how to transform that into the string to show the real data.
Any idea how to achieve that the data is still written into a field after a failing validation?
After trying out some things I found out how to do it.
At first I just changed the empty array to be the :field variable,too.
This doesn't work too well because it only remembers the ID of the value that has been entered before and like this the SELECT2-script could not find the value to that key and nothing is shown.
Then I created a new variable inside the controller in which I place the array with name and id:
field_object = ObjectsModel.find(#form_request.field.to_i)
#form_field = []
if !field_object.nil?
#form_field = [[field_object.name, field_object.id]]
end
And in the view I now use this field to show the available options:
<%= bootstrap_form_for(#form_request, url: '/form/request_form') do |f| %>
<%= f.select :field, #form_field, {label: 'Field label'} %>
<%= f.submit "Submit form" %>
<% end %>
This works perfectly fine for me without the need to touch the SELECT2-script.
The possible values are still fetched by AJAX but already filled out fields will persist upon redirect to another action.
I have a page on my website with a form that allows users to add tags to an item. I want to incorporate typeahead so that when a user starts typing a tag in the input box, a dropdown list appears with existing tags that match the string. I think I can accomplish this with the basic example but it doesn't seem to be working.
Here is my show page with the script:
<div id="add-tag-form">
<%= form_tag add_tag_path, id: "custom-tag",
class: "form-group",
autocomplete: "off",
remote:true
do %>
<%= text_field_tag :tag, nil, placeholder: 'Add tag', class: "form-control typeahead", id: 'add-tag' %>
<%= submit_tag 'Add' %>
<span id = "tag-block" class="help-block"></span>
<% end %>
</div>
<script>
$(document).ready(function(){
var substringMatcher = function(strs) {
return function findMatches(q, cb) {
var matches, substringRegex;
// an array that will be populated with substring matches
matches = [];
// regex used to determine if a string contains the substring `q`
substrRegex = new RegExp(q, 'i');
// iterate through the pool of strings and for any string that
// contains the substring `q`, add it to the `matches` array
$.each(strs, function(i, str) {
if (substrRegex.test(str)) {
matches.push(str);
}
});
cb(matches);
};
};
var tags = Tag.all.pluck(:name);
$('#add-tag-form .typeahead').typeahead({
hint: true,
highlight: true,
minLength: 1
},
{
name: 'tags',
source: substringMatcher(tags)
});
});
</script>
In the console I get Uncaught SyntaxError: unexpected token : which is pointing to the :name in the line var tags = Tag.all.pluck(:name);. My thoughts are the ruby isn't being recognized within the script tags but I could be wrong. What is the correct way to do this?
Also, do I need the $(document).ready line at the start of the script?
I'm trying to integrate ParsleyJS with Rails. The problem is that I can't seem to make a "hash in a hash"
<%= f.email_field :email ,
class: "form-control",
parsley: { type: "email", trigger: "keyup"},
placeholder: "Email-Address" %>
O end up with something like this: parsley="{:type=>"email", :trigger=>"keyup"}" in the HTML. For data such as data: { toggle: 'tooltip', original_title: 'thingie'}, these are parsed into data-toggle="tooltip".
This works:
parsley: { type: "email"} # It gets parsed to parsley-type
But I can't have two or more attributes. What gives?
<%= f.check_box:TYPE %> AB <br><br>
I have used the above mentioned in my code and when i click submit it takes 1 if checked and 0 if not checkedand it is stored in db. How can i store a string like AB if checked and nil if not checked and i want to store that string in db instead of 0 and 1?
This is the definition of this helper method:
check_box (object_name, method, options = {}, checked_value = "1", unchecked_value = "0")
So I supose you need something like:
<%= check_box :type, {}, "AB", "nil" %> AB <br><br>
But in your rails application you get string 'AB' and string 'nil', that how it works.
Rails 3.2 # http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html
check_box(object_name, method, options = {}, checked_value = "1", unchecked_value = "0")
ex.
<%= f.check_box( :type, {}, "yes", "no") %>