Ruby ActiveModel::MissingAttributeError - ruby

I'm trying to learn on my own ruby database relations.
I have a relation of 1 "Category" to many "Products" and I'm trying to add a product to the remote database (heroku server).
TIMESTAMP_create_products.rb
class CreateProducts < ActiveRecord::Migration
def up
create_table :products, primary_key: 'product_id' do |p|
p.index :product_id
p.string :name
p.decimal :price
p.references :categories, index: true
end
end
def down
drop_table :products
end
end
TIMETSTAMP_create_categories.rb
class CreateCategories < ActiveRecord::Migration
def up
create_table :categories, primary_key: 'category_id' do |c|
c.index :category_id
c.string :name
c.integer :parentId
end
end
def down
drop_table :categories
end
end
model.rb
class Products < ActiveRecord::Base
self.primary_key = "product_id"
validates :name, presence: true, uniqueness: true
belongs_to :categories, class_name: "Categories", foreign_key: 'category_id'
end
class Categories < ActiveRecord::Base
self.primary_key = "category_id"
validates :name, presence: true, uniqueness: true
has_many :products, class_name: "Products"
end
I add manually a category to the database and every time I try to execute the code:
Products.create(name: "name1", price: "1.1", categories: Categories.find(1))
It gives me the output:
ActiveModel::MissingAttributeError can't write unknown attribute category_id
Is there anything missing here? I don't understand why this is not working.

You may have a problem with singular / plural.
In your migration, to create the table products, you have the line:
p.references :categories, index: true
This should add to your table the column categories_id.
However, in the Products model, the foreign key is set to category_id. So when you try to attach a category to a production, it's trying to write the ID of the category to the column category_id of the table categories, which doesn't exists.
By changing the reference name in the products migration, everything should work fine:
create_table :products, primary_key: 'product_id' do |p|
p.index :product_id
p.string :name
p.decimal :price
p.references :category, index: true
end

Related

Ruby On Rails 4, dynamically create nested association inside a nested association

