How should I handle this Rails use case? - ruby-on-rails

I have an Exercise model, which has these columns (pseudo Ruby):
model Exercise do
string :name
calories_burned :float
end
I want that when a user adds an exercise to be able to do it in this fashion:
if previous exercises exist
show a select element with names of existing added
show a checkbox to allow adding a new one, switching the input
field to a textfield
else
show a textfield
The thing is, I don't know how I should put this in my view. Here's how the else case is handled:
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
I have something like this now:
<div class="field">
<% if #exercise_added %>
<div id="select_div">
<%= select_tag :name,options_for_select(#exercise_added) %>
<input type="checkbox" name="custom_type_checked" id="which_type">New type?</input>
</div>
<% end %>
<div id="regular_field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
</div>
In #exercise_added I have a list of names of all exercises from the database. What would be the best/cleanest way of handling this?
EDIT: For now,I have a textfield and a select, and by using Javascript, I'm changing the name of the element ( and hiding the other one ). So far, it's working, but I'd still be interested if other approaches exist.

You can check if the array #exercise_added is empty or not and show the select field or text field accordingly.
<div class="field">
<% if !#exercise_added.empty? %>
<div id="select_div">
<%= select_tag :name,options_for_select(#exercise_added) %>
<input type="checkbox" name="custom_type_checked" id="which_type">New type?</input>
</div>
<% else %>
<div id="regular_field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<%end%>
</div>

I would, by default, have the select box and a button shown, with the textbox hidden unless a variable #show_textbox is true. Something like this:
<div class="field">
<div id="select_div">
<%= select_tag :name,options_for_select(#exercise_added) %>
<%= f.submit "New Exercise" %>
</div>
<div id="regular_field" <%= hidden_unless #show_textbox %> >
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
</div>
Where I've written a helper function
def hidden_unless cond
raw "style=\"display: none;\"" unless cond
end
# this one is helpful, too
def hidden_if cond
raw "style=\"display: none;\"" if cond
end
Then, in my controller, check if the "New Exercise" button was pressed. If so, essentially set #show_textbox to true and then re-render the new form.
def create
# .....
# did we get here because the user pressed "New Exercise"?
if params[:commit].eql?("New Exercise")
#show_textbox = true
# probably some other code to replicate what happens in your #new action
render :action => new
end
# ....
end
You can check in your controller if the :name field has any text in it, and use that to override the select box.
This should work without javascript. I'd add some jQuery to replace the button with either a link or a check box, with the click handler for that connected to a function that shows the textbox, i.e. $('#regular_field').toggle();.
I didn't deal with hiding the select box. I actually think it might be better to leave that available. You could hide it using a similar method, anyways.

What if you used two forms? One form to handle the case when the exercise is in #exercise_added, and a second form to handle the creation of a new exercise. It might even boil down to the difference between a POST and a PUT, depending on what you're doing once an exercise is submitted from the drop-down list.
I'd be curious to see more of the code, as well as the controller, since it seems like this form might be nested?

Related

Serialized fields_for not populating from db on edit

On the edit page for this form all of the fields outside of the fields_for tag (inbox name, automatic reconciliation, and a few others not listed here) are all populating based on their corresponding db value. However, everything inside the fields_for tag are not, even though they're posting to the db just fine.
I posted :group_member_roles as an example but there are a few other fields inside their own other fields_for that are doing the same thing. It's just confusing that it will post to the db but not display on edit.
The more I read into fields_for the more I feel like I'm not using it correctly. It seems to be more inclined to populating db tables outside of the one your form is currently referencing, but I'm just trying to serialize data within the inbox table. When I look at the :group_member_roles column I want it to be an array/hash containing process true/false, action add/delete, and a string of values.
#_form.html.erb
<%= form_for(#inbox) do |f| %>
<%= f.label :inbox_name %>
<%= f.text_field :name, placeholder: "Inbox Name" %>
<%= f.label :automatic_reconciliation, "Turn on/off automatic reconciliation" %>
<div class="switch small">
<%= f.check_box :automatic_reconciliation, class: "switch-input" %>
<label class="switch-paddle" for="inbox_automatic_reconciliation">
<span class="show-for-sr">Automatic reconciliation</span>
<span class="switch-active" aria-hidden="true">On</span>
<span class="switch-inactive" aria-hidden="true">Off</span>
</label>
</div>
<%= f.fields_for :group_member_roles do |group_member_roles| %>
<h4>Group Member Roles</h4>
<%= group_member_roles.label :process, "Turn On/Off Processing" %>
<div class="switch small">
<%= group_member_roles.check_box :process, class: "switch-input" %>
<label class="switch-paddle" for="inbox_group_member_roles_process">
<span class="show-for-sr">Group Member Roles Processing</span>
<span class="switch-active" aria-hidden="true">On</span>
<span class="switch-inactive" aria-hidden="true">Off</span>
</label>
</div>
<%= group_member_roles.label :action, class: "hide" %>
<%= group_member_roles.select :action, ["Add", "Delete"], { selected: "Add" }, { class: "hide" } %>
<%= group_member_roles.label :values %>
<%= group_member_roles.text_field :values, placeholder: "1234, 1337, 1986" %>
<% end %>
Thanks in advance for any help or guidance.
The fields were being stored as a hash and the field was looking for an object to populate with so I added an OpenStruct dummy object to the fields_for to make it so. If anyone can think of a better way please let me know as this is pretty ugly code.
<%= f.fields_for :group_member_roles, OpenStruct.new(f.object.group_member_roles) do |group_member_roles| %>

create form fields on the fly from drop down

I dint even understand how to search for my problem scenario in google.
Problem : When a user selects from a drop-down, the below form fields should change accordingly.
Example : If a user selects "Human" from Drop-down , then below form_fields should be shown like "age" field ,"ethnicity" field etc..
If a user selects "Event" from drop-down, below form fields should show "Date", "venue" etc..
and By default we will have "SUBMIT" button.
Can anyone tell how to achieve this ? Any help with simple_form ruby gem also would be helpful.
You can do this with some simple javascript. Lets say you have a form with the following fields
<%= f.select :some_field, %w[Human Cat], {}, {:class => 'my-select'} %>
<div class="human">
<%= f.label :age %><br>
<%= f.text_field :age %>
</div>
<div class="cat" style="display:none;">
<%= f.label :sub_species %><br>
<%= f.text_field :sub_species %>
</div>
Now add some javascript to make it dynamic
<script>
$(".my-select").change(function(){
if($(".my-select").val() == "Human"){
$(".human").css('display', 'block');
$(".cat").css('display', 'none');
}else{
$(".human").css('display','none');
$(".cat").css('display', 'block');
}
})
</script>
This is quite easy to achieve with the simple_form gem and some simple javascript.
View
<%= simple_form_for #object do |f| %>
<%= f.input :attribute_name, :collection => ['Human', 'Event'], :input_html => { :class => 'dropdown' %>
<div class="toggle human" style="display:none;">
<%= f.input :age %>
</div>
<div class="toggle event" style="display:none;">
<%= f.input :date %>
</div>
<%= f.button :submit %>
<% end %>
The key here is wrapping the fields you want to toggle in div with specific selectors.
Then we look for a change event on the dropdown field, and toggle our divs accordingly.
Javascript
$('.dropdown').change(function() {
// hide divs first
$('form .toggle').hide();
// get value from dropdown
var divClass = $('.dropdown').val().toLowerCase();
// show necessary div
$('.' + divClass).show();
});
Using this approach, you don't need to write the specific case for every value of the dropdown, but can use the lower case value of the dropdown as the selector for the div.
Here is a simple example with static markup.

How to hide part of a rails 3 form depending on value selected from dropdown menu

I have a a partial, _form for one of my views in rails. It looks like so:
<%= form_for(#project) do |f| %>
<div class="field">
<%= f.label "Project Status" %><br />
<%= f.select :status, ["In Progress", "Cancelled"] %>
</div>
<div class="field">
<%= f.label "Capital Cost" %><br />
<%= f.text_field :capital_cost %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
I'd like the "capital cost" part of the form to be greyed out unless "In Progress" is selected from the dropdown menu, without having to reload the page. Is this possible? I saw some solutions using javascript, but I'm a complete beginner and couldn't get my head around them (unfortunately I don't have the time to learn to use js before I have to finish this project). Cheers!
For this you need some JavaScript. Use an onchange event handler to monitor the <select> input for changes. Compare the input value and conditionally set/unset a disabled attribute on the #project_capital_cost input. You can use jQuery for this.
By default, Rails 3 enables jQuery by including the jquery_rails gem in your Gemfile. Assuming you have jquery_rails included in your app and your <select> and <input> tags have #project_status and #project_capital_cost IDs respectively, add the following script into your _form partial with necessary modification:
<script>
$(document).ready(function(){
if($('#project_status').val() != "In Progress"){
$("#project_capital_cost").attr('disabled','disabled');
}
else{
$("#project_capital_cost").removeAttr('disabled');
}
$('#project_status').change(function(){
if($(this).val() != "In Progress"){
$("#project_capital_cost").attr('disabled','disabled');
}
else{
$("#project_capital_cost").removeAttr('disabled');
}
})
});
</script>
EDIT:
To hide div give some id to it:
<div class="field" id="my_div">
<%= f.label "Capital Cost" %><br />
<%= f.text_field :capital_cost %>
</div>
Then replace
$("#project_capital_cost").attr('disabled','disabled'); with $("#my_div").css('display','none')
and
$("#project_capital_cost").removeAttr('disabled'); with $("#my_div").css('display','block') in script.
To grey out the input, use the HTML input tag attribute disabled.
<input disabled="disabled">
Which from Rails is
<%= f.text_field :capital_cost, :disabled => "disabled", :id => "capital_cost_input" %>
To enable it when "In Progress" is selected will require AJAX and Javascript, but there is some help from Rails.
First
<%= f.select :status, ["In Progress", "Cancelled"],
{},
"data-remote" => true, "data-url" => ..._path %>
This will set the onchange attribute for you and make the AJAX call.
Add a route to handle the AJAX call, and supply the URL for the "data-url".
In the view template for the AJAX action, write the Javascript to enable the input.
Something like
$('#capital_cost_input').removeAttr("disabled")

Custom form processing

I have some custom form (user reputation) that doesn't link with any model directly.
I have several reputation criteria which affects final returation value
Here is code of the form
<%= form_tag("/add_reputing",:method => "POST") do%>
<div class="reputing_column">
<p>
<b>Your feedback:</b>
</p>
<p>
<%= text_area_tag :comment,"",{:class=>"or-form-textarea"} %>
</p>
<%= submit_tag("Submit",:class=>"or-button")%>
</div>
<div class="reputing_column">
<p>
<b>Recomendation:</b>
</p>
<% #criterias.each do |c| %>
<div class="reputing_row">
<label><%= c.name%>:</label>
<div>
<% (c.rating_from .. c.rating_to).each do |i| %>
<%= radio_button_tag "reputing_#{c.id}", i%><%= (i<1)? i : "+#{i}"%>
<% end %>
</div>
</div>
<% end %>
</div>
<% end %>
In controller I need to summirize a values of "reputing_#{c.id}" fields. And then add a record to user reputation table.
How it will be better and properly to process data from this form in controller? I tried to google that problem, but found nothing.
No answers, so I'll try to clarify the dealing with, as you called them, custom forms.
Here's the form for selecting a preferred color via radio buttons.
= form_for :preferences, url: '', method: :post do |f|
- %w[black blue white green red yellow].each do |color|
= f.radio_button :color, color
= f.label :color, color.capitalize, value: color
= f.submit
The cool thing about forms in Rails that they can be used with or without a model. If you have an instance variable called #preferences then this form will respect that and will call the color method on it to determine the "current" color. This color will be selected on the generated form. If this variable doesn't exist it won't be a big deal.
In any case, after submitting the form you'll be able to access the selected color via:
params[:preferences][:color]

React: form building in a Rails-like way

I am trying to enhance an existing Rails application using React (react-rails gem).
This app has a form built with following code:
<%= form_for #article do |f| %>
<div class="form-group">
<%= f.label :title %>
<%= f.text_field :title %>
</div>
<div class="form-group">
<%= f.label :body %>
<%= f.text_area :body, size: "60x12" %>
</div>
<div class="form-group">
<label><%= f.checkbox :sets_expiration_date %> Sets expiration date</label>
<%= f.date_select :expiration_date, start_year: Date.today.year %>
</div>
<button type="submit" class="btn btn-default">Create</button>
<% end %>
I want this form to have following functionalities:
When the user toggles the checkbox, the three drop-down lists for the expiration_date field shows or hides.
When the user submits, the form data is sent to the server via Ajax for validation and persistence.
When the validation fails, the relevant labels and input fields get surrounded with red border.
When the form data gets saved successfully, the form disappears and a message appears.
In my first attempt, I managed to achieve the goal but I found that I had to write vanilla HTML code a lot.
This is a disappointment for me.
Especially, I don't like to specify the name and defaultValue attributes for each <input> tag
like <input name="article[title]" defaultValue={this.props.object.title}>.
I also had to write rather long JavaScript code to create three drop-down lists for the expiration_date field.
How can I construct such a form using React efficiently? Are there any good plugins?

Resources