How to set-up Rails form select for a collection - ruby-on-rails

I'm working on a code base that I'm not very familiar with, specifically Haml. I need to set-up a select dropdown to select a user.
I have the following code in my controller:
def edit
#franchise = Franchise.find params[:id]
#ab_reps = User.where role: "admin-ab"
authorize! :update, #franchise
end
I have the following code in my form (that doesn't currently work):
= f.select :ab_rep, options_for_select(#ab_reps, f.object.ab_rep), {prompt: "AB Representative"}, {label: false, right_class: "col-sm-10", class: "ab-rep-field"}
Couple questions:
1.) #ab_reps is an array of user objects. I have the following method in my user model:
def name
[first_name, last_name].compact.join(" ")
end
How do I get the select to display the user names instead of the user objects (which it currently does) ?
2.) Is my current set-up even close to being correct?
Thanks for your help!

You are close, you need to provide the methods for the option value and the option text, as well as the collection which in your case is #ab_reps. Additionally you can provide a hash for prompts and for html_options such as class names, which you've done.
Rails has a few different helpers you can use for select tags including options_from_collection_for_select. I've used collection_select often, http://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/collection_select
= f.collection_select :ab_rep, #ab_reps, :id, :name, {prompt: "AB Representative"}

Related

Ruby on rails - bind a selected value to a select element for update

I can not figure out why this is not working, I saw a couple of examples and seems to be right.
I have two clases that are related, consultant and salary (a salary belongs_to a consultant).
The problem I have is, when I want to edit a salary, the consultant that appears on the form is not bind to the select (in the select it just appears the list as if I was creating a new one)
<%= f.select :consultant_id, options_for_select(Consultant.active.map{|s|[s.first_name, s.id]}, params[:consultant_id]), {}, class: 'form-control' %>
I think you should check your route that the :consultant_id param is available on this page. Else you may need to change the params[:consultant_id] to something like salary.consultant_id
Alternatively, you can use the collection_select method as such:
f.collection_select(:consultant_id, Consultant.active, :id, :first_name, prompt: true, class: 'form-control')
Let me know whichever works for you.
Note: It's not best practice referring to domain object within your view.

How to send two values with a rails collection_select

I want to send two values with my collection select. Currently, i'm saving the ID but I want to have access to the name in my controller as well.
= f.collection_select :foo_id, #foos, :id, :name
That's my code, pretty simple. Just having trouble getting access to that name.
The collection also comes from a external API, so I don't want to have to touch the API again to get the name.
As, I said in the comment. You can customize the <option> tag values like :
= f.collection_select :foo_id, #foos, ->(ob) { "#{ob.name}|#{ob.id}" }, :name
Now, inside the controller just split it the value on |, and use it.
This is just an idea out of millions.

Rails Form_For Select With Dual Purpose

I have form for adding a new job. On my form I have a select drop-down list. I need to associate the new job to a customer. The following works great.
<%= f.collection_select :customer_id, Customer.all, :id, :business_name %>
But, what if I want to also be able to send in a customer_id to the new form? Can I have the form's select drop-down show all the possible customers, as above, but have it auto select the customer_id I pass into the form, if a customer_id is passed in?
url = ...jobs/new
OR
url = ...jobs/new?customer_id=5
I apologize if I did not explain this well enough.
Thanks in advance.
--jc
I think you do what you're trying to achieve this by populating the customer_id field on the job you're creating in your controller if customer_id is present in the request params. This should make that particular customer be the initially selected option in the form.
http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#method-i-collection_select
e.g. Something like.
if params[:customer_id].present?
job.customer_id = params[:customer_id]
end
If you declaring the instance variable #customer in your controller action then you can use selected option as:
<%= f.collection_select :customer_id, Customer.all, :id, :business_name, {:selected => #customer.id} %>

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 select helper - set default?

Rails 2.3.11
I did read this answer, but it's not working for me.
I would like the default option for this selection box to be the event_id passed through the URL.
f.select :event_id, #events, :selected => url_args["event_id"]
An example #events is[["SC 2 Tournament", 195], ["Obstacle Course", 196], ["Mortal Combat", 197]]
The following also didn't work:
adding ".to_i" to "url_args["event_id"
using options_for_select(#events, url_args["event_id"]
Thank you!
This is a lot easier if you use the collection_select helper:
f.collection_select :event_id, #events, :id, :name
Then to select the default option (and have that be selected on pageload), you can simply assign it to whatever Object it is that the form is for within the controller. eg like this:
def new
#events = Event.all
#thing = Thing.new(:event => #events.first)
end
I'm not sure where your url_args comes from, but I'm guessing it's probably from a param in the URL, in which case you can do this:
Thing.new(:event_id => params[:event_id])
One last thing - collection_select won't quite work with #events as you've specified it, as you're using a nested Array, when it's expecting an Array of Objects that it can call id and name on in order to retrieve the values and display text for the select options. To fix that, simply redefine #events within your controller, using one of the ActiveRecord finders, such as Event.all or Event.find(..).
Make sense?

Resources