Custom form processing - ruby-on-rails

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]

Related

Rails simple form doen't pass params from input

I want to display a list of InvestorTypes (as a radio button) but before each type I should be able to add an explanation of that type. Here is what I've got:
<%= simple_form_for(resource, as: resource_name, url: users_user_experience_level_path(resource_name), html: { method: :put }) do |f| %>
<div class="form-inputs">
<% User::USER_EXPERIENCE_LEVEL.each do |level| %>
<b>Investor type <%= level %></b>
<%= t("user.description.#{level}") %>
<%= f.input :experience_level, collection: [level], as: :radio_buttons, label: false %>
<% end %>
</div>
<div class="form-actions">
<%= f.button :submit, 'Submit' %>
</div>
<% end %>
Which gives me expected view:
Investor type Beginner
Some explanation of what is going on
[checkobox] type Beginner
Investor type Expert
Some clarification of who is an expert and what ever you want to display here
[checkbox] type Expert
Investor type Institutional
Some clarification of who is an institutional client and some legal stuff
[checkbox] type Institutional
But when Submit button is pressed it doesn't pass input value (radio box selection which user chose) into the params:
=> #<ActionController::Parameters {"experience_level"=>""} permitted: true>
[EDIT]
class User < ApplicationRecord
USER_EXPERIENCE_LEVEL = %w[institutional beginner expert].freeze
end
It looks to me like you're using simple form wrong. The "collection" input in Simple Form is expecting to get an entire list of options, not just one option.
Looping in the way you're doing it is creating one group for each experience level, and each group only has one button in it. So it might visually look correct, but it's not functioning the way you intended. Instead you want to create one group of radio buttons for experience level such that each button changes the value of experience level.
Because you're doing this with significant customization around the appearance, it's probably not a good use of Simple Form, and instead you should fall back to the normal Rails form helpers.
You want to pass a block to f.input to get the simple form wrapper and then use the lower level rails helpers:
<%= simple_form_for(resource, as: resource_name, url: users_user_experience_level_path(resource_name), html: { method: :put }) do |f| %>
<div class="form-inputs">
# adds the simple form wrapper
<%= f.input :experience_level do %>
# iterates across the options and yields a input builder to each iteration
<%= f.collection_checkboxes(:experience_level, User::USER_EXPERIENCE_LEVEL, :value_method, :label_method) do |cb| %>
# There are three special methods available:
# object, text and value,
# which are the current item being rendered, its text and value methods, respectively.
<%= t("user.description.#{cb.text}") %>
<%= cb.check_box %>
<% end %>
<% end %>
</div>
<div class="form-actions">
<%= f.button :submit, 'Submit' %>
</div>
<% end %>
If you don't actually have a model you can use #itself to iterate across a flat array:
<%= f.collection_checkboxes(:experience_level, User::USER_EXPERIENCE_LEVEL, :itself, :itself) do |cb| %>
Or an array of pairs:
<%= f.collection_checkboxes(:experience_level, User::USER_EXPERIENCE_LEVEL.zip(User::USER_EXPERIENCE_LEVEL), :first, :last) do |cb| %>
Or even a struct.

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| %>

Pass multiple params to the current page with form_tag in Rails

I want to pass several params in the url of the current page with a form_tag but I have failed to understand to correct syntax.
Quick explanation: I have outfits (model) that has many outfit_items (model).
Each outfit_item has available_sizes (attribute of outfit_item). All of this is set by the admin.
Then on the show page of an Outfit, (for example http://localhost:3000/outfits/7) I want to display the available sizes for each outfit_item, let the visitor pick his size for each item and press submit. The selected sizes should then appear in the URL.
Here is what I have in my show view, at the url :
<%= form_tag(#outfit_path, :method=>'post') do %>
<% #outfit.outfit_items.each do |outfit_item| %>
<div class="col-md-2 col-sm-6 col-xs-6">
<%= image_tag outfit_item.item_image.url(:medium) %><br>
<% sizes = outfit_item.available_sizes.split(",") %>
<%= select_tag "size#{outfit_item.category}", "<option>#{sizes[1]}</option><option>#{sizes[2]}</option><option>#{sizes[3]}</option><option>#{sizes[4]}</option>".html_safe, :class => "input-mini select-mini" %><br>
<%= hidden_field_tag "size#{outfit_item.category}", value: outfit_item.category %>
</div>
<% end %>
<%= submit_tag "ok size" %>
<% end %>
I want to land on this url when I hit submit
http://localhost:3000/outfits/7?size1=42&size2=L&size3=S&size4=44
Thanks for your help
You could do like this. Hope it helps.
<%= form_tag(#outfit_path, url: your_path(size1: value1, size2: value2, ......) :method=>'post') do %>
I would do it like this:
<%= form_tag(outfit_path(#outfit), :method=>'get') do %>
<% #outfit.outfit_items.each do |outfit_item| %>
<div class="col-md-2 col-sm-6 col-xs-6">
<%= image_tag outfit_item.item_image.url(:medium) %><br>
<% sizes = outfit_item.available_sizes.split(",") %>
<%= select_tag "size#{outfit_item.category}", options_for_select(sizes), :class => "input-mini select-mini" %><br>
<%= hidden_field_tag "size#{outfit_item.category}", value: outfit_item.category %>
</div>
<% end %>
<%= submit_tag "ok size" %>
<% end %>
Some assumptions:
Notes:
outfits_path(#outfit) would normally (from convention) be "/outfits/<outfit id>", so that's what i've used here - this is what i'd expect from convention
If you want to land on the url, ie make it public, you should make it a GET request, not a post request. so i've changed the form to make a GET request
you've got a hidden_field_tag in there. This will show up in
your url as well, so it's impossible to get the exact url you desire
AND have the hidden field tag in there.
options_for_select(sizes) is a much nicer way of generating a bunch of option tags
I get the feeling that there's a much nicer way to do what you're trying to do here, but without knowing more about your schema i can't say what.

How to define a select field in a nested form?

What is the correct way to include a select field within a nested form in Rails 3.2?
I currently have
//IN THE PARENT FORM
<%= f.fields_for :crayons do |crayon| %>
<%= render 'caryon_fields', :f=>crayon %>
<% end %>
//IN THE PARTIAL
<div class="nested-fields">
<%= select (:crayon, :color, [['Red',1],['Blue',2],['Yellow',3],['Green',4]] ) %>
</div>
This is not saving the selected value to the database. I assume this is because the builder is not being passed.
How should I define a select field with hardcoded options in a nested field? Do I need to change tag, i.e. select_tag or collection_select. I'm still unsure of the differences between all these. If anyone can point me towards a clear description it would be much appreciated.
Thanks!
You need associate to your form in your partial like that :
<div class="nested-fields">
<%= f.select (:crayon, :color, [['Red',1],['Blue',2],['Yellow',3],['Green',4]] ) %>
</div>
Whitout partial it's :
<%= f.fields_for :crayons do |crayon| %>
<div class="nested-fields">
<%= crayon.select (:crayon, :color, [['Red',1],['Blue',2],['Yellow',3],['Green',4]] ) %>
</div>
<% end %>

How should I handle this Rails use case?

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?

Resources