I am trying to add a boolean attribute (third_party) to my current collection_select that currently just shows name:
<div class='form-group'>
<%= f.label :project_component_id, class: "form-label" %>
<%= f.collection_select :project_component_id, issue.project.project_components.order("LOWER(name)"), :id, :name, {include_blank:true}, class: "form-control input-sm" %>
</div>
How would I append third_party so that each select option is shown as "name(third_party)"?
Thanks!
You can create an instance method in your model which interpolates the attribute you need with the extra text and pass it as the fourth option to your collection_select helper:
I assume is called ProjectComponent, so:
class ProjectComponent < ApplicationRecord
def name_with_thirdparty
"#{name}(#{third_party})"
end
So in your view:
<%= f.collection_select(
:project_component_id,
issue.project.project_components.order("LOWER(name)"),
:id,
:name_with_thirdparty,
{ include_blank: true },
class: 'form-control input-sm') %>
Related
I have an Exam and an ExamBattery that is just a collection of Exams. They have a has_and_belong_to_many declaration for each other, and ExamBattery accepts nested attributes for Exam, like so:
class Exam < ApplicationRecord
has_and_belongs_to_many :exam_batteries
validates_presence_of :name
end
class ExamBattery < ApplicationRecord
has_and_belongs_to_many :exams
accepts_nested_attributes_for :exams, reject_if: lambda { |attrs| attrs['name'].blank? }
validates_presence_of :name
end
When I create a new Exam, I want to be able to assign it to one or many ExamBatteries, so in ExamsController I whitelisted the array exam_battery_ids to accept multiple ExamBatteries to assign them to the current Exam (no other change was made, the controller is just from the scaffold):
def exam_params
params.require(:exam).permit(:name, :description, :order, :price, exam_battery_ids: [])
end
Also, in the view exams/new I added a multiple select to send the desired exam_battery_ids as params:
<%= form_with(model: exam, local: true) do |form| %>
# ... typical scaffold code
<div class="field">
<% selected = exam.exam_batteries.collect { |eb| eb.id } %>
<%= form.label :exam_battery_ids, 'Add batteries:' %>
<%= form.select :exam_battery_ids,
options_from_collection_for_select(ExamBattery.all, :id, :name, selected),
{ prompt: 'None' },
multiple: true %>
</div>
<% end %>
The idea is to be able to create a new ExamBattery with new Exams in it, in the same form (I haven't wrote that part yet, I can only edit for now). Also, when I edit an ExamBattery I want to be able to edit its Exams and even assign them to other ExamBatteries (if I select 'None', or JUST another exam battery, it would stop being assigned to the current ExamBattery), so in exam_batteries/edit (actually, the form partial in it) I have this code:
<%= form_with(model: exam_battery, local: true) do |form| %>
# ... normal scaffold code
<div class="field">
<!-- it should be exam_battery[exams_attributes][#_of_field][order] -->
<!-- it is exam_battery[exam_battery_ids][] -->
<% selected = exam_battery.exams.map { |exam| exam.id } %>
<%= form.label :exam_battery_ids, 'Edit batteries:' %>
<%= form.select :exam_battery_ids,
options_from_collection_for_select(ExamBattery.all, :id, :name, selected),
{ prompt: 'None' },
multiple: true %>
</div>
<% end %>
And in ExamBatteriesController I whitelisted the exam_batteries_attributes, with exam_battery_ids: [] as a param:
params.require(:exam_battery).permit(:name, :certification, exams_attributes: [:name, :description, :order, :price, exam_battery_ids: []])
But when in the ExamBattery form I try to edit the Exam's exam_batteries, the info doesn't update, because the params are like this:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"blah", "exam_battery"=>{"name"=>"Battery1", "certification"=>"test1", "exams_attributes"=>{"0"=>{"name"=>"Exam1", "description"=>"", "order"=>"", "id"=>"3"}, "1"=>{"name"=>"Exam2", "description"=>"", "order"=>"", "id"=>"4"}, "2"=>{"name"=>"Exam3", "description"=>"", "order"=>"", "id"=>"5"}}, "exam_battery_ids"=>["", "", "", "", "", "3"]}, "commit"=>"Update Exam battery", "id"=>"3"}
The exam_battery_ids are sent as a different param because the select name is exam_battery[exam_battery_ids][] instead of something like exam_battery[exams_attributes][0][name], as it happens with the other fields. How can I fix that?
Thanks.
I had an error in the form. In exam_batteries/edit I didn't notice I was using the form_with variable (form) and not the fields_for variable (builder), so it should be like this:
<div class="field">
<!-- it should be exam_battery[exams_attributes][0][order] -->
<!-- it is exam_battery[exam_battery_ids][] -->
<% selected = exam_battery.exams.map { |exam| exam.id } %>
<%= builder.label :exam_battery_ids, 'Escoge una batería' %>
<%= builder.select :exam_battery_ids,
options_from_collection_for_select(ExamBattery.all, :id, :name, selected),
{
include_hidden: false,
prompt: 'Ninguna'
},
multiple: true %>
</div>
With that it should work.
The only issue now is that I can't get the selected batteries when I show them in the fields_for, but I'm working on it.
UPDATE: I can show the current exam_batteries of the exam in the nested form by replacing the selected variable in the view with this:
<% selected = exam_battery.exams[builder.options[:child_index]].exam_batteries.map { |eb| eb.id } %>
If you know about a cleaner method, please let me know.
In my rails project I have two models, Car Make & Car Model, with a 1:M relationship (i.e. one Audi has many Audi models).
In my Views page, I want a form with two input fields for car make & car model. Ideally, I will be able to input a car make (i.e. Audi) and the second input field will have a drop down menu with all the models available for the make (2016 Audi A6, 2017 Audi A7).
I've set up all the relations and in the models I have saved a foreign key of the make.
currently in _form.html.erb I have
<div class="field">
<%= f.label :make_id, "Make:"%><br>
<%#= f.number_field :make_id %>
<%= f.collection_select :make_id, Make.all,
:id,:makes_info, {:include_blank => 'Please Select'} %>
</div>
<div class="field">
<%= f.label :model_id, "Model:" %><br>
<%= f.collection_select :model_id, Model.all,
:id,:model_info, {:include_blank => 'Please Select'} %>
</div>
If you want it to truly be dynamic, you would need to use an AJAX request to update the second select after the first is picked. You'd also need to use the options_for_select method inside of the select tag
Some more info to accompany what was already provided.
It's known as dynamic select boxes:
#config/routes.rb
resources :makes do
get :models, on: :collection #-> url.com/makes/models
end
#app/controllers/makes_controller.rb
class MakesController < ApplicationController
def models
#make = Make.find(params[:make][:make_id])
respond_to do |format|
format.js
end
end
end
#app/views/makes/models.js.erb
$select = $("select#models");
$select.empty();
<% #make.models.each do |model| %>
$select.append($('<option>').text(<%=j model.name %>).attr('value', <%= model.id %>));
<% end %>
#views
<%= f.collection_select :make_id, Make.all, :id, :makes_info, {include_blank: 'Please Select'}, { data: { remote: true, url: make_models_path }} %>
<%= f.collection_select :model_id, Model.all, :id,:model_info, {include_blank: 'Please Select'}, { id: "models" } %>
I am trying to link multiple rails models in my app. I am trying to let users create reviews on a product using a form. I am trying to use the rails DRY principle.
I first made a bat table with bat name, model year, and an image. Then I created a manufacturer table which only lists the names of the manufacturers of bats. My bats model belongs_to :manufacturer and my manufacturer model has_many :bats.
Instead of creating multiple tables using manufacturer, (listing the name of the manufacturer at least 3 times for each bat) how can I link my two models together?
My form is submitted to the review model. In the form I already have <%= f.collection_select :bat_id, Manufacturer.all, :id, :manufacturer, include_blank: true %>, which lists all of the possible manufacturers in a drop down menu. HOWEVER, nothing is submitted to the :bat_id parameter in the review form when submitted.
--One guess is to have the manufacturer_id integer stored in the bat model as an integer under the column manufacturer_id(Note: already done this, but I don't know how to submit that in a form?)
--Another guess is to have the bat model inherit from the manufacturer model
Any help is greatly appreciated
My full form:
<%= form_for(#review) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field" align= "center">
<h3>Select bat</h3>
<%= f.collection_select :bat_id, Manufacturer.all, :id, :manufacturer, 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 %>
according to the documentation
http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#method-i-collection_select
the params in the collection_select is supposed to be:
f.collection_select(:post, :author_id, Author.all, :id,
:name_with_initial, prompt: true)
where post is the Model,author_id is the attribute
or you could try using:
=f.select( :bat_id, options_from_collection_for_select(#manufacturers,"id","manufacturer",
f.object. bat_id),{})
and put the
#manufacturers = Manufacturer.all
inside the controller
I'm in trouble with a form I'm doing on rails 3.
What I want to do is:
I want to pass an extra parameter only to decide how many builds you want to do
to the next form. I'm trying to pass the value through a text_field_tag, but I can't get it
on the controller side.
This is what I've done:
Model:
class Story < ActiveRecord::Base
attr_accessible :resume,
:title,
:prelude,
:chapter_numbers
attr_accessor :chapter_numbers
# etc etc etc
end
View:
<%= simple_form_for(#story) do |f| %>
<div class="field">
<%= f.input :prelude, as: :text, input_html: { rows: 10, style: 'width: 100%' } %>
</div>
<div class="field">
<%= text_field_tag :chapter_numbers %>
</div>
<% end %>
the extra parameter is :chapter_numbers, which I want to catch in the controller as
params[:chapter_numbers], but it's not working. Tried to add it as virtual attribute (don't know if it's necessary)
Thanks in advance!
text_field_tag is an independent field, and won't be sent in your params
text_field_tag And text_field Are Different
You'd need to use f.text_field because this will send the required params to your controller, like this:
<%= f.text_field :chapter_numbers %>
or in your case (with simple form):
<%= f.input :chapter_numbers, as: :text %>
Good resource here about this
When user clicks AddDate in my event planning app, I add a row as seen below so user can add a date and start/end time, and AM/PM.
But in my form using nested attributes, it seems my select controls need a reference to the model field they set (:start_time and :end_time). But the start and end times are create from TWO select controls, one for the hours and one for the minutes. So I'm not sure how the values chosen in the two selects will be combined to form the start and end times.
<div class="user_event_inline_container margin_left_ten padding_right_gone">
<%= f.label :start_time, "Start", class: 'info_inline_control info_label five_margin_right' %>
<%= f.select :start_time, options_for_select([['1',1],['2',2],['3',3],['4',4],['5',5],['6',6],['7',7],['8',8],['9',9],['10',10],['11',11],['12',12]]), class: (field_class(#user_event, :start_time) + 'info_inline_control') %>
<%= f.select :start_time, options_for_select([['00',1],['15',2],['30',3],['45',4]]), class: (field_class(#user_event, :start_time) + 'info_inline_control') %>
<%= f.select :start_am_pm, options_for_select([['am',1],['pm',2]]), class: (field_class(#user_event, :start_am_pm) + 'info_inline_control') %>
</div>
<div class="user_event_inline_container margin_left_ten padding_right_gone">
<%= f.label :end_time, "End", class: 'info_inline_control info_label five_margin_right' %>
<%= f.select :end_time, options_for_select([['1',1],['2',2],['3',3],['4',4],['5',5],['6',6],['7',7],['8',8],['9',9],['10',10],['11',11],['12',12]]), class: (field_class(#user_event, :end_time) + 'info_inline_control') %>
<%= f.select :end_time, options_for_select([['00',1],['15',2],['30',3],['45',4]]), class: (field_class(#user_event, :end_time) + 'info_inline_control') %>
<%= f.select :end_am_pm, options_for_select([['am',1],['pm',2]]), class: (field_class(#user_event, :end_am_pm) + 'info_inline_control') %>
</div>
Why don't you use a time_select instead?
Doing it this way, you'll need to merge them manually in your controller using params[] values and Date.parse().
You can also try using f.time_select, which should function as a normal field after you submit.
Might find this useful: Where is the Rails method that converts data from `datetime_select` into a DateTime object?
Personally, I write custom interfaces for my date fields using jQuery plugins and then use javascript to merge all the fields into a hidden field that actually gets submitted.