Uniq value in option_from_collection_for_select - ruby-on-rails

How i can print only unique value in options_from_collection_for_select() helper ?
Because i don't want to have 10 times the same value...
<%= select_tag :type, options_from_collection_for_select(
Course.where(category_id: #category.id),
:learning_type,
:learning_type,
#type)
%>

I'm not sure what you are trying to do here. Let's say you have Course model, and you want to show the uniq learning_type of the course. You can get the results as an array with something like:
Course.where(category_id: #category.id).pluck(:learning_type).uniq
or
Course.where(category_id: #category.id).pluck('DISTINCT learning_type')
It's always better to use Fat model and use scopes in your Course model thought.
Now you can easily use the array with that form helper, something like:
<%= select_tag :type, options_for_select(Course.where(category_id: #category.id).pluck('DISTINCT learning_type')) %>

Related

Rails grouped_collection_select value_method with parameters

Is there any way to use grouped_collection_select value_method with parameters in Rails?
I'm trying to filter out a couple of options based on the current_user (effectively using something like: signed_by(current_user)) but I'm having some difficulty passing it in.
<%= f.grouped_collection_select :author_id, Author.posts, :signed_by, :title, :id, :email %>
Any ideas?
It's not possible to pass parameters to the value_method in this case because the value_method option is "the name of a method which, when called on a child object of a member of collection, returns a value to be used as the contents of its tag". In other words, it's just a string or symbol that will get called on the Author.posts collection.
If you're trying to filter out some options, I would suggest filtering them from the collection, and then passing the filtered collection to this method. Something like:
# author_helper.rb
def filtered_author_posts
Author.posts.where.not(signed_by: current_user)
end
<%= f.grouped_collection_select :author_id, filtered_author_posts, :signed_by, :title, :id, :email %>

Field gets radio button's item id instead of its value

I have snippet:
<%= f.input :purpose, as: :radio_buttons, collection: category.subcategories,
wrapper: :vertical_collection_inline %>
which lines values of category.subcategories horizontally how I want
The problem is, when I select either of option, it assigns that option's ID, but not its value.
How should I refactor the code?
Using IDs has advantages as warned in the comments, however what you’re trying to do should work with either:
category.subcategories.collect(:&values)
Where values is the name of the field which hols “Rent” etc.
The more railsy way to do this is with collection_radio_buttons, like this:
f.collection_radio_buttons(:purpose, category.subcategories, :value, :value)
Again where “value” is the field name.

Why select_tag displays only one column?

I have the following select_tag in my view:
<%= select_tag :users, options_from_collection_for_select(#users, 'id','firstname' , 'lastname') %></p></br>
I want to display the firstname and lastname in the select_tag, but it always displays the first parameter after the 'id' in this case the firstname.
What I'm doing wrong?
Use this instead
<%= select(:users, :id, #users.map {|u| [u.firstname + " " + u.lastname,u.id]}) %>
Im confident that options_for_select only allows you to put 1) The value that you want each option to have, 2) The id or label you want that option to have.
What you'd do is, in your User model, set a method to concatenate both the user first and last name into one and then use that as your option_for_select id.
User Model
def userFullName
self.firstname+' '+self.lastname
end
Then use it in your select_tag as this:
<%= select_tag :users, options_from_collection_for_select(#users, 'id','userFullName') %>
From Api Doc for options_from_collection_for_select you can get this:
options_from_collection_for_select(collection, value_method, text_method, selected = nil)
If you only want to display the options, that's is the right way to do it.
You only specify a 4th parameter if you want to preselect one option.
If you want to concatenate the name, you could do it as Oscar Valdez is telling you to.
Check more info for options_from_collection_for_select here: http://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/options_from_collection_for_select

Array as Parameter from Rails Select Helper

I'm working on a legacy project that is using acts_as_taggable_on which expects tags to come in arrays. I have a select box allowing users to select a tag on a Course in a field called categories. The only way mass assignment create will work is if params looks like this params = {:course => {:categories => ['Presentation']}}. I've currently a view with this helper:
<%= f.select 'categories', ['Presentation' , 'Round Table' , 'Demo', 'Hands-on'] %>
Which will give me a parameter like params = {:course => {:categories => 'Presentation'}}. This doesn't work since Acts as tag gable apparently can't handle being passed anything other than a collection.
I've tried changing categories to categories[] but then I get this error:
undefined method `categories[]' for #<Course:0x007f9d95c5b810>
Does anyone know the correct way to format my select tag to return an array to the controller? I'm using Rails 3.2.3
I didn't work with acts_as_taggable_on, but maybe this simple hack will be suitable for you? You should put it before mass-assignment.
category = params[:course][:categories]
params[:course][:categories] = [category]
If you are only going to allow the selection of ONE tag, you could do:
<%= f.select 'categories', [['Presentation'] , ['Round Table'] , ['Demo'], ['Hands-on']] %>
Each one item array will have first for the display value, and last for the return value, which in this case will both return the same thing, as the first element of the array is the same as the last element when the array as one element.
Seems like select doesn't give you that option.
If I understand correctly, one option might be to use a select_tag instead and just be explicit about where you want the selection in the params:
<%= select_tag 'course[categories][]', options_for_select(['Presentation' , 'Round Table' , 'Demo', 'Hands-on']) %>
That ought to get your params the way you need them.
Here's what I'm using for one of my projects:
<% options = { include_blank: true } %>
<% html_options = { required: true, name: "#{f.object_name}[#{resource.id}][days][]" } %>
<%= f.select :days, DAYS, options, html_options %>
Without html_options[:name], Rails handles the name of the select tag and spits out something like
service[service_add_ons_attributes][11][days]
but I need
service[service_add_ons_attributes][11][days][]
So I override it.
Hope that helps.

String concatenation not possible?

So over the last 2 hours, I've been trying to fill a combobox with all my users. I managed to get all firstnames in a combobox, but I want their full name in the combobox. No problem you would think, just concatenate the names and you're done. + and << should be the concatenation operator to do this.So this is my code:
<%= collection_select(:user, :user_id, #users, :user_id, :user_firstname + :user_lastname, {:prompt => false}) %>
But it seems RoR doesn't accept this:
undefined method `+' for :user_firstname:Symbol
What am I doing wrong?
What you need to do is define a method on the User model that does this concatenation for you. Symbols can't be concatenated. So to your user model, add this function:
def name
"#{self.first_name} #{self.last_name}"
end
then change the code in the view to this:
<%= collection_select(:user, :user_id, #users, :user_id, :name, {:prompt => false}) %>
Should do the trick.
This isn't really rails giving you an error, it's ruby. You're trying to combine the symbols :user_firstname and :user_lastname
A symbol is a variable type, just like integer, string, or datetime (Well technically they're classes, but in this context we can think of them as variable types). They look similar to strings, and can function similarly to them, but there is no definition for the behavior of symbol concatenation. Essentially you're trying to send the method user_firstnameuser_lastname which is just as non-sensical as trying to concat two Symbols.
What you need to understand is that this parameter is looking for a method on your User object, and it won't understand the combination of two symbols. You need to define a method in your model:
def fullname
[user_firstname, user_lastname].reject{|v| v.blank?}.join(" ")
end
This'll return your first + last name for you, and then in the parameter you should send :fullname (because that's the method it'll call on each user object in the collection):
<%= collection_select(:user, :user_id, #users, :user_id, :fullname, {:prompt => false})%>
Also, it's considered poor practice to prefix every single column with the table name. user.user_firstname just looks redundant. I prefer to drop that prefix, but I guess it's mostly up to personal preference.
The arguments for value and display attribute are method names, not expressions on a user object.
To control the format more precisely, you can use the select tag helper instead:
select("user", "user_id", #users.each {|u| [ "#{u.first_name u.last_name}", u.user_id ] })
The docs are pretty useful.

Resources