Rails: Multiple references to the same model error - ruby-on-rails

I have a Message model that has a user and a teammember (both are users).
The models are:
# message.rb
class Message < ActiveRecord::Base
belongs_to :user
belongs_to :teammember, :class_name => "User", :foreign_key => 'teammember_id'
end
# user.rb
class User < ActiveRecord::Base
has_many :messages
end
And I have this migration:
class CreateMessages < ActiveRecord::Migration
def change
create_table :messages do |t|
t.references :user, index: true, foreign_key: true
t.references :teammember, index: true, foreign_key: true
t.text :body
t.boolean :read, default: false
t.timestamps null: false
end
end
end
When I run the rake db:migrate locally (with sqlite3) everything works fine.
The problem is that when I deploy to heroku (that uses postgresql) and run
heroku run rake db:migrate
It raises the next error:
PG::UndefinedTable: ERROR: relation "teammembers" does not exist
: ALTER TABLE "messages" ADD CONSTRAINT "fk_rails_7efc67ccc9"
FOREIGN KEY ("teammember_id")
REFERENCES "teammembers" ("id")
Do you know what is the problem and how can I fix it?

Rails guesses based on the association, because you're referencing a table it can't determine from the association you'll have to add it yourself.
class CreateMessages < ActiveRecord::Migration
def change
create_table :messages do |t|
t.references :user, index: true, foreign_key: true
t.references :teammember, index: true
t.text :body
t.boolean :read, default: false
t.timestamps null: false
end
add_foreign_key :messages, :users, column: :teammember_id
end
end

Related

Rails 5 error when creating model instance with foreign keys

I have two models in use at this point: Airports and Flights.
Flights belong to both an origin airport and destination airport. When I try to create a Flight model instance, I get the following error:
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such table: main.destination_airports
I have set up my code to match the example here: https://www.theodinproject.com/courses/ruby-on-rails/lessons/active-record-associations
I've researched the problem (here and elsewhere), but can't turn up anything that seems to match my situation. I can't figure out what's going wrong. Has to be something simple. Something with the migrations, maybe? Thanks in advance for the help.
Relevant code:
Airport model:
class Airport < ApplicationRecord
has_many :departing_flights, foreign_key: "origin_airport_id",
class_name: "Flight"
has_many :arriving_flights, foreign_key: "destination_airport_id",
class_name: "Flight"
validates :abbreviation, presence: true, length: { is: 3 }
end
Flight model:
class Flight < ApplicationRecord
belongs_to :origin_airport, class_name: "Airport"
belongs_to :destination_airport, class_name: "Airport"
has_many :bookings
has_many :passengers, through: :bookings
end
Migrations:
class CreateAirports < ActiveRecord::Migration[5.1]
def change
create_table :airports do |t|
t.string :abbreviation
t.string :full_name
t.string :city
t.string :state
t.string :zip
t.timestamps
end
end
end
class CreateFlights < ActiveRecord::Migration[5.1]
def change
create_table :flights do |t|
t.references :origin_airport, foreign_key: true
t.references :destination_airport, foreign_key: true
t.datetime :depart_time
t.datetime :arrive_time
t.integer :capacity
t.string :airline
t.string :flight_number
t.timestamps
end
end
end
Check the filenames of the migrations, perhaps they are not being run in the correct order?
Also, you may just need to run the migration in the right environment (RAILS_ENV=development)
Update: I found the (an?) answer - changing the migration for the flights table to replace t.references with t.integer and the column name with "x_id" corrects the problem. So, does references only work if using the model name for the column id?

ActiveModel::UnknownAttributeError: unknown attribute when seeding belongs_to relationship

Trying to seed a has_many/belongs_to relationship.
A user has_many scripts, a script belongs_to a user.
When seeding the script, I get this error:
ActiveModel::UnknownAttributeError: unknown attribute 'user_id' for
Script.
I'd think that this line in my migration would create a user_id attribute for script?
t.belongs_to :user, index: true, foreign_key: true
app/models/script.rb
class Script < ApplicationRecord
belongs_to :user
has_many :commits
has_many :script_users, through: :commits, source: :user
end
app/models/user.rb
class User < ActiveRecord::Base
has_many :scripts
has_many :used_scripts, through: :commits, source: :script
has_many :commits
end
db/migrate/20171231022826_create_scripts.rb
class CreateScripts < ActiveRecord::Migration[5.1]
def change
create_table :scripts do |t|
t.string :name
t.string :skill
t.string :bot_for
t.string :game_for
t.belongs_to :user, index: true, foreign_key: true
t.timestamps
end
end
end
db/seeds.rb
admin = User.create!(
email: 'a#a.com',
password: 'adminadmin',
password_confirmation: 'adminadmin'
)
script = Script.create!(
name: 'YWoodcutter',
skill: 'Woodcutting',
bot_for: 'Android',
game_for: "CandyLand,
user_id: admin.id
)
ActiveModel::UnknownAttributeError: unknown attribute 'user_id' for
Script.
I've made sure to rake:db reset and still get error.
Thank you
UPDATE:
I did a few things and it's working OK now. I believe the issue may have been that my user migration was created after my script migration. The user migration should done before scripts, so I changed the dates to change the order they were migrated in. Did a rake rake db:rollback & db:reset for good measure too.
belongs_to is an alias of reference and it should work same as references
If its not working for you just try with following solution
class CreateScripts < ActiveRecord::Migration[5.1]
def change
create_table :scripts do |t|
t.string :name
t.string :skill
t.string :bot_for
t.string :game_for
t.references :user, index: true, foreign_key: true
t.timestamps
end
end
end
Create Model with below line
rails g model script references:user
It will by default below line in migration file
t.references :user, foreign_key: true
and add belongs_to :user in script model . It might be t.references :user in rails 5 not t.belongs_to :user

