Default radio button with scope in model? - ruby-on-rails

What is the best way I can make One-Shot the default radio button selection?
_form
<% Challenge::CATEGORY.each do |c| %>
<span class="label label-primary"> <%= label(c, c) %> </span>
<%= f.radio_button(:category, c, :class => "date-format-switcher") %>
<% end %>
<div id='id_of_first_div'>
One-Shot
</div>
<div id='id_of_second_div'>
Ongoing
</div>
<script>
$(function(){
$('#challenge_category_one-shot').click(function(){ $('#id_of_first_div').show(); $('#id_of_second_div').hide(); });
$('#challenge_category_ongoing').click(function(){ $('#id_of_first_div').hide(); $('#id_of_second_div').show(); });
});
</script>
challenge.rb
scope :oneshot, -> { where(categories: 'One-Shot') }
scope :ongoing, -> { where(categories: 'Ongoing') }
CATEGORY = ['One-Shot', 'Ongoing']
schema
t.string "category"

If you are intent on using f.radio_button then you could add the parameter
checked: (c=='One-Shot')
You could also use r.collection_radio_buttons instead:
<% categories = ['One-Shot', 'Ongoing'] %>
<%= f.collection_radio_buttons :category, categories, :to_s, :to_s, {checked: 'One-Shot'} %>

Related

Displaying different divs based on dropdown selection in Rails form

