Rails strong parameters of enumerated type - ruby-on-rails

I've got paramerers which are sent by a form like:
{ "mac"=>{"0"=>["111", "222"], "1"=>["333", "444"]} }
How can I permit them in a proper way, because I've found just an ugly solution:
params.permit(mac: Hash[(0..100).map { |i| [i.to_s, []] }])

Fetch the keys out of the :mac key and then permit them.
mac_keys = params.fetch(:mac, {}).keys
params.permit(mac: mac_keys)

will you consider the hash's keep_if method, as params is just a hash.
params[:mac].keep_if {|k, v| k.to_i >= 0 and k.to_i <= 100}

Related

ruby delete hash of hash based on identical values for different keys

I have a hash of hashes like this:
authors = {"7"=> {"id"=>"60"} , "0"=> {"id"=>"60"} , "1"=> {"id"=>"99"}, "8"=> {"id"=>"99"}, "15"=> {"id"=>"19"} }
I want to merge each hash where the id of the hash in that hash is duplicated (or remove each second hash with same hash of hash id).
In this case, I want to end up with
authors = {"7"=> {"id"=>"60"} , "1"=> {"id"=>"99"}, "15"=> {"id"=>"19"}}
There are quite a few questions on sorting hashes of hashes, and I've been trying to get my head around this, but I don't see how to achieve this.
Here are two ways.
#1
require 'set'
st = Set.new
authors.select { |_,v| st.add?(v) }
#=> {"7"=>{"id"=>"60"}, "1"=>{"id"=>"99"}, "15"=>{"id"=>"19"}}
#2
authors.reverse_each.with_object({}) { |(k,v),h| h[v] = k }.
reverse_each.with_object({}) { |(k,v),h| h[v] = [k] }
#=> {"7"=>[{"id"=>"60"}], "1"=>[{"id"=>"99"}], "15"=>[{"id"=>"19"}]}
or
authors.reverse_each.to_h.invert.invert.reverse_each.to_h
Try this one
authors.to_a.uniq { |item| item.last["id"] }.to_h
=> {"7"=>{"id"=>"60"}, "1"=>{"id"=>"99"}, "15"=>{"id"=>"19"}}
uniq method with a block can do the work

How to accept hash parameters

Here are the parameters being passed:
{"utf8"=>"✓",
"authenticity_token"=>"j3R0aro/Arg4Y3Zu6zIIxZYbYTxqoqyKEGc11CkvYDU=",
"inventory"=>{
"9"=>"0",
"12"=>"0",
"1"=>"0",
"2"=>"0",
"3"=>"0",
"10"=>"0",
"11"=>"0",
...
}
}
I can't seem to grab the params in inventory, for whatever reason, the code below keeps wanting to grab the inventory as one long array of hashes rather than the hashes themselves. What am I doing wrong?
def inventory_params
params.permit(inventory: [{:itemlist_id => :quantity}] )
#inventory_params = params.reject { |k, v| (v == "") || ( v == "0" ) }
end
I also tried params.permit(inventory: {:itemlist_id => :quantity} ) which didn't work either
params.require(:model_name).permit(:inventory)
will work I guess.
What ended up working:
params["inventory"]

Rails array sort

I have in rails this array:
#array = [{'82'=>'1'}, {'81'=>'0'},{'32'=>'12'}]
How can I sort it to have that result? I want to have this:
#array = [{'32'=>'12'}, {'82'=>'1'},{'81'=>'0'}]
and next - how then I can get #array[0] hash key (32)
This is an array of hash where hash is {'user_id'=>'counter'}
This will sort the array by value, in descending order, in place:
array.sort! { |h1, h2| h2.values.first <=> h1.values.first }
It can also be done with sort_by! followed by reverse!.
array.sort_by! { |h| h.values } .reverse!
Then, these will get you the first value and first key, respectively:
array.first.values.first
array.first.keys.first
Just append keys.sort to the end of the array. Use #array.keys.sort
#array.sort { |x,y| x.keys.first <=> y.keys.first }
Try using Enumerable#sort_by, and Array#reverse! to change the order.
> #array.sort_by { |h| h.values.first }.reverse!
=> [{"32"=>"12"}, {"82"=>"1"}, {"81"=>"0"}]

