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.
Related
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| %>
I have a model called Foo, which has many bars. I want to be able to add / remove foo.bars by adding or removing associated foo.bars.ids. How can I achieve this?
I tried:
Foo#edit
def edit
#bars = #foo.bars
end
Form
<%= form_for #foo, url: edit_foo_path(#foo.id) do |p| %>
...
<%= p.text_area #bars %> #<= returns undefined method `Collection..' for `foo`
...
<%= p.fields_for #foo.bars do |b| %>
<%= b.text_area :ids %> #<= returns in 'unpermitted param 'bar' on #update'
<% end %>
...
<% end %>
I'm thinking fields_for would not work here anyway since I am not updating bar's attributes. Instead, I want to be able to add / remove foo.bars by listings their ids
Hook into the Foo#bar_ids and Foo#bar_ids= methods which the has_many association gives you. You could do this via checkboxes for example.
<% form_for #foo do |f| %>
<% #bars.each do |bar| %>
<div class="bar--checkbox">
<%= check_box_tag "foo[bar_ids]", bar.id, #foo.bar_ids.include?(bar.id) %>
<%= bar.name %>
</div>
<% end %>
<%= f.submit "Save" %>
<% end %>
Now, in params you'll get something like
params = {:id => 123, :foo => {:bar_ids => [1, 5, 8, 10]})
and you can do the usual update controller code:
#foo = Foo.where(:id => params[:id])
#updated = #foo.update_attributes(params[:foo])
which is like doing this:
#foo.bar_ids = [1, 5, 8, 10]
#foo.save
NOTE - in your code you're setting #bars to be #foo's current bars. It could be all the bars in the system for example, which would be better in terms of adding and removing whichever bars you want.
I am trying to create a checklist in rails using form_for. This checklist is taken from a table which I gained in the create action of my sign_ins controller:
#content = OrientationContent.where(site_id: session[:site_id])
In my view I want to use the form_for helper to iterate through the list in #content:
<%= form_for(:sign_ups ) do |f| %>
<% #content.each do |c| %>
<%= f.check_box nil %> <%= c %> <br>
<% end %>
<% end %>
However this is not working and it produces two square brackets on the page: [].
How do I go through the list and print the name while creating a check box on the left of it? The check box does not have any meaning or data, I just need it present for reference.
Solved:
In the controller, need to pluck an individual field:
#content = OrientationContent.where(site_id: 1).pluck(:content)
In the view, structure as so:
<%= form_for(:sign_ups) do |f| %>
<% #content.each do |c| %>
<%= f.check_box nil %> <%= c %> <br>
<% end %>
<% end %>
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
I have a partial that needs to have some controller logic run before it can render without issue. Is there some way to associate the partial with some controller logic that is run whenever it is rendered?
For example, this is what my current code looks like:
MyDataController:
class MyDataController < ApplicationController
def view
#obj = MyData.find(params[:id])
run_logic_for_partial
end
def some_method_i_dont_know_about
#obj = MyData.find(params[:id])
# Doesn't call run_logic_for_partial
end
def run_logic_for_partial
#important_hash = {}
for item in #obj.internal_array
#important_hash[item] = "Important value"
end
end
end
view.html.erb:
Name: <%= #obj.name %>
Date: <%= #obj.date %>
<%= render :partial => "my_partial" %>
some_method_i_dont_know_about.html.erb:
Name: <%= #obj.name %>
User: <%= #obj.user %>
<%# This will fail because #important_hash isn't initialized %>
<%= render :partial => "my_partial" %>
_my_partial.html.erb:
<% for item in #obj.internal_array %>
<%= item.to_s %>: <%= #important_hash[item] %>
<% end %>
How can I make sure that run_logic_for_partial is called whenever _my_partial.html.erb is rendered, even if the method isn't explicitly called from the controller? If I can't, are there any common patterns used in Rails to deal with these kinds of situations?
You should be using a views helper for this sort of logic. If you generated your resource using rails generate, a helper file for your resource should already be in your app/helpers directory. Otherwise, you can create it yourself:
# app/helpers/my_data.rb
module MyDataHelper
def run_logic_for_partial(obj)
important_hash = {}
for item in obj.internal_array
important_hash[item] = "Important value" // you'll need to modify this keying to suit your purposes
end
important_hash
end
end
Then, in your partial, pass the object you want to operate on to your helper:
# _my_partial.html.erb
<% important_hash = run_logic_for_partial(#obj) %>
<% for item in important_hash %>
<%= item.to_s %>: <%= important_hash[item] %>
<% end %>
Or:
# app/helpers/my_data.rb
module MyDataHelper
def run_logic_for_partial(item)
# Do your logic
"Important value"
end
end
# _my_partial.html.erb
<% for item in #obj.internal_array %>
<%= item.to_s %>: <%= run_logic_for_partial(item) %>
<% end %>
EDIT:
As commented Ian Kennedy points out, this logic can also reasonably be abstracted into a convenience method in your model:
# app/models/obj.rb
def important_hash
hash = {}
for item in internal_array
important_hash[item] = "Important value"
end
hash
end
Then, you'd access the important_hash attribute in the following manner in your partial:
# _my_partial.html.erb
<% for item in #obj.important_hash %>
<%= item.to_s %>: <%= item %>
<% end %>
What you're trying to do runs against the grain of how Rails controllers/views are designed to be used. It would be better to structure things a bit differently. Why not put run_logic_for_partial into a helper, and make it take an argument (rather than implicitly working on #obj)?
To see an example of a view "helper", look here: http://guides.rubyonrails.org/getting_started.html#view-helpers