I am trying to create a form in Rails that includes a dropdown menu with three options: 'foo', 'bar', and 'baz'. If the user selects one of these options, I want to display a different div based on the selected option.
Here is my code:
<% options = [['Foo', 'foo'], ['Bar', 'bar'], ['Baz', 'baz']] %>
<%= form.label :type %>
<%= form.select :type, options_for_select(options, #selected_type), name: 'type' %>
<% if #selected_type == 'foo' %>
<div>
<%= form.hidden_field :type, value:'foo' %>
</div>
<% elsif #selected_type == 'bar' %>
<div>
<%= form.hidden_field :type, value:'bar' %>
</div>
<% elsif #selected_type == 'baz' %>
<div>
<%= form.hidden_field :type, value:'baz' %>
</div>
<% end %>
This is in my controller:
#vendor_item = VendorItem.new
#selected_type = params[:type]
puts "Selected type: #{#selected_type}"
I have implemented this using a select element, but the form is not working as expected. When I select an option from the dropdown menu, the form is not being submitted, and the divs are not being displayed.
CASE 1: If the form should be submitted on the server side, after the dropdown change:
<% options = [['Foo', 'foo'], ['Bar', 'bar'], ['Baz', 'baz']] %>
<%= form_with url: "your URL goes here", class: 'test_submit_form' do |form| %>
<%= form.label :type %>
<%= form.select :type, options_for_select(options, #selected_type), name: 'type' %>
<% if #selected_type == 'foo' %>
<div>
<%= form.hidden_field :type, value:'foo' %>
</div>
<% elsif #selected_type == 'bar' %>
<div>
<%= form.hidden_field :type, value:'bar' %>
</div>
<% elsif #selected_type == 'baz' %>
<div>
<%= form.hidden_field :type, value:'baz' %>
</div>
<% end %>
<%= form.submit %>
<% end %>
Javascript:
<script>
$('#type').on('change', function(){
$('form.test_submit_form').submit();
});
</script>
CASE 2: If you just need to show/hide DIVs on client side, after dropdown change:
<% options = [['Foo', 'foo'], ['Bar', 'bar'], ['Baz', 'baz']] %>
<%= form_with url: "your URL goes here", class: 'test_submit_form' do |form| %>
<%= form.label :type %>
<%= form.select :type, options_for_select(options, #selected_type), name: 'type' %>
<div class="option-container foo" style="display: <%= #selected_type == 'foo' ? 'block' : 'none'%>">
<%= form.hidden_field :type, value:'foo' %>
</div>
<div class="option-container bar" style="display: <%= #selected_type == 'bar' ? 'block' : 'none'%>">
<%= form.hidden_field :type, value:'bar' %>
</div>
<div class="option-container baz" style="display: <%= #selected_type == 'baz' ? 'block' : 'none'%>">
<%= form.hidden_field :type, value:'baz' %>
</div>
<%= form.submit %>
<% end %>
Javascript:
<script>
$('#type').on('change', function(){
$('.option-container').hide();
$('.option-container.' + $(this).val()).show();
});
</script>
Notice the option-container and option (foo, bar, baz) class on div and controller code will remain the same for both cases:
#selected_type = params[:type]

NoMethodError in Discussions#create

Below is code extract from my file Users/JBossman/sites/discussions/app/views/discussions/_form.html.erb where line #20 raised this error undefined method 'map' for nil:NilClass
enter code here
<%= simple_form_for(#discussion) do |f| %>
<%= f.error_notification %>
<div class="field">
<div class="control">
<%= f.input :title, required: true, input_html: { class: 'input' }, wrapper: false, label_html: { class: "label" } %>
</div>
</div>
<div class="field">
<div class="control">
<%= f.input :content, required: true, input_html: { class: 'textarea' }, wrapper: false, label_html: { class: "label" } %>
</div>
</div>
<div class="field">
<label class="label">Channel</label>
<div class="control has-icons-left">
<span class="select">
<%= f.input_field :channel_id, collection:#channels.map { |c| [c.channel, c.id] }, prompt: "Select channel" %>
</span>
<span class="icon is-small is-left">
<i class="fa fa-tag"></i>
</span>
</div>
</div>
<div class="field">
<div class="control">
<%= f.button :submit, class:"button is-info" %>
</div>
</div>
<% end %>
the error is here: #channels.map { |c| [c.channel, c.id] }
your #channels variable is nil.
make sure you set #channels in your create action.
Looks like #channels is nil. Ideally, it should be initialized as [] empty array.
Alternatively, you can also use (#channels || []).map { |c| [c.channel, c.id] } to render empty form.
change #channels.map { |c| [c.channel, c.id] } to below, as #channels is not set(nil).
Assuming that you are having Channel model.
i. If you want to display all the channels in collection, then you can do it as below:
Channel.pluck(:channel, :id)
ii. If you want to display specific channels in collection, then define scope in Channel like favorites
Channel.favorites.pluck(:channel, :id)
I fixed a similar problem with a little change .map to .collect function, you may give it a try..

Rails Submit button not submitting

I've moved from BS3 to Materialize so I am going through and changing my forms - I have 4 forms that are extremely similar, but as I switched the first one over it's no longer submitting. The button doesn't even seem like it's getting clicked, but I tied a generic 'logMe' function to it and sure enough it is.
My routes are the exact same for both, the new form is
<div class="row">
<%= form_with(model: #statement, local: true) do |form| %>
<% if #statement.errors.any? %>
<% #statement.errors.full_messages.each do |message| %>
<script>
$(function() {
Materialize.toast("<%= message %>", 3000);
});
</script>
<% end %>
<% end %>
<div class="row">
<div class="input-field col s12">
<i class="material-icons prefix">account_circle</i>
<!--<label for="icon_prefix">SoW Type:</label>-->
<%= form.label :statement_type, 'Type:' %>
<%= form.text_field :statement_type, :id => "disabled", :value => (params[:statement_type]), readonly: true, :disabled => true %>
</div>
</div>
<div class="row">
<div class="input-field col s6">
<i class="material-icons prefix">contacts</i>
<%= form.label :name, "Name:" %>
<%= form.text_field :name, :id => 'required_field1' %>
</div>
<div class="input-field col s6">
<i class="material-icons prefix">contacts</i>
<%= form.label :cost, "Cost:" %>
<%= form.text_field :cost, :id => 'required_field2' %>
</div>
</div>
<div class="row">
<div class="input-field col s6">
<i class="material-icons prefix">date_range</i>
<%= form.label :start_date, "Start Date" %>
<%= form.text_field :start_date, :class => 'datepicker', "data-provide" => 'datepicker', :id => 'required_field4', :placeholder => "YYYY-MM-DD" %>
</div>
<div class="input-field col s6">
<i class="material-icons prefix">date_range</i>
<%= form.label :end_date, "End Date" %>
<%= form.text_field :end_date, :class => 'datepicker', "data-provide" => 'datepicker', :id => 'required_field5', :placeholder => "YYYY-MM-DD" %>
</div>
</div>
<div class="row">
<div class="input-field col s12">
<i class="material-icons prefix">perm_contact_calendar</i>
<%= form.collection_select(:client_id, current_user.clients.order(:name),:id,:name, :class => "browser-default", :prompt => "Choose a client" ) %>
</div>
</div>
<div class="row">
<div class="col s12">
<%= form.submit 'Submit', :class =>'btn btn-default', :id => 'register', :onclick => "testMe()"%>
</div>
</div>
<% end %>
</div>
<script type="text/javascript">
$(document).ready(function (){
$('select').material_select();
validate();
$('#required_field1, #required_field2').change(validate);
});
function testMe(){
console.log('hi')
}
function validate(){
if ($('#required_field1').val().length > 0 &&
$('#required_field2').val().length > 0
){
$("input[type=submit]").prop("disabled", false);
}
else {
$("input[type=submit]").prop("disabled", true);
}
}
var from_$input = $('#required_field4').pickadate({
selectMonths: true, // Creates a dropdown to control month
selectYears: 15, // Creates a dropdown of 15 years to control year,
today: 'Today',
clear: 'Clear',
close: 'Ok',
closeOnSelect: true,
format: 'yyyy-mm-dd'
}),
from_picker = from_$input.pickadate('picker')
var to_$input = $('#required_field5').pickadate({
selectMonths: true, // Creates a dropdown to control month
selectYears: 15, // Creates a dropdown of 15 years to control year,
clear: 'Clear',
close: 'Ok',
closeOnSelect: true,
format: 'yyyy-mm-dd'
}),
to_picker = to_$input.pickadate('picker')
// Check if there’s a “from” or “to” date to start with.
if ( from_picker.get('value') ) {
to_picker.set('min', from_picker.get('select'))
}
if ( to_picker.get('value') ) {
from_picker.set('max', to_picker.get('select'))
}
// When something is selected, update the “from” and “to” limits.
from_picker.on('set', function(event) {
if ( event.select ) {
to_picker.set('min', from_picker.get('select'))
}
else if ( 'clear' in event ) {
to_picker.set('min', false)
}
})
to_picker.on('set', function(event) {
if ( event.select ) {
from_picker.set('max', to_picker.get('select'))
}
else if ( 'clear' in event ) {
from_picker.set('max', false)
}
})
</script>
I've tried commenting out all JS, switching it to a regular button, linting it and using Rubocop but I don't see anything off. I went through the HTML to make sure the button was inside the form, and it is.
This isn't the first form I've transitioned, but the first I'm having issues with.
(I assume only the view is relevant since it isn't getting to the controller at this point.)
Just to be safe - The view rendering the form is
<div class="row">
<div class="col s12"><span class="flow-text" style="text-align: center;"><h1>New <%= params[:statement_type] %></h1></span></div>
</div>
<% if params[:statement_type] == 'Proposal' %>
<%= render 'proposal_form' %>
<% elsif params[:statement_type] == 'Concept' %>
<%= render 'concept_form' %>
<% elsif params[:statement_type] == 'SoW' %>
<%= render 'sow_form' %>
<% elsif params[:statement_type] == 'Misc' %>
<%= render 'misc_form' %>
<% end %>
<%= link_to 'Back', statements_path %>
SoW + Proposal work. SoW doesn't.
My issue ended up not being HTML based, but Rails based in the end.
My static element that is populated by a param was causing the issue.
<%= f.text_field :statement_type, :id => "disabled", :value => (params[:statement_type]), readonly: true %>
By removing the id: disabled it resolved the inability for the Submit button to submit. Unfortunately, it also makes MaterializeCSS back to highlighting the field when I select it, but my issue was the Submit button not working.

How to use radio button to not send data to the server?

I am able with the radio button and a little javascript to toggle between the two categories, but even if one category is hidden it's data still sends.
challenge.rb
class Challenge < ActiveRecord::Base
scope :oneshot, -> { where(categories: 'One-Shot') }
scope :ongoing, -> { where(categories: 'Ongoing') }
_form
<%= form_for(#challenge) do |f| %>
<%= f.text_field :action %>
<% Challenge::CATEGORY.each do |c| %>
<%= label(c, c) %>:
<%= f.radio_button(:category, c, :class => "date-format-switcher", checked: (c=='One-Shot')) %>
<% end %>
<div id='id_of_first_div'>
<%= f.date_select :deadline %>
</div>
<div id='id_of_second_div'>
<%= f.date_select :date_started %>
</div>
<% end %>
<script>
$(function(){
$('#id_of_second_div').hide();
$('#challenge_category_one-shot').click(function(){
$('#id_of_first_div').show().attr('disabled', false);
$('#id_of_second_div').hide().attr('disabled', true);
});
$('#challenge_category_ongoing').click(function(){
$('#id_of_first_div').hide().attr('disabled', true);
$('#id_of_second_div').show().attr('disabled', false);
});
});
</script>
Radio Button HTML
<input class="date-format-switcher" type="radio" value="One-Shot" checked="checked" name="challenge[category]" id="challenge_category_one-shot" />
<input class="date-format-switcher" type="radio" value="Ongoing" name="challenge[category]" id="challenge_category_ongoing" />
Adapting Fiddle
<input id='a-selector' type='radio' name='selector' value='A' checked/> A
<input id='b-selector' type='radio' name='selector' value='B'/> B
<div id='details'>
<div id='for-a'>
<%= f.date_select :deadline, include_blank: true, selected: Date.current %>
</div>
<div id='for-b'>
<%= f.date_select :date_started, include_blank: true, selected: Date.current %>
</div>
</div>
<script>
var removed = $('#for-b').detach();
$('#a-selector').click(function() {
$('#details').append(removed);
removed = $('#for-b').detach();
})
$('#b-selector').click(function() {
$('#details').append(removed);
removed = $('#for-a').detach();
})
</script>
Setting a form element as disabled only disables user interaction with it; it doesn't remove it from the form's data (although your jQuery code is actually setting the div to disabled, which does nothing, but fixing that wouldn't help at all). What you want to do instead is clear the value of the date elements, e.g.,
<script>
$(function(){
$('#id_of_second_div').hide();
$('#challenge_category_one-shot').click(function(){
$('#id_of_first_div').show();
$('#id_of_second_div').hide();
$('#id_of_second_div select').value('')
});
$('#challenge_category_ongoing').click(function(){
$('#id_of_second_div').show();
$('#id_of_first_div').hide();
$('#id_of_first_div select').value('')
});
});
</script>
Though for that to work, you will need to add include_blank: true as an option to your date_select tags:
<%= f.date_select :deadline, include_blank: true %>
This will add the empty value as an option to your date selects, so that the above code can reset them to that empty value.
I'd also like to note -- all of this is just front-end logic, which any malevolent (or curious) user can circumvent. Your backend code (i.e., your controller) should handle discarding the fields you don't need based on your business logic, too.

show rest of a form if a checkbox is ckecked in ruby on rails

I need to ask to my user if will pay a service with credit card...if it checked the option pay_with_card? it must show the rest of the form, that ask for other data like card number, mail, etc. if the user don't checked it, it must show a message, the question is...how can I do this? thanks in advance
<%= form_for(#product) do |f| %>
<%= f.label :pay_with_card? %>
<%= f.check_box :pay_with_card,{}, "Yes", "No"%>
<div>
<%= f.label :card_number %> <%= f.text_field :card_number %>
</div>
<div>
<%= f.label :mail %> <%= f.text_field :mail %>
</div>
<% end %>
Make the card number/mail details div style="display:none;", then add some javascript to the checkbox to change it to display:block;
Something like this:
<%= form_for(#product) do |f| %>
<%= f.label :pay_with_card? %>
<%= f.check_box :pay_with_card,{}, "Yes", "No"%>
<div id="card_details" style="display:none;">
<%= f.label :card_number %> <%= f.text_field :card_number %>
<%= f.label :mail %> <%= f.text_field :mail %>
</div>
<% end %>
<script type="text/javascript">
var checkbox = document.getElementById('product_pay_with_card');
var details_div = document.getElementById('card_details');
checkbox.onchange = function() {
if(this.checked) {
details_div.style['display'] = 'block';
} else {
details_div.style['display'] = 'none';
}
};
</script>
How about using jQuery?
First, wrap your credit card fields in a div with class credit_card_fields and than add this JS code to your page:
$("input[type='checkbox']#pay_with_card").on('change', function(){
$('.credit_card_fields').toggle();
});
You can use JS for it or move pay_with_card out of form like:
<%= link_to 'pay with card', your_current_path(:pay_with_card => 1) %>
<%= form_for(...) do |f| %>
<% if params[:pay_with_card] %>
<%= # fields for card %>
<% end %>
<% end %>
You can do it through jQuery, for example:
$ ->
$('select#pay_with_card').change ->
if $(this).val() == 'yes'
$('.card_block').slideDown('fast')
else
$('.card_block').slideUp('fast')
assumed that part of the form with payment card is included in the div with .card_block class
Ok my solution is this: all the code in the view, if a user check pay_with_card...(mi code is in spanish) it shows the complete form...if is not checked don´t show nothing, just the same checkbox asking for payment... thanks guys.
function mostrar (){
var checkbox = document.getElementById('chk_tarjeta');
if (checkbox.checked)
document.getElementById("card_details").style.display = "block";
else
document.getElementById("card_details").style.display = "none";
</script>
<h1>Forma de Pago</h1>
<%= form_for(#product) do |f| %>
<div id="product_pay_with_card">
<div >
<%= f.label :paga_con_tarjeta? %></br>
<%= f.check_box :paga_con_tarjeta, :id => "chk_tarjeta", :onclick => "mostrar();" %>
<div>
</div>
</div>
<div id="card_details" >
<div>
<%= f.label :numero_de_tarjeta %></br>
<%= f.text_field :numerotarjeta %>
</div>
<div>
<%= f.label :codigo_de_seguridad %></br>
<%= f.text_field :codigoseguridad %>
</div>
This worked for me with a form_with model and bootstrap
Change my_hidden_form with an id that makes sense for your form.
Original code is haml
= form_with scope: :model, url: models_path, local: true do |form|
.row
.col-6
.form-group
%h5.mb0 THE CASE TO TICK
= form.check_box :form_value, {:data => {:aria => {controls: :my_hidden_form, expanded: false}, :toggle => "collapse", :type => "checkbox", :target => "#my_hidden_form" }}
.row
.col-6
.form-group.collapse#my_hidden_form
%h5.mb0 THE FORM TO SHOW WHEN CASE IS TICKED
= form.text_field :name, placeholder: "A name"
.row
.col-md-12.text-right
= form.submit 'Submit', class: "btn btn-primary"
Converted to erb/html with https://haml2erb.org/
<%= form_with scope: :model, url: models_path, local: true do |form| %>
<div class="row">
<div class="col-6">
<div class="form-group">
<h5 class="mb0">THE CASE TO TICK
<%= form.check_box :form_value, {:data => {:aria => {controls: :my_hidden_form, expanded: false}, :toggle => "collapse", :type => "checkbox", :target => "#my_hidden_form" }} %>
</h5>
</div>
</div>
</div>
<div class="row">
<div class="col-6">
<div class="form-group collapse" id="my_hidden_form">
<h5 class="mb0">THE FORM TO SHOW WHEN CASE IS TICKED
<%= form.text_field :name, placeholder: "A name" %>
</h5>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12 text-right">
<%= form.submit 'Submit', class: "btn btn-primary" %>
</div>
</div>
<% end %>
Since the approach suggested by #Unixmonkey didn't work for me, here's a slight variation I put together using an event listener.
<script type="text/javascript">
const checkbox = document.getElementById('product_pay_with_card');
const details_div = document.getElementById('card_details');
checkbox.addEventListener("change", (event) => {
if (event.currentTarget.checked) {
details_div.style['display'] = 'block';
}
else {
details_div.style['display'] = 'none';
}
});
</script>

Resources