I have 3 models
class Patient < ActiveRecord::Base
has_one :address, as: :person
has_many :doctors
accepts_nested_attributes_for :address, :reject_if => :all_blank, :allow_destroy => true
validates_associated :address
accepts_nested_attributes_for :doctors, :reject_if => :all_blank, :allow_destroy => true
validates_associated :doctors
end
class Doctor < ActiveRecord::Base
after_initialize :init, unless: :persisted?
has_one :address, as: :person
belongs_to :patient
accepts_nested_attributes_for :address, :reject_if => :all_blank, :allow_destroy => true
validates_associated :address
def init
self.address ||= build_address
end
end
class Address < ActiveRecord::Base
belongs_to :person, polymorphic: true
end
I am using simple_form and cacoon to handle my UI.
I had to ask Specialist initialize address on Model level, other wise address of specialist does not get initialized for cacoon.
in my controller, I initiate my Doctor and Address with
#patient.doctor.build
#patient.address ||= Address.new
However, I got an error message if every inputs were blank for specialist's address.
SQLite3::ConstraintException: NOT NULL constraint failed: addresses.line_1: INSERT INTO "addresses" ("person_type", "person_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)
Does this mean it automatically generate address during save even though
accepts_nested_attributes_for :address, :reject_if => :all_blank, :allow_destroy => true
was set?
Is there any way to solve this? or is there a better way to achieve what I want?
You should not use the init method to initialise the address. Instead, you should use the :wrap_object option cocoon provides (documentation).
For instance, in your case that would become something like
link_to_add_association 'add doctor', f, :doctors, wrap_object: Proc.new {|doctor| doctor.build_address; doctor }

Validate uniqueness nested model params

I have three models:
class User < ActiveRecord::Base
has_many :user_countries
accepts_nested_attributes_for :user_countries, reject_if: :all_blank
validate :user_countries
end
class UserCountry < ActiveRecord::Base
belongs_to :user
belongs_to :country
end
class Country < ActiveRecord::Base
has_many :user_countries
has_many :users, :through => :user_countries
end
In a the user creation form I can create user_countries too. How I can validate in server the uniqueness of country_id in user_countries. A user has many countries: France, United State... but not for example: France and France.
I've added this to user_countries.. but it don't work:
validates :user_id, uniqueness: {scope: :country_id, allow_blank: false}
Try this in the user_country model.
class UserCountry < ActiveRecord::Base
belongs_to :user
belongs_to :country
validates_uniqueness_of :user_id, scope: :country_id, allow_blank: false
end
Also, you need to create a migration like below to add unique indexes on database level.
add_index :user_countries, [ :user_id, :country_id ], :unique => true

How to use unique key as foreign key

I have an N:N relationship between 2 tables, users and titles. These tables link using a third table purchases which should have the id of each of the others table. The problem is that for the titles I do not require the title_id on the purchases table, but a different column named item_id which is UNIQUE and NOT NULL on the titles table.
Currently I have the following migration, but it is not working. I might be missing something:
class CreatePurchases < ActiveRecord::Migration
def change
create_table :purchases, :id => false do |t|
t.belongs_to :title, foreign_key: 'item_id'
t.belongs_to :user, :null => false
end
end
end
How can I get my purchases table to reference the titles table using that item_id key on the titles table rather than title_id ?
Migration:
class CreatePurchases < ActiveRecord::Migration
def change
create_table :purchases, :id => false do |t|
t.integer :item_id
t.integer :user_id, :null => false
end
end
end
In your models:
# app/models/title.rb
class Title < ActiveRecord::Base
# ...
has_and_belongs_to_many :users,
class_name: "User",
foreign_key: "item_id",
association_foreign_key: "user_id",
join_table: "purchases"
# ...
end
# app/models/user.rb
class User < ActiveRecord::Base
# ...
has_and_belongs_to_many :titles,
class_name: "Title",
foreign_key: "user_id",
association_foreign_key: "item_id",
join_table: "purchases"
# ...
end
Don't forger add indexes to migration if its need.

How can two user instances have the same account

In my rails app I want to create a shared account (later with different access levels). I want two instances of the User to have the same account.
My User Model has_many :accounts and my Account belongs_to :user
In the rails console when I do, e.g:
account = Account.first
account.user_id = [1, 2]
account.save
it returns true but when I check it again account.user_id = nil
How should I go on about it, then?
EDIT:
The Account Model:
class Account < ActiveRecord::Base
belongs_to :user
has_many :products
validates_presence_of :title
end
and the User model:
class User < ActiveRecord::Base
has_many :accounts
has_many :products, through: :accounts
accepts_nested_attributes_for :accounts
validates_presence_of :name
before_save do
self.email = email.downcase unless :guest?
end
validates :name, presence: true, length: { maximum: 50 }, unless: :guest?
end
EDIT 2:
I've updated the models relationship so the new Account model is:
class Account < ActiveRecord::Base
has_and_belongs_to_many :users
validates_presence_of :title
end
and the new User model is:
class User < ActiveRecord::Base
has_and_belongs_to_many :accounts
belongs_to :account
has_many :products, through: :accounts
accepts_nested_attributes_for :accounts
validates_presence_of :name
before_save do
self.email = email.downcase unless :guest?
end
validates :name, presence: true, length: { maximum: 50 }, unless: :guest?
end
I also created a new migration, a accounts_users table
class CreateAccountsUsersJoinTable < ActiveRecord::Migration
def change
create_join_table :users, :accounts do |t|
## Not sure if this is necessary
##t.index [:user_id, :account_id]
##t.index [:account_id, :user_id]
t.belongs_to :user
t.belongs_to :account
end
end
end
Still I can't have a account with multiple users

rails belong_to which class to choose

There is a model relation like this.
class A
belongs_to :ref_config,:class_name => 'User'
end
My question is :
the A has a attribute named flag, now i want to create a function like this:
if flag == 1, I want the class A like this belongs_to :ref_config,:class_name => 'Department and if flag == 2, i want the class A like this belongs_to :ref_config,:class_name => 'User'
How can I implement the function
Thank you!
Have a look at polymorphic associations, which will let you use the same belongs_to relation to refer to different models.
You could configure your models something like this:
class A < ActiveRecord::Base
belongs_to :ref_config, :polymorphic => true
end
class Department < ActiveRecord::Base
has_many :as, :as => :ref_config
end
class User < ActiveRecord::Base
has_many :as, :as => :ref_config
end
To set up the needed columns in the A table, use a migration like this:
class CreateAs < ActiveRecord::Migration
def self.up
create_table :as do |t|
t.string :name # or whatever other attributes A should have
t.references :ref_config, :polymorphic => true
end
end
def self.down
drop_table :as
end
end
From the little i got your question following may help you.
class A
belongs_to :department_config, :class_name => 'Department', :conditions=> flag= 1
belongs_to :user_config, :class_name => 'User', :conditions=> flag= 2
end

Resources