Rails form dropdown using two text_method - ruby-on-rails

I am creating a form has a drop down selection. I want to use two "text_method"s for the input but I am unsure how to do this. I want to include the year and name (both are two different columns in my rails model.
Here is what I have but it does not work:
<%= f.collection_select :bat_id, Bat.all, :id, :model_year, :model_name, include_blank: true %>
Here is the official documentation- http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#method-i-collection_select

Use this in your view:
<%= f.collection_select :bat_id, Bat.all, :id, :model_year_and_name, include_blank: true %>
Add a method like this to your Bat model:
def model_year_and_name
"#{model_year} #{model_name}"
end

Related

collection_select show multiple object attributes?

In addition to showing the challenge's name. I also want to show its deadline next to the name.
It would look like this for example:
Visit London 09/09/16
Make $1,000,000 10/15/18
Knit a Scarf 01/11/19
Instead of just this:
<%= f.collection_select :challenge_id, current_user.challenges.order(:deadline),:id,:name, include_blank: true %>
Define a method name_with_deadline in challenge.rb
def name_with_deadline
"#{name} #{deadline}"
end
and then make use of this method as label in the collection.
<%= f.collection_select :challenge_id, current_user.challenges.order(:deadline),:id, :name_with_deadline, include_blank: true %>
The name_with_deadline method will called for every object in the collection to retrieve the label text.
Hope this helps!
You can add a virtual attribute to you model like below:
def name_deadline
"#{name} #{deadline}"
end
collection_select:
<%= f.collection_select :challenge_id, current_user.challenges.order(:deadline),:id,:name_deadline, include_blank: true %>

Rails - How to call values from one model into another model form

I'm working on some app and I have 2 models. Categories in which I create category names and Question. Category has_many questions and Question belongs_to Category.
I've added category_id to Question model.
Now I need to take all Category_names and display them in form where I create Question so User can choose in which category_name will save question.
I've tried something like this in firs line of code but not working.
<%= f.input :category_id, Category.all.map(&:name) %>
<%= f.input :question_name, wrapper: :vertical_text_input, as: :text %>
<%= link_to "Markdown help", "http://assemble.io/docs/Cheatsheet-Markdown.html", target: "_blank", class: "right" %>
<%= f.input :answer %>
<%= f.input :image, as: :attachinary %>
QUESTION: How to display all Category names in form where I create new Questions?
you may wanna use a select box and use the collection select rails helper :
f.collection_select(:category_id, Category.all, :id, :name)
Also you can use this way.
<%= f.select :category_id, Category.all.map(&:name), {prompt:"Choose Category"}%>
#Jhon suggestion.
<%= f.select :category_id, Category.pluck(:name), {prompt:"Choose Category"}%>

drop down select switches to first value in list in edit mode

I have a drop down select that is set up like below:
<%= select_tag :city_id, option_groups_from_collection_for_select(#regions, :cities, :name, :id, :name) %>
It works fine, except that when I load the edit view the list loads the first item in the select, not the saved value. Is there parameter I'm missing? On rails 4.
According to the documentation on option_groups_from_collection_for_select found here: http://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/option_groups_from_collection_for_select
It has a sixth parameter that is the selected value, so just add the last parameter with the value you want and it will work:
<%= select_tag :city_id,
option_groups_from_collection_for_select(#regions, :cities, :name, :id, :name, "your_city") %>
Instead of using select_tag use select
# f being your form object
<%= f.select :city, option_groups_from_collection_for_select(#regions, :cities, :name, :id, :name) %>
Considering you have a valid association with city

Rails collection_select vs f.collection_select

I can't understand the difference between the two. Can someone please explain the difference when using form_for?
Say you have this: <%= form_for(#post) do |f| %>
Examples- When would you use this?
<%= collection_select(:post, :author_id, Author.all, :id, :name_with_initial, prompt: true) %>
vs. use this?
<%= f.collection_select(:post, :author_id, Author.all, :id, :name_with_initial, prompt: true) %>
Rails Api
When you use f.some_form_helper the helper will already know the name of the model you want to make the field name for. This way you can drop that :post argument. form_for(#post) gives you the f form builder object that knows what model the form is for.
With the regular collection_select (or any other helper with f.) you have to pass in, as the first argument, the name of the model the field is for.
Your example is a bit off because you passed in the same arguments to both. f.collection_select doesn't need the :post.
This is correct use of the non f. helper:
<%= collection_select(:post, :author_id, Author.all, :id, :name_with_initial, prompt: true) %>
This is a corrected way to use the f. helper:
<%= f.collection_select(:author_id, Author.all, :id, :name_with_initial, prompt: true) %>
the f object has a reference back to the model you passed in to form_for via f.object. This is how it knows to call collection_select(:post, ...) under the hood.

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()

Resources