Rails: How to convert hash of array of objects to json - ruby-on-rails

I'm a java and Js developer, so I'm completetly new to rails and ruby. In one of my project I'm using rails to consume an api and return in back to js. I'm converting the api response to a model in ruby.
Now, it's in format of {KEY1=>[{array of objects(my model)}], KEY2=>[{array of objects(my model)}]}
Also the keys to model is in snake_case. My requirement is to loop through this and convert this into JSON with camel case keys.
Api response after converting to model: { KEY1=>[{#person_name:"abc", #person_id="123"}],KEY2:[{#personName:"bca", #person_id="231"}] }
Desired output: { KEY1:[{personName:"abc", personId:"123"}],KEY2:[{personName:"bca",personId:"231"}] }
I tried using .map and .transform_values till now, but don't know where I'm doing wrong.
Any help is appreciated.

You can add the following to your ApplicationRecord class:
class ApplicationRecord < ActiveRecord::Base
def serializable_hash(options = {})
hash = super
return hash unless options[:camelize]
hash.deep_transform_keys { |key| key.to_s.camelize(options[:camelize]) }
end
end
This will allow you to call to_json(camelize: :lower) on pretty much any object:
{
KEY1: Person.where(...),
KEY2: Person.where(...),
}.to_json(camelize: :lower)
To automatically serialize the whole collection

You can do something like this:
{
KEY1: Person.where(...).select(:name, :id).map { |p| Hash[p.serializable_hash.map { |key, value| ["#{p.model_name.name.downcase}#{key.capitalize}", value] }] },
KEY2: Person.where(...).select(:name, :id).map { |p| Hash[p.serializable_hash.map { |key, value| ["#{p.model_name.name.downcase}#{key.capitalize}", value] }] }
}.to_json

Related

i want to add numbering at the beginning of the name in the dropdown list in ruby on rails

in my controller i have written like this
#agendas = #agendas.each{ |e| puts e.name }
#agenda_alpha = #agendas.each_with_index.map { |agenda_key, i| ["#{i+1}.#{agenda_key}"] }
in my slim file i wrote this
label_method: ->(agenda) { #agenda_alpha },
This are the attributes in my rails console
i have to fetch the name attribute into the dropdown
It probably makes sense to translate the options into the required format in the controller or a helper first.
#options = %w[Apple Ball Cat]
#options = #options.each_with_index.map { |value, i| ["#{i}.#{value}", value] }
#=> [["0.Apple", "Apple"], ["1.Ball", "Ball"], ["2.Cat", "Cat"]]
Then just use this #options in your view:
f.select(:attribute_name, #options)

How can I build a GQL from a ruby hash?

I am building a rspec helper to test my graphql requests.
So far this is my helper:
def mutation_params(name, attributes:, return_types:)
{
query:
<<~GQL
mutation {
#{name}(
input: { attributes: #{attributes} })
#{return_types}
}
GQL
}
end
and I have to declare the attributes like this:
let(:attributes) do
<<~GQL
{
email: "#{email_param}",
password: "#{password_param}"
}
GQL
end
Now I want to know what I can do to be able to simply pass my arguments as a hash, and have the mutations_params method build the GQL from that hash, by iterating over them.
let(:attributes) do
{
email: email_param,
password: password_param
}
end
Something like:
def mutation_params(name, attributes:, return_types)
gql_attributes = <<~GQL
{
}
GQL
attributes.each do |key, value|
gql_attributes merge with
<<~GQL
"#{key}": "#{value}"
GQL
end
{
query:
<<~GQL
mutation {
#{name}(
input: { attributes: #{gql_attributes} })
#{return_types}
}
GQL
}
end
but that obviously does not work. I think my problem is I don't really understand what that <<~GQL is and how to manipulate it.
You're looking for the squiggly heredoc which was introduced in Ruby 2.3. It's like a normal heredoc but it leaves off leading indentation. https://ruby-doc.org/core-2.5.0/doc/syntax/literals_rdoc.html
So in other words, it's just a string! The GQL bit is arbitrary but a nice way of communicating the purpose of the heredoc.
You could write a helper like this to turn hashes into GraphQL strings
def hash_to_mutation(hash)
attr_gql_str = attributes.map{|k,v| "#{k}: #{v.inspect}"}.join(", ")
" { #{attr_gql_str} } "
end
Then assuming attributes is a hash as in your example you could just
def mutation_params(name, attributes:, return_types:)
{
query:
<<~GQL
mutation {
#{name}(
input: { attributes: #{hash_to_gql(attributes)} })
#{return_types}
}
GQL
}
end

how to create an array of hashes by looping over array of objects

I have following array of hash. I am trying to loop over it and build an array of hash of values of id and product_order_id.
objects =
[
#<Product: 0x00007ffd4a561108
#id="1",
#product_id="2",
#product_order_id="23",
#description="abc",
#status="abcde",
#start_date=nil,
#end_date=nil>,
#<Product: 0x00007ffd4a560c80
#id="45",
#product_id="22",
#product_order_id="87",
#description="ahef",
#status="gesff",
#start_date=nil,
#end_date=nil>
......more objects.....
]
This is what it should look like
[{ "1": "23" }, { "45": "87" }] -->its going to be uuid
I tried doing this but no luck
def mapped_product(objects)
mapping = []
objects.each do |object|
mapping << {
object.product_order_id: object.id
}
end
end
Any idea?
inline solution:
> Hash[objects.map{|p| [p.id, p.product_order_id] }]
# Output : [{ 1=>23 }, { 45=>87 }]
I'd usually implement it using an each_with_object
objects.each_with_object({}) { |obj, acc| acc[obj.id] = obj.product_order_id }
Unless I reaaaly want to squeeze some performance, than I'd go with Gagan's answer
Have you tried this?
def mapped_product(objects)
mapping = []
objects.each do |object|
mapping << {
object.id => object.product_order_id # I'm using an `=>` here
}
end
mapping # return the new mapping
end
I've just changed the : on the hash for a => to "make it dynamic" and swapped the values of id and product_order_id
You can also use a map here:
def mapped_product(objects)
objects.map do |object|
{ object.id => object.product_order_id }
end
end

Rails merge multiple object into one array

I am creating API. Using ActiveRecords. Problem I am getting
Multiple array object of country, all I want one array containing all location
Current Output
{
"id": "180a096",
"country": [
{
"location": "US"
},
{
"location": "CH"
}
]
}
Expected Output
{
"id": "180a096",
"country": [
{"location":["US","CH"]}
]
}
Code
def as_json(options={})
super(:only => [:id ],:include => { :country => { :only => :location } })
end
Can anyone help me to restructured the object as in expected output.
If your hash is called hash you can do:
hash[:country].map {|h| h[:location]}
If you have to access attributes on associated models you can do:
countries.pluck(:location)
Unrelated to the question, but when I have to manage country info in my app I tend to use the countries gem. https://github.com/hexorx/countries
It has all kinds of useful helper methods, and it prevents you from having to maintain standardized country information.
You can simply map all the location and assign it to hash[:country]
2.4.0 :044 > hash[:country].map! { |c| c[:location] }
=> ["US", "CH"]
2.4.0 :045 > hash
=> {:id=>"180a096", :country=>["US", "CH"]}
As mentioned in my comment, you can do in one line like
actual_hash[:country].map! { |country| country[:location]}
actual_hash # => {:id=>"180a096", :country=>["US", "CH"]}
The output is clean but not as expected.
Or, a bit more lines to get the exact output:
location_array = [{location: []}]
actual_hash[:country].each { |country| location_array[0][:location] << country[:location]}
actual_hash[:country] = location_array
actual_hash # => {:id=>"180a096", :country=>[{:location=>["US", "CH"]}]}
def rearrange_json(input)
input_hash = JSON.parse(input)
output_hash = input_hash.clone
output_hash[:country] = {location: []}
input_hash[:country].map {|l| output_hash[:country][:location] << l[:location] }
output_hash.as_json
end
With this method, you can convert your json to a hash, then rearrange its content they way you want by adding the country codes as values for the [:country][:location] key of the output hash, and end up with some properly formatted json. It's not a one-liner, and probably not the most elegant way to do it, but it should work.

Rails, Grape create custom JSON from collection

I started to learn how to use Grape. I have collection with a lot of attributes and want only some of them. I did something like this:
get :all_elements do
[
my_collection.each do |element|
{
id: element.id,
name: element.name
}
end
]
end
However this is not working. How can I create custom json array from collection?
Please try this code.
list = my_collection.map do |element|
{ :id => element.id,
:name => element.email
}
end
list.to_json

Resources