Passing array via hidden fields to rails - ruby-on-rails

i have a hidden_tag like this in my form
<%= f.hidden_field :loc , {:multiple => true} %>
which renders to
<input id="business_loc" multiple="multiple" name="business[loc][]" type="hidden" style="color: rgb(175, 175, 175); " value="">
currently am setting the business_loc value as a comma seperated string hoping rails would recognize when submit the form. But this is the value i got on the server side
"loc"=>["80.22167450000006,13.0454044"]
instead
"loc"=>[80.22167450000006,13.0454044]
how do i set the correct value in hidden field, so rails can understand it correctly.

You need to use multiple hidden fields, one for each element of the array of values.
For example:
<input id="business_loc" multiple="multiple" name="business[loc][]" type="hidden" style="color: rgb(175, 175, 175); " value="80.22167450000006">
<input id="business_loc" multiple="multiple" name="business[loc][]" type="hidden" style="color: rgb(175, 175, 175); " value="13.0454044">
...if you need code to dynamically add these with JS, here's a jQuery example:
var field = $('<input id="business_loc" multiple="multiple" name="business[loc][]" type="hidden" style="color: rgb(175, 175, 175); " value="13.0454044">');
var form = $('#your-form-id');
form.append(field);

I've found text_area's to make things work without having to add a bunch of hidden forms. Just set the value of the text area to something that looks like [1,31,51,61] and it should work, assuming in your model you have serialize :var

I had this same problem recently. My solution was to handle it on the server side by simply splitting the array at the comma. In my case it looks like this:
# thing_that_has_many_objects.rb <-- showing custom setter method from the model because my example involves using a virtual attribute
# params[object_ids] = ["1,2,3,4,5"] <-- from the form - note the format of array with only one element
def objects=(object_ids)
split_array = object_ids[0].split(',')
split_array.each do |id|
self.objects.build(object_id: id)
end
end

Related

