Rails create record fails - ruby-on-rails

Here is my table structure
class CreateStudentAssignments < ActiveRecord::Migration[5.1]
def change
create_table :student_assignments do |t|
t.string :title
t.string :subject
t.text :description
t.float :amount, default: 0
t.date :start_date
t.date :due_date
t.integer :word_count
t.time :approximate_estimated_duration
t.boolean :active, default: true
t.float :overall_rating
t.integer :view_count, default: 0
t.boolean :assignment_approved, default: false
t.references :assignment_status, foreign_key: true
t.references :student, foreign_key: { to_table: :users }
t.references :difficulty_level, foreign_key: true
t.references :writer, foreign_key: { to_table: :users } # Assignment accepted writer
t.timestamps
end
end
end
While try to create a record
p = {title: "title", subject: "subject", description: "des", amount: 5.00, start_date: Date.today + 1, due_date: Date.today + 5, word_count: 100, approximate_estimated_duration: 1000, overall_rating: 4, view_count:4, assignment_status: AssignmentStatus.last, difficulty_level_id: 4, student: User.last}
StudentAssignment.create(p).errors
ActiveModel::MissingAttributeError: can't write unknown attribute `student_id`
from (irb):56
How to pass that user?
Thanks in advance

Related

How do I write a finder when I have a belongs_to relationship but no underlying database column? [duplicate]

I'm working with a legacy database that gives the following schema for the tables product and familia_producto (rake db:schema:dump)
create_table "producto", primary_key: "barcode", force: true do |t|
t.string "codigo_corto", limit: 16, null: false
t.string "marca", limit: 35
t.string "descripcion", limit: 50
t.string "contenido", limit: 10
t.string "unidad", limit: 10
t.float "stock", default: 0.0
t.float "precio"
t.float "precio_neto"
t.float "costo_promedio"
t.float "fifo"
t.float "vendidos"
t.boolean "aplica_iva"
t.integer "otros_impuestos", limit: 2
t.integer "familia", limit: 2, default: 1, null: false
t.integer "id_tipo_producto", limit: 2, null: false
t.boolean "es_perecible"
t.float "dias_stock", default: 1.0
t.float "margen_promedio", default: 0.0
t.boolean "es_venta_fraccionada"
t.float "stock_pro", default: 0.0
t.float "tasa_canje", default: 1.0
t.float "precio_mayor"
t.float "cantidad_mayor"
t.boolean "es_mayorista"
t.boolean "estado"
t.boolean "precio_editable"
end
create_table "familia_producto", force: true do |t|
t.string "nombre", limit: 32, null: false
end
In the models I've this
class FamiliaProducto < ActiveRecord::Base
self.table_name = 'familia_producto'
has_many :productos, :class_name => 'Producto', :primary_key => 'barcode', :foreign_key => 'familia'
end
class Producto < ActiveRecord::Base
self.table_name = 'producto'
belongs_to :familia_producto, :class_name => 'FamiliaProducto'
end
But when I call the .familia the producto object throws me a number, not the FamiliaProducto object.
2.1.0 :012 > p = Producto.all[0]
Producto Load (1.7ms) SELECT "producto".* FROM "producto"
=> #<Product......
2.1.0 :013 > p.familia
=> 2
That 2 should be the FamiliaProducto object.
You must use the name of the association, also need to add the foreign key to the belongs_to
class Producto < ApplicationRecord
belongs_to :familia_producto, class_name: 'FamiliaProducto', foreign_key: 'familia'
end
class FamiliaProducto < ApplicationRecord
has_many :productos, class_name: 'Producto', foreign_key: 'familia'
end
p = Producto.first
# Returns a FamiliaProducto object
p.familia_producto
# Returns an integer
p.familia

ActiveRecord How to combine two conditions on a where with a join

I have two tables with a join table in between:
Series
create_table "series", force: :cascade do |t|
t.string "title", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
class Series < ApplicationRecord
include PgSearch::Model
has_many :makers
has_many :creators, through: :makers
has_many :sources, dependent: :destroy
has_many :entries, through: :sources
validates :title, presence: true
pg_search_scope :search_by_title, against: {
title: 'A',
title_en: 'B',
title_en_jp: 'C'
}
end
Maker
create_table "makers", force: :cascade do |t|
t.bigint "series_id", null: false
t.bigint "creator_id", null: false
t.bigint "creator_type", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["creator_id"], name: "index_makers_on_creator_id"
t.index ["series_id", "creator_id", "creator_type"], name: "index_makers_on_series_and_creator_and_type", unique: true
t.index ["series_id"], name: "index_makers_on_series_id"
end
# frozen_string_literal: true
class Maker < ApplicationRecord
extend Enumerize
belongs_to :series
belongs_to :creator
validates :series, uniqueness: { scope: %i[creator creator_type] }
enumerize :creator_type, in: {
author: 1,
artist: 2
}, predicates: true, scope: true
end
Creator
create_table "creators", force: :cascade do |t|
t.string "name", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["name"], name: "index_creators_on_name"
end
class Creator < ApplicationRecord
include PgSearch::Model
has_many :makers
has_many :series, through: :makers
pg_search_scope :search_by_title, against: :name
end
Based on the tables above, I wanted to create a where method, which would find Series for specific makers. The issue is for series that have two makers, usually an author and artist.
So while this code works, to find a Series for a specific creator:
def self.find_by_creators(title, creators)
where(title: title)
.joins(makers: :creator)
.where(
makers: {
creator_type: :author,
creators: { name: creators[:authors] }
}
)
end
when trying to add another where, nothing gets returned:
def self.find_by_creators(title, creators)
where(title: title)
.joins(makers: :creator)
.where(
makers: {
creator_type: :author,
creators: { name: creators[:authors] }
}
)
.where(
makers: {
creator_type: :artist,
creators: { name: creators[:artists] }
}
)
end

