Add_column migration column order - ruby-on-rails

I use Rails 4, SQLite version 3.8.2 and I would like to add new column to my db.
I create new migration:
rails g migration AddFooToStudents foo:string
so I get then :
class AddFooToStudents < ActiveRecord::Migration
def change
add_column :students, :foo, :string, after: :name
end
end
then I run migration:
rake db:migrate
== 20150803095305 AddFooToStudents: migrating
=================================
-- add_column(:students, :foo, :string, {:after=>:name})
-> 0.0009s
== 20150803095305 AddFooToStudents: migrated (0.0011s)
========================
Everythink seems to be OK, in database has been added foo column but instead of after name column, it has been added at the end of table
ActiveRecord::Schema.define(version: 20150803095305) do
create_table "students", force: :cascade do |t|
t.string "name"
t.string "lastname"
t.integer "age"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "second_name", default: "Untitled"
t.string "foo"
end
end
I completely don't know what I do wrong

You're using the after option, and so you could reasonably expect it to put it after :name.
However, this isn't documented very well (if at all) but the after option only works in some DBMSs (possibly only MySQL).
What i do is add my own sql to do this, after the add_column call, like so:
add_column :students, :foo, :string
ActiveRecord::Base.connection.execute("ALTER table students MODIFY COLUMN foo varchar(255) AFTER name")
Your SQL will need to be DBMS-specific, ie tailored to MySql, PostGresql, SQLite etc.

Well, SQLite does not handle AFTER syntax so in this situation the best solution is leave unchanged order of columns or create new table.

Related

Why is this duplicate column error appearing?

