form to conditionally display fields based on array position - ruby-on-rails

the following rails controller action, creates an array of records to be created:
#guests = []
#quantity.times do
#guests << Guest.new
end
Then the form invokes the array of records to be created in the following manner
<%= form_tag guests_path do %>
<% #guests.each do |guest| %>
<%= fields_for 'guests[]', guest do |f| %>
The goal is to render some fields only for the first of these records/
How can the index value of the first guest be invoked (various attempts such as if #guests[0] generate errors.

I think what you are looking for is each with index
<%= form_tag guests_path do %>
<% #guests.each_with_index do |guest,index| %>
# Do something with index
<%= fields_for 'guests[]', guest do |f| %>

Related

edit form inputs not appearing for non-persisted data

I have an edit form that is not a devise form (i have a devise edit on a different view) to edit a users details. However the form inputs only appear if the data is already there. So a user is unable to add new details to the form, as the inputs don't appear at all.
Is this happening as i'm not using a devise form view?
This is the code in my own edit file:
<%= render "devise/registrations/details", f: f, resource: #resource, addressable: #resource, default_location: nil %>
Then in the devise/registration/details i have this:
<%= f.simple_fields_for :address do |fields| %>
<%= render "address/fields", fields: fields, addressable: addressable, resource: resource %>
<% end %>
However, i think the inputs are not showing up as fields are blank in the iteration. However these fields are showing up in the actual devise/edit file, even if they are blank, just not in my new one.
When using fields_for and simple_fields_for (which is basically just a pimped up version of the former) you have to "seed" the inputs in order for them to appear.
Consider this simplified plain rails example:
class UsersController < ApplicationController
def new
#user = User.new
#user.build_address
end
# ...
end
<%= simple_form_for(#user) do |f| %>
<%= f.simple_fields_for(:address) do |af| %>
<%= af.input :street %>
<% end %>
<% end %>
If we remove the line #user.build_address there will be no nested inputs. Thats because simple_fields_for calls the method #address on #user and creates inputs for the record. If the association is one or many to many it would iterate through the association. If the method returns nil or empty there are no inputs to create - it would be like calling form_for with nil.
You can also pass a second argument to fields_for to manually specify the record object:
<%= simple_form_for(#user) do |f| %>
<%= f.simple_fields_for(:address, #user.address || #user.build_address) do |af| %>
<%= af.input :street %>
<% end %>
<% end %>
In Devise you can do this by passing a block to super or by overriding #build_resource.
class MyRegistationsController < Devise::RegistrationsController
def new
super { |resource| resource.build_address }
end
end

Saving check box values to the database

I allow users to group contacts together using checkboxes in the new and edit forms:
<% current_user.contacts.all.each do |contact| %>
<% checked = #group.contacts.include?(contact) %>
<%= check_box_tag "contacts[]", contact.id, checked %>
<%= f.label contact.name %>
<% end %>
Until recently, I was able to use the following code in create action to create a group:
def create
#group = current_user.groups.new(group_params)
#contacts = Contact.find(params[:contacts])
#group.contacts << #contacts
if #group.save
......
end
To ensure that already checked values aren't added to a group during the update action, I used a hidden tag in the form.
<%= hidden_field_tag "contacts[]",'' %>
<% current_user.contacts.all.each do |contact| %>
<% checked = #group.contacts.include?(contact) %>
<%= check_box_tag "contacts[]", contact.id, checked %>
<%= f.label contact.name %>
<% end %>
Now, I'm unable to create or update a group as the hidden_field value is also passed along. An Active Record not found : Couldn't find all Contacts with 'id': (, 3, 4) (found 2 results, but was looking for 3) error. How can I solve this?
I think you want the hidden field tag to be nil rather than an empty string
<%= hidden_field_tag "contacts[]", nil %>
But as you're using rails 4 then collection_check_boxes might be of interest

proper syntax for a form_for in ruby

I am trying to write a form for an array
<%= form_for #user, html: {multipart:true} do |f| %>
<%= render "shared/error_messages", object: f.object %>
<label for="user-amenities" class="top">Amenities</label>
<ul class="group" id="user-amenities">
<% User.amenities_list.each_with_index do |amenity, index| %>
<li class="checkbox-li">
<input type="checkbox" name="user_amenities_indicies[]" value="<%= index %>">
<%= amenity %>
</input>
</li>
</ul>
<% end %>
However I am not utilizing the |f| and it is not saving the options in the amenities_indices. Any idea on how to refactor this code to utilize the f so the user information can be saved?
Try simple_form https://github.com/plataformatec/simple_form/blob/master/README.md
What you're looking for is :collection and then :as
Code Block
The refactoring you seek is basically that you need to use the f. with all your inputs
Reason being that if you call form_for, it essentially means you're calling a huge code block, in which every attribute needs to be bound to your form object, in order to render with your params hash correctly
In short - your form_for renders an HTML form, keeping the names of the <input> elements in line with the requirement of your application to load the params. The problem you have is that omitting the f. call will keep those inputs outside the scope for your params, leading to the issue you're seeing.
--
Save
If you don't have any associative data (which I've described below), you'll want to include your inputs in the f. code block:
<%= form_for #user do |f| %>
<% User.amenities_list.each_with_index do |amenity, index| %>
<%= f.check_box :user_amenities_indicies, index %>
<% end %>
<% end %>
This will pass the checked values of the user_amenities_indicies checkboxes through to your controller. This should work, and is the correct syntax for you
--
fields_for
A further addition is that I don't know whether you're trying to populate associative data or not here - but if you were trying to create data for another model, you'll want to use fields_for:
#app/controllers/users_controller.rb
Class UsersController < ApplicationController
def new
#user = User.new
#user.user_amenities.build
end
def create
#user = User.new(user_params)
#user.save
end
private
def user_params
params.require(:user).permit(:user, :params, user_amenities_attributes: [])
end
end
This will allow you to create a form using fields_for, like this:
<%= form_for #user do |f| %>
<%= f.fields_for :user_amenities do |ua| %>
# fields for user_amenities
<% end %>
<% end %>

Creating multiple objects in a form Rails

So I have an interesting problem I'm working on. I am trying to create multiple objects of the same model in one view. I would like to display all the possible objects in my view, check boxes to select which ones to create, then submit and create all the corresponding objects.
Now the objects to select are gotten using an API request and returned in JSON format. The JSON is then displayed on the view for the user to select, then an array containing all the selected objects is sent back to the controller for creation.
Here is the relevant code that I've tried so far.
objects_controller.rb
def new
#possible_objects = <api call to get objs>
#objects = []
end
def create
params[:objects].each do |obj|
# create and save obj
end
end
objects/new.html.erb
<% form_for #objects do |f| %>
<% #possible_objects.each do |api_obj| %>
<%= check_box_tag(api_obj["name"])%>
<%= api_obj["name"] %>
<% end %>
<%= f.submit %>
<% end %>
This is definitely not the right approach, as the form will not accept an empty array as a parameter. I'm not sure where else to go with this, any pointers in the right direction would be great. Thanks.
Thanks to MrYoshiji for pointing me in the right direction, this is what ended up working
objects_controller.rb
def
#possible_objects = <api call to get objs>
end
def create
params[:objects].each do |object|
new_obj = Object_Model.new( <params> )
new_obj.save
if !new_obj.save
redirect_to <path>, alert: new_obj.errors.full_messages and return
end
end
redirect_to <path>, notice: 'Successfully created.'
end
objects/new.html.erb
<%= form_tag objects_path(method: :post) do %>
<% #possible_objects.each do |api_obj| %>
<%= check_box_tag 'objects[]', api_obj %>
<%= possible_object["name"] %>
<% end %>
<%= submit_tag 'Create'%>
<% end %>
Can you try the following?
# view
<% form_tag my_objects_path(method: :post) do |f| %>
<% #possible_objects.each do |api_obj| %>
<%= check_box_tag 'objects[names][]', api_obj["name"] %>
<%= api_obj["name"] %>
<% end %>
<%= f.submit %>
<% end %>
# controller
def create
params[:objects][:names].each do |obj_name|
YourModelForObject.create(name: obj_name)
end
end
See this comment on the documentation of check_box_tag: http://apidock.com/rails/ActionView/Helpers/FormTagHelper/check_box_tag#64-Pass-id-collections-with-check-box-tags

Rails, array of objects form

I'm developing a rails application.
I want the user to be able to make a selection between an array of models
In one controller, I create an array of models.
def myController
#data = []
#data += [MyData.find(2)]
#data += [MyData.find(5)]
#data += [MyData.find(7)]
end
In the view, I can't use the form_for because can't be used in an array, so I have:
<%= form_tag 'myOp' do |f|%>
<%= fields_for :test, #data do |builder|%>
<%= render 'sub_form', :f => builder %>
<% end %>
<% end %>
Now in the sub_form, I want to recieve each of the items of the array, but instead, I'm getting the full array.
How can I get each of the items of the array in the subform?
Is there a better way to do this?
Thanks
So first in your controller
def my_action
#datas = MyData.find(2, 5, 7)
end
Then in your view
You need to iterate through the #datas array and yield the fields for each object. That is because fields_for yields fields for one object only, not arrays of objects.
<%= form_tag 'myOp' do |f|%>
<% #datas.each_with_index do |data, i| %>
<%= fields_for "test_#{i}", data do |builder|%>
<%= render 'sub_form', :f => builder %>
<% end %>
<% end %>
<% end %>
I hope this will correct the issue:
<%= form_tag 'myOp' do |f|%>
<%= fields_for :test, #data.each do |builder|%>
<%= render 'sub_form', :f => builder %>
<% end %>
<% end %>
Normally an array object can be seperated using .each method. May that would work here also. Try it.

Resources