Hi I'm working on a rails project, I updated the development database of my project recently. I had sqlite, now I have Postgres.
I have this method for my Product model:
def self.update_products!
ec_products = ElemetalCapital::Product.all
transaction do
ec_products.each do |ec_product|
product = ElemetalCapitalProduct.where(id: ec_product.id).first_or_initialize
product.spot_id = ec_product.spot
product.goldtrex_markup ||= 1 # default to a 1% markup
product.description = ec_product.description
product.metal = ec_product.metal
product.weight = ec_product.weight
product.elemetal_capital_premium = ec_product.premiumBuy
product.save!
end
end
end
Before the Postgres update, the method was working properly. However, after the update I'm getting this error, how can I fix that problem:
[2] pry(main)> Product.update_products!
(0.5ms) BEGIN
ElemetalCapitalProduct Load (0.5ms) SELECT "products".* FROM "products" WHERE "products"."type" IN ('ElemetalCapitalProduct') AND "products"."id" = $1 ORDER BY "products"."id" ASC LIMIT 1 [["id", "GKILO-OPM"]]
(0.4ms) ROLLBACK
ActiveResource::ResourceNotFound: Failed. Response code = 404. Response message = Not Found.
from /Users/enriquesalceda/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activeresource-4.0.0/lib/active_resource/connection.rb:144:in `handle_response'
Something that is very strange on the is the "products"."id" = $1
, it shouldn't be $1.
This app use the API of a supplier elemetal capital, which provides the info about their products, and prices, then after a few calculations we update the shopify database. Just for the record:
This is my entire Product model:
class Product < ActiveRecord::Base
self.primary_key = :id
monetize :elemetal_capital_premium_cents, allow_nil: true
belongs_to :spot
def to_hash
instance_variables.each_with_object({}) do |var, hash|
hash[var.to_s.delete("@")] = instance_variable_get(var)
end
end
def metal_name
case metal
when "Ag" then "Silver"
when "Au" then "Gold"
when "Pd" then "Palladium"
when "Pt" then "Platinum"
end
end
def price
# return 1300 if spot.nil?
spot_price = spot.ask
ec_price = spot_price + elemetal_capital_premium
total_price = ec_price * weight
gt_price = total_price + (goldtrex_markup / 100 * total_price)
gt_price.exchange_to(:AUD)
end
def shopify_variant_data
{
barcode: id,
price: price.to_s,
weight: weight,
weight_unit: "oz",
grams: weight * 31.1034768
}
end
before_create :shopify_create
def shopify_create
data = {
title: "#{metal_name} - #{description}",
variants: [
shopify_variant_data
]
}
sp = ShopifyAPI::Product.create(data)
self.shopify_id = sp.id
end
before_update :shopify_update
def shopify_update
sp = ShopifyAPI::Product.find(shopify_id)
variant = sp.variants.first
shopify_variant_data.each do |k, v|
instance_variable_set("@#{k.to_s}".to_sym, v)
end
variant.save!
end
def self.update_products!
ec_products = ElemetalCapital::Product.all
transaction do
ec_products.each do |ec_product|
product = ElemetalCapitalProduct.where(id: ec_product.id).first_or_initialize
product.spot_id = ec_product.spot
product.goldtrex_markup ||= # default to a 1% markup
product.description = ec_product.description
product.metal = ec_product.metal
product.weight = ec_product.weight
product.elemetal_capital_premium = ec_product.premiumBuy
product.save!
end
end
end
end
This is the schema:
ActiveRecord::Schema.define(version: 20150609085027) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "deliveries", force: :cascade do |t|
t.string "receiver"
t.datetime "delivery_day"
t.string "tracking_number"
t.text "delivery_notes"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "ticket_id"
end
create_table "elemetal_capital_trades", force: :cascade do |t|
t.string "location"
t.string "currency"
t.string "side"
t.string "elemetal_capital_product_id"
t.integer "quantity"
t.string "elemetal_capital_trade_id"
t.float "price_per_unit"
t.float "weight"
t.float "price_per_weight"
t.float "price_total"
t.string "time_stamp_origin"
t.string "metal"
t.float "spot"
t.integer "line_item_id"
end
add_index "elemetal_capital_trades", ["line_item_id"], name: "index_elemetal_capital_trades_on_line_item_id", using: :btree
create_table "employees", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "items", force: :cascade do |t|
t.integer "quantity"
t.string "item_description"
t.float "unit_price"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "ticket_id"
end
create_table "line_items", force: :cascade do |t|
t.integer "quantity"
t.integer "shopify_line_item_id"
t.integer "order_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "shopify_product_id", limit: 8
end
add_index "line_items", ["order_id"], name: "index_line_items_on_order_id", using: :btree
create_table "orders", force: :cascade do |t|
t.integer "order_number"
t.integer "shopify_order_id"
t.integer "total"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "payments", force: :cascade do |t|
t.datetime "value_date"
t.integer "reference_number"
t.float "contract_rate", default: 0.0
t.string "trade_notes"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "ticket_id"
t.float "usd_payment", default: 0.0
end
create_table "products", id: false, force: :cascade do |t|
t.string "id", null: false
t.string "type", null: false
t.text "description", null: false
t.decimal "weight", null: false
t.string "metal", null: false
t.string "spot_id", null: false
t.integer "elemetal_capital_premium_cents"
t.decimal "goldtrex_markup", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "shopify_id", limit: 8, null: false
end
add_index "products", ["shopify_id"], name: "index_products_on_shopify_id", unique: true, using: :btree
add_index "products", ["spot_id"], name: "index_products_on_spot_id", using: :btree
create_table "spots", id: false, force: :cascade do |t|
t.string "id", null: false
t.integer "bid_cents", null: false
t.integer "ask_cents", null: false
end
create_table "tickets", force: :cascade do |t|
t.integer "goldtrex_employee"
t.string "ticket_number"
t.datetime "elemetal_capital_order_date"
t.string "trader"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "au"
t.float "au_spot_price"
t.boolean "ag"
t.float "ag_spot_price"
t.boolean "deposit"
t.float "deposit_amount"
end
end
Rails uses ORM, which hides all logic of working with DB into nice methods. Basically that means that if you change the DB – nothing will happen, app will continue to work as expected (should mention, this statement does not applicable in any case as DBs differ, but not in this case). If you get 404 – it means item is missing in the database, nothing wrong about that.
When you said you changed DB from sqlite to Postgres – had you migrated the data? Try run
ElemetalCapitalProduct.count
from the console to ensure it has anything. If it does, compare data you had in sqlite and the data you receive in Postgres.