I am trying to add a new column active to my table students.
I ran rails g migration add_active_to_students active:boolean to generate this migration:
class AddActiveToStudents < ActiveRecord::Migration[5.0]
def change
add_column :students, :active, :boolean, default: true
end
end
But when I run rails db:migrate I get this error:
PG::DuplicateColumn: ERROR: column "active" of relation "students" already exists
: ALTER TABLE "students" ADD "active" boolean DEFAULT 't'`
As you can see there is not actually an active column in students:
create_table "students", force: :cascade do |t|
t.integer "club_id"
t.string "email"
t.string "address_line_1"
t.string "address_line_2"
t.string "city"
t.string "state"
t.integer "postcode"
t.string "phone1"
t.string "phone2"
t.string "first_name"
t.string "last_name"
t.date "dob"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "picture"
t.integer "payment_plan_id"
t.string "parent1"
t.string "parent2"
t.string "size"
t.text "notes"
t.index ["club_id"], name: "index_students_on_club_id", using: :btree
end
So why would I be getting this error?
I followed the steps that #demir posted and found that, yes, the column was in the database without being listed in the schema. ALTER TABLE students DROP COLUMN active did not give an error message however it also didn't remove the column.
In the end I removed it by:
Entering the console
rails console
Deleting the column
ActiveRecord::Base.connection.remove_column :students, :active
You may have added it somehow. Have you checked the PG database? Connect to the application database and see if there is an active field.
List databases
\l
Connect database
\c your_app_database_name
List table columns
\d+ students
Check active field, remove it if exist.
ALTER TABLE students DROP COLUMN active
You have this column in your DB, but it wasn't dumped to your schema.rb. Maybe a migration was stopped after it added the column, but before it wrote to schema.rb?
You can remove this column manually, running rails dbconsole and then:
ALTER TABLE students DROP COLUMN active
You can follow the above solutions i.e. drop the column from DB first and then run the migration. Most probably what has happened is, you created and run some migration but later deleted that migration file without doing a db:rollback.
One more option that you can consider is to put a conditional migration like:
class AddActiveToStudents < ActiveRecord::Migration[5.0]
def change
unless column_exists? :students, :active
add_column :students, :active, :boolean, default: true
end
end
end

Why does setting a default value for an existing column in an ActiveRecord Migration not extend to existing associations on production?

If I add a default value to an existing column through an ActiveRecord Migration, when deploying my changes to production, existing associations are not affected.
I can drop to a rails production console and iterate over every single record and set the value on the new column to false on each record however it's tedious and doesn't scale well.
class AddDefaultValuesToAFewColumns < ActiveRecord::Migration[5.2]
def change
change_column :downloads, :is_deleted, :boolean, :default => false
end
end
create_table "downloads", force: :cascade do |t|
t.string "version"
t.string "comment"
t.string "contributors"
t.string "release_date"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "download_url"
t.boolean "is_deleted", default: false
end
The expected result would be for associations when queried from the rails console to return false for is_deleted, rather it returns nil. Why is this and what alternative solutions are there?
That's how it works. When you change the column default value, you are configuring the default value for new records, not existing ones. If you want to update existing values with false then do something like Download.where(is_deleted: nil).update_all(is_deleted: false) right after the change_column line:
class AddDefaultValuesToAFewColumns < ActiveRecord::Migration[5.2]
def change
change_column :downloads, :is_deleted, :boolean, :default => false
Download.where(is_deleted: nil).update_all(is_deleted: false)
end
end

My database isn't running all of my migrations, but says the schema number has

I was trying to fix a bad migration. I reset my database a couple times and it's just causing further problems, namely that not all my migrations are even running now.
Below are all the migrations, the one that was broken is the one yet to be run. But when I try to do a rake db:migrate I get this error:
undefined method `to_sym' for
nil:NilClass/usr/local/lib/ruby/gems/2.2.0/gems/activerecord-4.2.1/lib/active_record/connection_adapters/abstract/schema_definitions.rb:258:in
`column'
This is an issue in itself but what is most confusing to me is that the migration to create the simulation table just isn't running. My scheme looks like this:
ActiveRecord::Schema.define(version: 20150806192507) do
create_table "users", force: :cascade do |t|
t.string "email", limit: 96, default: "", null: false
t.string "encrypted_password", limit: 60, default: "", null: false
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
end
Any suggestions as to:
The simulations table is not being created when I do a reset and re-migrate.
The final migration to remove the verdict column is failing.
These are the migrations I have:
1.
class DeviseCreateUsers < ActiveRecord::Migration
def change
create_table(:users) do |t|
## Database authenticatable
t.string :email, :null => false, :default => "", limit: 96
t.string :encrypted_password, :null => false, :default => "", limit: 60
t.timestamps
t.index :email, unique: true
end
end
end
2.
class CreateSimulations < ActiveRecord::Migration
def change
# Needs the hash column worked out before this is run
create_table :simulations do |t|
t.integer :x_size
t.integer :y_size
t.string :verdict
t.string :arrangement
end
add_reference :simulations, :user, index: true
end
end
3.
class AddOpinionToSimulation < ActiveRecord::Migration
def change
add_column :simulations, :opinion, :hash
end
end
Finally, this is the bad one I was trying to run that started these problems. I have deleted the file to stop it from attempting to be migrated:
class RemoveVerdictFromSimulations < ActiveRecord::Migration
def change
remove_column :simulations, :verdict
end
end
Any suggestions?
There is no table simulations in your schema. If if it's not there, then you'll never be able to run that third migration.
First, refresh your database schema to make sure it's accurate in relation to your database with rake db:schema:dump
If there is indeed no simulations table, then first make sure that migration 2 succeeds.
Check schema_migrations table. If there are two rows there, then rails will think that the simulations table got created already, just delete the last entry from this table and migrate again making sure that the simulations table gets created this time, then try again with migration 3
My solution to this particular error was to go into my SQL database, delete every single version in the schema table. Then I did a
rake db:drop
I then walked through each version to make sure they migrated in order using:
rake db:migrate VERSION=<VERSION_NUMBER_FROM_EARLIEST_TO_LATEST>
If I ran into an error about a table not existing using:
rake db:prepare
Seemed to fix it aside from the last problem migration.

Activerecord migration error on postgresql

I have a error without explanation.
My error :
G::UndefinedColumn: ERROR: column "conjoncture_index_id" referenced in foreign key constraint does not exist
: ALTER TABLE "reports" ADD CONSTRAINT "fk_rails_c25ad9a112"
FOREIGN KEY ("conjoncture_index_id")
REFERENCES "conjoncture_indices" ("id")
My migration :
class AddColumnToReports < ActiveRecord::Migration
def change
add_reference :reports, :conjoncture_indice, index: true
add_foreign_key :reports, :conjoncture_indices
end
end
My create table migration :
class CreateConjonctureIndices < ActiveRecord::Migration
def change
create_table :conjoncture_indices do |t|
t.date :date
t.float :value
t.timestamps null: false
end
end
end
My model :
class ConjonctureIndice < ActiveRecord::Base
has_many :reports
by_star_field :date
end
My ConjonctureIndice shema.rb part :
create_table "conjoncture_indices", force: :cascade do |t|
t.date "date"
t.float "value"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
I'm looking for "conjoncture_index" in my project but nothing... I think that a old version of the project uses "conjoncture_index" instead "conjoncture_indice" but all occurence are deleted.
In rails , The migration names are plural whereas the model names are singular . So the model name should had been Index but it cannot be as it's a reserved keyword , the plural of which transforms to ConjunctureIndices .
Note - If you are still in doubt , then you can drop and re-create the database but i suspect the naming convention to be an issue in your case .
Ok i found the problem. i think that the error message is the same as before but he refer to a other table called "confidence_indices". The error come from "indice" word.. when i delete it i have no problem.

Postgres error when I try to run heroku run rake db:migrate

My sqlite3 database works fine in development but when I try to migrate it to production I get the following error:
PG::Error: ERROR: relation "movies" does not exist
: ALTER TABLE "movies" ADD COLUMN "production_company" character varying(255)/app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.12/lib/active_record/connection_adapters/postgresql_adapter.rb:652:in `async_exec'
I know a few people have posted about this but nothing I've tried seems to work. Anyone know how I might fix this?
Here's the migration:
class AddProductionCompanyToMovies < ActiveRecord::Migration
def change
add_column :movies, :production_company, :string, :limit => nil
end
end
Here's my schema.rb file if this helps:
ActiveRecord::Schema.define(:version => 20130331014529) do
create_table "movies", :force => true do |t|
t.string "title"
t.string "actor_1"
t.string "locations"
t.string "release_year"
t.string "string"
t.string "actor_2"
t.string "actor_3"
t.string "writer"
t.string "director"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "production_company"
t.string "distributor"
t.string "fun_facts"
end
end
Here's the migration where I create the movies table:
class Movies < ActiveRecord::Migration
def up
end
def down
end
end
It's not the best approach but a quick fix would be to replace that migration with this:
class AddProductionCompanyToMovies < ActiveRecord::Migration
def change
create_table :movies do |t|
t.string :production_company
t.timestamps
end
end
end
Your migration where you create the movie table is incorrect. The up and down methods you have don't do anything. Because of this, there is no movie table to add the production_company column to.
You need something like this;
class Movies < ActiveRecord::Migration
def change
create_table :movies do |t|
t.string :title
t.string :actor
.
. #add your columns you want in your initial migration here
.
end
end
I can't say why things worked in development in SQLite but at some point you successfully created the movies table and then maybe you altered the migration after that. This is easy to do (I've done it!).
A lot of people recommend that when you set up production you don't run your migrations to set up the database, but instead use rake db:schema:load (in fact, if you read the comments at the top of your db/schema.rb file it specifically describes this).
Another point is that a lot of people recommend having the same database in development as in production as there are subtle differences that can lead to unexpected problems in production (this is not what has caused your issue). If you're only just starting out then don't worry about it for now; it's just one more headache to set up PostgreSQL on your own machine; but it's something to keep in mind as you progress.

Resources