problems with a scope in habtm

I have a habtm relationship between Dish and DailyMenu. Here is a scope
scope :menu_available, -> (type_id, daily_menu_id){ where('dish_type_id = ?', type_id) & where(joins(:daily_menus).where.not('daily_menu_id = ?', daily_menu_id)) }
It intends to find dishes of some type but that are not currently included in menu. Sadly it does not work correctly. Need some help please
A DishType model
class DishType < ActiveRecord::Base
include DishTypeSetter
enum meal:[:main_course, :second_course, :drink]
end
Dish model
class Dish < ActiveRecord::Base
has_and_belongs_to_many :daily_menus
has_many :orders
has_many :users, through: :orders
belongs_to :dish_type
scope :main_meals, -> { joins(:dish_type).where('meal = ?', 0) }
scope :second_meals, -> { joins(:dish_type).where('meal = ?', 1) }
scope :drinks, -> { joins(:dish_type).where('meal = ?', 2) }
#scope :menu_available, -> (type_id, daily_menu_id){ where('dish_type_id = ?', type_id) & where(joins(:daily_menus).where.not('daily_menu_id = ?', daily_menu_id)) }
scope :menu_available, lambda { |type_id, daily_menu_id|
where(joins(:daily_menus).where('daily_menu_id != ? AND dish_type_id = ?', daily_menu_id, type_id))
}
validates :dish_type, :name, presence: true
validates :name, uniqueness: { scope: :dish_type_id }
end
Menu model
class DailyMenu < ActiveRecord::Base
has_and_belongs_to_many :dishes
has_many :orders
has_many :users, through: :orders
end
Also about DishType model - it only has has_many dishes association(I moved this to a concern)/ But it does not have has_many daily_menus/
create_table "daily_menus", force: :cascade do |t|
t.string "day"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.date "date"
end
add_index "daily_menus", ["day"], name: "index_daily_menus_on_day", unique: true, using: :btree
create_table "daily_menus_dishes", force: :cascade do |t|
t.integer "daily_menu_id"
t.integer "dish_id"
end
create_table "dish_types", force: :cascade do |t|
t.integer "meal"
end
create_table "dishes", force: :cascade do |t|
t.string "name"
t.integer "type"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "dish_type_id"
end
add_index "dishes", ["dish_type_id", "name"], name: "index_dishes_on_dish_type_id_and_name", unique: true, using: :btree
scope :menu_available, lambda { |type_id, daily_menu_id|
joins(:daily_menus)
.where('dishes.dish_type_id = ? AND daily_menus.id != ?', type_id, daily_menu_id)
}

Rails: auto update reference table when update foreign_key

