I have a Rails 6 app (6.0.0rc1). It has book and author models that have has_many :through associations. I created a join table with
rails g migration CreateJoinTableAuthorsBook author:references books:references
As you can see, I named the table incorrectly and I referenced the book incorrectly. I deleted the migration and created a new migration
rails g migration CreateJoinTableAuthorsBooks author:references book:references
Now when I run the migration, I get
ArgumentError: you can't define an already defined column 'author_id'.
I've searched my entire Rails app, but I can't find 'author_id' anywhere. I ran the previous migration (the one with the incorrect values). How can I delete the previous 'author_id' so I can successfully run the migration?
UPDATE The problem likely lies in the new migration. In Rails 5.2 (I don't have Rails 6 handy) rails g migration CreateJoinTableAuthorsBooks author:references book:references produces a migration like so:
create_join_table :authors, :books do |t|
t.references :author, foreign_key: true
t.references :book, foreign_key: true
end
create_join_table :authors, :books already creates a table with references (although they're not declared foreign keys). t.references :author and t.references :book are redundant. In Rails 5.2 this redundancy is overlooked, but perhaps Rails 6 does not.
For this reason I'd recommend tweaking your migration so everything is properly declared and indexed.
create_join_table :authors, :books, column_options: { null: false, foreign_key: true } do |t|
t.index [:author_id, :book_id]
t.index [:book_id, :author_id]
end
The normal procedure for fixing a goofed migration is to first rollback the migration with rails db:rollback, then delete the bad migration file. Rolling back requires the migration you're rolling back still exists (and is reversible).
Otherwise, start with a fresh development database using the version in db/schema.rb with rails db:reset. Note this will blow away your dev and test databases; that shouldn't be an issue. Be sure your db/schema.rb doesn't contain changes from your goofed migration, usually you can assure this by checking it out from version control.
Finally if everything is really messed up including db/schema.rb, rails db:migrate:reset will re-run all your migrations, rebuild db/schema.rb fresh, and provide you with fresh development and test databases.
create_join_table :authors, :books
will fix it for you as rails 6 doesn't need those declarations.
I had this same issue when working on a Rails 6 application.
== 20200711132707 CreateProducts: migrating ===================================
-- create_table(:products)
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:
you can't define an already defined column 'voltage'.
Here’s how I fixed it:
The issue was that I defined a model attribute twice, which in this case was voltage:decimal. So when I run rails db:migrate it throws the error.
I fixed by first deleting the migration file for products.
And then recreating the migration for products.
This time when I ran rails db:migrate everything worked well.
That's all.
I hope this helps
I had the same issue,
you do NOT need anymore the references:
# remove these:
t.references :author, foreign_key: true
t.references :book, foreign_key: true
Note: you can still use the options used in t.references with create_join_table, using the column_options arg.
For example:
create_join_table :authors, :books, column_options: { type: :uuid, null: false, index: true, foreign_key: true } do |t|
...
end
Related
So I'm working with a colleague who added some additional migration files and per normal procedure once I pulled their version I ran rails db:migrate. I end up getting the following errors:
Index name 'index_authorizations_on_user_id' on table 'authorizations' already exists
ArgumentError: Index name 'index_authorizations_on_user_id' on table 'authorizations' already exists
So I went and checked the schema and the table is already present. So why is it failing? Typically in the past it only generates new table entries/updates when doing a migration so why isn't it just ignoring it?
I've tried doing a rollback and get:
This migration uses remove_columns, which is not automatically reversible.
I've tried doing bin/rails db:migrate RAILS_ENV=development and I get the same errors.
I've done a db:reset, db:drop, and it all comes back to an issue with pending migrations that I cannot get to run. What am I doing wrong?
They added the following migration: 20171024074328_create_authorizations.rb
class CreateAuthorizations < ActiveRecord::Migration[5.1]
def change
create_table :authorizations do |t|
t.string :provider
t.string :uid
t.references :user, foreign_key: true
t.timestamps
add_index :authorizations, :user_id
add_index :authorizations, [:provider, :uid], unique: true
end
end
end
This:
t.references :user, foreign_key: true
adds an index on authorizations.user_id for you. If you check the references documentation it will point you at add_reference and that says:
:index
Add an appropriate index. Defaults to true. [...]
So index: true is the default when you call t.references :user and that creates the same index that add_index :authorizations, :user_id creates.
So the only thing that I've found that "worked" was to actually delete the migration files then run rails db:migrate. Didn't catch on anything, no errors.
Not a fan of the fact that this worked.
Check if it's a table or a changed table, most times you need to drop the table or delete the column then run the migration again and it'll be good to go
class CreateComments < ActiveRecord::Migration
def change
create_table :comments do |t|
t.integer :link_id
t.text :body
t.references :user, index: true, foreign_key: true
t.timestamps null: false
end
add_index :comments, :link_id
end
end
I was deploying my app to heroku and had to redo the database in Pg insteand of sqlite 3. When I migrate my database I am gettting this
NameError: uninitialized constant CreateCommments
I have been search SO all day and tried many of the solutions but to no avail. I have searched spelling errors, dropped, recreated the database. My database.yml is up to date and gem and gemlock are clean of sqlite, but it will not stop yelling at me. Thank you in advance.
The error is because the filename is incorrect. It has to be a timestamp with the class name then in snake case, like
20170602175844_create_comments.rb
You can of course do this manually and just change the filename, or run in the console and get a new migration
rails g migration create_comments
Note:
It doesn't have to be a timestamp though, that's just the way the rails rake task does it. You can also use a numerical sequence like if you create your files manually. This is just done to be able to see what migrations have already run and to be able to rollback to a specific version. Also so that the migrations run in a specific order.
1_create_comments.rb
I have two set up two database tables called 'points' and 'activities'. I want to give the table 'points' a foreign key 'activity_id' by setting up the associations as follows:
class Activity < ActiveRecord::Base
belongs_to :user
has_many :points, dependent: :destroy
...
end
and
class Point < ActiveRecord::Base
belongs_to :activity
end
In addition, I have the following migrations file for creating the points table:
class CreatePoints < ActiveRecord::Migration
def change
create_table :points do |t|
t.integer :activity_id
t.timestamps null: false
t.boolean :activities_completed, array: true, default: []
t.integer :point_value
t.float :time_left
end
end
end
However, when I run
rake db:reset
rake db:migrate
rake db:seed
and then check the the table points by
rails c
Point.column_names
then the foreign key is missing:
irb(main):001:0> Point.column_names
=> ["id", "created_at", "updated_at", "activities_completed", "point_value", "time_left"]
What am I doing wrong? What can I do to make the foreign key activity_id a column of the points table?
I am new to Ruby and Rails. My Rails version is 4.24. Any help is appreciated.
Your create table migration should have a "t.belongs_to :activity, index: true" instead of creating the field activity_id with type integer.
You should have done something like this to add activity_id to your points table.
t.references :activity, index: true, foreign_key: true
#this would have created activity_id column in points
Since now, you have already created your migrations and ran rake db:migrate, learn to remove a column from a table. You need to write migrations to remove activity_id from your points table and add it again.
rails generate migration RemoveActivityIdFromPoints activity_id:integer
rails g migration AddActivityRefToPoints activity:references
These two should create proper migrations for you. Check your migrations folder for confirmation that everything went well, and run rake db:migrate and test again.
Follow this link to learn more about it. http://guides.rubyonrails.org/active_record_migrations.html
I discovered that there was a more fundamental problem. The migration script was not being executed during rake db:migrate. Therefore the changes I had made to the migration were ineffective. I therefore had to use
rake db:migrate:redo VERSION=20160605234351
When I ran this command, then the foreign key appeared.
On migration I get the following error message:
PG::UndefinedTable: ERROR: relation "actioncodes" does not exist
: ALTER TABLE "organizations" ADD CONSTRAINT "fk_rails_4ecaa2493e"
FOREIGN KEY ("actioncode_id")
REFERENCES "actioncodes" ("id")
I have the following migration file for Organizations:
class CreateOrganizations < ActiveRecord::Migration
def change
create_table :organizations do |t|
t.string :name, null: false, limit: 40
t.references :actioncode, index: true, foreign_key: true
t.boolean :activated
t.datetime :activated_at
t.timestamps null: false
end
end
end
And for Actioncodes I have the migration file:
class CreateActioncodes < ActiveRecord::Migration
def change
create_table :actioncodes do |t|
t.string :code, null: false, limit: 20
t.string :description, limit: 255
t.timestamps null: false
end
end
end
class AddIndexToActioncodesCode < ActiveRecord::Migration
def change
add_index :actioncodes, :code, unique: true
end
end
The organization model file includes: belongs_to :actioncode.
While the actioncodes model file includes: has_many :organizations.
Any idea what could be causing the error message?
If I remove index: true, foreign_key: true from the migration file, it migrates without errors. And when I replace that line with the incorrect line t.references :actioncode_id, index: true, foreign_key: true, it gives the error below, where the last line ("ids") suggests Rails somehow seems to have problem with the name of the table?
PG::UndefinedTable: ERROR: relation "actioncode_ids" does not exist
: ALTER TABLE "organizations" ADD CONSTRAINT "fk_rails_604f95d1a1"
FOREIGN KEY ("actioncode_id_id")
REFERENCES "actioncode_ids" ("id")
So the issue is happening because CreateOrganizations migration is being run before CreateActioncodes is executed.
CreateActioncodes is to be run first thereby ensuring that the action codes table exists.
The order in which migrations are run is based on the time stamp of the migration - as indicated in the name of the file. 20141014183645_create_users.rb will run before 20141014205756_add_index_to_users_email.rb as the timestamp of the second one - 20141014205756 is after that of the first one - 20141014183645.
Make sure the time-stamps of the CreateOrganizations migration is after that of CreateActioncodes migration.
Either you could manually change the timestamp in the file names. Or delete these migration files, and create them in the correct order.
The foreign_key: true in this line:
t.references :actioncode, index: true, foreign_key: true
tells Rails to create a foreign key inside the database. A foreign key:
constraint specifies that the values in a column (or a group of columns) must match the values appearing in some row of another table. We say this maintains the referential integrity between two related tables.
So it is some logic inside the database (where it belongs) that ensures you can't put invalid values in your actioncode column and that you can't remove entries from the actioncodes table that are being used elsewhere.
In order to create the constraint, the referenced table (actioncodes) needs to exist before you refer to it. Looks like your migrations are trying to create organizations before actioncodes so all you need to do is rename the CreateOrganizations migration file so that its timestamp prefix comes after the one for CreateActioncodes. The prefix is just a timestamp in the format YYYYMMDDhhmmss so change the CreateOrganizations timestamp to the CreateActioncodes timestamp with one more second.
I was also getting this error. If you are using a test database to run rspec make sure you run rake db:test:prepare in the terminal before running rspec.
I had this same challenge when working on a Rails 6 application in Ubuntu 20.04.
I am working on a College Portal where I have model called School and another called Program. The model Program belongs to the model School, so it is required that I add a school references column to the programs table.
I used this command this create the migration file:
rails generate model School name:string logo:json motto:text address:text
rails generate model Program name:string logo:json motto:text school_id:references
However, when I run the command: rails db:migrate
I was getting the error:
== 20201208043945 CreateSchools: migrating ====================================
-- create_table(:schools)
-> 0.0140s
== 20201208043945 CreateSchools: migrated (0.0141s) ===========================
== 20201208043958 CreatePrograms: migrating ===================================
-- create_table(:programs)
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:
PG::UndefinedTable: ERROR: relation "school_ids" does not exist
Here's how I solved it:
The issue was from the command:
rails generate model Program name:string logo:json motto:text school_id:references
It is supposed to be school:references and not school_id:references, so during the migration Rails is unable to find the table school_ids.
So I modified the command to:
rails generate model Program name:string logo:json motto:text school:references
And it worked fine.
That's all.
I hope this helps
I have looked through many SO and google posts for generating migration of join table for has many and belongs to many association and nothing work.
All of the solutions are generating a empty migration file.
I am using rails 3.2.13 and I have two tables: security_users and assignments. These are some of things I have try:
rails generate migration assignments_security_users
rails generate migration create_assignments_security_users
rails generate migration create_assignments_security_users_join_table
rails g migration create_join_table :products, :categories (following the official documentation)
rails generate migration security_users_assignments security_user:belongs_to assignments:belongs_to
Can anyone tell how to create a join table migration between two tables?
To autopopulate the create_join_table command in the command line, it should look like this:
rails g migration CreateJoinTableProductsSuppliers products suppliers
For a Product model and a Supplier model. Rails will create a table titled "products_suppliers". Note the pluralization.
(Side note that generation command can be shortened to just g)
Run this command to generate the empty migration file (it is not automatically populated, you need to populate it yourself):
rails generate migration assignments_security_users
Open up the generated migration file and add this code:
class AssignmentsSecurityUsers < ActiveRecord::Migration
def change
create_table :assignments_security_users, :id => false do |t|
t.integer :assignment_id
t.integer :security_user_id
end
end
end
Then run rake db:migrate from your terminal. I created a quiz on many_to_many relationships with a simple example that might help you.
I usually like to have the "model" file as well when I create the join table. Therefore I do.
rails g model AssignmentSecurityUser assignments_security:references user:references
There's embeded generation for join table in rails
rails g migration AddCityWorkerJoinTable cities:uniq workers
which generates following migration
create_join_table :cities, :workers do |t|
t.index [:city_id, :worker_id], unique: true
end
❗️ NOTE:
models names should go in alphabet order
put :uniq only on first param
I believe this would be an updated answer for rails 5
create_table :join_table_name do |t|
t.references :table_name, foreign_key: true
t.references :other_table_name, foreign_key: true
end