Haroon
Haroon

Reputation: 3472

Ruby - Access value from json array

I am creating an array of fields

def create_fields fields
  fields_list = []

  fields.each do |field|
    # puts "adding_field to array: #{field}"
    field_def = { field: field, data: { type: 'Text', description: '' }  }
    fields_list.push field_def
  end
  fields_list
end

The fields_list is being set to a jsonb field.

Lets say I pass in

create_fields ['Ford', 'BMW', 'Fiat']

Json result is an array:

{"field"=>"Ford", "data"=>{"type"=>"Text", "description"=>""}}
{"field"=>"BMW", "data"=>{"type"=>"Text", "description"=>""}}
{"field"=>"Fiat", "data"=>{"type"=>"Text", "description"=>""}}

How can I access the 'Ford' from the json array? Am i creating the array incorrectly? Is there a better way to create this array so I can access the field i want?

This assertion passes assert_equal(3, fields.count)

However i want to get 'Ford' and check it's properties, e.g. type = 'Text', type could equal 'Number' or whatever.

Upvotes: 0

Views: 3914

Answers (4)

cpetrich
cpetrich

Reputation: 172

This is a structure that makes more sense to me for accessing values based on known keys:

def create_fields fields
  fields_hash = {}

  fields.each do |field|
    fields_hash[field] = {type: 'Text', description: ''}
  end
  fields_hash
end

# The hash for fields_hash will look something like this:
{
  Ford: {
    type: "Text",
    description: ""
  },
  BMW: {...},
  Fiat: {...}
}

This will allow you to access the values like so: fields[:Ford][:type] in ruby and fields.Ford.type in JSON. Sounds like it would be easier to return an Object rather than an Array. You can access the values based on the keys more easily this way, and still have the option of looping through the object if you want.

Upvotes: 3

Oleksandr Holubenko
Oleksandr Holubenko

Reputation: 4440

So, you have result of your method:

result = 
  [
   {"field"=>"Ford", "data"=>{"type"=>"Text", "description"=>""}},
   {"field"=>"BMW", "data"=>{"type"=>"Text", "description"=>""}},
   {"field"=>"Fiat", "data"=>{"type"=>"Text", "description"=>""}}
  ]

to get 'Ford' from it you can use simple method detect

result.detect { |obj| obj['field'] == 'Ford' }
#=> { "field"=>"Ford", "data"=>{"type"=>"Text", "description"=>""}

Also I recommend you to edit your method to make it more readable:

def create_fields(fields)
  fields.map do |field|
    {
      field: field,
      data: {
        type: 'Text',
        description: ''
      }
    }
  end
end

Upvotes: 1

oreoluwa
oreoluwa

Reputation: 5633

Obviously, there are several ways of creating or accessing your data, but I'd always lean towards the developer picking a data structure best suited for your application. In your case currently, in order to access the Ford hash, you could use the Ruby Array#detect method as such:

ford = fields_list.detect{|field_hash| field_hash['field'] == 'Ford' }
ford['data'] # => {"type"=>"Text", "description"=>""}
ford['data']['type'] # => 'Text'

Upvotes: 1

akg
akg

Reputation: 341

The result of your create_fields method with the specified parameters is the following:

[
  {:field=>"Ford", :data=>{:type=>"Text", :description=>""}}, 
  {:field=>"BMW", :data=>{:type=>"Text", :description=>""}},
  {:field=>"Fiat", :data=>{:type=>"Text", :description=>""}}
] 

It means that if you want to access the line belonging to "Ford", you need to search for it like:

2.3.1 :019 > arr.select{|e| e[:field] == "Ford" }
 => [{:field=>"Ford", :data=>{:type=>"Text", :description=>""}}] 
2.3.1 :020 > arr.select{|e| e[:field] == "Ford" }[0][:data][:type]
 => "Text" 

This is not optimal, because you need to search an array O(n) instead of using the pros of a hash. If there are e.g.: 2 "Ford" lines, you'll get an array which contains 2 elements, harder to handle collisions in field value.

It would be better if you created the array like:

def create_fields fields
  fields_list = []

  fields.each do |field|
    # puts "adding_field to array: #{field}"
    field_def = [field, { type: 'Text', description: '' }  ]
    fields_list.push field_def
  end
  Hash[fields_list]
end

If you choose this version, you can access the members like:

2.3.1 :072 > arr = create_fields ['Ford', 'BMW', 'Fiat']
 => {"Ford"=>{:type=>"Text", :description=>""}, "BMW"=>{:type=>"Text", :description=>""}, "Fiat"=>{:type=>"Text", :description=>""}} 
2.3.1 :073 > arr["Ford"]
 => {:type=>"Text", :description=>""} 
2.3.1 :074 > arr["Ford"][:type]
 => "Text" 

Both of the above examples are Ruby dictionaries / Hashes. If you want to create a JSON from this, you will need to convert it:

2.3.1 :077 > require 'json'
 => true 
2.3.1 :078 > arr.to_json
 => "{\"Ford\":{\"type\":\"Text\",\"description\":\"\"},\"BMW\":{\"type\":\"Text\",\"description\":\"\"},\"Fiat\":{\"type\":\"Text\",\"description\":\"\"}}" 

Upvotes: 5

Related Questions