first item in array from the multiple collection_select is always blank - ruby-on-rails

the relevant part of the new form looks like this:
<%= f.fields_for :event_artists do |fea| %>
<%= fea.collection_select :artist_id, Artist.all, "id", "name", {include_blank: true}, {multiple: true} %>
<% end %>
on the log, you can see that the first item of the array is always blank, even if I didn't select the blank field
"event_artists_attributes"=>{"0"=>{"artist_id"=>["", "2", "5"]}}}
is there a way to fix this? perhaps, make it so that if the blank field is selected, then no actual event_artists can be selected in that case, and vice versa?

The empty artist_id is important. On another form, you may have omitted the artist select altogether, in which case, the artists association should not be affected.
If the artist select is included, and you de-select all artists, the artists need to be removed from the artists association. Normal HTML behavior would not include the artist_id parameter in the PUT at all when nothing is selected. Your controller in that case would think that you do not want to modify the artists association at all.
To solve this, the collection_select includes a hidden field with a blank value to let the controller know that the form intends to alter the artists association. If no artists have been selected, that blank element in the array will ensure all artists are removed from the association.

I think the problem has to do with the order of arguments. I looked at collection_select and tried the following code in an app I'm working on.
<%= collection_select(:category, :category_id, Category.all, :id, :name, {}, {multiple: true}) %>
UPDATE:
<%= fea.collection_select :artist_id, Artist.all, "id", "name", {prompt: true}, {multiple: true} %>

Related

Collection_select doesn't let me select when multiple => true

