Can someone help me figure out how to require and permit a set of parameters that looks like this:
<ActionController::Parameters {
"people"=>[
{"id"=>"1", "first"=>"Jane", "last"=>"Doe"},
{"id"=>"2", "first"=>"John", "last"=>"Doe"}
]
} permitted: false>
The data is being prepared in Javascript with this:
const formData = new FormData()
people.forEach(person => {
formData.append('people[][id]', person.id)
formData.append('people[][first]', person.first)
formData.append('people[][last]', person.last)
})
I've tried some different formats (is there a more Railsish way to structure that?), and lots of different inputs to permit with no luck. My current attempt is
params.require(:people).each { |person| person.permit(:id, :first, :last) }
This doesn't crash, but also doesn't seem actually permit anything.
I've also tried setting up my data with people[][person][id] so I could do
params.require(:people).permit(person: [:id, :first, :last])
but that didn't work either.
params.require(:people)
params.permit(people: [:id, :first, :last])
The first line is just to raise an error if the key is missing. .permit(people: [:id, :first, :last]) permits the people key and an array of hashes with the keys :id, :first, :last.
Related
Consider the following rails link:
search_path(:query => params[:query], type: params[:type], sort: params[:sort])
There is a lot of duplication here. Is it possible to define these parameters in an array and they pass into the link? Eg.
params: [:query, :type, :sort] # -> pass each into the link like "key: value"
I can't think of how you could do it exactly passing it as an array like you show, however you could do something like:
search_path(params.slice(:query, :type, :sort))
This will give you the same hash you're passing in. In my opinion, it's a little cleaner.
parameters = ActionController::Parameters.new(query: 'query', type: 'type', sort: 'sort', other: 'other')
=> {"query"=>"query", "type"=>"type", "sort"=>"sort", "other"=>"other"}
parameters.slice(:query, :type, :sort)
=> {"query"=>"query", "type"=>"type", "sort"=>"sort"}
I was stuck at a point badly..when I was doing with Rails form_for submit request with remote:true with a hidden field containing array of hashes as below:
<%= f.hidden_field :staff_stat_data, :value =>[{a: "a"} , {b: "b"}] %>
then I am getting hash as a string in parameter like:
"{:a=>\"a\"} {:b=>\"b\"}"
Badly stuck with this.
You're not getting a hash, you're getting a string that kind of looks like a hash.
Remember that each parameter is just a string, that's how data is passed between clients and servers. Rails can sometimes receive an array, but only when the parameter names describe an array (e.g, "user_favourites[]").
If you want to pass a single string that represents an array or hash, you can use JSON to encode/parse the data.
In your view, first change the array to its JSON representation like this:
<%= f.hidden_field :staff_stat_data, :value => [{a: "a"} , {b: "b"}].to_json %>
Then in your controller, change it to a hash by parsing the JSON like this:
staff_stat_data = JSON.parse(params[:staff_stat_data])
This will return you an array, where each element is a hash, just like you want.
You can try this out easily in your Rails console.
json = [{a: "a"} , {b: "b"}].to_json # => "[{\"a\":\"a\"},{\"b\":\"b\"}]"
JSON.parse(json) # => [{a: "a"} , {b: "b"}]
I'm using a collection_select to pass the param product_id from a view to the controller, but i'm having problems on acessing that value. The other parameters are fine. If i do something like aux = params[:product_id] it saves the value 0 instead of 1, that is the value that the controller receives as you can see in the request log. Any help would be appreciated!
PS: I think it may be related with the curly brackets you can see around the product_id param as you can see in the request log
<%= collection_select(:params, :product_id, Product.all, :id, :name, :prompt => true) %>
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"hE4qrSZnI8LLy6sNzR2fkRxKZpFoOHZLun6Z/cIsHDxGcCaC+zVPLk1qYFhf6iuhbmsZX0us75FIiqJ7c06Mxw==",
"params"=>{"product_id"=>"1"},
"quantity"=>"1",
"event_id"=>"5",
"commit"=>"GO!",
"method"=>"post"}
You're sending a key params inside of the real params, to access your value do it like:
params[:params][:product_id]
or use:
collection_select(:object, :product_id, Product.all, :id, :name, prompt: true)
to get product_id in params
So over the last 2 hours, I've been trying to fill a combobox with all my users. I managed to get all firstnames in a combobox, but I want their full name in the combobox. No problem you would think, just concatenate the names and you're done. + and << should be the concatenation operator to do this.So this is my code:
<%= collection_select(:user, :user_id, #users, :user_id, :user_firstname + :user_lastname, {:prompt => false}) %>
But it seems RoR doesn't accept this:
undefined method `+' for :user_firstname:Symbol
What am I doing wrong?
What you need to do is define a method on the User model that does this concatenation for you. Symbols can't be concatenated. So to your user model, add this function:
def name
"#{self.first_name} #{self.last_name}"
end
then change the code in the view to this:
<%= collection_select(:user, :user_id, #users, :user_id, :name, {:prompt => false}) %>
Should do the trick.
This isn't really rails giving you an error, it's ruby. You're trying to combine the symbols :user_firstname and :user_lastname
A symbol is a variable type, just like integer, string, or datetime (Well technically they're classes, but in this context we can think of them as variable types). They look similar to strings, and can function similarly to them, but there is no definition for the behavior of symbol concatenation. Essentially you're trying to send the method user_firstnameuser_lastname which is just as non-sensical as trying to concat two Symbols.
What you need to understand is that this parameter is looking for a method on your User object, and it won't understand the combination of two symbols. You need to define a method in your model:
def fullname
[user_firstname, user_lastname].reject{|v| v.blank?}.join(" ")
end
This'll return your first + last name for you, and then in the parameter you should send :fullname (because that's the method it'll call on each user object in the collection):
<%= collection_select(:user, :user_id, #users, :user_id, :fullname, {:prompt => false})%>
Also, it's considered poor practice to prefix every single column with the table name. user.user_firstname just looks redundant. I prefer to drop that prefix, but I guess it's mostly up to personal preference.
The arguments for value and display attribute are method names, not expressions on a user object.
To control the format more precisely, you can use the select tag helper instead:
select("user", "user_id", #users.each {|u| [ "#{u.first_name u.last_name}", u.user_id ] })
The docs are pretty useful.
I've got a form that allows the user to put together a hash.
The hashes desired end format would be something like this:
{1 => "a", 2 => "x", 3 => "m"}
I can build up something similar by having lots of inputs that have internal brackets in their names:
<%= hidden_field_tag "article[1]", :value => a %>
However, the end result is that builds a hash where all the keys are strings and not integers:
{"1" => "a", "2" => "x", "3" => "m"}
I'm currently fixing this by generating a new hash in the controller by looping over the input hash, and then assigning that to params. Is there a cleaner, DRYer way to do this?
Your params will always come in with string keys and values. The easiest way to fix this is to either write your own extension to Hash or simply inject as required:
numeric_keys = params['article'].inject({ }) do |h, (k, v)|
h[k.to_i] = v
h
end
Then you have a hash with the keys converted to integer values, as you like.
A simple extension might be:
class Hash
def remap_keys
inject({ }) do |h, (k, v)|
h[yield(k)] = v
h
end
end
end
This is much more generic and can be used along the lines of:
params['article'].remap_keys(&:to_i)
That depends a bit what you want to use it for. Maybe it is easier to just use strings as keys, and do the "conversion" when accessing the array (or not at all)?
It is also possible to build an array using something like
<%= hidden_field_tag "article[]", :value => "x" %>
this will return "article" as an array, and you can access it directly by index. However, there is no way to influence the position - the array will contain all values in order of appearance.
Lastly, you can make your own version of Hash or just modify the keys, as has been explained.