Search code examples
ruby-on-railsrubyruby-hash

Rails model results to hash - variable as a key issue


I've tried to put results from my vote model in a hash for further usage, but I don't know how to create a hash key from a variable in Ruby. See example below:

    def create_hash_array(campaign_votes)
        target_hash = Hash.new
        campaign_votes.each_with_index do |cv,i|
          target_hash[cv.content_id] = {} if i == 0

          if target_hash[cv.content_id].member?(cv.vote_button_id)
            target_hash[cv.content_id][cv.vote_button_id] = (target_hash[cv.content_id][cv.vote_button_id]).to_i + 1
          else
            target_hash[cv.content_id] = {cv.vote_button_id => nil}
          end

        end
        target_hash
    end

Usually I got an error:

undefined method `member?' for nil:NilClass

but it comes from unrecognized target_hash[cv.content_id], how can I make does variable to be recognized target_hash[cv.content_id] ??


Solution

  • I think your code can be boiled down to this:

    def create_hash_array(campaign_votes)
      target_hash = Hash.new { |h,k| h[k] = Hash.new(0) }
    
      campaign_votes.each do |cv|
        target_hash[cv.content_id][cv.vote_button_id] += 1
      end
    
      target_hash
    end
    

    There's multiple problems here, many to do with getting all tangled up in the process. You initialize the element of the target_hash structure only on the 0 index position, yet each campaign_vote could have different content_id values, meaning you're missing out on those.

    This approach creates a single auto-generating Hash that will populate keys with counter hashes, that is hashes defaulting to 0. That means you can always navigate them and += 1 will work because of the default.

    This approach is pretty common in Ruby, especially Hash.new(0), which is super handy for doing simple counters of arbitrary objects.