How do I build this JSON object in ruby? - ruby-on-rails

I need to bring an array of ruby objects in JSON. I will need to find the item in the JSON object by id, so I think it is best that the id is the key of each object. This structure makes the most sense to me:
{
"1": {"attr1": "val1", "attr2": "val2"},
"2": {"attr1": "val1", "attr2": "val2"},
"3": {"attr1": "val1", "attr2": "val2"}
}
That way I can easily call into the json object like console.log(json_obj[id].attr1)
The issue is that I am not quite sure how to build this in ruby. This is as far as I have gotten:
# in ruby
#book_types = []
BookType.all.each do |bt|
#book_types << {bt.id => {:attr => bt.attr}}
end
#book_types = #book_types.to_json
// In JS
var bookTypes = JSON.parse('<%=raw #book_types %>');
2 questions: How can I build this in ruby? Is there a better way to accomplish what I am doing?
Also just a note that I am building this on the Rails framework
Thanks!

Assuming BookType is an ActiveRecord class, you can just do this:
BookType.all(:select => "attr1, attr2").to_json
...where "attr1, attr2" is a list of the attributes you want to include in your JSON.
If you want the ids as keys, you can do this instead:
BookType.all.inject({}) { |hsh, bt|
hsh[bt.id] = { "attr1" => bt.attr1, "attr2" => bt.attr2 }
hsh
}.to_json

Related

Rails app: I need to build a json object from params inside a loop

I need to build a json object inside a loop using params.
My params look like this...
params[:answers]
returns => {"1"=>"answer1", "2"=>"answer2"}
The keys in this json object are the id's of the survey question.
So I planed to loop through the keys to build the json object like this...
def build_answersheet_json(params[:answers], params[:survey_id])
params[:answers].keys.each do |question_id|
current_question = question_id
current_answer = params[:answers][question_id]
end
end
Since im using "t.json" in my migration to save json to postgres, I wanted to use the extracted question_id and answer to build a json object that looks something like this...
{
survey_id: '1',
answers: {
question: [{
question_id: 1,
answer: 'answer1'
}, {
question_id: 2,
answer: 'answer2'
}]
}
}
Ive been trying to do this using a method that looks somthing like this...
build_answersheet_json(params[:answers], params[:survey_id])
Ive tried JSON.parse() and Ive tried to just logically work through it but I cant seem to figure this out.
Any help is appreciated.
Maybe you can try something like that:
/* fake params (to test) */
params = {
survey_id: '1',
answers: {
"1"=>"answer1",
"2"=>"answer2",
"3"=>"answer3",
"4"=>"answer4"
}
}
def build_answersheet_json(answers, survey_id)
{
survey_id: survey_id,
answers: answers.map { |k,v| { question_id: k.to_i, answer: v } }
}
end
survey = build_answersheet_json(params[:answers], params[:survey_id])
puts survey.class
#Hash
puts survey.to_json
# formated JSON string:
# {
# "survey_id":"1",
# "answers":[
# {"question_id":1,"answer":"answer1"},
# {"question_id":2,"answer":"answer2"},
# {"question_id":3,"answer":"answer3"},
# {"question_id":4,"answer":"answer4"}
# ]
# }
In order to save to a t.json postgress column type, just pass the Hash survey object, like that:
YourModel.create(survey: survey)
Source: http://edgeguides.rubyonrails.org/active_record_postgresql.html
Try
{
survey: ¯\_༼◉ل͟◉༽_/¯,
}
Json may not be parsed if json have construction like this:
survey = {
}
Json may not contain = and assignment
Check real variables values with puts varname.inspect near at code lines where you meet unexpected behaviour.

Rails 4 and returning JSON response: how to correctly append extra data?

