Rails 3.1 deep nesting with RABL - ruby-on-rails

I'm using the RABL gem to render JSON user data for users of comments which are children of annotations which are children of images. I'd like to do something similar to:
object #image
node :annotations do
#image.annotations.map { |a| {
:id => a.id,
:x1 => a.x1,
:x2 => a.x2,
:y1 => a.y1,
:y2 => a.y2,
node :comments do
#image.annotations.comments.map { |c| {
:body => c.body,
:user_id => c.user_id,
:name => User.find(c.user_id).name,
:user_icon => user_icon(User.find(c.user_id), 'square', 30)
}}
end
}}
end
I know this isn't valid in RABL, I also tried using child instead of node, but couldn't access the user data that way. How should I go about doing this and whats the proper syntax to make this happen?

I got this answer from #calvin-l. The trick was to just map the a.comments then grab the data from each comment that way:
node :annotations do
#image.annotations.map { |a| {
:id => a.id,
:x1 => a.x1,
:x2 => a.x2,
:y1 => a.y1,
:y2 => a.y2,
:comments => a.comments.map { |c| {
:body => c.body,
:created_at => c.created_at,
:user => {
:id => c.user.id,
:facebook_id => c.user.facebook_id,
:name => c.user.name,
:username => c.user.username
}
}}
}}
end

Related

How to convert mongoid criteria to array?

I have a mongoid criteria categories and I need to convert to an array. I'm using categories.to_a but this dont works and always that the mongoid criteria is iterate by .map it's doing a .find a new query.
How can I fix this?
def self.mapOffers (array, user)
array.map { |u|
{
:id => u.id.to_s,
:name => u.name,
:description => u.description,
:price => u.price,
:url => u.url,
:categories => Category.mapCategories(u.categories.to_a, user),
:picture => u.picture.url,
:accepts_cash => u.accepts_cash_transactions,
:location => {
:longitude => u.longitude,
:latitude => u.latitude,
:street => u.street,
:neighborhood => u.neighborhood,
:number => u.number,
:zip => u.zip,
:city => u.city,
:state => u.state,
:complement => u.complement,
:country => u.country,
},
:fixedMeetingPoint => u.fixedMeetingPoint,
:meetingPoint => {
:street => u.meetingPointStreet,
:neighborhood => u.meetingPointNeighborhood,
:number => u.meetingPointNumber,
:zip => u.meetingPointZip,
:city => u.meetingPointCity,
:state => u.meetingPointState,
:complement => u.meetingPointComplement,
:country => u.meetingPointCountry,
:latitude => u.meetingPointLatitude,
:longitude => u.meetingPointLongitude,
},
:notes => u.notes,
}}
end
def self.mapCategories (array, user)
array.map { |u| {
:id => u.id.to_s,
:name => u.name,
:selected => !user.nil? && u.users.include?(user),
:picture => u.picture.url,
}}
end
Starting from criteria:
scope = Band.where(name: 'foo')
... retrieve the complete result set from the database and store in an array:
bands = scope.to_a
... then iterate the array any number of times:
bands.each { |band| ... }
bands.each { |band| ... }

Shippo API Integration: Status returns as "ERROR" even if "VALID"

