I have a strange SQLException with my association.
I`ve created a join table using migration:
create_join_table :reviews, :posts
So there is a table in db posts_reviews
In both models I`ve configured relations:
class Post < ActiveRecord::Base
has_and_belongs_to_many :reviews
class Review < ActiveRecord::Base
has_and_belongs_to_many :posts
But when I run this command Post.find(X).reviews << Review.find(Y)
The result is:
SQLite3::SQLException: no such table: : INSERT INTO "" ("post_id", "review_id") VALUES (?, ?)
So the join table name is empty.
My schema.rb
create_table "posts", force: true do |t|
t.integer "user_id"
t.string "post_title", limit: 1024
t.text "post_body"
t.boolean "promo_material", default: false
t.integer "views_count", default: 0
t.integer "comments_count", default: 0
t.integer "votes_count", default: 0
t.datetime "created_at"
t.datetime "updated_at"
t.string "main_image"
end
create_table "posts_reviews", id: false, force: true do |t|
t.integer "review_id", null: false
t.integer "post_id", null: false
end
create_table "reviews", force: true do |t|
t.integer "user_id"
t.integer "composition_id"
t.text "review_text"
t.boolean "promo_material", default: false
t.integer "rating", default: 0
t.integer "views_count", default: 0
t.integer "comments_count", default: 0
t.integer "votes_count", default: 0
t.datetime "created_at"
t.datetime "updated_at"
t.string "promo_image"
end
Related
currently I have this query:
Mother.joins(camp: [{ sub_center: [{ health_center: :block }] }])
which essentially joins the mother table to the block table through the camp, sub_center, and health_center tables (I know it's a lot to take). I want to be able to do something like this:
Mother.joins(camp: [{ sub_center: [{ health_center: :block }] }]).where(sub_center_id: 1)
However, I get that sub_center_id is an undefined column PG::UndefinedColumn: ERROR: column mothers.sub_center_id does not exist
How do I get it to query camp.sub_center_id instead of mother.sub_center_id? In other words, how do I execute a where clause on nested joined tables?
Here's the schema for given tables:
create_table "mothers", force: :cascade do |t|
t.integer "camp_id"
t.integer "eligible_couple_id"
t.string "pcts_id"
t.integer "thumb_id"
t.string "survey_id"
t.string "necklace_id"
t.integer "necklace_replacement_number", default: 0
t.boolean "facility_referral_true", default: false
t.float "weight_at_las_pnc"
t.integer "created_by"
t.integer "updated_by"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "reg_id"
t.string "nfc_data"
t.datetime "date_of_registration"
t.integer "status", default: 1, null: false
t.datetime "deleted_at"
t.datetime "completed_at"
end
create_table "camps", force: :cascade do |t|
t.string "english_name"
t.string "local_name"
t.float "latitude"
t.float "longitude"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "created_by"
t.integer "updated_by"
t.integer "sub_center_id"
t.integer "week_of_the_month"
t.integer "status", default: 1
t.integer "day"
t.datetime "deleted_at"
end
create_table "health_centers", force: :cascade do |t|
t.integer "block_id"
t.string "english_name"
t.string "local_name"
t.boolean "phc_true", default: false
t.boolean "ipd_true", default: false
t.boolean "fru_true", default: false
t.boolean "always_open_true", default: false
t.string "phone_number"
t.integer "created_by"
t.integer "updated_by"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "status", default: 1
t.datetime "deleted_at"
end
create_table "sub_centers", force: :cascade do |t|
t.integer "health_center_id"
t.string "english_name"
t.string "local_name"
t.boolean "phc_true", default: false
t.boolean "ipd_true", default: false
t.boolean "fru_true", default: false
t.boolean "always_open_true", default: false
t.string "phone_number"
t.float "latitude"
t.float "longitude"
t.integer "created_by"
t.integer "updated_by"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "status", default: 1
t.datetime "deleted_at"
end
create_table "blocks", force: :cascade do |t|
t.string "english_name"
t.string "local_name"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "created_by"
t.integer "updated_by"
t.integer "status", default: 1
t.datetime "deleted_at"
end
You can always use the string method to reference the column, instead of the symbol one.
Mother.
joins(camp: { sub_center: { health_center: :block } }).
where('camps.sub_center_id = ?', 1)
or with the symbol method
Mother.
joins(camp: { sub_center: { health_center: :block } }).
where(camps: { sub_center_id: 1 } )
I have a page where users can add favorites. Right now the page sorts their posts into favorites but sorts them by .order(created_at: :desc) for the Post databases created_at field. How can I change this to use the Vote table and its created_at frield.
#posts = Post.where(id: current_user.find_voted_items.map(&:id)).order(created_at: :desc).paginate(:page => params[:page], :per_page => 36)
Here is the relevant schema
create_table "votes", force: :cascade do |t|
t.integer "votable_id"
t.string "votable_type"
t.integer "voter_id"
t.string "voter_type"
t.boolean "vote_flag"
t.string "vote_scope"
t.integer "vote_weight"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "posts", force: :cascade do |t|
t.string "soundcloud"
t.string "title"
t.string "artist"
t.string "audio"
t.string "image"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "download"
t.integer "cached_votes_total", default: 0
t.integer "cached_votes_score", default: 0
t.integer "cached_votes_up", default: 0
t.integer "cached_votes_down", default: 0
t.integer "cached_weighted_score", default: 0
t.integer "cached_weighted_total", default: 0
t.float "cached_weighted_average", default: 0.0
end
Thank you
If you want to return the posts, it makes more sense to use the posts database. If you want to return all of the votes for one post using the vote database instead, you could try something like this:
#votes = Vote.where(votable_id: some_post.id).order('created_at DESC')
But I'm not sure I understand what you would like to return from the Vote database.
User has many profiles such has admin and merchant etc in my rails db schema. Now how do i write code to check if current user is admin ?
More info : User table is separate and profile table is separate. They are linked in user model through has_and_belongs_to_many :profiles
Here is my schema :
create_table "profiles", force: true do |t|
t.string "name", null: false
t.string "description"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "profiles", ["name"], name: "index_profiles_on_name", unique: true, using: :btree
create_table "profiles_roles", id: false, force: true do |t|
t.integer "profile_id"
t.integer "role_id"
end
create_table "profiles_users", id: false, force: true do |t|
t.integer "profile_id"
t.integer "user_id"
end
create_table "role_types", force: true do |t|
t.string "name"
t.string "description"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "roles", force: true do |t|
t.string "name", null: false
t.string "description"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "role_type_id"
t.string "display_name"
end
add_index "roles", ["name"], name: "index_roles_on_name", unique: true, using: :btree
create_table "users", force: true do |t|
t.string "username", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "email", default: ""
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at"
t.datetime "updated_at"
t.string "first_name"
t.string "last_name"
t.string "msisdn"
t.string "city"
t.string "address"
t.integer "e_bills_count", default: 0
t.string "notification_url"
t.string "notification_params", default: [], array: true
t.boolean "notification_post", default: true
t.string "legal_info"
t.string "greeting_message"
t.boolean "email_notification", default: false
t.string "website"
t.string "logo"
t.string "signature"
t.string "additional_notification_params", default: ""
t.string "currency"
end
There is no single dogmatic 'rails-way' to do this. The simplest way is to add a boolean column 'is_admin'. But because this does not scale to well with other scenarios, this is often widened to a schema where there is an extra 'roles' table and a has_many relationship to the user model.
Thare are also gems for more sophisticated authorization models:
https://github.com/ryanb/cancan/wiki/Role-Based-Authorization
An example implementation could be:
self.profiles.map(&:name).include?('admin')
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.
i have two objects
- material
- lesson
each material can have and belong to lesson; each lesson can have and belong to material.
in material_controller when i try to create
#material = Material.new(params[:material])
class Material < ActiveRecord::Base
has_and_belongs_to_many :lessons
attr_accessible :content_type, :user_id, :lesson_ids
here is params
"material"=>{"content_type"=>"2",
"detail_content"=>"",
"user_id"=>"5",
"lesson_ids"=>"[]"},
create_table "lessons", :force => true do |t|
t.string "title"
t.string "description"
t.integer "course_id"
t.integer "sequence"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "lessons_materials", :force => true do |t|
t.integer "lesson_id"
t.integer "material_id"
end
create_table "materials", :force => true do |t|
t.integer "content_type"
t.text "detail_content"
t.text "embedded_content"
t.string "stored_file_name"
t.string "stored_content_type"
t.integer "stored_file_size"
t.datetime "stored_updated_at"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.integer "user_id"
end
I think your lesson_ids param should be nil when you have no lesson associated, instead of being an array.