add hash to hashes in ruby - ruby-on-rails

final_sub_hash = {}
<% workers.each do |work| %>
<% sub_hash = {} %>
<% sub_hash = {:name => work['name'], :gender => work['gender']} %>
<% final_sub_hash.update(sub_hash) %>
<% end %>
What I am trying to do is append the values of sub_hash to final_sub_hash but I am not able to figure out how can I do that. Please help me find a solution.

hash.store(key, value) stores a key-value pair in hash.
Example:
hash #=> {"a"=>1, "b"=>2, "c"=>55}
hash["d"] = 30 #=> 30
hash #=> {"a"=>1, "b"=>2, "c"=>55, "d"=>30}
What you are trying to do is a list.
Example:
works = []
work.append(hash) #=> [ {"a"=>1, "b"=>2, "c"=>55, "d"=>30} ]

I arrived here from a search for how to add a hash to a hash. In case anyone else wonders the same, here's a nice example
# Create a hash
h = {a: 1, b: 2}
# => {:a=>1, :b=>2}
# Add a hash to the existing hash
h.store(:c, {i: 10, ii: 20})
# > {:a=>1, :b=>2, :c=>{:i=>10, :ii=>20}}
The new key can be a symbol (like :c, as above), but it could also be a string:
h.store("c", {i: 10, ii: 20})
# => {:a=>1, :b=>2, "c"=>{:i=>10, :ii=>20}}

Related

How do I get a fresh copy of an array in each iteration?

I cannot understand the following behavior
<% filter.each do |f| %>
<% aux = #taxon_ids %>
<%= check_box_tag "filter_taxon", aux << f[:id], #taxon_ids.include?(f[:id]) %>
...
<% end %>
for each loop of my function the aux var is not re-initializing. Indeed there is accumulating each id in him self.
Unless you're assigning a new object (or one of the literal shorthands like []) then Ruby assignment is by reference, look:
[14] pry(main)> x = []
=> []
[15] pry(main)> y = x
=> []
[16] pry(main)> y << 1
=> [1]
[17] pry(main)> x
=> [1]
If you want your own copy of that array then use the .dup or .clone method:
aux = #taxon_ids.dup

Rails 4 Strong Params with multiple objects and integer keys