Hashes in hashes ruby on rails

I'm passing the below information through parameter from view to controller
parameters:{"Something"=>{"a" => "1", "b" => "0", "c" => "1", "d" => "0" #and so on}}
I want to access all the characters that have "1" as their value and concatenate into the string.
I tried
Something.each do |key, value|
if(value == "1")
string = string + key
end
end
It is throwing error saying that it could not execute nil.each and that i might be expecting an array.
It appears to me that Something is a hash and in turn has some hashes in it.
So i initialised Something to
Something = Hash.new { |Something, k| Something[k] = Hash.new }
But i still get the same error.
Just work with the params hash. This should do what you need:
params["Something"].select {|k, v| v == "1"}.keys.reduce(:+)
select filters the params to only those with the value "1"
keys returns an array with all the keys in the hash
reduce joins all elements with a concat operation (+)
Edit
To concatenate and add the "Extra" word:
For each parameter:
params["Something"].select {|k, v| v == "1"}.keys.inject("") {|result, p| result += "Extra #{p}"}
Only to the extra parameters, but not to the first one:
params["Something"].select {|k, v| v == "1"}.keys.inject {|result, p| result += "Extra #{p}"}
See more information on inject here.

Ruby on Rails: Array to Hash with (key, array of values)

Lets say I have an Array of content_categories (content_categories = user.content_categories)
I now want to add every element belonging to a certain categorie to content_categories with the category as a key and the the content-item IDs as elements of a set
In PHP something like this is possible:
foreach ($content_categories as $key => $category) {
$contentsByCategoryIDArray = Category.getContents($category[id])
$content_categories[$key][$contentsByCategoryIDArray]
}
Is there an easy way in rails to do this?
Greets,
Nico
Your question isn't really a Rails question, it's a general Ruby programming question.
Your description isn't very clear, but from what I understand, you want to group IDs for common categories using a Hash. There are various other ways of doing this, but this is easy to understand::
ary = [
'cat1', {:id => 1},
'cat2', {:id => 2},
'cat1', {:id => 3}
]
hsh = {}
ary.each_slice(2) { |a|
key,category = a
hsh[key] ? hsh[key] << category[:id] : hsh[key] = [category[:id]]
}
hsh # => {"cat1"=>[1, 3], "cat2"=>[2]}
I'm using a simple Array with a category, followed by a simple hash representing some object instance, because it makes it easy to visualize. If you have a more complex object, replace the hash entries with those objects, and tweak how you access the ID in the ternary (?:) line.
Using Enumerable.inject():
hsh = ary.each_slice(2).inject({}) { |h,a|
key,category = a
h[key] ? h[key] << category[:id] : h[key] = [category[:id]]
h
}
hsh # => {"cat1"=>[1, 3], "cat2"=>[2]}
Enumerable.group_by() could probably shrink it even more, but my brain is fading.
I'd use Enumerable#inject
content_categories = content_categories_array.inject({}){ |memo, category| memo[category] = Category.get_contents(category); memo }
Hash[content_categories.map{|cat|
[cat, Category.get_contents(cat)]
}]
Not really the right answer, because you want IDs in your array, but I post it anyway, because it's nice and short, and you might actually get away with it:
content_categories.group_by(&:category)
content_categories.each do |k,v|
content_categories[k] = Category.getContents(v)
end
I suppose it's works
If i understand correctly, content_categories is an array of categories, which needs to be turned into a hash of categories, and their elements.
content_categories_array = content_categories
content_categories_hash = {}
content_categories_array.each do |category|
content_categories_hash[category] = Category.get_contents(category)
end
content_categories = content_categories_hash
That is the long version, which you can also write like
content_categories = {}.tap do |hash|
content_categories.each { |category| hash[category] = Category.get_contents(category) }
end
For this solution, content_categories must be a hash, not an array as you describe. Otherwise not sure where you're getting the key.
contents_by_categories = Hash[*content_categories.map{|k, v| [k, Category.getContents(v.id)]}]

Resources