This is the template with multiple => true, but when i remove the multiple the selection tray works perfectly and takes in a single value.
What i need is multiple options to be selected and to be stored in the confirer_string as a string.
The problem i'm encountering is that all the options are listed but they coudn't be selected though they can be clicked on.
new.html.erb
<%= form_with(model: #base, local: true) do |form| %>
<%= form.label :description %>
<%= form.text_field :description, id: :base_tbl_description %>
<%= form.label :confirer_string %>
<%= form.collection_select(:confirer_string, Confirmer.all , :position, :name,{ :prompt => "Please select" }, { :multiple => true } ) %>
<%= form.submit %>
<% end %>
Is it a problem since i'm not using id's but integer fields. And one more thing :confirer_string is of type string.
There are two models, without any association between them. All i'm trying to do is get the list of options from the other model to be listed as option in the selection of primary model. Then the set of selected options will return their position, which will be stored in the confirer_string.
Thing is i cant select anything, not even one option when multiple is true.
UPDATE: i got the multiple select working again but i need to use ctrl+click to select mutliple entries. But the data is not storing, it is giving unpermitted error: conf_string
Just add the {attribute_name: []} in the strong params.

Retrieving contact details from contact id using collection select

I use the following collection select to let users pick the contact name.
<div class="form-group">
<%= f.label :contact %>
<%= f.collection_select(:contact, current_user.contacts.all, :id, :name, prompt: true, class: "form-control") %>
</div>
But, instead of name, it's the id that's displayed when I use email.contact in the show page. I have tried using email.contact.name and it returns a NoMethodError. As for the associations, Email has_many contacts and contacts belongs_to email. I even tried using inverse_of these association, but still unable to retrieve the contact name. Is there a workaround that could solve this?
If you look at collection_select
collection_select(object, method, collection, value_method, text_method, options = {}, html_options = {})
If you look at docs it says
The :value_method and :text_method parameters are methods to be called on each member of collection. The return values are used as the value attribute and contents of each tag, respectively.
So you need to pass value_method as the method you want it to save in db, right now you are using it as id. To save name you can do something like this:
<%= f.collection_select(:contact, current_user.contacts.all, :name, :name, prompt: true, class: "form-control") %>

Rails Multiple Input Field in Form to One Integer Attribute in Model

I am trying to allow a user to input two different things in two different drop down menus from the same form and it will store an integer into a review table.
I want the user to be able to select model_name in one drop down and manufacturer in another drop down. The result will store a bat_id integer into the form. (Telling you which bat the user is selecting)
I have seen a couple questions about date & time but they store the values directly in the model. I am trying to store an integer - bat_id so that the bat_id will directly link the review model to the bat model.
Examples I have found that are close:
How do ruby on rails multi parameter attributes really work (datetime_select)
Rails multiple fields to one model attribute
Using multiple input fields for one attribute
Rails Update Single Attribute with Multiple Fields
My form now:
<%= form_for(#review) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field" align= "center">
<h3>Select Brand</h3>
<%= f.collection_select :manufacturer_id, Manufacturer.all, :id, :manufacturer, include_blank: true %>
<h3>Select Bat</h3>
<%= f.grouped_collection_select :bat_id, Manufacturer.all, :bats, :manufacturer, :id, :model_year_and_name, include_blank: true %>
<h3>What do you like about this bat?</h3>
<%= f.text_area :pros, placeholder: "Enter what you like..." %>
<h3>What do you not like about this bat?</h3>
<%= f.text_area :cons, placeholder: "Enter what you don't like..." %></br>
</div>
<div align="center">
<%= f.submit "Add Review", class: "btn btn-large btn-info" %>
</div>
<% end %>
I am submitting to the review table and trying to submit both of these to the bat_id attribute.
<h3>Select Brand</h3>
<%= f.collection_select :manufacturer_id, Manufacturer.all, :id, :manufacturer, include_blank: true %>
<h3>Select Bat</h3>
<%= f.grouped_collection_select :bat_id, Manufacturer.all, :bats, :manufacturer, :id, :model_year_and_name, include_blank: true %>
In my bat model I have: has_many :reviews & In my reviews model I have: belongs_to :bat
UPDATE: Is it possible to use a hidden field with the combination of javascript and my two inputs to determine my one output bat_id?
Update I changed my dropdown code to what works so that I enter in manufacturer_id & bat_id when both are selected. However I still think there is a way to store one value in my review model. I am using javascript very similiar to this
From a UI perspective this seems broken... users will be able to associate any model year & name with any manufacturer, even if that manufacturer did not produce that model year & name.
Assuming you will introduce some javascript to handle that, from a rails perspective you will get undefined behavior with two :bat_id fields in the same form. I think you need this:
<h3>Select Brand</h3>
<%= f.collection_select :manufacturer_id, Manufacturer.all, :id, :manufacturer, include_blank: true %>
<h3>Select Bat</h3>
<%= f.collection_select :bat_id, Bat.all, :id, :model_year_and_name, include_blank: true %>
Alternatively you can just create one dropdown containing a composite field, like this:
<h3>Select Bat</h3>
<%= f.collection_select :bat_id, Bat.all.sort {|a, b| a.manufacturer_model_year_and_name <=> b.manufacturer_model_year_and_name}, :id, :manufacturer_model_year_and_name, include_blank: true %>
and then in your Bat model introduce something like this:
def manufacturer_model_year_and_name
"#{self.manufacturer.name}: #{self.model_year_and_name}"
end
As discussed in your other answer, you shouldn't need to store the manufacturer_id on your review model.
I would recommend creating a Manufacturer select that isn't accessed in your Review model, but is simply used to filter the list of bats on the form.
The best way to do this is probably to add some custom data attributes to the Bat select.
<%= collection_select :manufacturer, :manufacturer_id, Manufacturer.all, :id, :manufacturer %>
<%= f.select :bat_id, Bat.all.map{ |b| [b.model_year_and_name, b.id, {'data-manufacturer' => b.manufacturer_id}] } %>
Then use some javascript to filter the Bat select when the Manufacturer select is changed.
Unfortunately you cannot just set display: none to an option element to hide it. This does not hide the option in many browsers. So the best method is to use a bit of jQuery to clone the original select every time the manufacturer select is changed, and remove any option that isn't associated with the selected manufacturer. Like so:
// rename the original select and hide it
$('#bat_id').attr('id', 'bat_id_original').hide();
$('#manufacturer_id').on('change', function() {
$('#bat_id').remove(); // remove any bat_id selects
$bat = $('#bat_id_original')
.clone() // clone the original
.attr('id', 'bat_id') // change the ID to the proper id
.insertAfter('#bat_id_original') // place it
.show() // show it
.find(':not(option[data-manufacturer="' + $(this).val() + '"])')
.remove(); // find all options by other manufacturers and remove them
});
You might need to change a few things to get this to work in your installation, but you can view a static demo on jsFiddle here: http://jsfiddle.net/JL6M5/
You will probably need to reject the manufacturer_id field on form submit, avitevet already pointed out this answer which should help there: Rails: Ignoring non-existant attributes passed to create()

Rails + Ransack - Drop Down List Collection?

I am loving the ransack gem for its flexibility, however I am unable to get the standard collection_select to function properly. Perhaps someone can assist.
Example:
<%= collection_select(:expense, :project_id, Project.all,
:id, :name, { prompt: 'Select Project'}, { class: 'span4' }) %>
in this case, this code is from an expense entry screen, so the first parameter is the expense object. What should it be in the ransack form? Also, I know I need to get the suffix in there. In this example, I would like project_id_eq to be the search pattern.
Also, my form is on a controller and view called "reports", I am not putting this search in the default controllers.
Thanks!
Seems that this will work.
<%= f.select :project_id_eq, options_from_collection_for_select(Project.all, "id", "name", #search.project_id_eq) %>
If anyone has another suggestion, would love to know it too.
To do this with an include_blank, put it outside of the parentheses:
ex:
<%= f.select :languages_id_eq, options_from_collection_for_select(Language.all, "id", "name"), include_blank: true %>
== UPDATE ==
better yet, use f.collection_select. This way after the user searches for something using the drop down, that option is preselected on the following page:
<%= form.collection_select :vendor_id_eq, Vendor.all, :id, :name, include_blank: true %>

rails: collection_select for current_user

I have a Box which has many Items which belongs to a Category.
When the Box is created it has the user_id.
Items has a category_id.
I've seen that if you have a user_id in the table concerned it works okay:
<%= f.collection_select :category_id, Category.where(:user_id => current_user.id), :id , :name %>
But how can I get a Category collection_select from what the current_user has entered - do I have to add a user_id to Categories or can I join my tables somehow?
Maybe this way is easier:
<%= f.collection_select :category_id, current_user.categories, :id, :name %>
PS: Even better if you put this in your controller, so, in case you have to change the select and add some clauses, you will not need to change almost all your views, just the controller (MVC).

Resources