I have a SQL query returns some data, here is some sample output:
[
{
"AccountCode": "111123456",
"AccountID": 123456,
"BalanceCurrent": "-8.0",
"Phone": "123456888",
}
]
This is a Hash with an array. There are times when there will be multiple hashes within the array. Just one in this example though.
As stated, this data comes directly from the database.
I have a lookup_phone method in my Customer model that runs the SQL query and then executed in the customer_controller.rb file like so:
customer_phone = Customer.lookup_phone(params[:Phone])
Now, I need to append some extra data to these hash(es) that do not come from the database, like so:
data = [
:match_found => true,
:transfer_flag => false,
:confirm_id => 2
]
This data variable needs to be WITHIN each hash object, not a separate hash object on its own.
Using a simple array concat or + always makes the data a separate hash object. I've come across some good posts saying to use reduce along with merge, but those are Hash methods, not Array methods.
If I try to set data as a Hash instead of an array, I get
no implicit conversion of Hash into Array when I try to do
customer_phone.reduce({}, :merge)
after running customer_phone += data
What is the proper way to append data to an existing Hash object?
maybe combine each and merge
base = [
{
"AccountCode": "111123456",
"AccountID": 123456,
"BalanceCurrent": "-8.0",
"Phone": "123456888",
}
]
data = {:match_found=>true, :transfer_flag=>false, :confirm_id=>2}
base.each { |el| el.merge!(data) }
#=> [{:AccountCode=>"111123456", :AccountID=>123456, :BalanceCurrent=>"-8.0", :Phone=>"123456888", :match_found=>true, :transfer_flag=>false, :confirm_id=>2}]
You can add attr_accessor to your Customer model like this
class Customer
attr_accessor :data
end
With your data array:
data_array = [
:match_found => true,
:transfer_flag => false,
:confirm_id => 2
]
Then, you can execute the query combined with each function:
customer_phone = Customer.lookup_phone(params[:Phone]).each {|e| e.data = data_array}
Access it:
customer_phone.first.data
To render json:
render json: customer_phone, methods: [:data]

Merge two JSON with a matching ID in Rails

I got two JSON that are structured like this. First one comes from an API:
[
{
"course_code":"Basic 101 - 0913",
"name":"Basic 101",
"start_at":"2013-09-16T00:00:00+02:00",
"end_at":"2013-10-13T23:55:00+02:00",
"workflow_state":"available"
},
{"course_code":"Medium 201 - 0913",
"name":"Medium 201",
"start_at":"2013-08-06T16:55:25+02:00",
"end_at":null,
"workflow_state":"available"
}
]
The second one is a JSON export from my database:
[
{
"id":1,
"course_id":"Basic 101",
"name":"Basic Level",
"description":"blablabla",
"discipline_id":"1",
"duration":"28",
"created_at":null,
"updated_at":null
},
{
"id":2,
"course_id":"Medium 201",
"name":"Medium Level",
"description":"blablabla",
"discipline_id":"1",
"duration":"28",
"created_at":null,
"updated_at":null
}
]
I would like to merge these two JSON into one, with matched :name in the first JSON and :course_id in the second one.
If you know good tutorials on using JSON in Rails, I'm really interested.
This isn't really a JSON issue.
When parsing JSON data it returns arrays and hashes.
One way of merging it in this case would be to loop through the data and check for the parameters you want/need to match. Once you find a match you can either manually create a new Hash with the needed data or you could use
hash1.merge(hash2)
http://www.ruby-doc.org/core-1.9.3/Hash.html#method-i-merge
which would return a hash consisting of both Hashes - attributes with the same name would be overwritten in the first hash.
Just a quick answer, to let you know where to go. Assuming first json is in json1 and second is in json2 variables, this code:
require 'json'
arr1 = JSON.parse(json1)
arr2 = JSON.parse(json2)
mrg = []
arr1.each do |el1|
arr2.each do |el2|
if el2['course_id'] == el1['name']
mrg.push(el1.merge(el2))
end
end
end
p mrg
Will print:
[
{
"course_code"=>"Basic 101 - 0913",
"name"=>"Basic Level",
"start_at"=>"2013-09-16T00:00:00+02:00",
"end_at"=>"2013-10-13T23:55:00+02:00",
"workflow_state"=>"available",
"id"=>1,
"course_id"=>"Basic 101",
"description"=>"blablabla",
"discipline_id"=>"1",
"duration"=>"28",
"created_at"=>nil,
"updated_at"=>nil
},
{
"course_code"=>"Medium 201 - 0913",
"name"=>"Medium Level",
"start_at"=>"2013-08-06T16:55:25+02:00",
"end_at"=>nil,
"workflow_state"=>"available",
"id"=>2,
"course_id"=>"Medium 201",
"description"=>"blablabla",
"discipline_id"=>"1",
"duration"=>"28",
"created_at"=>nil,
"updated_at"=>nil
}
]

Take array and convert to a hash Ruby

