Unable to serialize as ActiveSupport::HashWithIndifferentAccess anymore
1.9.2 normally includes Psych as the YAML library. However, libyaml is an external dependency, and 1.9.2 defaults to using Syck (the old library) if libyaml is not available when Ruby is compiled: link
The fact that Psych YAML-izes ActiveSupport::HashWithIndifferentAccess as a standard hash is an oustanding issue on Psych's Github. Seems to be fixed in 1.9.3 though.
Cannot merge Hash object with ActiveSupport::HashWithIndifferentAccess
Issue is h1
has symbol keys and h2
has string keys
Make h1
as HashWithIndifferentAccess
h1 = {
:hot_products=>{:enabled=>true, :always_enable=>false, :order=>0},
:recent_products=>{:enabled=>true, :always_enable=>true, :order=>1},
:event_promotion=>{:enabled=>true, :always_enable=>false, :order=>2}
}.with_indifferent_access
and
h2 = {
"hot_products"=>{"enabled"=>"1"},
"recent_products"=>{"enabled"=>"0"},
"event_promotion"=>{"enabled"=>"1"}
}
Now, you can deep_merge
the hash and it will return you proper result
h1.deep_merge(h2)
{
"hot_products"=>{"enabled"=>"1", "always_enable"=>false, "order"=>0},
"recent_products"=>{"enabled"=>"0", "always_enable"=>true, "order"=>1},
"event_promotion"=>{"enabled"=>"1", "always_enable"=>false, "order"=>2}
}
Parameters double posting ActiveSupport::HashWithIndifferentAccess
You have a field called hashtag
with a value #content
, on a form for an object of class Hashtag
, hence:
{hashtag(class): {hashtag(field): '#content'}}
No implicit conversion of ActiveSupport::HashWithIndifferentAccess into String?
webp = webhook[:shipping_lines].first # Return hash
like:
{:id=>271878346596884015, :title=>"Generic Shipping", :price=>"10.00", :code=>"null", :source=>"shopify", :phone=>"null", :requested_fulfillment_service_id=>"null", :delivery_category=>"null", :carrier_identifier=>"null", :discounted_price=>"10.00", :tax_lines=>[]}
Try:
Rails.logger.debug("webp::::::::::" + webp[:code])
Result:
webp::::::::::null
Unserializing a column in a database in Rails
Updated Answer
You can use YAML.parse
for this, then its built in to_ruby
method:
str = "---\n- !ruby/hash:ActiveSupport::HashWithIndifferentAccess\n id: 21\n title: Salade César\n price: 10\n tax_rate: '0.0'\n quantity: 1\n options: []\n- !ruby/hash:ActiveSupport::HashWithIndifferentAccess\n id: 22\n title: Steak\n price: 14\n tax_rate: '0.0'\n quantity: 1\n options: []\n"
YAML.parse(str).to_ruby
# => [{"id"=>21, "title"=>"Salade César", "price"=>10, "tax_rate"=>"0.0", "quantity"=>1, "options"=>[]}, {"id"=>22, "title"=>"Steak", "price"=>14, "tax_rate"=>"0.0", "quantity"=>1, "options"=>[]}]
YAML.parse(str).to_ruby.to_json
# => "[{\"id\":21,\"title\":\"Salade C\\u00e9sar\",\"price\":10,\"tax_rate\":\"0.0\",\"quantity\":1,\"options\":[]},{\"id\":22,\"title\":\"Steak\",\"price\":14,\"tax_rate\":\"0.0\",\"quantity\":1,\"options\":[]}]"
N.B. your string in the question is invalid YAML, which meant this wasn't working to begin with, and as such the answer below :)
Original Answer
The built in parser isn't working for this, so here's a simple Ruby solution:
str = "---\n- !ruby/hash:ActiveSupport::HashWithIndifferentAccess\n id: 21\n title: Salade César\n price: 10\n tax_rate: '0.0'\n quantity: 1\n options: []\n- !ruby/hash:ActiveSupport::HashWithIndifferentAccess\n id: 22\n title: Steak\n price: 14\n tax_rate: '0.0'\n quantity: 1\n options: []\n"
DELIMITER = "!ruby/hash:ActiveSupport::HashWithIndifferentAccess".freeze
str.split(DELIMITER).each_with_object([]) do |yaml_hash, array|
hash = yaml_hash.lines.each_with_object({}) do |line, hash|
stripped_line = line.chomp.delete(' ')
k, v = stripped_line.split(':')
hash[k] = v if k && v
end
array << hash unless hash.empty?
end.to_json
Basically, you use the serialized !ruby/hash:ActiveSupport::HashWithIndifferentAccess
to split the stored string into hashes, then iterate through these mapping to their respective hashes.
Let me know how you get on with this or if you've any questions - hope it helps.
Why iterate loop on instance of ActiveSupport::HashWithIndifferentAccess never executed?
Use .each do |key, value|
instead of |r1|
and replace r[0]
with k
and r[1]
with v
How to elegantly symbolize_keys for a 'nested' hash
There are a few ways to do this
There's a
deep_symbolize_keys
method in Railshash.deep_symbolize_keys!
As mentioned by @chrisgeeq, there is a
deep_transform_keys
method that's available from Rails 4.hash.deep_transform_keys(&:to_sym)
There is also a bang
!
version to replace the existing object.There is another method called
with_indifferent_access
. This allows you to access a hash with either a string or a symbol like howparams
are in the controller. This method doesn't have a bang counterpart.hash = hash.with_indifferent_access
The last one is using
JSON.parse
. I personally don't like this because you're doing 2 transformations - hash to json then json to hash.JSON.parse(JSON[h], symbolize_names: true)
UPDATE:
16/01/19 - add more options and note deprecation of deep_symbolize_keys
19/04/12 - remove deprecated note. only the implementation used in the method is deprecated, not the method itself.
Rails 5: unable to retrieve hash values from parameter
take a look to this. Very weird since ActionController::Parameters
is a subclass of Hash, you can convert it directly to a hash using the to_h
method on the params hash.
However to_h
only will work with whitelisted params, so you can do something like:
permitted = params.require(:line_item).permit(: line_item_attributes_attributes)
attributes = permitted.to_h || {}
attributes.values
But if instead you do not want to whitelist then you just need to use the to_unsafe_h
method.
Update
I was very curious about this issue, so I started researching, and now that you clarified that you are using Rails 5, well that's the cause of this issue, as @tillmo said in stable releases of Rails like 4.x, ActionController::Parameters
is a subclass of Hash, so it should indeed respond to the values
method, however in Rails 5 ActionController::Parameters
now returns an Object instead of a Hash
Note: this doesn’t affect accessing the keys in the params hash like params[:id]
. You can view the Pull Request that implemented this change.
To access the parameters in the object you can add to_h
to the parameters:
params.to_h
If we look at the to_h
method in ActionController::Parameters
we can see it checks if the parameters are permitted before converting them to a hash.
# actionpack/lib/action_controller/metal/strong_parameters.rb
def to_h
if permitted?
@parameters.to_h
else
slice(*self.class.always_permitted_parameters).permit!.to_h
end
end
for example:
def do_something_with_params
params.slice(:param_1, :param_2)
end
Which would return:
{ :param_1 => "a", :param_2 => "2" }
But now that will return an ActionController::Parameters
object.
Calling to_h
on this would return an empty hash because param_1 and param_2 aren’t permitted.
To get access to the params from ActionController::Parameters
, you need to first permit the params and then call to_h
on the object
def do_something_with_params
params.permit([:param_1, :param_2]).to_h
end
The above would return a hash with the params you just permitted, but if you do not want to permit the params and want to skip that step there is another way using to_unsafe_hash
method:
def do_something_with_params
params.to_unsafe_h.slice(:param_1, :param_2)
end
There is a way of always permit the params from a configuration from application.rb, if you want to always allow certain parameters you can set a configuration option. Note: this will return the hash with string keys, not symbol keys.
#controller and action are parameters that are always permitter by default, but you need to add it in this config.
config.always_permitted_parameters = %w( controller action param_1 param_2)
Now you can access the params like:
def do_something_with_params
params.slice("param_1", "param_2").to_h
end
Note that now the keys are strings and not symbols.
Hope this helps you to understand the root of your issue.
Source: eileen.codes
How is GUI and Game Program Flow compared to Web programs
There's almost always a loop in all of these - but it's not something you would tend to think about during most of your development.
If you take a step back, your web applications are based around a loop - the Web Server's accept()
loop:
while(listening) {
get a socket connection;
handle it;
}
.. but as a Web developer, you're shielded from that, and write 'event driven' code -- 'when someone requests this URL, do this'.
GUIs are also event driven, and the events are also detected by a loop somewhere:
while(running) {
get mouse/keyboard/whatever event
handle it
}
But a GUI developer doesn't need to think about the loop much. They write 'when a mouse click occurs here, do this'.
Games, again the same. Someone has to write a loop:
while(game is in progress) {
invoke every game object's 'move one frame' method;
poll for an input event;
}
... while other code is written in a more event-driven style: 'when a bullet object coincides with this object, trigger an explosion event'.
Related Topics
Ruby: Length of a Line of a File in Bytes
How to Count Duplicates Hash Itens in Ruby 1.8.5 ( Sketchup Ruby API )
Flatten a Ruby Array Without Using Built-In 'Flatten' Method
Loop Within Loop in Rails Controller
Ruby Selenium Web Driver: How to Count Child Element Nodes of a Specific Node
Confused with Ruby Accessor Methods
How to Dry Up Method with Multiple { 'Not Found' }
How to Implement Editing/Formating Text Area in Rails
Display Result Data Without Page Refresh on Form Submission in Ruby on Rails
How to Access HTML Elements That Are Rendered in JavaScript Using Xpath
Rails Object Based Permission/Authorization Engine
How to Print All the Staged File Names Using Ruby Git Pre-Commit Hook
Iterate JSON with Ruby and Get a Key,Value in an Array
How to Access Text Field in an Iframe