Read a JSON document and create a new one in Rails - ruby-on-rails

How can I read everything inside a JSON document and create another one with new names?
I can't find something that will help me create a new JSON file in an easy way.
Edit:
I am retrieving a ton of data in JSON format from a MongoDB database (as an array [{"xxx": "zz"}, ... ]). What I need is to cycle trough each document, each field and create a new JSON document using those fields.
thanks

Here's the gist of what you want:
#keys = {
"old" => "new",
"foo" => "bar"
}
def rename_key(pair)
old_key = pair.keys.first
{ #keys[old_key] => pair[old_key] }
end
pairs = ActiveSupport::JSON.decode(json)
pairs.map! { |pair| rename_key(pair) }
new_json = pairs.to_json
Obviously, you'd want to turn this into a class or two. Note that I made the assumption that all data from Mongo was in the form of simple key => value pairs, based on your description.

Related

Convert field from integer to string in one rails Active Record relation before sending json

In my Rails 4 app, I actually send an active record relation in JSON with:
[...]
wine['varietals'] = record.varietals
#wines << wine
format.json { render :json => { :success => "OK", :items => #wines } }
[...]
wine['varietals'] is an array of AR relations. My problem is the varietal model contains a field named grape_id that is an integer. I need to send it in string for my WS. I don't want to make a custom conversion to JSON just for this field.
How to force this field to be string before the automatic JSON conversion ? If possible I don't want to make an array of hashes and keep the AR style with dot: model.field
wine['varietals'].each do |varietal|
varietal.grape_id.to_s
end
Of course this doesn't work.
All Rails models have an as_json method that gets called when rednering the model to JSON. You can override this method within your models to set up custom JSON formatting. In your case, you may want to add something like this to your Wine model:
def as_json(opts = {})
json = super(opts)
json["grape_id"] = self.grape_id.to_s
json
end
The method gives you the default model JSON when you call the super method and set it to the json variable, then stringifies grape_id and sets it in the JSON, and finally returns the updated JSON.
Now, any time a controller returns a JSON version of single Wine model, or an association of multiple Wine models, the JSON will be formatted through this updated method and the grape_id will be stringified every time.

check if name == keyword

So i have a json here and im trying to search for name
I am trying to read through the whole json, and only match to name. But im not sure how to go about that.
I parsed the json below into a variable called jsondata
and created this loop here to read it.
jsondata.each do |links|
puts links
end
But how can i go about only reading the name field and matching it to a string? Lets say im looking looking for the word leo.
{"files":[{"name":"github.jpeg","size":10852,"deleteType":"DELETE","deleteUrl":"http://gifs.meow.me/github.jpeg","url":"http://gifs.meow.me/github.jpeg"},{"name":"leo.jpg","size":51678,"deleteType":"DELETE","deleteUrl":"http://gifs.meow.me/leo.jpg","url":"http://gifs.meow.me/leo.jpg"},{"name":"leo2.jpg","size":41407,"deleteType":"DELETE","deleteUrl":"http://gifs.meow.me/leo2.jpg","url":"http://gifs.meow.me/leo2.jpg"}]}
You can search each string under the key of "name" for the needle you're looking for using String#include? or String#index. The Enumerable method select would be a good choice for selecting only the hashes that contain the data you're looking for:
jsondata["files"].select{|h| h["name"].include? "leo" }
This presumes you have parsed the json data into a Ruby hash:
jsondata = {"files"=>[
{"name"=>"github.jpeg",
"size"=>10852,
"deleteType"=>"DELETE",
"deleteUrl"=>"http=>//gifs.meow.me/github.jpeg",
"url"=>"http=>//gifs.meow.me/github.jpeg"},
{"name"=>"leo.jpg",
"size"=>51678,
"deleteType"=>"DELETE",
"deleteUrl"=>"http=>//gifs.meow.me/leo.jpg",
"url"=>"http=>//gifs.meow.me/leo.jpg"},
{"name"=>"leo2.jpg",
"size"=>41407,
"deleteType"=>"DELETE",
"deleteUrl"=>"http=>//gifs.meow.me/leo2.jpg",
"url"=>"http=>//gifs.meow.me/leo2.jpg"}
]}
jsondata["files"].select{|h| h["name"].include? "leo" }
# => [{"name"=>"leo.jpg", "size"=>51678, "deleteType"=>"DELETE", "deleteUrl"=>"http=>//gifs.meow.me/leo.jpg", "url"=>"http=>//gifs.meow.me/leo.jpg"}, {"name"=>"leo2.jpg", "size"=>41407, "deleteType"=>"DELETE", "deleteUrl"=>"http=>//gifs.meow.me/leo2.jpg", "url"=>"http=>//gifs.meow.me/leo2.jpg"}]
jsondata.each do |link|
if link.name =~ /leo/
# do something
end
end
or
jsondata.each do |link|
if link.name.include? 'leo'
# do something
end
end
Using jsondata as defined by #Cam, you can do the following.
jsondata["files"].each_with_object({}) { |g,h|
h[g["name"]]=g["url"] if g["name"] =~ /\Aleo/ }
#=> {"leo.jpg"=>"http=>//gifs.meow.me/leo.jpg",
# "leo2.jpg"=>"http=>//gifs.meow.me/leo2.jpg"}

Rails how to build a hash from results

I have a table on Db with two fields: group and text
I want to retrieve all records and convert into an hash grouped by the group field, and containing an array of all texts, something like this:
{
'group_1': ['text1','text2',...]
'group_2': ['text1','text2',...]
'group_3': ['text1','text2',...]
}
I acomplish it partially with this
MyModel.all.group_by(&:group)
but it returns an array with all the full AR object, i just want an array of all the text strings
I was trying with map but I can figure out how to do this without using each
Any idea?
Try the following:
MyModel.all.select([:text, :group]).group_by(&:group)
If you wanted to use an iterator (ex: each/map), here is how you would do it:
grouped_models = MyModel.all.group_by(&:group)
grouped_models.map do |group, models|
grouped_models[group] = models.map(&:text)
end
grouped_models
# => { 'group_1' => ['text1', 'text2'], 'group_2' => ['text'] }

Mapping through a hash of key/values

I have a form being submitted that is saving multiple records, and the parameters look something like this:
{
"utf8"=>"✓",
"_method"=>"put",
"products"=> {
"321" => {
"sale_price"=>"10"
},
"104" => {
"sale_price"=>"10"
}
}
}
Then in my controller, I have this:
#updated_products = Product.update(params[:products].keys, params[:products].values)
This expects the keys (321, 104) to be IDs.
However, I'm using the to_param in my model to change my urls from IDs to another column value.
Is there a way to take the params[:products].keys and swap them for the appropriate IDs so I can use IDs in the .update() statement.
I can use Product.find_by_column_name(321).id to get the id although I don't know how to do this. Still new to rails.
Any help would be appreciated. Thanks.
Looking at the source code here #update iterates through each key and runs update_attributes so it goes through all the validations. You can change your method to
#updated_products = params[:products].inject([]) do |array, (column_id, attributes)|
product = Product.find_by_column_id column_id
if product.update_attributes(attributes)
array << product
else
array
end
end
This may seem a little complex but it is equal to this one below which is easier to understand and code read
#updated_products = []
params[:products].each do |column_id, attributes|
product = Product.find_by_column_id column_id
if product.update_attributes(attributes)
#updated_products << product
end
end

Ruby/Rails - Can't access JSON object attributes directly in controller

I am setting up an API.
The client (using HTTParty) posts this to the API:
{:body =>
{
:product=> {:description=>"some text", :cost => "11.99"},
:brand=> {:name=>"BrandName", :etc =>"hey"}
}
}
The server/api receives the post.
Now, if I access params[:brand] I get:
{"name"=>"BrandName", "etc" =>"hey"}
If I do this:
Brand.new(params[:brand])
Then I get a new Brand object with the "name" and "etc" attributes populated correctly.
However, if I try to access params[:brand][:name], I just get nil
Any ideas?
Thanks.
Use params[:brand]["name"] or params["brand"]["name"]
Hash keys can be any sort of object. Common rails practice is to use symbols as hash keys, but when translated from JSON, the keys are likely to be strings.

Resources