ToddT
ToddT

Reputation: 3258

Hash not being added to array

I give up, I have no idea why the hashes I'm creating are not being added to the end of the array. When I pp the hash it is correct, but for some reason the first hash is getting duplicated, while the second hash isn't being added..

The result I'm getting is this:

[{:id=>"36757153479", :quantity=>1, :status=>"new"}, 
{:id=>"36757153479", :quantity=>1, :status=>"new"}]
#notice that the id is the same

While what I want is this:

[{:id=>"36767751239", :quantity=>1, :status=>"new"},
{:id=>"36757153479", :quantity=>1, :status=>"new"}]

The incoming array looks like this:

me = [{"id"=>36767751239, "quantity"=>1,"vendor"=>"Martha
Stewart", "product_id"=>9707911431, "gift_card"=>false}, {"id"=>36757153479,
"quantity"=>1, "vendor"=>"Naturalizer", "product_id"=>9707504007,
"gift_card"=>false}]

And my code that steps thru it is this:

incoming_cart_array = []
incoming_cart_hash = {}
unless me.nil?
  me.each do |product|
    incoming_cart_hash[:id] = product['variant_id'].to_s
    incoming_cart_hash[:quantity] = product['quantity']
    incoming_cart_hash[:status] = "new"
    incoming_cart_array << incoming_cart_hash
  end
end

I've done this sort of thing 100's of times, but somehow this isn't working. Its probably something right in front of me, I just can't see it.

Thanks

Upvotes: 1

Views: 37

Answers (2)

akuhn
akuhn

Reputation: 27813

Your code creates only one {} ever, so you get an array with n times the same hash.

You must create a new {} for each iteration.

incoming_cart_array = []
unless me.nil?
  me.each do |product|
    incoming_cart_hash = {}
    ...
  end
end

Pro tipp — best practice in Ruby is to use map to create and array from an array. And you can use literal syntax to create a new hash, and use && to check for the nil case.

incoming_cart_array = me && me.map do | product | 
  {
    id: product['id'].to_s,
    quantity: product['quantity'],
    status: "new",
  }
end 

Upvotes: 1

Frederik Spang
Frederik Spang

Reputation: 3454

I seemed to be able to solve it as

incoming_cart_array = []
unless me.nil?
  me.each do |product|
    incoming_cart_hash = {}
    incoming_cart_hash[:id] = product['id'].to_s
    incoming_cart_hash[:quantity] = product['quantity']
    incoming_cart_hash[:status] = "new"
    incoming_cart_array << incoming_cart_hash
  end
end

However, I cannot seem to find the reason, that it cannot overwrite incoming_cart_hash[:id] when it isn't defined in the same scope. I'll dig into it, and update my answer if I figure it out!

Edit: My first initial though after a little debugging is, that when the hash isn't a local variable, it's defined (In the Ruby Source, which is C-based), as a pointer to the hash-type. Therefore in the array << hash line, you're inserting a pointer to the hash in the array. When you're running me.each n-times (2 in this case), the hash is updated, thus you'll have n-pointers in the array, all pointing to the same element. The hash which you're updating. It's seen as the same ruby object.

If you're outputting incoming_cart_hash.object_id inside the loop, each time, you'll see that the object_id is the same every time, when the hash-definition is outside the loop. However, when it's inside - defined as a new local variable every time, it'll differ, as it is a new and redefined object every time.

I found a bit of notes about it here: Ruby - Parameters by reference or by value?

Upvotes: 3

Related Questions