How to Serialize as Activesupport::Hashwithindifferentaccess Anymore

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

  1. There's a deep_symbolize_keys method in Rails

    hash.deep_symbolize_keys!

  2. 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.

  3. There is another method called with_indifferent_access. This allows you to access a hash with either a string or a symbol like how params are in the controller. This method doesn't have a bang counterpart.

    hash = hash.with_indifferent_access

  4. 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



Leave a reply



Submit