I have multiple dropdown when I select items. It also creates null value How can I remove null values from this array?
= f.select(:doc, file.all.collect {|a| [a.name, a.id]}, {}, id: "id-select2", class: "form-control", :multiple => true).
You have two problems there
Your collect is returning some nil elements(As Joseph said), in this case the name attribute is what it can be nil, so you can check for that on the collect
Solution(compact) [UPDATE]
f.select(:doc, file.all.collect {|a| [a.name, a.id] if a.name, include_hidden: false }.compact, {}, id: "id-select2", class: "form-control", :multiple => true)
Specify the include_blank option https://api.rubyonrails.org/classes/ActionView/Helpers/FormBuilder.html#method-i-select
f.select(:doc, file.all.collect {|a| [a.name, a.id] if a.name }.compact, { include_blank: false, include_hidden: false }, id: "id-select2", class: "form-control", :multiple => true)
According to the docs for select helper I have found this gotcha
The HTML specification says when multiple parameter passed to select
and all options got deselected web browsers do not send any value to
server. Unfortunately this introduces a gotcha: if an User model has
many roles and have role_ids accessor, and in the form that edits
roles of the user the user deselects all roles from role_ids multiple
select box, no role_ids parameter is sent. So, any mass-assignment
idiom like To prevent this the helper generates an auxiliary hidden
field before every multiple select. The hidden field has the same name
as multiple select and blank value.
Note: The client either sends only the hidden field (representing the
deselected multiple select box), or both fields. This means that the
resulting array always contains a blank string.
In case if you don't want the helper to generate this hidden field you
can specify include_hidden: false option.
So if you add the include_hidden: false option then you won't get the empty string on your multiple option when the data is sent to the controller.
You can use compact. For example:
a = [nil, 2, 3, 4, 5]
without_nil = a.compact
# [2, 3, 4, 5]
using compact! will modify the original array whereas compact returns a new array.
you can filter that in database query for example (I assume id is primary key and is not null):
file.where('name IS NOT NULL').load
compact isn't working for you because you're likely calling it on the result of the collect. If you have an array like [['a', 1], ['b', nil]], calling compact on it won't do anything because the ['b', nil] is not nil. It only contains it. So you need to avoid loading the Files where name == nil.
You'd want something like this instead:
f.select(:doc, file.where('name IS NOT NULL').collect { |f| [f.name, f.id] }, {}, id: "id-select2", class: "form-control", multiple: true)
It might be more helpful if we knew exactly what file is.
Related
I am using Ransack to search a database with multiple fields. On the view side, I am pre-populating the default field values in my search form with the previous query, which is available in the view, from the controller as #q, using search_form_for #q.
Throughout the form, this is working successfully, but my field called deleted_eq always returns nil when I try to access it with f.object.deleted_eq to check the value. This is despite other field query values being returned properly in the same place using the same format, e.g. f.object.line_type_eq.
Is "deleted" a special field name in Ransack? All fields in my query are working as expected in the controller to return the correct results.
Changing the name of "deleted" would require a database migration and lots of code changes in the project, so I'd hope to check if it is a reserved name before I make all those changes for testing.
Edit for more info:
Rails 5.2.1, Ransack 2.0.1
deleted_eq is a dropdown done with f.select with descriptive text option names that are mapped to 'true', 'false', and ''. So yes, ultimately I believe Ransack is handling it as a boolean.
<%= f.select :deleted_eq, options_for_select([['Active Records', 'false'],
['Deleted Records Only', 'true'], ['Active and Deleted Records', '']],
f.object.deleted_eq || 'false'), {}, { :class => 'form-control',
:onChange => "searchOnchange();" } %>
Figured this out.
It seems like deleted_eq can be nil if a blank value is supplied. I had the most luck adapting another solution I found online like so:
<%= f.select :deleted_eq, [['Active Records', 0], ['Deleted Records', 1]],
{ include_blank: 'All Records', selected: params[:q] ? params[:q][:deleted_eq] : 0 },
{:class => 'form-control', :onChange => "searchOnchange();" } %>
It's a shame that the include_blank option ("All Records") always has to display as the first item in the dropdown, but since I'm able to choose what starts selected, and I can choose "Active Records", it's not the end of the world.
I want to send a different value to the server than what the text representation of the value is for a select field. All of my attempts at this seem to fail. Here is what I'm currently working with.
<td><%= f.select :code, ["BOB"], { value: "STEVE" }, { class: "account-rep-code", "data-user-codes" => current_user.code_list } %></td>
On submit of this example, I want to send "STEVE" to the server not "BOB". But "BOB" keeps sending anyway. How can I adjust this so that "STEVE" sends to the server as the value of the field?
The ActionView/Helpers/FormBuilder#select is defined as:
select(method, choices = nil, options = {}, html_options = {}, &block)
Where the choices parameter is an array of arrays, and the first value in each of them corresponds to the option "inner html", and the second one, to the option value. So in your case you could add [%w[BOB STEVE]] and this would give you an option like:
<option value="STEVE">BOB</option>
So
<%= form.select :name, [%w[BOB STEVE]], ... %>
I want to limit the entry possibilities for a text field in my model to a previously defined array.
How do I make an options_for_select with just a 1-dimensional array like ["foo","bar","foobar"]?
I tried
form_for #mappings do |f|
f.select(:mapping_type, options_for_select(["foo","bar","foobar"]), class: "..."
end
But the select box comes out all messed up like this:
<select name="section_mapping[mapping_type]" id="section_mapping_mapping_type">
as opposed to what it should be:
<select name="mapping_type" >
EDIT:
I changed the f.select to select_tag and the form shows up without any errors but when I submit it, it leaves that field empty
EDIT 2:
f.collection_select(:mapping_type, options_for_select([...]), class: "..."
works as in it submits the form with the value correctly, but the HTML class is not applied. Why is that?
Basically, you want to be able to tie your collection select to a property of the object (in your case, #mappings)
Also, from the doc on rails collection_select, it will take options as follow:
collection_select(object, method, collection, value_method, text_method, options = {}, html_options = {}) public
Objet: the object you are binding the selected option to (#mappings [f]) in this case
method: The property/attribute of the object (in this case, mapping_type)
collection: The collection for select ( ["foo","bar","foobar"] )
value_method: The value you want to send back with the submit (Note that this is a method which means you should be able to call it on an object.) more on this later.
text_method: The value you want to show as text on the select option on the view (this is also a method as above, more on this later as well)
options: any additional option you want, (e.g: include_blank)
html_options: eg: id, class etc.
As concerning the value_method and text_method, these are methods that should be called on your collection, which means that your collection will be an array of objects.
To this end, you can have the following:
class CollectionArr
include ActiveModel::Model
attr_accessor :name
ARR = [
{"name" => "foo"},
{"name" => "bar"},
{"name" => "foobar"}
]
def self.get_collection
ARR.collect do |hash|
self.new(
name: hash['name']
)
end
end
end
From here, calling CollectionArr.get_collection will return an array of objects where you can cal .name to return either foo, bar, or foobar. This makes using the collection_select and easy deal from here:
<%= f.collection_select : mapping_type, CollectionArr.get_collection, :name, :name, {:include_blank => "Select one"} %>
And all is green...
In my rails app, i have a drop down box where i retrieve all groups from the Group table and display them using the collection_select tag.
When the user selects 'None', I want to pass '0' as option value.
Currently, an empty string is passed.
Is there a way to include option value = 0 for 'None'?
<%= f.collection_select :SUB_GROUP, Group.all, :Group_ID, :Group_ID, :include_blank => 'None' %>
Many many thanks for any suggestion provided
If you use options_for_select in combination with select_tag you can achieve that using this:
options_for_select(
[['None', '0']].concat(
Group.all.collect { |g| [g.group_id.to_s, g.group_id.to_s] }
)
)
In order to keep your views uncluttered, you might want to generalize and move this into a helper method with a reasonable name.
I need to create a select box from the values available in a Hash.
For instance, I have a 'thing' and the 'thing' has a variety of status fields:
1 => 'State A'
2 => 'State B'
available via a method on thing.
How can I build a select tag from this?
Just as Schrockwell has said:
Hash.each |a| returns an array of the form a = [key, value], so for the hash #status_fields you can write:
<%= collection_select('thing', 'status', #status_fields, :first, :last) %>
Alternatively, if you'd like the key to show up in the select list and the value point to the select list value, then:
<%= collection_select('thing', 'status', #status_fields, :last, :first) %>
This will select the option given by thing.status or nothing if nil is returned
If you want to just create any selection not tied to an object use
<%= select_tag('name', options_from_collection_for_select(#status_fields, :first, :last, '2')) %>
where '2' is the index of the desired selection
PS: I don't have enough reputation to just amend the original post or comment on it
you could do something like
select "foo", "bar", #hash_object
or
select "foo", "bar", #hash_object.map { |h| [h.key, h.value] }
I'd probably invert your hash first to make the key point to the value
The select helper method will accept a hash in the form { text_displayed_in_select => select_value }, so you'll probably want to invert that hash.
Hash.each |a| returns an array of the form a = [key, value], so for the hash #status_fields you can write:
<%= collection_select('thing', 'status', #status_fields, :first, :last) %>
Alternatively, if you'd like the key to show up in the select list and the value point to the select list value, then:
<%= collection_select('thing', 'status', #status_fields, :last, :first) %>