I've got a fairly simple (it seems) bit of code to create a multiple-selection element:
<%= form_for #post do |f| %>
#stuff
<%= fields_for :tags |tag_fields| %>
<%= tag_fields.label :select_tags %>
<%= tag_fields.select :tags, Tag.all, multiple: true %>
<% end %>
<% end %>
For some reason when it renders the page, the multiple: true part isn't getting parsed, and the form is just rendering as a generic dropdown with only one option selectable. What am I missing?
(Rails version is 5.0.0 in case relevant)
The signature of the select helper is:
select(method, choices = nil, options = {}, html_options = {}, &block)
multiple is an HTML option, therefore you should use:
<%= tag_fields.select :tags, Tag.all, {}, multiple: true %>
Related
I have a model Responsibility with has one text field of responsibility. Other model is Stage, in Stage form field there is a text_field responsibility I want to render an option list from responsibilities table how can i do that in rails?
routes.rb
resources :projects do
resources :responsibilities
resources :stages
end
stage _form.html.erb
<%= form_with(model: stage, url: [#project, stage], local: true) do |form| %>
<div>
<%= form.label :responsibility, :class=>"required" %>
<%= form.text_field :responsibility %>
</div>
<div>
<%= form.submit %>
</div>
<% end %>
How can I render responsibilities list as an option in stage responsibility form field?
what is tried is:
stage _form.html.erb
<div>
<%= form.label :responsibility %>
<%= select_tag "colors", #responsibilities , multiple: true %>
</div>
stages_controller.rb
def new
#stage = Stage.new
#project = Project.find(params[:project_id])
#responsibilities = #project.responsibilities
end
I was able to render form but in responsibility field none of the responsibility was accessed as option.
select_tag accepts as a second parameter string that contains options as a string.
Rails provides some helper methods that are useful for generation of those <option>
tags
options_from_collection_for_select, options_for_select
If you inspect with your browser's developer tools the html code of the <select> tag you will see something like this:
<select name="colors[]" id="colors" multiple="multiple">
#<Responsibility::ActiveRecord_Relation:0x00007f3f72cc7eb0>
</select>
This is because select_tag calls to_s method of #responsibilities collection.
The correct way of creating select_tag would looks something like this:
<%= select_tag "colors", options_from_collection_for_select(#responsibilities, :id, :name) , multiple: true %>
There is another way to build select field using the FormBuilder method collection_select. It might look something like this:
<div>
<%= form.label :responsibility %>
<%= form.collection_select :responsibility, #responsibilities, :id, :name, prompt: true %>
</div>
I hope this answer will be useful.
I'm playing with ActiveStorage and trying to upload some files locally. Everything works great with the code below, but only if I remove multiple: true from the form. When it is on the form, I get an unpermitted param "files" error in the console. The unpermitted param comes from the way the form is submitting the hash.
Without multiple: true the hash lists attachments as an array (this is the working version):
"article"=>{"files"=>[#<ActionDispatch::Http::UploadedFile:0x007fb4e8e287f0
But with it turned on it it removes the array:
"article"=>{"files"=>#<ActionDispatch::Http::UploadedFile:0x007fb4eb07b7d0
What is causing this form behavior and how can I fix it?
I got the code sample from Engine Yard and here is the project code:
<h3>Attach files to this post</h3>
<%= form_with model: #article, local: true do |f| %>
<div class="form-row">
<%= f.label :file_upload, 'Attach a file' %>
<%= f.file_field :files, multiple: true %>
</div>
<%= f.submit %>
<% end %>
<h3>Attached files</h3>
<% #article.files.each do |file| %>
<%= link_to file.blob.filename, url_for(file) %>
<% end %>
When you use multiple: true you need to permit an array explicit in the article_params for :files:
For example:
params.require(:article).permit(:author, :text, files: [])
You can read more under Action Controller
Good luck!
The documentation for Rails select form helper states (see documentation):
select(object, method, choices = nil, options = {}, html_options = {}, &block)
Which allows adding a class simple, like so:
<%= f.select :some_attr, MYOPTIONS, {}, {class: 'my-class'} %>
My question is, how do I add a class to it when using it as a block? Rails documentation states:
select(report, "campaign_ids") do
available_campaigns.each do |c|
content_tag(:option, c.name, value: c.id, data: { tags: c.tags.to_json })
end
end
It doesn't work when I use it like so:
<%= f.select :some_attr, {}, {class: 'my-class'} do %>
<% MYOPTIONS.each do |MYOPTION| do %>
<%= content_tag :option, MYOPTION.label, value: MYOPTION.value %>
<% end %>
<% end %>
Nor does it work if I use:
f.select :some_attr, class: 'my-class' do
The class is not applied to the select tag in the HTML.
I solved my own problem, although I don't fully understand the answer, so if someone else understands this better, I'd love to hear your answer.
To get it to work, I simply added an additional empty hash to the beginning, like so:
<%= f.select :some_attr, {}, {}, {class: 'my-class'} do %>
<% MYOPTIONS.each do |MYOPTION| do %>
<%= content_tag :option, MYOPTION.label, value: MYOPTION.value %>
<% end %>
<% end %>
The second hash is still options and the last is still html_options, so as an example, you can also add include_blank like so:
f.select :some_attr, {}, {include_blank: true}, {class: 'my-class'}
However, I don't know what the first hash is, nor what values can be passed there. I've looked at the Rails source, but I still have no clue. If you have insight into this, I'd love to hear it.
A couple oddities to be aware of:
In your example, you're using f.select, which you can find a reference for here:
https://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/select
Only the first parameters is required, the rest have defaults. However, to assign that HMTL class, you had to have a value for the fourth parameter, which necessitated having something for the second and third parameters as well.
What you ended up with is a valid solution:
<%= f.select :some_attr, {}, {}, {class: 'my-class'} do %>
<% MYOPTIONS.each do |MYOPTION| do %>
<%= content_tag :option, MYOPTION.label, value: MYOPTION.value %>
<% end %>
<% end %>
The block, when provided, takes precedence over the literal value (an empty hash in this case).
Surprisingly, if you were rendering this tag using select_tag instead of f.select, passing a block wouldn't be an option:
https://apidock.com/rails/ActionView/Helpers/FormTagHelper/select_tag
I have what I hope to be a simple question. I need to display the value for an attribute on the Edit page, while keeping the input field for the same attribute. How might this be accomplished?
Well generally you can just use the original object, like you'll have an #foo that you'll have used in your form_for statement, so you can just use that directly: = #foo.the_attribute
If you're within a partial, or elsewhere where you have only the form builder instance, then you can refer to the underlying object with the .object method, eg.:
= form_for #foo do |f|
# in here, f.object == #foo
In my case, I'm working with accepts_nested_attributes_for in two models. Event accept nested objects from Speaker. And Speaker has a perfil_id attribute which could be ['Maker', 'Developer', 'Entrepreneur', ...].
The Speaker's form is a partial rendered from the principal form, Event's form:
<%= form_for(event) do |f| %>
<%= f.text_field :title %>
<%= f.label :title, 'Event name' %>
<%= f.fields_for :speakers do |builder| %>
<%= render 'events/partials/speaker_fields', f: builder %>
<% end %>
<%= f.submit %>
<% end %>
Partial
<%= builder.number_field :name %>
<%= builder.label :name %>
<% options = options_from_collection_for_select(#profiles, 'id', 'name', f.object.member_profile_id ) %>
<%= select_tag "event[speakers_attributes][profile_id]", options, prompt: 'Select a Profile' %>
When editing Event's Speakers I wanted a select_tag to select the profile name for the actual Speaker.
I could not use an input field for this. So I need to get the correct values from the builder object and I get what I need by doing this:
f.object.profile_id
Passing it as a fourth param to the select options I get this working:
<% options = options_from_collection_for_select(#profiles, 'id', 'name', f.object.profile_id ) %>
I hope it could be useful for you too!
I know this question has been answered before, but none of the methods had worked for me.
I have a view with a select_tag that loads options from my database. <%= select_tag :nom, options_from_collection_for_select(Usuario.all, :id, :tienda), prompt: "Seleccionar tienda" %>
then, I use a link_to <%= link_to("Cargar", :action => 'rel') %><br>to load the query on my controller
def rel
#nom = params[:nom]
#tie = Av.find_by_sql(["SELECT * FROM avm.avs where usuario_id in(select id from avm.usuarios where tienda = ?)", #nom])
render('rel')
The problem is that when I select any value on my select_tag it does not pass that value and sets the value to nil...
I also used a collection_select and doesn't work either. <%= collection_select(:tienda, :tienda, Usuario.all, :id, :tienda)%>
I really broke my head off trying to figure out why. Thanks in advance!
Use form_tag:
<%= form_tag action: rel do %>
<%= select_tag :nom, options_from_collection_for_select(Usuario.all, :id, :tienda), prompt: "Seleccionar tienda" %>
<br>
<%= link_to("Cargar", '#', onclick: 'this.parentNode.submit(); return false') %>
<% end %>
Hint: replace find_by_sql by Arel:
#tie = Av.where("usuario_id IN (#{Usuario.select('id').where('tienda = ?', #nom).to_sql})")
I think you should put the select_tag in a form_tag block, and use submit_tag instead of link_to. If you just use a link no parameters will be passed to the controller (hence you get nil).
Something like:
<%= form_tag action: 'rel' do %>
<%= select_tag :nom, options_from_collection_for_select(Usuario.all, :id, :tienda), prompt: "Seleccionar tienda" %>
<%= submit_tag 'Cargar' %>
<% end %>
Just be mindful that this approach is not safe as there is no authenticity token verification.