Rails: Relation does not exist for reference with class name in production

I created two references in a migration that are aliases for a reference to my User table:
class CreateInvitations < ActiveRecord::Migration[5.0]
def change
create_table :invitations do |t|
t.references :owner, references: :user, foreign_key: true # the owner
t.references :invitee, references: :user, foreign_key: true # the invitee
t.references :core_bot, foreign_key: true # the associated page (core_bot_active)
t.string :email
t.string :token
t.timestamps
end
end
end
In my User model:
has_many :invitations, foreign_key: :owner_id
has_many :invitations, foreign_key: :invitee_id, dependent: :destroy
In my Invitation model:
belongs_to :owner, class_name: :User
belongs_to :invitee, class_name: :User
Everything works well in development but when I try to migrate in production with Heroku heroku run rake db:migrate, I get the following error:
PG::UndefinedTable: ERROR: relation "owners" does not exist : CREATE
TABLE "invitations" ("id" serial primary key, "owner_id" integer,
"invitee_id" integer, "core_bot_id" integer, "email" character
varying, "token" character varying, "created_at" timestamp NOT NULL,
"updated_at" timestamp NOT NULL, CONSTRAINT "fk_rails_59e24979a9"
FOREIGN KEY ("owner_id") REFERENCES "owners" ("id") , CONSTRAINT
"fk_rails_00204dc74b" FOREIGN KEY ("invitee_id") REFERENCES
"invitees" ("id") , CONSTRAINT "fk_rails_34505bdb65" FOREIGN KEY
("core_bot_id") REFERENCES "core_bots" ("id") )
I tried without references: :user but I get the same error.
Any idea what's wrong here?
Your development is probably an sqLite database but Heroku uses PostgreSQL and the interpretation of the migration is generating a foregn key to owners
Write the migration like this instead...
class CreateInvitations < ActiveRecord::Migration[5.0]
def change
create_table :invitations do |t|
t.references :owner, index: true # the owner
t.references :invitee, index: true # the invitee
t.references :core_bot, foreign_key: true # the associated page (core_bot_active)
t.string :email
t.string :token
t.timestamps
end
add_foreign_key :invitations, :users, column: :owner_id
add_foreign_key :invitations, :users, column: :invitee_id
end
end
It's one of the risks with developing using a different database product than the production implementation. Migrations may not work exactly the same. If planning to deploy to Heroku you should look at using postgreSQL in development.
I don't how to fix your problem. But I allways creating migrations for Postgres DB with foreign keys like this:
def change
create_table :invitations do |t|
t.integer :owner_id
t.integer :invitee_id
t.references :core_bot, foreign_key: true # the associated page (core_bot_active)
t.string :email
t.string :token
t.timestamps
end
add_index :invitations, :owner_id
add_foreign_key :invitations, :users, column: :owner_id
add_index :invitations, :invitee_id
add_foreign_key :invitations, :users, column: :invitee_id
end
try removing foreign_key: true from the options, since we are giving it a references, I think we don't need a foreign_key: true option
class CreateInvitations < ActiveRecord::Migration[5.0]
def change
create_table :invitations do |t|
t.references :owner, # the owner
t.references :invitee, # the invitee
t.references :core_bot # the associated page (core_bot_active)
t.string :email
t.string :token
t.timestamps
end
end
end

Referencing a table twice in rails/postgres

