Include counts in as_json method - ruby-on-rails

I have a Customers table and an Orders table. Each customer has multiple orders. When I do a Customers.all.as_json(:include => :orders), I get all the orders but I just want to get the count
I tried Customers.all.as_json(:include => {:orders => {:only => [], :methods => [:custom_method_to_get_order_count}}) though it gets the correct count I have array of object that are equal to count.
Wrong output! :(
[
{
:customer_id => 1,
:customer_name => "ABC",
:orders => [
{:custom_method_to_get_order_count => 2},
{:custom_method_to_get_order_count => 2}
]
},
{
:customer_id => 2,
:customer_name => "DEF",
:orders => [
{:custom_method_to_get_order_count => 3},
{:custom_method_to_get_order_count => 3},
{:custom_method_to_get_order_count => 3}
]
},
{
:customer_id => 3,
:customer_name => "XYZ",
:orders => [
{:custom_method_to_get_order_count => 10},
{:custom_method_to_get_order_count => 10},
{:custom_method_to_get_order_count => 10},
{:custom_method_to_get_order_count => 10},
{:custom_method_to_get_order_count => 10},
{:custom_method_to_get_order_count => 10},
{:custom_method_to_get_order_count => 10},
{:custom_method_to_get_order_count => 10},
{:custom_method_to_get_order_count => 10},
{:custom_method_to_get_order_count => 10}
]
}
]
Correct output I am looking for
[
{
:customer_id => 1,
:customer_name => "ABC",
:orders => {
:custom_method_to_get_order_count => 2
}
},
{
:customer_id => 2,
:customer_name => "DEF",
:orders => {
:custom_method_to_get_order_count => 3
}
},
{
:customer_id => 3,
:customer_name => "XYZ",
:orders => {
:custom_method_to_get_order_count => 10
}
}
]

You can also use like this:
class Customers
def get_orders_count
self.orders.count
end
end
and now you can get all orders count in customer object:
Customers.all.as_json(method: :get_orders_count)
Output will be something like:
[
{
:customer_id => 1,
:customer_name => "ABC",
:get_orders_count => 12
},
{
:customer_id => 2,
:customer_name => "DEF",
:get_orders_count => 20
},
{
:customer_id => 3,
:customer_name => "XYZ",
:get_orders_count => 50
}
]

Never mind! I got the answer.
class Customers
def custom_method_to_get_order_count
Orders.where(:customer_id => id).count
end
end
What's happening to me, whenever I post the question on SO, I get the answer!

Related

How to create an array of hashes by mapping 2 hashes in ruby on rails

I am using Ruby on Rails application. I want to combine 2 array of hashes with hash and to result in array of hashes.
Inputs:
first_array_of_hash = [{:name => "John", :age => 34, :mode => "nullable"},{:name => "Rose", :age => 30, :mode => "nullable"}]
second_hash = {:field_name => "", :field_age => nil, :field_nullable => false, :field_default => ""}
I want my result to be like below
result = [{:field_name => "John", :field_age => 34, :field_nullable => true, :field_default => ""},{:field_name => "Rose", :field_age => 30, :field_nullable => true, :field_default => ""}]
You can use a regular Array#map for this:
first_array_of_hash = [{:name => "John", :age => 34, :nullable => 'yes'},{:name => "Rose", :age => 30, :nullable => 'no'}]
second_hash = {:field_name => "", :field_age => nil, :field_nullable => false, :field_default => ""}
def transform(object)
{
field_name: object[:name],
field_age: object[:age],
field_nullable: object[:mode] == 'nullable'
}
end
result = first_array_of_hash.map do |object|
second_hash.merge(transform(object))
end
puts result

Ruby on Rails How to build a Payment model to deal with Paypal REST SDK

I'd like to create a Payment model along the official Paypal Example on Github.
But I'm stuck in the creating of the model with the desired fields.
Payment.new({
:intent => "sale",
:payer => {
:payment_method => "paypal" },
:redirect_urls => {
:return_url => "http://localhost:3000/payment/execute",
:cancel_url => "http://localhost:3000/" },
:transactions => [{
:item_list => {
:items => [{
:name => "item",
:sku => "item",
:price => "5",
:currency => "USD",
:quantity => 1 }]},
:amount => {
:total => "5",
:currency => "USD" },
:description => "This is the payment transaction description." }]})
Starting with rails g model Payment intent:string ... I don't know how to create the nested fields like
:redirect_urls => {
:return_url => "http://localhost:3000/payment/execute",
:cancel_url => "http://localhost:3000/" }
and more deeper
:transactions => [{
:item_list => {
:items => [{
:name => "item",
:sku => "item",
:price => "5",
:currency => "USD",
:quantity => 1 }]},
Thanks for any help!
You can use OpenStruct to do this for you. It will be something like this :
paypal_hash = {
:intent => "sale",
:payer => {
:payment_method => "paypal" },
:redirect_urls => {
:return_url => "http://localhost:3000/payment/execute",
:cancel_url => "http://localhost:3000/" },
:transactions => [{
:item_list => {
:items => [{
:name => "item",
:sku => "item",
:price => "5",
:currency => "USD",
:quantity => 1 }]},
:amount => {
:total => "5",
:currency => "USD" },
:description => "This is the payment transaction description." }]}
paypal_obj = OpenStruct.new(paypal_hash)
paypal_obj.intent
# => "sales"

Rails how to group by nested hash

I have no clue to solve this question. I got a nested hash inside an array called data. Here is its structure.
data =
[
{
:id => 1,
:name => "S1",
:children => [
{
:id => 10,
:name => "S10",
:children => [
{
:id => 20,
:name => "S20"
}
]
}
]
},
{
:id => 1,
:name => "S1",
:children => [
{
:id => 10,
:name => "S10",
:children => [
{
:id => 21,
:name => "S21"
}
]
}
]
},
{
:id => 1,
:name => "S1",
:children => [
{
:id => 11,
:name => "S11",
:children => [
{
:id => 22,
:name => "S22"
}
]
}
]
}
]
As you can see, there are bunch of elements which have the same id in the first layer or second layer, so I need to group them.
I hope the result will be
result=
[
{
:id => 1,
:name => "S1",
:children => [
{
:id => 10,
:name => "S10",
:children => [
{
:id => 20,
:name => "S20"
},
{
:id => 21,
:name => "S21"
}
]
},
{
:id => 11,
:name => "S11",
:children => [
{
:id => 22,
:name => "S22"
}
]
}
]
}
]
I've tried somthing like
data.group_by{|s| s[:id]}
However, it would only group the first layer, I don't know how to group nested structure.
Yeah you need some kind of recursive method to recursively combine and group the nested children.
This produces the result you want:
def group(data)
r = {}
# Combine the children
data.each do |d|
if r[d[:id]]
r[d[:id]][:children] += d[:children]
else
r[d[:id]] = d
end
end
# Now group the children
r.values.map do |d|
d[:children] = group(d[:children]) if d[:children]
d
end
end

Why am I getting singleton cant be dumped err?

When I try to add a variable value into session, I am getting singleton cant be dumped err.
Here is the value in the varibale
[
[0] {
:id => "574ecb43a7a5bb44c000443b",
:_id => "574ecb43a7a5bb44c000443b",
:active => true,
:capabilities => {
:network_connections => [
[0] {
:type => "ethernet-wan",
:name => "wan"
},
[1] {
:type => "ethernet-lan",
:name => "lan"
},
[2] {
:type => "wifi",
:name => "wlan"
},
[3] {
:type => "cellular",
:name => "wwan"
}
]
},
:commander_ids => [],
:created_at => "2016-05-11T15:46:12+00:00",
:deleted_at => nil,
:firmware_upgradable => true,
:ingestor_ids => [],
:last_known_translator_port => nil,
:long_description => "this is a liong desc",
:manufacturer => "test_sushant",
:model => "sushant_test",
:name => "zxc",
:parent_gateway_data_source_type_id => nil,
:rule_ids => [],
:software => "qwe",
:translator => "edge",
:type => "asd",
:updated_at => "2016-05-11T15:46:12+00:00",
:user_id => "572adee5a7a5bb320b000852"
},
The variable is an array of objects. I do not know why this is causing an err.

Advanced grouping in Ruby

I want to group events by their days.
Prefact:
Available days are 1,2,3,4,5,6,7
One event can not contain duplicates. e.g [1,1,2,3]
Setup is Ruby 1.9.2 with Rails 3.2
An event is containing like 8-10 more attributes(unnecessary to include in example, but should be considered, these attributes should still be there after grouping.) In other words the event objects should not be altered only grouped as is.
Consider an array with objects:
events = [
{
:name => "event1",
:days => [1,2,3,4,5]
},
{
:name => "event2",
:days => [1,4,5]
},
{
:name => "event3",
:days => [1]
},
{
:name => "event4",
:days => [2]
},
{
:name => "event5",
:days => [3]
},
{
:name => "event6",
:days => [4]
},
{
:name => "event7",
:days => [5]
},
{
:name => "event8",
:days => [1,2,3]
},
{
:name => "event9",
:days => [1,5]
},
{
:name => "event10",
:days => [1,2]
},
{
:name => "event11",
:days => [1,2,3,4,5]
}
]
To be grouped an event must have at least 3 days. And these days should be in numerically order.
Example(should be grouped): [1,2,3]
Example(should not be grouped): [1,4,5]
Events that's not suitable for grouping should be placed in each day they contain.
Example: [1,4,5] should be placed in 1,4 and 5.
The desired result of events array above:
[
{
:heading => "1",
:events => [
{
:name => "event3",
:days => [1]
},
{
:name => "event9",
:days => [1,5]
},
{
:name => "event10",
:days => [1,2]
},
{
:name => "event2",
:days => [1,4,5]
}
]
},
{
:heading => "2",
:events => [
{
:name => "event4",
:days => [2]
},
{
:name => "event10",
:days => [1,2]
}
]
},
{
:heading => "3",
:events => [
{
:name => "event5",
:days => [3]
}
]
},
{
:heading => "4",
:events => [
{
:name => "event6",
:days => [4]
},
{
:name => "event2",
:days => [1,4,5]
}
]
},
{
:heading => "5",
:events => [
{
:name => "event7",
:days => [5]
},
{
:name => "event9",
:days => [1,5]
},
{
:name => "event2",
:days => [1,4,5]
}
]
},
{
:heading => "1-3",
:events => [
{
:name => "event8"
}
]
},
{
:heading => "1.5",
:events => [
{
:name => "event1"
},
{
:name => "event11"
}
]
}
]
It is very advanced Ruby here. Maybe too advanced for me, everything I've tried ends up missing one part of the equation. But hey it's Ruby, it shouldn't be that hard?
EDIT: Updated example with clarification and corrected expected output
require 'pp'
pp(events.inject(Hash.new { |h, k| h[k] = [] }) do |m, e|
days = e[:days]
event = { :name => e[:name] }
if days.size >= 3 && days.last - days.first + 1 == days.size
m["%d-%d" % [days.first, days.last]] << event
else
days.each { |d| m[d.to_s] << event }
end
m
end)
I would modify DigitalRoss's answer slightly. I would change
if days.size >= 3 && days.last - days.first + 1 == days.size
to
if days.size >= 3 && (days.first..days.last).to_a == days
This will catch [1,1,3,4]...
It would also be wise to sort the days array before testing!

Resources