I am trying this for the first time and am not sure I have quite achieved what i want to. I am pulling in data via a screen scrape as arrays and want to put them into a hash.
I have a model with columns :home_team and :away_team and would like to post the data captured via the screen scrape to these
I was hoping someone could quickly run this in a rb file
require 'open-uri'
require 'nokogiri'
FIXTURE_URL = "http://www.bbc.co.uk/sport/football/premier-league/fixtures"
doc = Nokogiri::HTML(open(FIXTURE_URL))
home_team = doc.css(".team-home.teams").map {|team| team.text.strip}
away_team = doc.css(".team-away.teams").map {|team| team.text.strip}
team_clean = Hash[:home_team => home_team, :away_team => away_team]
puts team_clean.inspect
and advise if this is actually a hash as it seems to be an array as i cant see the hash name being outputted. i would of expected something like this
{"team_clean"=>[{:home_team => "Man Utd", "Chelsea", "Liverpool"},
{:away_team => "Swansea", "Cardiff"}]}
any help appreciated
You actually get a Hash back. But it looks different from the one you expected. You expect a Hash inside a Hash.
Some examples to clarify:
hash = {}
hash.class
=> Hash
hash = { home_team: [], away_team: [] }
hash.class
=> Hash
hash[:home_team].class
=> Array
hash = { hash: { home_team: [], away_team: [] } }
hash.class
=> Hash
hash[:hash].class
=> Hash
hash[:hash][:home_team].class
=> Array
The "Hash name" as you call it, is never "outputed". A Hash is basically a Array with a different index. To clarify this a bit:
hash = { 0 => "A", 1 => "B" }
array = ["A", "B"]
hash[0]
=> "A"
array[0]
=> "A"
hash[1]
=> "B"
array[1]
=> "B"
Basically with a Hash you additionally define, how and where to find the values by defining the key explicitly, while an array always stores it with a numerical index.
here is the solution
team_clean = Hash[:team_clean => [Hash[:home_team => home_team,:away_team => away_team]]]

Ruby on Rails: Array to Hash with (key, array of values)

Lets say I have an Array of content_categories (content_categories = user.content_categories)
I now want to add every element belonging to a certain categorie to content_categories with the category as a key and the the content-item IDs as elements of a set
In PHP something like this is possible:
foreach ($content_categories as $key => $category) {
$contentsByCategoryIDArray = Category.getContents($category[id])
$content_categories[$key][$contentsByCategoryIDArray]
}
Is there an easy way in rails to do this?
Greets,
Nico
Your question isn't really a Rails question, it's a general Ruby programming question.
Your description isn't very clear, but from what I understand, you want to group IDs for common categories using a Hash. There are various other ways of doing this, but this is easy to understand::
ary = [
'cat1', {:id => 1},
'cat2', {:id => 2},
'cat1', {:id => 3}
]
hsh = {}
ary.each_slice(2) { |a|
key,category = a
hsh[key] ? hsh[key] << category[:id] : hsh[key] = [category[:id]]
}
hsh # => {"cat1"=>[1, 3], "cat2"=>[2]}
I'm using a simple Array with a category, followed by a simple hash representing some object instance, because it makes it easy to visualize. If you have a more complex object, replace the hash entries with those objects, and tweak how you access the ID in the ternary (?:) line.
Using Enumerable.inject():
hsh = ary.each_slice(2).inject({}) { |h,a|
key,category = a
h[key] ? h[key] << category[:id] : h[key] = [category[:id]]
h
}
hsh # => {"cat1"=>[1, 3], "cat2"=>[2]}
Enumerable.group_by() could probably shrink it even more, but my brain is fading.
I'd use Enumerable#inject
content_categories = content_categories_array.inject({}){ |memo, category| memo[category] = Category.get_contents(category); memo }
Hash[content_categories.map{|cat|
[cat, Category.get_contents(cat)]
}]
Not really the right answer, because you want IDs in your array, but I post it anyway, because it's nice and short, and you might actually get away with it:
content_categories.group_by(&:category)
content_categories.each do |k,v|
content_categories[k] = Category.getContents(v)
end
I suppose it's works
If i understand correctly, content_categories is an array of categories, which needs to be turned into a hash of categories, and their elements.
content_categories_array = content_categories
content_categories_hash = {}
content_categories_array.each do |category|
content_categories_hash[category] = Category.get_contents(category)
end
content_categories = content_categories_hash
That is the long version, which you can also write like
content_categories = {}.tap do |hash|
content_categories.each { |category| hash[category] = Category.get_contents(category) }
end
For this solution, content_categories must be a hash, not an array as you describe. Otherwise not sure where you're getting the key.
contents_by_categories = Hash[*content_categories.map{|k, v| [k, Category.getContents(v.id)]}]

Resources