I'm submitting a form with 2-4 objects at once, depending on how many the parent has. I realize that this is probably unconventional, but I really wanted the user to be able to edit all of the objects at once on one form. On my form, I'm doing:
<%= simple_fields_for "derps[]", derp do |f| %>
<% end %>
Then I'm doing this in the controller:
def update
#derps = []
#rejects = []
derps_params.each do |key, hash|
derp = Derp.find(key)
derp.assign_attributes(hash)
#rejects << derp unless derp.save
end
if #rejects.empty?
redirect_to #parent, flash: {success: 'Derps were successfully updated.'}
else
#derps = #rejects
render :edit
end
end
Lets say there are two objects - the params are coming through as:
"derps"=>{"1"=>{"attribute"=>"39", "another_attribute"=>"serp", "a_third_attribute"=>"yerp"}, "2"=>{"attribute"=>"30", "another_attribute"=>"49", }}
I had this working in Rails 3 without strong params. I'm upgrading to rails 4 and I'm struggling with how to get this working - I keep getting "Unpermitted parameters: 1, 2"
I'm assuming I need to do something like:
def mashes_params
params.require(:derps).permit(
id: []
or
def mashes_params
params.require(:derps).permit(
:id,
Something along those lines, but I've tried it every way I can think of without luck.
Any ideas here?
I've found that the command line is immensely helpful for debugging Strong Parameters in Rails 4. Here's how I tested your problem in the console:
rails c # From within your project directory, short for 'rails console'
params = ActionController::Parameters.new( { derps: { 1 => { attribute: 39, another_attribute: "serp" }, 2 => { attribute: 30, another_attribute: 49 } } } )
params # To make sure that the object looks the same
permitted = params.require( :derps ).permit( 1 => [ :attribute, :another_attribute ], 2 => [ :attribute, :another_attribute ] )
permitted # To see what you'd get back in your controller
Hopefully with this tool, you'll be able to debug anything that my answer didn't provide more easily than trial and error.
Final Edit (hopefully):
Had to rethink this from the ground up. I came to the conclusion: Since :id works as a wildcard, but is not allowed as the key of the hash, why not always make the keys 1-4, so I can whitelist them explicitly, then get the ID from a key-value in the hash, much like is done in traditional form nesting? Thats how I ended up solving it. Here's the final implementation that I have working:
<% i = #parent.derps.index(derp) + 1 %>
<%= simple_fields_for "derps[#{i}]", derp do |f| %>
<%= f.hidden_field :id, value: derp.id %>
<%= render "rest_of_the_fields" %>
<% end %>
Then in the controller:
def update
#derps = []
#rejects = []
derp_params.each do |key, hash|
derp = Derp.find(hash.delete("id"))
derp.assign_attributes(hash)
#rejects << derp unless derp.save
end
if #rejects.empty?
redirect_to #parent, flash: {success: "Derps updated successfully."}
else
#derps = #rejects
render :edit
end
end
Then here are the strong params:
def derp_params
p = [:id, :attribute_1, :another_attribute, ...]
params.require(:derps).permit(
"1" => p, "2" => p, "3" => p, "4" => p
)
end
Phew. Hope this helps someone.
The absolute best solution I've seen is here:
def product_params
properties_keys = params[:product].try(:fetch, :properties, {}).keys
params.require(:product).permit(:title, :description, properties: properties_keys)
end
I made one more change to iterate through the unnamed keys since my property_keys have more nested keys and values:
response_keys = params[:survey][:responses].try(:fetch, :properties, {}).keys
params.require(:survey).permit(responses: response_keys.map {|rk| [rk => [:question_id, :answer_id, :value]]})
Here is the approach I am currently using. You can permit each nested params one by one like this:
params = ActionController::Parameters.new(
"derps" => {
"1" => {
"attribute" => "39",
"another_attribute" => "serp",
"a_third_attribute" => "yerp"
},
"2" => {
"attribute" => "30",
"another_attribute" => "49"
}
}
)
# => <ActionController::Parameters {"derps"=>{"1"=>{"attribute"=>"39", "another_attribute"=>"serp", "a_third_attribute"=>"yerp"}, "2"=>{"attribute"=>"30", "another_attribute"=>"49"}}} permitted: false>
params.fetch(:derps).map do |i, attrs|
[
i,
ActionController::Parameters.new(attrs).permit(
:attribute,
:another_attribute,
:a_third_attribute,
)
]
end.to_h.with_indifferent_access
#=> {"1"=><ActionController::Parameters {"attribute"=>"39", "another_attribute"=>"serp", "a_third_attribute"=>"yerp"} permitted: true>, "2"=><ActionController::Parameters {"attribute"=>"30", "another_attribute"=>"49"} permitted: true>}
Here is a sort of dirty way of accomplishing this which builds on the answer above by Greg Blass
This can handle an infinite number of indexes with nested params
def foo_bar_params
num_keys = params[:foo_bars].keys.size
the_params = [:id, :attr1, :attr2, :another]
permit_hash = {}
i = 0
while i < num_entries
permit_hash[i.to_s] = the_params
i += 1
end
params.require(:foo_bars).permit(permit_hash)
end
Im sure there is a fancier way to do this, but this way is readable and I can easily tell what is going on...and most importantly it works

How do I print an array in Rails?

I am new to Rails and I am using Ruby version 1.9.3 and Rails version 3.0.0.
I want to print an array in Rails. How do I do that?
For example, we have to use print_r to print an array in PHP:
<?php
$a = array ('a' => 'apple', 'b' => 'banana', 'c' => array ('x', 'y', 'z'));
print_r ($a);
?>
Output:
<pre>
Array
(
[a] => apple
[b] => banana
[c] => Array
(
[0] => x
[1] => y
[2] => z
)
)
</pre>
How do I print an array in Rails?
You can use inspect like:
#a = ['a', 'b']
p #a #['a', 'b']
Or:
p #a.inspect #"[\"a\", \"b\"]"
You need to use awesome_print gem.
require 'awesome_print'
hash = {:a=>1,:b=>2,:c => [1,2,3]}
ap hash
output:
{
:a => 1,
:b => 2,
:c => [
[0] 1,
[1] 2,
[2] 3
]
}
It depends on what you want to use the array for.
To blindly output an array in a view, which has to be in a view, you should use debug and inspect like this:
<%= #array.inspect() %>
<%= debug #array %>
However, if you want to iterate through an array, or do things like explode(), you'll be better suited using the Ruby array functions.
You've got a couple of options here. I'm assuming you're doing this in an ERB template.
This will convert the array to YAML and print it out surrounded in <pre> tags
<%= debug [1,2,3,4] %>
And this will print it out formatted in a readable Ruby syntax:
<pre><%= [1,2,3,4].inspect %></pre>
Check out "Debugging Rails Applications" for more info.

Rails: Preserving GET query string parameters in link_to

I have a typical search facility in my app which returns a list of results that can be paginated, sorted, viewed with a different records_per_page value, etc. Each of these options is controlled by parameters in the query string. A simplified example:
/search?q=test&page=2
Now say I need to display a set of links that set records_per_page value to 10, 20, 30. Each link must include the existing query parameters, which can be a very long set, plus a new per_page parameter.
/search?q=test&page=2& ... &per_page=10
/search?q=test&page=2& ... &per_page=20
/search?q=test&page=2& ... &per_page=30
Is there an easy way to do it with just link_to helper or I need to parse and reproduce the query string from previous request somehow?
link_to 'Link', request.query_parameters.merge({:per_page => 20})
link_to 'Link', params.merge({:per_page => 20})
The simplest way to merge the new params with the query parameters and NOT with all parameters (including those obtained through the path) is to merge with request.query_parameters
link_to 'Search', search_path(request.query_parameters.merge({ per_page: 20 }))
Otherwise you end up with query strings duplicating the path parameters, for example ?action=index&controller=products&foo=bar instead of ?foo=bar.
If you want to keep existing params and not expose yourself to XSS attacks, be sure to clean the params hash, leaving only the params that your app can be sending:
# inline
<%= link_to 'Link', params.slice(:sort).merge(per_page: 20) %>
If you use it in multiple places, clean the params in the controller:
# your_controller.rb
#params = params.slice(:sort, :per_page)
# view
<%= link_to 'Link', #params.merge(per_page: 20) %>
You can just throw elements of the params hash at link_to. Like
link_to "some_other_link", "/search", :page => params[:page]
This works if the links you are processing aren't given to you by request.params.
require 'rack/utils'
require 'uri'
def modify_query url, options={}
uri = URI(url)
query_hash = Rack::Utils.parse_query(uri.query)
query_hash.merge!(options)
uri.query = Rack::Utils.build_query(query_hash)
uri.to_s
end
puts modify_query('/search?q=test&page=2&per_page=10', 'per_page' => 20)
puts modify_query('/search?q=test&page=2', 'per_page' => 30)
# Outputs
# /search?q=test&page=2&per_page=20
# /search?q=test&page=2&per_page=30
What about
<%= link_to 'Whatever', :overwrite_params => { :pear_page => 20 } %>
?
A bit late i know..
If your using this as a way to filter search results have a look at my helper :)
This automagicly removes all blank and unneeded params and add the class "selected" if all of it's new params were already set.
def search_to s, args={}
selected = 0
args.each do |k, v|
selected = selected + 1 if params[k] == v.to_s || ( params[k].nil? && v.blank? )
end
if #search_params_base.nil?
#search_params_base = request.parameters.clone
#search_params_base.delete(:action)
#search_params_base.delete(:controller)
#search_params_base.delete(:page)
#search_params_base.delete_if{|k, v| v.nil? || v.blank?}
#search_params_base.delete(:utf8) if #search_params_base[:keywords].nil?
end
search_params = #search_params_base.merge(args)
search_params.delete_if{|k, v| v.nil? || v.blank?}
link_to s, search_path + '?' + search_params.to_param, :class => selected == args.length ? 'selected' : nil
end
You can then just use this in your view:
search_to '$80 to $110', :price => 80..110
Or in your case:
search_to '30 per page', :page => params[:page], :per_page => 30

On the fly tags generation for XML Builders

I have a hash like,
object = { :type => 'book', :name => 'RoR', :price => 33 }
OR
object = { :type => 'wig', :name => 'Elvis-Style', :price => 40, :color => 'black' }
The problem is that keys in above hash may be different all the time or even increase and decrease depending upon the object type.
What I want to do generate XML for above hashes using Xml::Builder. The XML tags are decided by the keys in the hash and text inside a tag is value corresponding that key.
I can use eval to do this like below. However, I think there must be a better way to do it.
object.each do |key, text|
eval("xml.#{key.to_s} do
#{text}
end
")
end
#object.each do |k, v|
xml.tag!(k.to_s, v)
end
Rails supports to_xml on Hash classes.
hash = { :type => 'book', :name => 'RoR', :price => 33 }
hash.to_xml
# Returns
# <?xml version=\"1.0\" encoding=\"UTF-8\"?>
# <hash>
# <type>book</type>
# <name>RoR</name>
# <price type=\"integer\">33</price>
# </hash>
If you want to skip the types then:
hash.to_xml(:skip_types => true)
If you want to give a different root then:
hash.to_xml(:root => 'options')
This one worked.
#object.each do |k, v|
xml.tag!(k.to_s, v)
end
out << "<#{key}>#{html_escape(value)}</#{key}>"

Resources