Rails JSON : Empty/Blank data will not save in database - ruby-on-rails

I have this in my controller
#geo.message_notification = {
trigger_event: params[:ng_geo][:trigger_event],
ptc: {
id: params[:ng_geo][:ptc]
},
message: params[:ng_geo][:message],
mode: params[:ng_geo][:mode],
remind_interval: params[:ng_geo][:remind_interval],
document: {
id: params[:ng_geo][:document]
}
}.to_json
will produce JSON:
{
"trigger_event":"IOR",
"ptc":
{
"id":"184"
},
"message":"could you please be faster?",
"mode":"",
"remind_interval":"",
"document":
{
"id":"234"
}
}
As you can see in the JSON, empty data (mode & remind_interval) still save in db. how to avoid this so will produce just only attr with data:
{
"trigger_event":"IOR",
"ptc":
{
"id":"184"
},
"message":"could you please be faster?",
"document":
{
"id":"234"
}
}

Well, it seems to me there are some fundamental issues here.
First of all, a controller is not a good place to do this kind of stuff.
Second, you should pass this logic to database wrapper, like active record or mongoid.
Or you could do it quick and dirty:
#geo.message_notification = {
...
}.select{|_,v| !v.blank?}.to_json

Try this solution please:
ng_geo_params = params[:ng_geo].slice(:trigger_event, :ptc, :message, :mode, :remind_interval, :document).delete_if { |k, v| v.blank? }
# OR if you can
ng_geo_params = params.require(:ng_geo).permit(:trigger_event, :ptc, :message, :mode, :remind_interval, :document).delete_if { |k, v| v.blank? }
message_notification_hash = {}
ng_geo_params.each do |k, v|
if k == :ptc || k == :document
message_notification_hash[k] = { id: v }
else
message_notification_hash[k] = v
end
end
#geo.message_notification = message_notification_hash.to_json

Related

How to use variables in GraphQL mutation for bulk adjust inventory?

I trying to bulk adjust inventory item of my Shopify product variants as explained in this article: https://www.shopify.com/partners/blog/multi-location_and_graphql
I tried hardcoding the variants ID in the query and it worked great :
<<-'GRAPHQL'
mutation {
inventoryBulkAdjustQuantityAtLocation(
locationId: "gid://shopify/Location/5537988719",
inventoryItemAdjustments: [
{inventoryItemId: "gid://shopify/InventoryItem/21112836292719", availableDelta: 1},
{inventoryItemId: "gid://shopify/InventoryItem/21112836325487", availableDelta: 10}
]) {
inventoryLevels {
available
}
}
}
GRAPHQL
Now I am trying to set the product variants ID as variables like follow:
require "graphql/client"
require "graphql/client/http"
class HomeController < ApplicationController
API_KEY = 'XXXXXX'.freeze
PASSWORD = 'XXXXXX'.freeze
SHARED_SECRET = 'XXXXXX'.freeze
SHOP_NAME = 'xxxxxx'.freeze
API_VERSION = '2019-04'.freeze
shop_url = "https://#{API_KEY}:#{PASSWORD}##{SHOP_NAME}.myshopify.com/admin"
ShopifyAPI::Base.site = shop_url
ShopifyAPI::Base.api_version = API_VERSION
CLIENT = ShopifyAPI::GraphQL.new
BULK_ADJUST = CLIENT.parse <<-'GRAPHQL'
mutation inventoryBulkAdjustQuantityAtLocation($inventoryItemAdjustments: [InventoryAdjustItemInput!]!, $locationId: ID!) {
inventoryBulkAdjustQuantityAtLocation(inventoryItemAdjustments: $inventoryItemAdjustments, locationId: $locationId) {
inventoryLevels {
id
}
userErrors {
field
message
}
}
}
GRAPHQL
def bulk_update_inventory
inventoryItemAdjustments = [
{ "inventoryItemId" => "gid://shopify/InventoryItem/1234", "availableDelta" => 1 },
{ "inventoryItemId" => "gid://shopify/InventoryItem/5678", "availableDelta" => 10 }
]
variables = {
"inventoryItemAdjustments" => inventoryItemAdjustments,
"locationId" => "gid://shopify/Location/9012"
}
result = CLIENT.query(BULK_ADJUST,
variables: variables)
render :json => { :result => result }
end
end
When I try to run the query I reach the following error:
Unknown action
The action 'bulk_update_inventory' could not be found for HomeController
There is anybody knows why do I have this error?
Finally got the answer!
The correct query was:
BULK_ADJUST = CLIENT.parse <<-'GRAPHQL'
mutation($inventoryItemAdjustments: [InventoryAdjustItemInput!]!, $locationId: ID!) {
inventoryBulkAdjustQuantityAtLocation(inventoryItemAdjustments: $inventoryItemAdjustments, locationId: $locationId) {
inventoryLevels {
id
}
userErrors {
field
message
}
}
}
GRAPHQL
The word "inventoryBulkAdjustQuantityAtLocation" after the "mutation" keyword had to be removed.
check your routes file and make sure you set one up for that special path.