When i try to update foreign_key for table BusinessCard. It auto update the Company table without needed.
My Console Image
Can someone help me with this. Thanks
Edit---
My Controller
def update
#bc = BusinessCard.find_by(business_card_id: params[:id], deleted: false)
raise "名刺情報は存在しておりません。" unless #bc
raise "同じ名刺情報が存在しております。" if (#bc.name != params[:name] or #bc.email != params[:email] or #bc.company.name != params[:c_name]) and BusinessCard.joins(:company).where(name: params[:name], email: params[:email], deleted: 0, 'companies.name' => params[:c_name]).exists?
ActiveRecord::Base.transaction do
##bc.name = params[:name]
##bc.email = params[:email]
##bc.tel = params[:tel]
##bc.furigana = params[:furigana]
##bc.recieve_date = params[:recieve_date]
##bc.update_by = #current_user.user_id
#Company
#bc.company_id = bz_company if params[:c_name] and params[:c_post_code]
#department
##bc.department_id = bz_department if params[:d_name]
raise #bc.errors unless #bc.save
#images
#bz_omt if params[:i_omt]
#bz_ura if params[:i_ura]
end
render_json(#bc, :ok)
end
def bz_company
#company = Company.find_by(name: params[:c_name], post_code: params[:c_post_code])
#company = Company.new(name: params[:c_name], post_code: params[:c_post_code], create_by: #current_user.user_id) unless #company
#company.address = params[:c_address]
#company.email = params[:c_email]
#company.tel = params[:c_tel]
#company.fax = params[:c_fax]
#company.url = params[:c_url]
#company.deleted = 0
#company.update_by = #current_user.user_id
raise #company.errors unless #company.save
#company.company_id
end
BusinessCard Model
class BusinessCard < ApplicationRecord
#Association
#With Tag
has_many :map_tags, primary_key: 'business_card_id', foreign_key: 'business_card_id'
has_many :tags, :through => :map_tags
#with Comment
has_many :map_comments, primary_key: 'business_card_id', foreign_key: 'business_card_id'
has_many :comments, :through => :map_comments
#with Company
has_one :company, primary_key: 'company_id', foreign_key: 'company_id'
#with department
has_one :department, primary_key: 'department_id', foreign_key: 'department_id'
#with file_locations
has_many :file_locations, primary_key: 'business_card_id', foreign_key: 'business_card_id'
end
Company Model
class Company < ApplicationRecord
#Association
has_many :business_cards, primary_key: 'company_id', foreign_key: 'company_id'
end
Company Migration
class CreateCompanies < ActiveRecord::Migration[5.0]
def change
create_table :companies, id: false do |t|
t.column :company_id, 'INTEGER PRIMARY KEY AUTOINCREMENT'
t.string :name, limit: 150, null: false
t.text :address, limit: 1000, null: false
t.string :email, limit: 129
t.string :tel, limit: 20
t.string :fax, limit: 20
t.string :url, limit: 150
t.boolean :deleted, default: false
t.integer :create_by
t.integer :update_by
t.timestamps
end
end
end
BusinessCard Migration
class CreateBusinessCards < ActiveRecord::Migration[5.0]
def change
create_table :business_cards, id: false do |t|
t.column :business_card_id, 'INTEGER PRIMARY KEY AUTOINCREMENT'
t.string :name, limit: 50, null: false
t.string :furigana, limit: 50
t.string :email, limit: 129, null: false
t.string :tel, limit: 20, null: false
t.integer :owner_id
t.datetime :recieve_date
t.integer :company_id, null: false
t.integer :department_id, null: false
t.boolean :deleted, default: false
t.integer :create_by
t.integer :update_by
t.timestamps
end
add_index :business_cards, :business_card_id, :unique => true
end
end
Try this:
instead this in BusinnesCard Model
has_one :company, primary_key: 'company_id', foreign_key: 'company_id'
put this
belongs_to :company, primary_key: 'company_id', foreign_key: 'company_id'
PS Your code is little diry, i recommend you to replace primary_keys. For example, instead company_id, use id
You are using primary key column names that do not follow Rails' conventions. Therefore you have to tell Rails the names with primary_key= in your models:
# in app/models/company.rb
self.primary_key = 'company_id'
# in app/models/business_card.rb
self.primary_key = 'business_card_id'

Rails belongs_to with custom column name

I'm working with a legacy database that gives the following schema for the tables product and familia_producto (rake db:schema:dump)
create_table "producto", primary_key: "barcode", force: true do |t|
t.string "codigo_corto", limit: 16, null: false
t.string "marca", limit: 35
t.string "descripcion", limit: 50
t.string "contenido", limit: 10
t.string "unidad", limit: 10
t.float "stock", default: 0.0
t.float "precio"
t.float "precio_neto"
t.float "costo_promedio"
t.float "fifo"
t.float "vendidos"
t.boolean "aplica_iva"
t.integer "otros_impuestos", limit: 2
t.integer "familia", limit: 2, default: 1, null: false
t.integer "id_tipo_producto", limit: 2, null: false
t.boolean "es_perecible"
t.float "dias_stock", default: 1.0
t.float "margen_promedio", default: 0.0
t.boolean "es_venta_fraccionada"
t.float "stock_pro", default: 0.0
t.float "tasa_canje", default: 1.0
t.float "precio_mayor"
t.float "cantidad_mayor"
t.boolean "es_mayorista"
t.boolean "estado"
t.boolean "precio_editable"
end
create_table "familia_producto", force: true do |t|
t.string "nombre", limit: 32, null: false
end
In the models I've this
class FamiliaProducto < ActiveRecord::Base
self.table_name = 'familia_producto'
has_many :productos, :class_name => 'Producto', :primary_key => 'barcode', :foreign_key => 'familia'
end
class Producto < ActiveRecord::Base
self.table_name = 'producto'
belongs_to :familia_producto, :class_name => 'FamiliaProducto'
end
But when I call the .familia the producto object throws me a number, not the FamiliaProducto object.
2.1.0 :012 > p = Producto.all[0]
Producto Load (1.7ms) SELECT "producto".* FROM "producto"
=> #<Product......
2.1.0 :013 > p.familia
=> 2
That 2 should be the FamiliaProducto object.
You must use the name of the association, also need to add the foreign key to the belongs_to
class Producto < ApplicationRecord
belongs_to :familia_producto, class_name: 'FamiliaProducto', foreign_key: 'familia'
end
class FamiliaProducto < ApplicationRecord
has_many :productos, class_name: 'Producto', foreign_key: 'familia'
end
p = Producto.first
# Returns a FamiliaProducto object
p.familia_producto
# Returns an integer
p.familia

Resources