I have the following form:
<%= form_tag classification_code_rules_path do %>
<% #classification_code_rules.each do |rule| %>
<%= fields_for "classification_code_rule[]", rule do |pf| %>
<%= pf.text_field :name %>
<% end %>
<% end %>
<%= submit_tag %>
<% end %>
It sends what I want to the server:
Parameters: { ... "classification_code_rule"=>[{"name"=>"dasdsaf"}, {"name"=>"sfsdgdfhgf"}, {"name"=>"hfghfgjhgjhg"}], "commit"=>"Save changes"}
Since classification_code_rule is an array, I handle the params as follows:
def classification_code_rule_params
params[:classification_code_rule].each do |rule_param|
rule_param.permit!
end
end
But I am getting the following error:
When assigning attributes, you must pass a hash as an argument.
How can I handle this situation where the strong param is an array?
Try something like this
params.require(:classification_code_rule).map do |rule_param|
ActionController::Parameters.new(rule_param.to_hash).permit!
end
Related
I'm trying to submit multiple records in a single form in a rail 5.2 app. I'm not using accepts nested attributes of another model, as it always seemed to bring in the entries that were previously created. The entries can't be edited once created.
<%= form_tag entry_details_path do %>
<% #entries.each do |entry| %>
<%= fields_for 'entries[]', entry do |e| %>
<div class="field">
<%= e.label :user_account_id %><br>
<%= e.text_field :user_account_id %>
</div>
<div class="field">
<%= e.label :amount %><br>
<%= e.text_field :amount %>
</div>
<% end %>
<% end %>
<div class="actions">
<%= submit_tag %>
</div>
<% end %>
The params looks like:
"entries"=>[<ActionController::Parameters {"user_account_id"=>"3", "amount"=>"55"} permitted: false>, <ActionController::Parameters {"user_account_id"=>"4", "amount"=>"65"} permitted: false>]
I want to pash the entire array of hashes to a create such as:
def create_multiple_entries
#entries = Entries.create(multiple_entries_params)
#entries.reject! { |e| e.errors.empty? }
if #entries.empty?
redirect_to entries_path
else
render 'new'
end
end
The method above works if manually enter an array. My challenge is the strong parameters(I think). Right now I have:
def leave_accrual_details_params
params.require(:entries).permit([:user_account_id, :amount])
end
Which gives me the following error:
!! #<NoMethodError: undefined method `permit' for #<Array:0x00007fee4014ec78>>
Try the following for Rails 5:
def leave_accrual_details_params
params.require(:entries).map do |p|
p.permit(:user_account_id, :amount)
end
end
I have been hitting my head against a brick wall so it is time to seek smarter people.
I am trying to create multiple records of one model using form_tag and fields_for. I have been following all the help/issues/guides I can find but it doesn't seem to work for me. I am wondering if it something that changed going to Rails 5 but more likely it is me.
Basically I want a new/create version of the task system listed at the bottom of the api page, similar to this guys puppy creator.
The "new" page loads fine with as many records as I like, so that part is ok but it doesn't seem to be creating a collection to send through, it is just overriding and thus sending through the last set of params so only creating one record.
What I have.
# routes
resources :container_returns
controller
# container returns controller
def new
#containers = Container.where(id: params[:container_ids])
#container_returns = []
#containers.each do |container|
#container_returns << ContainerReturn.new(
{
container_id: container.id,
quantity: container.amount,
uom: container.uom,
material_restriction_id: container.material_restriction_id
}
)
end
end
view
# new.html.erb
<%= form_tag container_returns_path, method: :post do %>
<% #container_returns.each do |container_return| %>
<%= fields_for 'returns[]', container_return, hidden_field_id: true do |cr| %>
<div class="field">
<%= cr.label :container_id %>
<%= cr.number_field :container_id %>
</div>
<div class="field">
<%= cr.label :material_restriction_id %>
<%= cr.number_field :material_restriction_id %>
</div>
<div class="field">
<%= cr.label :quantity %>
<%= cr.text_field :quantity %>
</div>
<div class="field">
<%= cr.label :uom %>
<%= cr.text_field :uom %>
</div>
<% end %>
<% end %>
<%= submit_tag "lots of returns" %>
<% end %>
which submits
# params submitted
Started POST "/container_returns" for 127.0.0.1 at 2018-10-19 11:00:48 +0200
Processing by ContainerReturnsController#create as HTML
Parameters: {
"utf8"=>"✓", "authenticity_token"=>[removed],
"returns"=>{"container_id"=>"405", "material_restriction_id"=>"", "quantity"=>"100.0", "uom"=>"kg"}, "commit"=>"lots of returns"
}
hopefully it is just something stupid that I missed.
UPDATE:
if I add an index to the form it now believes me that my objects are different and sends through all the params I need.
<% #container_returns.each_with_index do |container_return, index| %>
<%= fields_for 'returns[]', container_return, index: index do |cr| %>
[...]
as mentioned in the update, if I add an ID to the initial create it builds the correct array that I was expecting. What I also found was if I send through an index position that also works.
<% #container_returns.each_with_index do |container_return, index| %>
<%= fields_for 'returns[]', container_return, index: index do |cr| %>
[...]
gives me what I was expecting
Parameters: {
"returns"=>{"0"=>{"container_id"=>"400",...},
"1"=>{"container_id"=>"401",...},
etc.
},
"commit"=>"lots of returns"
}
I have a dropdown in the form i'm using
<%= f.select(:visitable_id) do %>
<% #visitors.each do |visitor| %>
<%= content_tag(:option, visitor.name, value: visitor.id, data: {:type => visitor.class.name.to_s} ) %>
<% end %>
<% end %>
When submitted I get the visitable_id in the controller. But I would also like to receive the data of the data value in the content_tag. The: data: {:type => visitor.class.name.to_s}
How can you access the second value in the controller? Any help would be appreciated!
HTML5 data attributes are not sent with the form. Nor is anything else except the name and value of the inputs.
You could solve it by passing both values through a single option.
<%= f.select(:visitable_id) do %>
<% #visitors.each do |visitor| %>
<%= content_tag(:option, visitor.name, value: "#{visitor.class.name}=visitor.id") %>
<% end %>
<% end %>
You can then parse them out by splitting the string:
klass, id = params[:visitable_id].split('=')
But make sure you whitelist the acceptable values for klass to avoid a vulnerability where a malicious user can query any model.
i am trying to access the data from a form.
<% form_tag(:action => "test") do %>
<p>
Name:
<%= text_field_tag("name","web programmer") %>
</p>
<%= submit_tag ("Save data") %>
<% end %>
this form is in views/challenges/show.html
I have written this piece of code in challenges_controller
def test
#name = params[:name]
end
before_filter :test
now,If i try to access #name variable in views/challenges/show.html
heres the code for that part
<% if #name != null %>
<%= #name %>
<% end %>
I get the following error
"undefined local variable or method `null' "
i have addded the following route to my routes.rb
get 'challenges/test'
Can someone help me out with this issue?
You need to display your form so instead of using <% %> you need to use <%= %>, checkout this answer for differences between them. By default forms use POST verb and you have defined a route for GET request. Change your form to this:
<%= form_tag({action: :test}, {method: :get}) do %>
<p>
Name:
<%= text_field_tag("name","web programmer") %>
</p>
<%= submit_tag ("Save data") %>
<% end %>
In my Rails app, I have a form which uses fields_for many times, sometimes nesting calls to fields_for.
Unfortunately, the graphic designer insists that the input fields be ordered in such a way that they are not grouped according to the model to which they pertain. Therefore, I would like to make a helper that would build the fields_for blocks easily for me, but I can't see how to get the helper method to nest a variable number of blocks.
To illustrate, I envision code looking something like the following:
<%= form_for #object do |f| %>
<!-- The helper method should have a similar effect to the following... -->
<%= f.fields_for :assoc_a do |assoc_a_builder| %>
<%= assoc_a_builder.fields_for :assoc_b do |assoc_b_builder| %>
<%= assoc_b_builder.text_field :field_name %>
<% end %>
<% end %>
<!-- ...when given the following data... -->
<%= my_helper [f, :assoc_a, :assoc_b], :text_field, :field_name %>
<% end %>
Any idea how I can accomplish this?
I implemented the following helper method (probably not the best thing around).
Example function call in view:
<%= form_for #object do |builder| %>
<%= nested_form_field 'My label text', [builder, :association_name, :field_name], :collection_select, :my_model_id, MyModel.all, :id, :name %>
<% end %>
Function definition:
# Outputs a label and input, nesting calls to fields_for if 'form' arg is an Array.
# e.g. <%= nested_form_field nil, [builder, :approved_details], :collection_select, :my_model_id, MyModel.all, :id, :name %>
# Make label_text nil for just the input tag, no wrapping elements.
def nested_form_field label_text, form, helper_method, field, *args_for_helper_method
if form.is_a? Array
if form.length > 1
form.shift.fields_for form.first do |builder|
form[0] = builder
nested_form_field label_text, form, helper_method, field, *args_for_helper_method
end
else
nested_form_field label_text, form.first, helper_method, field, *args_for_helper_method
end
else
if label_text.nil?
form.send helper_method, field, *args_for_helper_method
else
%Q(<div class=row>
<div class=span4>#{label_text}</div>
#{ form.send helper_method, field, *args_for_helper_method }
</div>).html_safe
end
end
end
<%= simple_form_for(#primer3) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<% #primer3.attributes.each_pair do |name, value| %>
<%= f.input name if value %>
<% end %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>