nested forms problems on edit, unwanted hidden fields - ruby-on-rails

I'm working in Rails2, the helper creates a hidden_field which is not helping me...
I load the input like this:
- remote_form_for([:admin, #user]) do |f|
// [...]
- f.fields_for :account_user do |a|
= a.collection_select :id, #accounts, :id, :name}, { :style => "width:330px;"}
and I get a result like this:
<select style="width: 330px;" name="user[account_user_attributes][id]" id="user_account_user_attributes_id">
<option value="20">public</option>
<option value="21">Test Account</option>
<option value="73">ggg</option>
</select>
<input type="hidden" value="175" name="user[account_user_attributes][id]" id="user_account_user_attributes_id">
when I reach the controller my params hash is this:
(rdb:228) y params
--- !map:HashWithIndifferentAccess
commit: Save booker
_method: put
action: update
id: "50"
controller: admin/users
user: !map:HashWithIndifferentAccess
user_role: agent
password_confirmation: ""
username: ERIK
account_user_attributes: !map:HashWithIndifferentAccess
id: "175"
password: ""
email: e#visrez.com
The value 175 in the hash refers to #user.account_user.id, the old value, but I don't have the #user.account.id of the new selection.
What am I doing wrong?
Thank you
EDIT
I commented out the collection_select, and the hidden_field was still there, therefore... I need to change the title.
If I comment out f.fields_for the hidden_field disappears.
As pointed out by #jaydel, this is (very) probably the reason why I don't get the right value in the hash. - And the quest goes on...
Actually it's not my code, so now I'm checking for any overriding, as looks like it's not the standard behavior

So we found out that the hidden field was originated by
- remote_form_for([:admin, #user]) do |f|
- f.fields_for :account_user do |a| # <------- here
= a.collection_select :id, #accounts, :id, :name
A better look to the api unvealed the problem, and here is the correct use of fields_for:
- remote_form_for([:admin, #user]) do |f|
- f.fields_for #user.account_user do |a|
= a.collection_select :id, #accounts, :id, :name
So the method instead of the symbol.
Note: This code answers the question, but in my case I don't really need any fields_for in this relationship.

This is just a guess, but you're using user[account_user_attributes][id] in two places: the select itself, and the hidden input below it...is that something you put in?
When I use collection_select I don't see the hidden input in the source...
If this is indeed something you are putting in, it's possible that the hidden input is what's being picked up, rather than what the user selected in the dropdown.

Related

Rails - Select tag not pre-selected after Form's validation fail

I have select tag
<%= f.select :gender, ["M", "F"], include_blank: "---" %>
If other field has error, the select tag will be reset to "---" even though I have picked an option before.
The solution that I found is using collection_select which takes a ActiveRecord Model to be the option-value pair.
Is there other way to do this?
Thanks
[EDIT]
The answer from #Micah is correct but since my form is Nested, it's different syntax.
Here's my code:
<%= f.fields_for :users do |ff| %>
...
<%= ff.select :gender, ["M", "F"], include_blank: "---",
selected: ff.object.gender ? ff.object.gender : "" %>
...
<% end %>
When I handle errors I usually use render to display the previous page again so I'm going to explain how to handle that first.
When you render a view the params that got passed into your previous command carry over, meaning you'll have params[:object][:gender]as a parameter when you return to the view. Thus
<%= f.select :gender, ["M", "F"], include_blank: "---", selected: params[:object] ? params[:object][:gender] :"" %>
will set the selected value back to what was selected the first time through. Basically what it's doing is taking a conditional and then providing an if/else in the same line. (conditional) ? if true do this : else do this. In this case the conditional is that params[:object] exists (meaning you've attempted to create/edit once before) and if so reassign value otherwise leave blank and select default value, your "---".
If you use redirect_to you'll actually have to manually pass the params back through the redirect but that's fairly simple and just takes the following:
redirect_to new_object_path(params)

Form_for select field, concatenating data into the display string

I am trying to use a form_for collection_select to display some select field options of account types.
Its occurred to me that it would be easier for the user if they could see the price of the type in each select option
this is my currently not-working code:
<%= a.collection_select :account_type, AccountType.all, :id, (:name+" - "+number_to_currency(:price)) %>
how can i concatenate the values so that (:name+" - "+number_to_currency(:price)) will actually work and not throw an error?
See the documentation:
http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#method-i-collection_select
You can use the :text_method option to set the displayed text in the select dropdown.
In your AccountType model, define a method like this:
def name_with_price
"#{name} - $#{price}"
end
Then, in your view, you can use:
<%= a.collection_select :account_type, nil, AccountType.all, :id, :name_with_price %>

Can collection_select be used against yaml files?

My Rails application currently uses collection_select to select lookup values for drop downs etc. This has two advantages:
The values are consistent
The id of the selected value is stored in the database, not the text value
For example:
edit.html.erb
<div class="field">
<%= f.label :course_type %><br />
<%= f.collection_select :course_type, Lookup.find(:all,:conditions => ["model_name = 'course' and field_name = 'course_type'"]), :id, :lookup_text, include_blank: false,:prompt => "Course Type" %>
</div>
course_controller.rb
private
def get_lookups
#course = Course.find(params[:id])
#course_type = Lookup.find(#course.course_type).lookup_text
show.html.erb
<b>Course type:</b>
<%= #course_type %>
My application will be multi-lingual, and Rails handles this by using locale files.
The question is: Is it possible (and sensible) to populate lookup values from yml files, rather than model/tables, and can this be easily extended to handle multiple languages? How could the above code be replaced with yml-based code?
One solution would be to keep translations in the DB, perhaps with our Traco lib. I suspect it would work with collection_select.
If you want to pull options from your translation YML files, I suggest options_for_select. All in all something like:
en.yml
en:
my_options:
one: "Option 1"
two: "Option 2"
View:
select_tag :foo, options_for_select(t("my_options").invert)
Rails i18n gives you a hash if you translate a non-leaf key, like "my_options". You need the invert because options_for_select expects the text before the value, and a translation hash is the other way around.
To translate your collection_select, you simply create a new model method (let's say, "name_translated") which returns your translation from the YAML file:
View:
<%= f.collection_select :product_id, Product.all, :id, :name_translated %>
Model:
class Product < ActiveRecord::Base
def name_translated
I18n.t(name)
end
end
YAML file:
en:
name1: "Hammer"
name2: "Plastic sheets"
name3: "Duct tape"
I use select:
<%= f.select :role, MAIN_CONFIG['manager_roles'].map { |s| [s.last, s.first] }, selected: #manager.role %>
And my yaml file main_config.yml:
manager_roles:
admin: 'Суперадмин'
partner_admin: 'Администратор'
manager: 'Менеджер'

Can someone explain collection_select to me in clear, simple terms?

I am going through the Rails API docs for collection_select and they are god-awful.
The heading is this:
collection_select(object, method, collection, value_method, text_method, options = {}, html_options = {})
And this is the only sample code they give:
collection_select(:post, :author_id, Author.all, :id, :name_with_initial, :prompt => true)
Can someone explain, using a simple association (say a User has_many Plans, and a Plan belongs to a User), what I want to use in the syntax and why?
Edit 1: Also, it would be awesome if you explained how it works inside a form_helper or a regular form. Imagine you are explaining this to a web developer that understands web development, but is 'relatively new' to Rails. How would you explain it?
collection_select(
:post, # field namespace
:author_id, # field name
# result of these two params will be: <select name="post[author_id]">...
# then you should specify some collection or array of rows.
# It can be Author.where(..).order(..) or something like that.
# In your example it is:
Author.all,
# then you should specify methods for generating options
:id, # this is name of method that will be called for every row, result will be set as key
:name_with_initial, # this is name of method that will be called for every row, result will be set as value
# as a result, every option will be generated by the following rule:
# <option value=#{author.id}>#{author.name_with_initial}</option>
# 'author' is an element in the collection or array
:prompt => true # then you can specify some params. You can find them in the docs.
)
Or your example can be represented as the following code:
<select name="post[author_id]">
<% Author.all.each do |author| %>
<option value="<%= author.id %>"><%= author.name_with_initial %></option>
<% end %>
</select>
This isn't documented in the FormBuilder, but in the FormOptionsHelper
I've spent quite some time on the permutations of the select tags myself.
collection_select builds a select tag from a collection of objects. Keeping this in mind,
object : Name of the object. This is used to generate the name of the tag, and is used to generate the selected value. This can be an actual object, or a symbol - in the latter case, the instance variable of that name is looked for in the binding of the ActionController (that is, :post looks for an instance var called #post in your controller.)
method : Name of the method. This is used to generate the name of the tag.. In other words, the attribute of the object you are trying to get from the select
collection : The collection of objects
value_method : For each object in the collection, this method is used for value
text_method : For each object in the collection, this method is used for display text
Optional Parameters:
options : Options that you can pass. These are documented here, under the heading Options.
html_options : Whatever is passed here, is simply added to the generated html tag. If you want to supply a class, id, or any other attribute, it goes here.
Your association could be written as:
collection_select(:user, :plan_ids, Plan.all, :id, :name, {:prompt => true, :multiple=>true })
With regards to using form_for, again in very simple terms, for all tags that come within the form_for, eg. f.text_field, you dont need to supply the first (object) parameter. This is taken from the form_for syntax.

Rails: How to disable asterisk on form's required fields?

When I add the 'Required' attribute
to html input fields, Rails pre-pends an asterisk (*) before the label.
Does anyone know how to prevent this?
For some reason Rails transforms this:
<%= f.input :Company, :input_html => {:value => "", :id => "company_name"}, :label => "company name" %>
into this:
<div class="input string required">
<label for="company_name" class="string required">
<abbr title="required">*</abbr> company name</label>
<input type="text" value="" size="50" required="required" name="lead[Company]" id="company_name" class="string required">
</div>
I don't like that it wraps everything in a DIV and adds an ABBR element to the party.
How can I prevent this?
You can just set the required mark to empty value in simple_form's locale file:
en:
simple_form:
required:
text: 'required'
mark: '*'
Or use CSS to hide it.
In config/initializers/simple_form.rb add this line:
config.label_text = lambda { |label, required| "#{label}" }
I'm using Rails 3.1, and I have the following view code in my _form.html.erb for a given model:
<div>
<%= f.label :full_name %><br/>
<%= f.text_field :full_name, :required => true %><br/>
</div>
The label does not show an asterisk if you do it this way. Unless you post code I can't be sure of what your approach is and if my solution would fit said approach.
Updated Answer:
It sounds like you've inherited this code from someone. At any rate, after reading your code sample, you are most definitely using the simple_form gem. Information about that gem can be found here https://github.com/plataformatec/simple_form. To answer your question though, if you change your code the following:
<%= f.input :Company, :input_html => {:value => "", :id => "company_name"}, :label => "company name", :required => false %>
That should turn off the asterisk.
I would add, based on your disgust for the HTML generated from simple_form, it sounds like you should just do away with the gem and re-write your form code using the Rails default form helpers, which can be read about here http://guides.rubyonrails.org/form_helpers.html. Depending on the size of the code base, you might be better off just sucking it up and learning how to use the simple_form gem for the sake of saving time, but if you think you have the time to change it all, go for it.
The simplest way is to hide it with this css:
abbr[title="required"] {
display: none;
}
It isn't rails at all. It's the simple_form gem. So, if you don't want all the wrapping elements don't use simple_form. Use Rails form helpers. It would be more simple than customize something you don't like.
For anyone using Formtastic and having this issue, you can remove the asterisks by editing the config file, which is typically app/config/initializers/formtastic.rb.
Change this line: # Formtastic::SemanticFormBuilder.required_string = "(required)"
to be: Formtastic::SemanticFormBuilder.required_string = ""
More info here.
Code that has helped me solve the asterisk issue:
abbr[title="required"] {
display: none;
}
The chosen answer and the other suggestions asking to change the HTML in locales file dint help me with the latest Simple_form gem.
Aside from the global config suggested in the accepted answer, you can pass required: false as an input option, or defaults: { required: false } to set it for the whole form.
You can remove it from the whole form:
<%= simple_form_for #form, defaults: { required: false } do |f| %>
I found out that if you only want to remove the asterisk(*) behind it then all you have to do is to go to this file file /config/locales/simple_form.en.yml
once again is not a good practice to change your configuration files for gems and something your using for some reason, it always a question of why do you really use simple_form!
But for example I found out about that because there is great things about simple_form we use but nowadays is a better usability practice to have the asterisks on none required fields then required ones.
you can used form_for, and override method def label in config/initializer to add asterisk for mandatory fields as the following:
def label(object_name, method, content_or_options = nil, options = nil, &block)
if content_or_options.is_a?(Hash)
content_or_options.each do |key, val|
options[key] = val
end
content_or_options = method.to_s
end
content_or_options ||= method.to_s
presence_validations = [ActiveModel::Validations::PresenceValidator, ActiveRecord::Validations::PresenceValidator]
class_obj = options[:object].class if options[:object]
class_obj ||= object_name.to_s.camelize.constantize
validations = class_obj.validators_on(method.to_s).map(&:class)
if (presence_validations.map { |pv| validations.include?(pv) }).any?
content_or_options += "*"
end
Tags::Label.new(object_name, method, self, content_or_options, options).render(&block)
end
This method puts asterisk after all mandatory fields, if you used normal form_for, and used validates_presence_of

Resources