undefined method `map' for "1,2":String

I need to pass an array in a params, possible? Values can be, for example, ["1","2","3","4","5"] and these are strings but needs to eb converted to integers later.
I use a react_component in between a rails form_for. The html is like this:
<input type="hidden" name="people_id" id="people_id" value={this.state.people} />
The people array looks like this:
How can I pass the array in the value of the hidden field? The server error I got was
Im trying to do something like this in a model:
ids = params[:people_id]
ids.map do |b|
Foo.create!(people_id: b.to_i)
end
If I ids.split(",").map I get symbol to int error.
Edit:
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
Still not sure what the issue is as nothing works. Here is a minimal reproduction of my code:
This answer is my react component and that's how I add to the array. Still in the component, I have the hidden field:
<input type="hidden" name="[people_id][]" id="people_id" value={this.state.people} />
_form.html.erb:
<%= form_for resource, as: resource_name, url: registration_path(resource_name), :html => { :data => {:abide => ''}, :multipart => true } do |f| %>
<!-- react component goes here -->
<%= f.submit "Go", class: "large button" %>
<% end %>
The story is, guest can select few people during registration in one go. Those people will be notified when registration is complete. Think of it as "I am inviting these people to bid on my tender". Those numbers, in the array, are user_ids.
users/registrations_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController
# POST /resource
def create
super do |resource|
ids = params[:people_id].pop # logs now as "people_id"=>["1,2"]
resource.save!(ids.split(",").map |b| Foo.create!(people_id: b.to_i) end)
end
end
end
New error on line resource.save:
no implicit conversion of Symbol into Integer
Edit #2
If I only have, in the create method:
ids.split(",").map do |b|
resource.save!(Foo.create!(people_id: b.to_i))
end
It works! Foo is created two times each with the correct people_id.
Because I am creating more objects: Bar, I do not know how to do that in:
resource.save!(<the loop for Foo> && Bar.create!())
The flow must be:
Device creates the User
Foo is created with the loop
Bar is created
etc
It has to be done that way as an User object is created on the fly.
In Rails you use parameter keys with brackets on the end to pass arrays.
However you should not concatenate the values as a comma seperated list but rather send each value as a seperate param:
GET /foo?people_ids[]=1&people_ids[]=2&people_ids[]=3
That way Rails will unpack the parameters into an array:
Parameters: {"people_ids"=>["1", "2", "3"]}
The same principle applies to POST except that the params are sent as formdata.
If you want a good example of how this works then look at the rails collection_check_boxes helper and the inputs it generates.
<input id="post_author_ids_1" name="post[author_ids][]" type="checkbox" value="1" checked="checked" />
<label for="post_author_ids_1">D. Heinemeier Hansson</label>
<input id="post_author_ids_2" name="post[author_ids][]" type="checkbox" value="2" />
<label for="post_author_ids_2">D. Thomas</label>
<input id="post_author_ids_3" name="post[author_ids][]" type="checkbox" value="3" />
<label for="post_author_ids_3">M. Clark</label>
<input name="post[author_ids][]" type="hidden" value="" />
Updated:
If you intend to implement you own array parameters by splitting a string you should not end the input with brackets:
<input type="hidden" name="[people_id][]" value="1,2,3">
{"people_id"=>["1,2,3"]}
Notice how people_id is treated as an array and the input value is the first element.
While you could do params[:people_id].first.split(",") it makes more sense to use the correct key from the get go:
<input type="hidden" name="people_id" value="1,2,3">
Also you don't really want to wrap the "root" key in brackets. Thats used in rails to nest a param key in a hash eg. user[name].

Query string not being passed to controller

I have what should be a relatively simple form in Rails that I'm using to send an email for two different previews, a desktop preview and a mobile preview.
<form id="email-form" role="form" action="<%= action_name == 'desktop_preview' ? email_preview_newsletter_path(#newsletter) : email_preview_newsletter_path(#newsletter, mobile: 'true') %>">
<label for="email_address">Email</label>
<input type="email" id="email_address" name="email_address" value="<%= params[:email_address] %>" placeholder="PLEASE ENTER EMAIL">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<input type="submit" value="Send" class="btn btn-primary"></input>
</form>
Right now I have it setup so that both previews get sent to the same endpoint, '/email_preview', but in the case of the mobile_preview I want to pass in a 'mobile' query string so that it ends up looking like this:
'/email_preview?mobile=true'
When I inspect the form on the page everything looks in order, however when it gets passed to the controller the 'mobile' part of the query string disappears and only the 'email_address' exists.
I suppose I could pass in the mobile value as a hidden field, but something about that just doesn't feel right to me. What is the best way to setup this form so that both the 'mobile' and 'email_address' key value pairs are passed as query strings when sent to the controller?
In the process of writing out this question I realized exactly what the problem was:
I had the form setup as a GET request as opposed to a POST request.
This was causing any pre-established query strings to get erased in the process of setting up the GET params being defined in the form (in this case, the 'email_address' param). Changing the form from GET to POST, (i.e. form method="POST")
Took care of this issue. Please note that if you are going to manually setup a form like this in rails then you also need to explicitly take care of the csrf token. This can be done by inserting the following input with the helper method into your form:
input type="hidden" name="authenticity_token" value="<%=form_authenticity_token%>"

Multiple Select Sending Empty String to Rails Controller

I have a tradie model that has many tradie_category models. In the form for the tradie I added the following:
= form_for #tradie do |tradie|
= tradie.select :tradie_category_ids, #categories, {}, { multiple: true }
In the HTML, the following is generated...
<form accept-charset="UTF-8" action="/add_a_tradies/create" class="new_tradie" method="post">
<input name="tradie[tradie_category_ids][]" type="hidden" value="">
<select class="form-control" id="tradie_tradie_category_ids" multiple="multiple" name="tradie[tradie_category_ids][]">
<option value="2">mechanic</option>
<option value="1">plumber</option>
</select>
</form>
I removed the authenticity token and submit button because it's not necessary with my problem. Whenever I do post the form, the params tradie_category_ids is returned as an empty string. What's wrong and how do I fix it so I can created multiple tradie categories for the tradie that is created.?
It seems this issue was also reported in another question: Why is the first element always blank in my Rails multi-select, using an embedded array?
They outline the specification for it and how it will be resolved in Rails 4. The second most popular response says how to apply a fix for it in the mean time.
Try this
= form_for #tradie do |tradie|
= tradie.select :tradie_category_ids, #categories, {}, { multiple: "true" or 'true' }
Note the quotes around
{ multiple: "true" or 'true' } in

select checkbox with hidden input type

Folks,
I am using watir-webdriver, I have a piece in my HTML DOM which gets generated on the fly when I enter some credentials, this piece has a bunch of checkboxes, the number of checkboxes vary, I have to select one checkbox, below is an example of this, here I want to select the second checkbox(the one that has value "BS" for the input type hidden but the value for input type checkbox is same for all):
<li class="dir">
<input type="checkbox" value="1" onclick="$(this).next('.should_destroy').value = (this.checked?0:1)" name="should_not_destroy">
<input class="should_destroy" type="hidden" value="1" name="import[dir_attributes][][should_destroy]">
<input type="hidden" value="" name="import[dir_attributes][][id]">
<input type="hidden" value="Automation" name="import[dir_attributes][][path]">
<span class="dir_mode">Include</span>
Automation
</li>
<li class="dir">
<input type="checkbox" value="1" onclick="$(this).next('.should_destroy').value = (this.checked?0:1)" name="should_not_destroy">
<input class="should_destroy" type="hidden" value="1" name="import[dir_attributes][][should_destroy]">
<input type="hidden" value="" name="import[dir_attributes][][id]">
<input type="hidden" value="BS" name="import[dir_attributes][][path]">
<span class="dir_mode">Include</span>
BS
</li>
I may be able to do this with XPATH, but wanted to try a non XPATH solution. The input type hidden has the appropriate value that I need, for example above the second checkbox has value "BS" for input type hidden. I tried to use the hidden method like this:
h = ##browser.hidden(:value, "BS")
h.select
But I dont know what to do after this. I am trying to select the checkbox based on the value of the hidden element. Any feedback is much appreciated.
I would suggest using the visible elements instead. I think it makes it easier to read the test and seems more stable.
Try:
##browser.li(:class => 'dir', :text => /BS/).checkbox.set
Here we go, I think this will do it
Since you have to select the checkbox based on the hidden, you're going to have to go up a level to the containing li, then drill down to the checkbox
#browser.hidden(value: 'BS').parent.checkboxes.first.set

MVC partial views (or editor templates): append index to input name for multiple use of form?

How can I add an index, to input names and ids in forms that are used multiple times in one view?
I have created a form for photo rotator that provides the ability to edit a context-specific caption for each photo (billboard). I need to be able to include multiple instances of the form fields for this so the admins can edit all of the captions for a rotator's set of photos in one view, and so I need a way to keep ids and field names unique.
Editor templates automatically add a prefix, but when I loop over the photos like this:
<% foreach (var billboard in Model.Billboards ) { %>
<%: Html.EditorFor(x => billboard, "BillboardForm")%>
<% } %>
It simply adds "billboard_" as the prefix, which doesn't solve my problem.
I'd like to append the rotator id billboard id to the end of each input name and id:
<form action="/Rotators/Edit/5" method="post">
<input id="billboard_21_RotatorId" name="billboard_21_RotatorId" type="hidden" value="5" />
<input id="billboard_21_ImageId" name="billboard_21_ImageId" type="hidden" value="19" />
<label for="billboard_21_Title">Title</label>
<textarea cols="20" id="billboard_21_Title" name="billboard_21_Title" rows="2">Title</textarea>
<label for="billboard_21_Caption">Caption</label>
<textarea cols="20" id="billboard_21_Caption" name="billboard_21_Caption" rows="2">This is the caption</textarea>
<select id="billboard_21_TopicId" name="billboard_21_TopicId">
<option value="1">1st option</option>
</select>
</form>
Any easy way to do this??
plz download this sampel code from steve sanderson's blog post. it does not directly relate to your question. But in demo project you will find BeginCollectionItem html helper that is changing the prefix scope for input or series of inputs. This can give u a starting point
Edit:
in ur editor template u can use following method from steve's code like
using(Html.BeginHtmlFieldPrefixScope("BillBoard" + Model.ID.ToString())){
<label>Image<label>
#Html.TextBoxFor(x=>x.Image)
<label>Caption</label>
#Html.TextBoxFor(x=>x.Caption)
}
if ID is property of your model and has value e.g 4 then u will have html like
<label>Image</label>
<input name = "BillBoard4.Image" .../>
<label>Caption</label>
<input name = "BillBoard4.Caption" .../>
Note: The features used below may not have existed 4 years ago...
Firstly, you don't have to use beestings any more, the # syntax used
in the Razor examples is far cleaner.
The method you're calling is in System.Web.Mvc.Html.EditorExtensions:
public static MvcHtmlString EditorFor<TModel, TValue>(
this HtmlHelper<TModel> html,
Expression<Func<TModel, TValue>> expression
)
...
Your approach:
#foreach (var billboard in Model.Billboards ) {
#Html.EditorFor(x => billboard, "BillboardForm")
}
The body of expression x => billboard is a ConstantExpression.
This approach results in the appropriate scope applying in the EditorTemplate:
#for (var i = 0; i < Model.BillBoards.Count(); i++)
{
#Html.EditorFor(x => Model.BillBoards[i], "BillboardForm")
}
If Model.BillBoards is an array, the expression x => Model.BillBoards[i] can be described as
SimpleBinaryExpression{NodeType:ArrayIndex}(
Left: ConstantExpression,
Right: ConstantExpression
)
If Model.BillBoards is an IList<T>, the expression x => Model.BillBoards[i] can be described as
InstanceMethodCallExpressionN(
Method:RuntimeMethodInfo(IList<T>.get_Item (Int32 index)),
Object:PropertyExpression(ConstantExpression),
Arguments:[ConstantExpression]
)
The overloads of EditorFor() that accept Expressions check the expression body's Type and NodeType and construct the scope accordingly.
This code should be equivalent if you don't have anything else inside the loop:
#Html.EditorFor(x => Model.BillBoards, "BillboardForm")
If you only have a read-only view and an editing view, you can rename your templates and remove the second parameter. Assuming BillBoard is your Model class, rename BillboardForm.cshtml to EditorTemplates/BillBoard.cshtml, then change the code to
#Html.EditorFor(x => Model.BillBoards)

Resources