Is this the correct way of defining form, let me know if I need to provide any more details.
This is the UserPreference forms in new.html.erb
<%= form_for :user_preference, url: user_preferences_path do |u|%>
<p>
<%= u.label :title %><br>
<%= u.text_field :title %>
</p>
<p>
<%= u.label :description %><br>
<%= u.text_field :description %>
</p>
<p> <%= u.label :back_ground_color %><br>
<select name="bgcolor" id="bgcolor">
<option value="#FF3300">Orange</option>
<option value="#00FF00">Green</option>
<option value="#0000FF">Blue</option>
<option value="#FF0066">Pink</option>
<option value="#FFFF00">Yellow</option>
<option value="#FFFFFF">White</option>
</select>
</p>
<p>
<%= u.label :font %><br>
<select name="font" id="font">
<option value="Times New Roman">Times new Roman</option>
<option value="Verdana">Verdana</option>
<option value="Arial">Arial</option>
<option value="sans-serif">serif</option>
</select>
</p>
<br >
<p>
<%= u.submit %>
</p>
I am getting title and description when I am trying to render in html,
the attribute is not getting updated in database.
UserPreference.controller.rb
class UserPreferencesController < ApplicationController
def new
#user_preference = UserPreference.new
end
def create
#user_preference = UserPreference.new(userp_params)
#user_preference.save unless user_signed_in?
render plain: params[:user_preference].inspect
end
def edit
end
def update
end
private
def userp_params
params.require(:user_preference).permit(:title, :bgcolor, :font, :description)
end
end
When you say this
<%= u.text_field :description %>
because you are working with :user_preference, it will make an input like
<input type="text" name="user_preference[description]" value="foo">
(where 'foo' is the current value, or maybe it's blank)
Note the "name" attribute: this will go into params like
params = {:user_preference => {:description => "foo"}}
If you are going to hand-code the select then you need to make sure the name attribute has this structure too, eg
<select name="user_preference[bgcolor]" id="bgcolor">
So you will get params like
params = {:user_preference => {:description => "foo", :bgcolor => "#FFFFFF"}}
Which then allows you to say
#user_preference.attributes = params[:user_preference]
which is the standard way to deal with this in the controller.
However, rather than writing out all the html for the select, it's much nicer to use the rails form helpers (select in this case) like you do with the text fields. You can also define the options for the select with the options_for_select helper, which saves a lot of typing too.
<%= u.select :bgcolor, options_for_select([["Orange", "#FF3300"], ["Green", "#00FF00"], ["Blue", "#0000FF"], ["Pink", "#FF0066"], ["Yellow", "#FFFF00"], ["White", "#FFFFFF"]]) %>
It's also cleaner to define this variable of options in your code somewhere, eg in a UserPreference class method:
class UserPreference < ActiveRecord::Base
#class methods section
class << self
def bgcolor_options
[["Orange", "#FF3300"], ["Green", "#00FF00"], ["Blue", "#0000FF"], ["Pink", "#FF0066"], ["Yellow", "#FFFF00"], ["White", "#FFFFFF"]]
end
end
end
Now you can use the select like so:
<%= u.select :bgcolor, options_for_select(UserPreference.bgcolor_options) %>
http://guides.rubyonrails.org/form_helpers.html#the-select-and-option-tags
Related
I am trying to get the text_field in my form partial to comma-separate acts_as_taggable_on tags. Right now, when I reload the page, the commas disappear so if a field has two or more tags, they become one big tag instead. For instance, I get "Tag1 Tag2 Tag3" instead of "Tag1, Tag2, Tag3". I am using acts-as-taggable-on 3.4.2.
Here is my _form.html.erb partial:
<h2>Tags:</h2>
<p>Please separate the tags with a comma ','</p>
<% #article.tag_types.each do |tag| %>
<div class="form-group">
<strong><%= label_tag tag.to_s.titleize %></strong><br />
<%= f.text_field "#{tag.to_s.singularize}_list".to_sym, :placeholder => "Comma-separated list of #{tag.to_s}", class: 'form-control' %>
</div>
<% end %>
Every time I reload the edit page, the input value somehow removes the commas from the already-present tags, so the text field looks like this:
<input id="article_country_list" class="form-control" type="text" name="article[country_list]" value="China U.S.A." placeholder="Comma-separated list of countries">
instead of having value="China, U.S.A." as it should be.
Here is my model, article.rb:
class Article < ActiveRecord::Base
acts_as_taggable_on :people, :cities, :countries, :other
end
Any help would be much appreciated :)
Thanks!
Apparently this is a new security feature.
I solved the comma separation issue by doing:
<% #article.tag_types.each do |tag| %>
<div class="form-group">
<strong><%= f.label tag.to_s.titleize %></strong><br />
<% tag_sym = "#{tag.to_s.singularize}_list".to_sym %>
<% tag_list = "#{tag.to_s.singularize}_list" %>
<%= f.text_field tag_sym, value: #article.send(tag_list).to_s, :placeholder => "Comma-separated list of #{tag.to_s}", class: 'form-control' %>
</div>
<% end %>
Thanks! Since I am using ActiveAdmin with Formtastic I made a custom input.
So I created a new class: app/inputs/tag_list_input.rb with:
class TagListInput < Formtastic::Inputs::StringInput
def input_html_options
super.merge(:value => "#{#object.send(method).to_s.html_safe}")
end
end
and using this like:
f.input :some_tag_list, :as => :tag_list, :label => "SomeTags"
I would like to have the option value changed from the users name to the users ID on the option value in html.
For example:
<option value="John">John</option>
<option value="Jim">Jim</option>
<option value="Kelly">Kelly</option>
<option value="Monica">Monica</option>
<option value="Ralp">Ralp</option>
This is what my html is outputting, and i would like the value to be the users id, such as:
<option value="1">John</option>
<option value="2">Jim</option>
<option value="3">Kelly</option>
<option value="4">Monica</option>
<option value="5">Ralp</option>
I would also like it to be dynamic so when more and more users come I do not have to manually enter their names.
My rails for currently looks like this:
<%= form_tag '/login', method: 'post' do %>
Name:
<br/>
<%= select_tag :user_id, options_for_select(#users) %>
<br/>
<br/>
<%= submit_tag 'Login' %>
<% end %>
And my controller as such:
def login_user
user = User.find_by_name(params[:user_id])
if user
session[:user_id] = user.id
redirect_to user_path(user)
return
end
flash[:error] = 'Sorry that user not in the system.'
redirect_to root_path
end
Could someone please help point me in the right direction. Thank you in advance.
I don't understand what you mean by "dynamic". But following should fix your select issue
<%= form_tag '/login', method: 'post' do %>
Name:
<br/>
<%= select_tag :user_id, options_for_select(User.all.collect{|u| [u.name, u.id]}) %>
<br/>
<br/>
<%= submit_tag 'Login' %>
<% end %>
Got it, I used this instead:
<%= collection_select(:user, :id, User.all, :id, :name) %>
this gave me a drop down tab with user value and user name. Thank you all!
I have a nested form that is based off of the example in this rails cast:
http://railscasts.com/episodes/196-nested-model-form-revised
For my application, I'm trying to let people upload multiple files in a nested form. Each step can have many design files, and steps accept nested attributes for design files:
Step.rb:
class Step < ActiveRecord::Base
attr_accessible :design_files_attributes
has_many :design_files
accepts_nested_attributes_for :design_files, :allow_destroy => :true
...
end
DesignFile.rb:
class DesignFile < ActiveRecord::Base
belongs_to :step
...
end
I'm running into issues when I try to add an additional file after another file has already been added. This is what the form looks like in html:
<div class="upload_new_files">
<fieldset class="design_file_upload_fieldset">
<label for="step_design_files_attributes_0_design_file_path">test.pdf</label>
<input id="step_design_files_attributes_0__destroy" name="step[design_files_attributes][0][_destroy]" type="hidden" value="false">
<i class="icon-trash"></i> Remove File
<input id="step_design_files_attributes_0_step_id" name="step[design_files_attributes][0][step_id]" type="hidden" value="451">
<input id="step_design_files_attributes_0_project_id" name="step[design_files_attributes][0][project_id]" type="hidden" value="120">
<input id="step_design_files_attributes_0_user_id" name="step[design_files_attributes][0][user_id]" type="hidden" value="15">
<hr>
</fieldset>
<fieldset class="design_file_upload_fieldset">
<input id="step_design_files_attributes_70265135732560_design_file_path" name="step[design_files_attributes][70265135732560][design_file_path]" onchange="javascript: addField(this);" type="file" style="display: none;">
<input id="step_design_files_attributes_70265135732560__destroy" name="step[design_files_attributes][70265135732560][_destroy]" type="hidden" value="false">
<i class="icon-trash"></i> Remove File
<input id="step_design_files_attributes_70265135732560_step_id" name="step[design_files_attributes][70265135732560][step_id]" type="hidden" value="446">
<input id="step_design_files_attributes_70265135732560_project_id" name="step[design_files_attributes][70265135732560][project_id]" type="hidden" value="120">
<input id="step_design_files_attributes_70265135732560_user_id" name="step[design_files_attributes][70265135732560][user_id]" type="hidden" value="15">
<hr>
</fieldset>
</div>
But when I submit the form, the design_files_attributes aren't in the parameters. I'm expecting something like this:
Parameters: {"step"=>{ "design_files_attributes"=>{"0"=>{"id"=>"17" ...}}, "70265135732560"=>{...}...}
But, instead, I'm getting this:
Parameters: {"step"=> {"design_files_attributes"=>{"0"=>{"id"=>"17" ...}}
What isn't my new entry being submitted in the form parameters?
Edit
Here is the full params that are being submitted to the controller; I didn't include it above because it includes a lot of other things, but I have it here in case it's useful:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"...=", "step"=>{"name"=>"New Design File", "description"=>"", "question_attributes"=>{"description"=>"", "decision_attributes"=>{"description"=>"", "question_id"=>""}}, "design_files_attributes"=>{"0"=>{"_destroy"=>"false", "step_id"=>"451", "project_id"=>"120", "user_id"=>"15", "id"=>"17"}}, "last"=>"0", "published_on_date"=>"02/04/2014", "published_on_time"=>"05:02 PM", "timeZone"=>"EST"}, "commit"=>"Update Step", "project_id"=>"120", "id"=>"3"}
_step_form.html.erb
<%= semantic_form_for [#project, #step], :html => {:multipart => true} do |f| %>
<%= f.fields_for :design_files, multipart: true do |design_file_form| %>
<%= render 'design_file_fields', f: design_file_form %>
<% end %>
<p class="add_design_file" style="display:none;"><%= link_to_add_fields raw("<icon class='icon-plus-sign' style='color:green;'></icon> Add Another Design File"), f, :design_files %></p>
<% end %>
_design_file_fields.html.erb
<fieldset class="design_file_upload_fieldset">
<% if f.object.new_record? %>
<%= f.file_field :design_file_path, :onChange=>"javascript: addField(this);" %>
<% else %>
<%= f.label :design_file_path, f.object.design_file_path.to_s.split('/').pop() %>
<% end %>
<%= f.hidden_field :_destroy %>
<%= link_to raw('<i class="icon-trash"></i> Remove File'), "#", class: "remove_fields" %>
<%= f.hidden_field :step_id, :value => #step.id %>
<%= f.hidden_field :project_id, :value => #project.id %>
<%= f.hidden_field :user_id, :value => current_user.id %>
<hr>
</fieldset>
steps.js
// add a new design file field to the form
function addField(input) {
console.log('add design field input');
// remove the filefield of recently uploaded file and replace with existing file styling
var filename = $(input).val().split('\\').pop();
$(input).parent('fieldset').prepend('<label>'+filename+'</label>');
$(input).hide();
$('.add_fields').click();
}
application_helper.rb
def link_to_add_fields(name, f, association)
new_object = f.object.send(association).klass.new
id = new_object.object_id
fields = f.fields_for(association, new_object, child_index: id) do |builder|
render(association.to_s.singularize + "_fields", f: builder)
end
link_to(name, '#', class: "add_fields", data: {id: id, fields: fields.gsub("\n", "")})
end
Wow, the answer ended up being totally unrelated to what I had posted! The issue was with the form itself, which had an extra <% end %> element, causing the design files fields_for not being incorporated into the form. I'll leave this response in case it's useful for anyone else.
I'm admittedly a real novice at most of this, including forming and parsing params hashes. I'm trying to get a hash of instances of the same model from a form for a voting application. Users can vote for as many candidates as they wish according to rank.
My votes#new does create Candidate.count instances of Vote with the user_id and rank properly set. I know this because the form is correctly iterating through #user.votes for each candidate.
Here's a snippet of the rendered form:
<input id="vote_rank" name="vote[rank]" type="hidden" value="1" />
<label for="vote_Candidate">Candidate</label>
<select id="vote_candidate_id" name="vote[candidate_id]"><option value=""></option>
<option value="1">Smithers</option>
<option value="2">Mr. Burns</option>
<option value="3">Bart</option>
<option value="4">Lionel Hutz</option>
<option value="5">Jimbo</option>
<option value="6">Troy McClure</option>
<option value="7">Duffman</option>
<option value="8">Maggie</option>
<option value="9">Moe</option>
<option value="10">Principal Skinner</option>
<option value="11">Apu Nahasapeemapetilan</option></select>
I can't figure out how to get the collection back from the form to my votes#create. I am able to get a params hash with a single set of candidate_id and rank values (the last), but not all 11 instances I stuck in it in the first place. The form wants to give up the right data.
#user.votes.create(vote_params) in votes#create is throwing this error: undefined method `stringify_keys' for "rank":String
Here are my controller methods and form.
def new
#user = current_user
#votes = Candidate.count.times { |i| #user.votes.build(:rank => i + 1) }
end
def create
#user = current_user
#params[:user][:votes].each do |vote_params|
##user.votes.create(vote_params)
params[:vote].each do |vote_params|
#user.votes.create(vote_params)
end
respond_to do |format|
if #user.valid?
format.html { redirect_to #user, notice: 'votes were successfully created.' }
else
format.html { render action: "new" }
end
end
end
<%= form_for :votes, :url => votes_path do |f| %>
<% #user.votes.each do |v| %>
<%= fields_for v do |vote_fields| %>
<%= vote_fields.hidden_field :rank %>
<%= vote_fields.label "Candidate" %>
<%= vote_fields.collection_select :candidate_id, Candidate.all, :id, :name, :include_blank => true %>
<% end %>
<% end %>
<p><%= f.submit :class => 'medium radius button' %></p>
<% end %>
Here's the relevant HTML
Only one set of values is getting passed:
{"utf8"=>"✓", "authenticity_token"=>"bVLXCQtOffEtu5xBNI0e94o9j9mJ8alHhuBhDkkfaRA=", "vote"=>{"rank"=>"11", "candidate_id"=>""}, "commit"=>"Save Votes", "action"=>"create", "controller"=>"votes"}
although the form is trying to give up the right values:
vote[rank]:1
vote[candidate_id]:2
vote[rank]:2
vote[candidate_id]:4
vote[rank]:3
vote[candidate_id]:2
vote[rank]:4
vote[candidate_id]:9
etc. (up to 11!)
Any help appreciated.
Update:
Solved it sort of. I'm putting this up in case it helps someone since I haven't found anything directly on point and it took me a long time to figure this problem out.
My form was creating identically named objects, which were just overwriting. Explains why I was only ever able to get the last set of values into the database.
My form now iterates over the objects passed from votes#new and includes the vote's rank in the name.
<%= form_for :vote, :url => votes_path do |f| %>
<% #user.votes.each do |v| %>
<% if v.errors.any? %>
<h1>errors</h1>
<% end %>
<%= f.fields_for "#{v.rank}" do |builder| %>
<%= builder.hidden_field :rank, :value => v.rank %>
<div class="row">
<div class="one columns"><%= builder.label "Rank #{v.rank}", :class => "left inline" %></div>
<div class="eleven columns"><%= builder.collection_select :candidate_id, Candidate.all, :id, :name, {:include_blank => true}, :class => "two" %></div>
</div>
<% end %>
<% end %>
<%= f.submit "Submit", :confirm => "Please review your ballot and confirm that your votes are correct before submitting. This message will appear as a reminder each time you press 'Submit', even if you've edited your ballot.", :class => "small round button" %>
<% end %>
This craps out a params[:vote] hash of uniquely named hashes e.g.
{"1"=>{"rank"=>"1", "candidate_id"=>"5"}, "2"=>{"rank"=>"2", "candidate_id"=>"2"}, "3"=>{"rank"=>"3", "candidate_id"=>"7"}, "4"=>{"rank"=>"4", "candidate_id"=>"4"}, "5"=>{"rank"=>"5", "candidate_id"=>"10"}, "6"=>{"rank"=>"6", "candidate_id"=>""}, "7"=>{"rank"=>"7", "candidate_id"=>""}, "8"=>{"rank"=>"8", "candidate_id"=>""}, "9"=>{"rank"=>"9", "candidate_id"=>""}, "10"=>{"rank"=>"10", "candidate_id"=>""}, "11"=>{"rank"=>"11", "candidate_id"=>""}}
My votes#create method dumps an array made of key/value pairs from the params hash into #user.votes.create(my_array)
def create
#user = current_user
#user.votes.create(sanitize_and_compress_vote_array params[:vote])
redirect_to thankyou_path
end
Then next challenge is to get validation error messages to work properly. It's over my head because what I'm seeking to validate is an array of key value pairs by the uniqueness of candidate_id scoped by user_id before any values hit the database. It looks like Rails doesn't make this easy.
validates :candidate_id, :presence => true, :uniqueness => {:scope => :user_id, :message => "You may only vote for a candidate once."}
The validation works just fine for rejecting duplicate values, but it's useless because those values that already passed are obviously already in the database. I haven't found squat on how to validate members of a collection against themselves before they save and I feel like I'm talking to myself :-(
Right now, I'm using the form_for.select and options_for_select rails helpers to create a select box with the data from the model. However, what I really need is a combobox like the one introduced with HTML5:
<input type=text list=browsers >
<datalist id=browsers >
<option> Google
<option> IE9
</datalist>
Is there a rails helper for creating such elements?
No, but it's quite easy to setup your own form builder helper method to achieve such a result, a simple example would be:
app/form_builders/combobox_form_builder.rb
class ComboboxFormBuilder < ActionView::Helpers::FormBuilder
include ActionView::Context # for nested content_tag
include ActionView::Helpers::FormTagHelper #for sanitize_to_id method access
def combobox_tag(name, options, opts= {})
#template.content_tag(:input, :name => name, :id => sanitize_to_id(name), :type => "text", :list => opts[:list_id]) do
content_tag(:datalist, :id => opts[:list_id]) {options}
end
end
end
After restarting your server you can implement your new combobox using the form builder by specifying a builder argument in your form_for call:
<%= form_for #foo, builder: ComboboxFormBuilder do |f| %>
<%= f.combobox_tag(:browser, options_for_select(["Firefox", "Chrome", "IE9"]), :list_id => "list")%>
<% end %>
Output HTML:
<input type="text" name="browser" list="list" id="browser">
<datalist id="list">
<option value="Firefox">Firefox</option>
<option value="Chrome">Chrome</option>
<option value="IE9">IE9</option>
</datalist>
Keep in mind that both IE & Safari do not offer support for the HTML5 Datalist.
<%= form_for #person do |f| %>
<%= f.label :first_name, "First Name" %>:
<%= f.text_field :first_name, list: 'first-name' %>
<datalist id="first-name">
<% Person.all.each do |person| %>
<option value="<%= person.first_name %>"></option>
<% end %>
</datalist>
<%= f.submit %>
<% end %>
You may also want to do distinct:
<% Person.select(:first_name).distinct.each do |person| %>
Just example from my code:
= form_tag controller:'beer', action: 'create' do
= text_field :beer, :name, list: 'beer-name'
%datalist#beer-name
- Beer.all.each do |beer|
%option{value: beer.name}