I am doing self association in rails. I have Request model which should reference itself. Here is what i have:
class Request < ActiveRecord::Base
has_many :sub_requests, class_name: 'Request',
foreign_key: 'parent_request_id'
belongs_to :parent_request, class_name: 'Request'
end
and my migration:
class CreateRequests < ActiveRecord::Migration
def change
create_table :requests do |t|
t.references :parent_request, index: true
end
end
end
But I get an error as follows:
PG::UndefinedColumn: ERROR: column requests.parent_request_id does not exist
Have you run rake db:migrate? If you did, than try this one:
class Request < ActiveRecord::Base
has_many :sub_requests, class_name: 'Request', foreign_key: 'parent_request_id', primary_key: 'id'
belongs_to :parent_request, class_name: 'Request', foreign_key: 'parent_request_id', primary_key: 'id'
end
class CreateRequests < ActiveRecord::Migration
def change
create_table :requests do |t|
t.integer :parent_request_id, index: true
end
end
end
Related
Im trying to create a table with 2 FK Referencing 1 PK in another table.
class CreateJobapps < ActiveRecord::Migration[5.1]
def change
create_table :jobapps do |t|
t.references :job, foreign_key: { job: :id }, index: { unique: true}
t.references :user, foreign_key: { user: :id }, index: { unique: true}
t.timestamps
end
end
end
Is this method correct? if so, how can I get an output if I provide a FK of respected table.
Here is how my Jobapp table looks like
I tried using Jobapp.joins(:user) but to no avail
Am I supposed to write belongs_to or has_many in the model file?
class CreateJobapps < ActiveRecord::Migration[5.1]
def change
create_table :jobapps do |t|
t.references :job, foreign_key: { job: :id }
t.references :user, foreign_key: { user: :id }
t.timestamps
end
# Add a compound index instead - you may need to switch the order to
# tweak the index depending on how it is used.
add_index :jobapps, [:job_id, :user_id], unique: true
end
end
class Jobapp < ApplicationRecord
belongs_to :user
belongs_to :job
end
class User < ApplicationRecord
has_many :jobapps
has_many :jobs, through: :jobapps
end
class Job < ApplicationRecord
has_many :jobapps
has_many :users, through: :jobapps
end
Currently I have following migrations:
class CreateDevices < ActiveRecord::Migration[5.0]
def change
create_table :devices do |t|
t.string :name
t.string :abbr
t.timestamps
end
end
end
class CreateVendors < ActiveRecord::Migration[5.0]
def change
create_table :vendors do |t|
t.string :name
t.string :abbr
t.timestamps
end
end
end
class CreateDeviceVendors < ActiveRecord::Migration[5.0]
def change
create_table :device_vendors do |t|
t.string :device
t.string :vendor
t.timestamps
end
end
end
There is many to many relationship between device and vendor, so DeviceVendors table is getting used for that. Both tables abbr column (which is unique) is getting saved in this table as device and vendor respectively.
I am using this kind of table structure so that I can seed the data and don't have to check for ids in the primary tables.
How can I set the association in all three models so that I can access in better way. Something like this:
class Device < ApplicationRecord
has_many :device_vendors
has_many :vendors, through: device_vendors
end
class Vendor < ApplicationRecord
has_many :device_vendors
has_many :devices, through: device_vendors
end
class DeviceVendor < ApplicationRecord
belongs_to :device
belongs_to :vendor
end
I know I have to apply foreign_key: :abbr to belongs_to in models but not sure in which ones. Also whether I need to change/add the migration for this?
The foreign_key, as you point out, is on the belongs_to table, but you need to specify both primary_key and foreign_key (since none is the default id) in all associations:
class Device < ApplicationRecord
has_many :device_vendors, primary_key: "abbr", foreign_key: "device"
has_many :vendors, through: device_vendors
end
class Vendor < ApplicationRecord
has_many :device_vendors, primary_key: "abbr", foreign_key: "vendor"
has_many :devices, through: device_vendors
end
class DeviceVendor < ApplicationRecord
belongs_to :device, primary_key: "abbr", foreign_key: "device"
belongs_to :vendor, primary_key: "abbr", foreign_key: "vendor"
end
Also notice that the foreign key is not abbr, that's the primary key in both device and vendor; the foreign key is the one in the table with belongs_to (i.e. device and vendor in device_vendors).
So, I have a namespace for a part of the project.
class Namespace::Product < ActiveRecord::Base
belongs_to: :namespace_category, class_name: 'Namespace::Category'
...
end
class Namespace::Category < ActiveRecord::Base
has_many :products, :class_name => 'Namespace::Product'
...
end
The migration for Product looks like
create_table :namespace_products do |t|
t.belongs_to :namespace_category, index: true
...
end
So, when I do this
p = Namespace::Product.create(some_params)
c = Namespace::Category.find(id)
c.products << p
it throws me an error, saying ActiveModel::MissingAttributeError: can't write unknown attribute 'category_id', however I have an attribute
t.integer "namespace_category_id"
in my schema.rb, which was created by the migration.
For anyone on Rails 5+ looking back at this, you can also specify the namespace on the migration level if you don't want them on the associations:
def change
create_table :namespace_products do |t|
t.references :category, foreign_key: { to_table: :namespace_categories }
end
end
# or
def change
add_reference :namespace_products, :category, foreign_key: { to_table: :namespace_categories }
end
class Namespace::Product < ActiveRecord::Base
belongs_to :category
end
class Namespace::Category < ActiveRecord::Base
has_many :products
end
https://api.rubyonrails.org/v5.0.0/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_reference
I would just omit the namespaces from the associations:
class Namespace::Product < ActiveRecord::Base
belongs_to :category, class_name: 'Namespace::Category'
...
end
class Namespace::Category < ActiveRecord::Base
has_many :products, class_name: 'Namespace::Product'
...
end
class FixColumnName < ActiveRecord::Migration
def change
rename_column :namespace_products, :namespace_category_id, :category_id
end
end
Okay, I just had to specify foreign_key while defining has_many :products association in Namespace::Category, thanks to Max
I'm trying to build a messaging system through an API using Rails 4.
Models:
class User < ActiveRecord::Base
has_many :sent_messages, class_name: "Message", foreign_key: "sender_id"
has_many :received_messages, class_name: "Message", foreign_key: "recipient_id"
end
class Message < ActiveRecord::Base
belongs_to :sender, class_name: "User", primary_key: "sender_id"
belongs_to :recipient, class_name: "User", primary_key: "recipient_id"
end
Migrations:
class DeviseTokenAuthCreateUsers < ActiveRecord::Migration
def change
create_table(:users) do |t|
...
## User Info
t.string :name
...
end
end
end
and
class CreateMessages < ActiveRecord::Migration
def change
create_table :messages do |t|
t.string :msg_body
t.belongs_to :sender, class_name: "User", primary_key: "sender_id", index: true
t.belongs_to :recipient, class_name: "User", primary_key: "recipient_id", index: true
t.timestamps null: false
end
end
end
Message Controller:
class MessagesController < ApplicationController
def index
messages = Message.all
render :json => messages.as_json(:include => [:sender, :recipient])
end
end
PROBLEM
The thing is, when I go for a GET request of all the messages, I get this error:
ActiveRecord::StatementInvalid (SQLite3::SQLException: no such column: users.sender_id: SELECT "users".* FROM "users" WHERE "users"."sender_id" = ? LIMIT 1)
So, what am I doing wrong? Why? What can I do about this?
I'm trying design a model which has relation to itself
Model:
class Department < ActiveRecord::Base
belongs_to :organization
has_many :positions
has_many :sub_departments, class: 'Department', foreign_key: 'parent_id'
end
Migration:
class CreateDepartments < ActiveRecord::Migration
def change
create_table :departments do |t|
t.string :name
t.references :parent, index: true
t.references :organization, index: true
t.timestamps
end
end
end
When I call Department.first.sub_departments I get an error: NoMethodError: undefined method 'relation_delegate_class' for "Department":String. What am I doing wrong?
Thanks!
I think you should use class_name: instead of class:.