How to chaange my as_json method?

Now i have used the as_json method like this in my model
def as_json(options = {})
{
id: id,
diary_id: diary_id,
title: title,
post_date_gmt: date,
post_content: strip_tags(content),
smiley_id: smiley_id,
author_id: user_id,
author_name: user.display_name,
attachments: filter_attachments(options[:version]),
root_comments: format_comments(nested_comments.arrange(:order => :created_at)),
post_readings: post_readings.size,
is_read: read_by(options[:current_user])
}
end
I need to change this structure a bit as follows, Actually i want group this array by the date.
{
date_01: {
[post1], [post2], [post3]
},
date_02: {
[post1], [post2], [post3]
}
}
What should I do ?
I fixed the issue as follows
post_dates = (no_of_days.days.ago.to_date..(date_as_string.to_date + no_of_days.days)).map{ |date| date.strftime("%Y-%m-%d") }
# Arrange posts details under each date
i = 0
post_dates.each do |post_date|
posts_grouped_by_date[i] = {:post_date => post_date, :posts_for_date => diary.posts_for_date(Date.parse(post_date) )}
i = i + 1
end
render json: posts_grouped_by_date.sort_by {|hash| hash['post_date']}.as_json(current_user: current_user)
replace the values of data keys to an array of arrays. like below.
{
date_01: [
[post1], [post2], [post3]
],
date_02: [
[post1], [post2], [post3]
]
}

Join Ruby hash keys into string

I'm trying to create a Ruby template on the fly with Chef attributes but I can't figure out how to map the attributes to output the way I need.
Example Hash:
a = {
"route" => {
"allocation" => {
"recovery" => {
"speed" => 5,
"timeout" => "30s"
},
"converge" => {
"timeout" => "1m"
}
}
}
}
Would turn into:
route.allocation.recovery.speed: 5
route.allocation.recovery.timeout: 30s
route.allocation.converge.timeout: 1m
Thanks for the help.
You can use recursion if your hash is not large enough to throw stack overflow exception. I don't know what are you trying to achieve, but this is example of how you can do it:
a = {
"route" => {
"allocation" => {
"recovery" => {
"speed" => 5,
"timeout" => "30s"
},
"converge" => {
"timeout" => "1m"
}
}
}
}
def show hash, current_path = ''
hash.each do |k,v|
if v.respond_to?(:each)
current_path += "#{k}."
show v, current_path
else
puts "#{current_path}#{k} : #{v}"
end
end
end
show a
Output:
route.allocation.recovery.speed : 5
route.allocation.recovery.timeout : 30s
route.allocation.recovery.converge.timeout : 1m
I don't know Rails but I'm guessing that the following requires only a small tweak to give the result you want:
#result = []
def arrayify(obj, so_far=[])
if obj.is_a? Hash
obj.each { |k,v| arrayify(v, so_far+[k]) }
else
#result << (so_far+[obj])
end
end
arrayify(a)
#result
#=> [["route", "allocation", "recovery", "speed", 5],
# ["route", "allocation", "recovery", "timeout", "30s"],
# ["route", "allocation", "converge", "timeout", "1m"]]
EDIT: Did I completely misread your question - is the desired output a string? Oh dear.
I think this is a really good use case for OpenStruct:
require 'ostruct'
def build_structs(a)
struct = OpenStruct.new
a.each do |k, v|
if v.is_a? Hash
struct[k] = build_structs(v)
else
return OpenStruct.new(a)
end
end
struct
end
structs = build_structs(a)
output:
[2] pry(main)> structs.route.allocation.recovery.speed
=> 5
For anyone wanting to convert an entire hash with multi levels then here is the code I ended up using:
confHash = {
'elasticsearch' => {
'config' => {
'discovery' => {
'zen' => {
'ping' => {
'multicast' => {
'enabled' => false
},
'unicast' => {
'hosts' => ['127.0.0.1']
}
}
}
}
}
}
}
def generate_config( hash, path = [], config = [] )
hash.each do |k, v|
if v.is_a? Hash
path << k
generate_config( v, path, config )
else
path << k
if v.is_a? String
v = "\"#{v}\""
end
config << "#{path.join('.')}: #{v}"
end
path.pop
end
return config
end
puts generate_config(confHash['elasticsearch']['config'])
# discovery.zen.ping.multicast.enabled: false
# discovery.zen.ping.unicast.hosts: ["127.0.0.1"]