I am using PostgreSQL as my db in rails. I have a User model and a Product model. I am trying to make a Transaction model where I want to reference user twice, once as buyer and once as seller. I generated the models as suggested in this post (answer by toasterlovin)
Write a migration with reference to a model twice
However it gives me an error when I use PostgreSQL (with SQLite it worked fine). I get the following error. What can I do to resolve this?
{StandardError: An error has occurred, this and all later migrations canceled:
PG::UndefinedTable: ERROR: relation "buyers" does not exist
: ALTER TABLE "transactions" ADD CONSTRAINT "fk_rails_0b24a7fcc3"
FOREIGN KEY ("buyer_id")
REFERENCES "buyers" ("id")
C:/Users/Powerhouse/Desktop/CodingDojo/ruby/rails/demo/db/migrate/20161024032156_create_transactions.rb:3:in change'
C:inmigrate'
ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR: relation "buyers" does not exist
: ALTER TABLE "transactions" ADD CONSTRAINT "fk_rails_0b24a7fcc3"
FOREIGN KEY ("buyer_id")
REFERENCES "buyers" ("id")
C:/Users/Powerhouse/Desktop/CodingDojo/ruby/rails/demo/db/migrate/20161024032156_create_transactions.rb:3:in change'
C:inmigrate'
PG::UndefinedTable: ERROR: relation "buyers" does not exist
C:/Users/Powerhouse/Desktop/CodingDojo/ruby/rails/demo/db/migrate/20161024032156_create_transactions.rb:3:in change'
C:inmigrate'
Tasks: TOP => db:migrate
(See full trace by running task with --trace) }
Models
class User < ActiveRecord::Base
has_many :products
has_many :sales, :class_name => 'Transaction', :foreign_key => 'seller_id'
has_many :purchases, :class_name => 'Transaction', :foreign_key => 'buyer_id
end
Product Model
class Product < ActiveRecord::Base
belongs_to :user
end
Transaction model
class Transaction < ActiveRecord::Base
belongs_to :buyer, :class_name => 'User'
belongs_to :seller, :class_name => 'User'
belongs_to :product
end
Migration files
User
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :name
t.timestamps null: false
end
end
end
Product
class CreateProducts < ActiveRecord::Migration
def change
create_table :products do |t|
t.references :user, index: true, foreign_key: true
t.string :name
t.timestamps null: false
end
end
end
Transaction
class CreateTransactions < ActiveRecord::Migration
def change
create_table :transactions do |t|
t.references :buyer, index: true, foreign_key: true
t.references :seller, index: true, foreign_key: true
t.references :product, index: true, foreign_key: true
t.timestamps null: false
end
end
end
This is due to PostgreSql not understanding how to make the custom association foreign keys.
Try changing the migration file to,
class CreateTransactions < ActiveRecord::Migration
def change
create_table :transactions do |t|
t.integer :buyer_id
t.integer :seller_id
t.integer :product_id
t.timestamps null: false
end
add_index(:transactions, :buyer_id)
add_index(:transactions, :seller_id)
add_index(:transactions, :product_id)
add_foreign_key :transactions, :users, column: :buyer_id
add_foreign_key :transactions, :users, column: :seller_id
end
end
It automatically links buyer_id to user, taking the power of
belongs_to :buyer, :class_name => 'User'
The above line makes the buyer_id as foreign key.
You can also try,
class CreateTransactions < ActiveRecord::Migration
def change
create_table :transactions do |t|
t.references :buyer, index: true
t.references :seller, index: true
t.references :product, index: true
t.timestamps null: false
end
add_foreign_key :transactions, :users, column: :buyer_id
add_foreign_key :transactions, :users, column: :seller_id
end
end
Your problem is that when ActiveRecord see this:
t.references :buyer, index: true, foreign_key: true
it tries to create a foreign key inside the database (because foreign_key: true) but the naming conventions tell AR that it should be linking to the buyers table (because you're referencing :buyer).
Just like you specify class_name: in your model:
belongs_to :buyer, :class_name => 'User'
to tell AR not use the conventional Buyer name you can override the convention in your migration by modifying your :foreign_key option:
t.references :buyer, index: true, foreign_key: { to_table: :users }
to explicitly name the table. Similarly for your other reference that doesn't use the conventional naming scheme:
t.references :seller, index: true, foreign_key: { to_table: :users }

Change foreign key column name in rails

I have a Project migration class like this:
class CreateProjects < ActiveRecord::Migration
def change
create_table :projects do |t|
t.string :title
t.text :description
t.boolean :public
t.references :user, index: true, foreign_key: true
t.timestamps null: false
end
end
end
It creates a column name user_id in projects table but I want to name the column owner_id so I can use project.owner instead of project.user.
You can do it two ways:
#app/models/project.rb
class Project < ActiveRecord::Base
belongs_to :owner, class_name: "User", foreign_key: :user_id
end
OR
$ rails g migration ChangeForeignKeyForProjects
# db/migrate/change_foreign_key_for_projects.rb
class ChangeForeignKeyForProjects < ActiveRecord::Migration
def change
rename_column :projects, :user_id, :owner_id
end
end
then:
$ rake db:migrate

Resources