I've integrated Shippo with my Ruby on Rails Spree platform. Everything seems to be working great, except that when I go to create a transaction to print shipping labels, I get an error in the response.
Here's my response:
#<Transaction:0x3feee363470c[id=1b419434531e4b43b438c54b93e2a9f5]
{"object_state"=>"VALID", "status"=>"ERROR", "object_created"=>"2017-06-27T23:11:54.567Z", "object_updated"=>"2017-06-27T23:11:55.330Z", "object_id"=>"xxxx", "object_owner"=>"----#gmail.com", "test"=>true, "rate"=>{"object_id"=>"xxxx", "amount"=>"6.52", "currency"=>"USD", "amount_local"=>"6.52", "currency_local"=>"USD", "provider"=>"USPS", "servicelevel_name"=>"Priority Mail", "servicelevel_token"=>"usps_priority", "carrier_account"=>"xxxx"}, "tracking_number"=>"", "tracking_status"=>nil, "tracking_history"=>[], "tracking_url_provider"=>"", "label_url"=>"", "commercial_invoice_url"=>nil, "messages"=>[#<Hashie::Mash code="" source="USPS" text="Request failed. Please try again or contact Shippo support at support#goshippo.com.">], "order"=>nil, "metadata"=>"", "parcel"=>"xxxx"}->#<Shippo::API::ApiObject created=2017-06-27 23:11:54 UTC id="1b419434531e4b43b438c54b93e2a9f5" owner="xxxx#xxxx.com" state=#<Shippo::API::Category::State:0x007fddbca5a2e8 #name=:state, #value=:valid> updated=2017-06-27 23:11:55 UTC>
Here's the code used to create the label:
def self.createLabel(order_info)
shipping_info = order_info.shipping_address
stock_location = order_info.store.stock_location
address_from = {
:name => stock_location.name,
:company => order_info.store.name,
:street1 => stock_location.address1,
:street2 => stock_location.address2,
:city => stock_location.city,
:state => "#{Spree::State.find(stock_location.state_id)}",
:zip => stock_location.zipcode,
:country => "#{Spree::Country.find(stock_location.country_id)}",
:phone => stock_location.phone,
}
address_to = {
:name => "#{shipping_info.firstname} #{shipping_info.lastname}",
:company => shipping_info.company,
:street1 => shipping_info.address1,
:street2 => shipping_info.address2,
:city => shipping_info.city,
:state => "#{Spree::State.find(shipping_info.state_id)}",
:zip => shipping_info.zipcode,
:country => "#{Spree::Country.find(shipping_info.country_id)}",
:phone => shipping_info.phone,
:email => order_info.email
}
parcel = {
:length => getLength(order_info),
:width => getWidth(order_info),
:height => getHeight(order_info),
:distance_unit => :m,
:weight => getWeight(order_info),
:mass_unit => :lb
}
shipment = {
:address_from => address_from,
:address_to => address_to,
:parcels => parcel
}
#Shippo Carrier ids
#ups = Rails.application.secrets.ups_shippo_id
#usps = Rails.application.secrets.usps_shippo_id
transaction = Shippo::Transaction.create(
:shipment => shipment,
:carrier_account => "#{#usps}",
:servicelevel_token => "usps_priority",
:label_file_type => "PDF",
:async => false
)
end
Has anyone run into this issue before? I've looked at their documentation and cannot find any reason for a "status"=>"ERROR" message, when the "object_state"=>"VALID".
I'm happy to post more code if needed. Thanks.
What I found with lots of trial and error, was that the products I was sending to Shippo actually exceeded the weight the shipping carrier would allow in a package. (This was because my database was a bunch of dummy data). Be sure to be setting your measurement units as well, here:
parcel = {
:length => getLength(order_info),
:width => getWidth(order_info),
:height => getHeight(order_info),
:distance_unit => :m,
:weight => getWeight(order_info),
:mass_unit => :lb
}
After changing the data in my database to have reasonable weights on the products, this error went away.

possible to nest method calls on to_json

I'm trying to do something like this:
render :json => r.to_json(:methods => [:food_item => {:method => :price_value}])
but it's not working. Is something like this even possible?
thx
edit 1
no association
def food_item
MenuItem.find(food_id)
end
Is food_item an ActiveRecord association? If so, you could try
render :json => r.to_json(:include => { :food_item => { :only => :price_value } })
I'll refine my answer in response to "edit 1". First, remove your food_item method and add an actual association like this:
belongs_to :food_item, :class_name => "MenuItem", :foreign_key => "food_id"
and then do
render :json => r.to_json(:include => { :food_item => { :only => [:price_value] } })

Minimizing number of Queries

I currently have this:
data = []
products.each do |product|
categories = product.shop_categories.select("shop_categories.id, shop_categories.name").map do |category|
{
:name => category.name,
:category_id => category.id.to_s
}
end
data << {
:name => product.name,
:product_id => product.productid,
:manufacturer => product.manufacturer,
:detail => product.description,
:categories => categories,
:sales_rank => product.sales_rank,
:sale_price => product.sale_price.to_f,
:price => product.price.to_f,
:images => product.images,
:url => product.url,
:is_rated => current_user.voted_for?(product),
:is_liked => current_user.voted_as_when_voted(product),
:is_in_wishlist => current_user.has_product_in_wishlist?(product)
}
end
This part where products are searched for its shop_categories are taking up a huge amount of time to query since every product (100 per run) when it searches for the products' shop_categories.
Is there a way to minimize the number of queries or at least minimize the CPU being used up by this process?
Use includes to eager-load the association:
data = Product.includes(:shop_categories).collect do |product|
{
:name => product.name,
:product_id => product.productid,
:manufacturer => product.manufacturer,
:detail => product.description,
:categories => product.categories.collect { |c| { :name => c.name, :category_id => c.id.to_s } },
:sales_rank => product.sales_rank,
:sale_price => product.sale_price.to_f,
:price => product.price.to_f,
:images => product.images,
:url => product.url,
:is_rated => current_user.voted_for?(product),
:is_liked => current_user.voted_as_when_voted(product),
:is_in_wishlist => current_user.has_product_in_wishlist?(product)
}
end

include 2nd level in to_json

I'm using this code to convert a model to json. If i try to use an include 2nd level like this:
p = Product.includes({ :variants => { :stocks => :size } }).where(:id => params[:id]).first
render :json => p.variants.to_json(:include => { :stocks => { :include => :size } })
I receive this error:
undefined method `macro' for nil:NilClass
How I can solve that?
Try this:
render :json => p.variants.map { |v| v.as_json(:include => {:stocks => {:include => :size}}) }
Info about Object#as_json/to_json here.

Resources