Build hash index from collection in ruby

here is what I"m trying to get from collection of records:
{
"transaction": {
"amount":"45.55",
"currency":"CAD",
},
"detail": {
"0": {
"sku":"Product_id",
},
"1": {
"sku":"Product_id",
},
"2": {
"sku":"Product_id",
}
}
}
I need to loop through order items and build hash with index.
# Order model
order has_many :items, class_name: "LineItem"
Order.column_names
=> ["id", "amount", "currency"]
# LineItem model
LineItem.column_names
=> ["id", "sku", "order_id"]
Here is what I have so far but looks like I can't do this:
{
transaction: {
amount: order.subtotal,
currency: order.currency,
},
detail: {
order.items.each_with_index do |item, index|
index: {
sku: item.sku
}
end
}
}.to_json
So, let's try to build nested hash separately but no luck either.
ha = items.each_with_index do |item, index|
index => Hash.new(sku: item.sku)
end
Here is what I ended up doing
body = {
transaction: {
amount:"45.55",
currency:"CAD",
}
}
items_hash = {}
items.each_with_index do |item, index|
h = { "#{index}" => { sku: item.sku } }
items_hash.merge!(h)
end
details = { "transaction_detail" => items_hash }
hash = hash.merge!(details)
hash.to_json

Convert JSON to new structure

I have a json object i need to convert it to new structure
source json
{
"application.name" : "testing",
"application.button.close" : "close",
"application.button.delete" : "delete",
"module.content" : "admin"
}
expected json
{
"application": {
"name" : "testing",
"button": {
"close": "close",
"delete": "delete"
}
},
"module": {
"content" : "admin"
}
}
I will split each of key that contain '.' sign and move it into new object.
I have tried but not work as expectation. Details my code are as below
def convert
result = {}
key_list = {
"application.name" => "testing",
"application.button.close" => "close",
"application.button.delete" => "delete",
"module.content" => "admin"
}
key_list.each { |k, v|
levels = k.split('.')
add_to_hash(result, k, v, levels)
}
end
def add_to_hash(result, key, value, levels)
current_level = levels.first
if(levels.count == 1)
{key => value}
else
levels.shift
unless(result.has_key?(current_level))
result[current_level] = {}
end
result[current_level].merge!( add_to_hash(result[current_level], levels.join('.'), value,levels) )
result
end
end
I am using ruby. thanks all!
Please try like this code.
class Converted
def self.convert
result = {}
key_list = {
"application.name" => "testing",
"application.button.close" => "close",
"application.button.delete" => "delete",
"module.content" => "admin"
}
key_list.each { |k, v|
levels = k.split('.')
add_to_hash(result, k, v, levels)
}
result
end
def self.add_to_hash(result, key, value, levels)
current_level = levels.first
if(levels.count == 1)
{key => value}
else
levels.shift
unless(result.has_key?(current_level))
result[current_level] = {}
end
result[current_level].merge!(add_to_hash(result[current_level], levels.join('.'), value,levels) )
result
end
end
end
Converted.convert

Resources