So I made a mistake when generating the model.
I need to remove the "integer: string" and I want to the movie_id to be a integer not a string. Thanks
Review(id: integer, rating: integer, comment: text, created_at: datetime, updated_at: datetime, user_id: integer, movie_id: string, integer: string)
Any help will be appreciated!
You can use the command.
rake db:rollback
then go to the migration file.
remove
t.string :integer
and update
t.integer :movie_id
save and again run command.
rake db:migrate
You can also add another migration to do this. create a migration file. write following code in it
def change
remove_column :reviews, :integer, :string
change_column :reviews, :movie_id, :integer
end
and run
rake db:migragte
You can write another migration file for that, in which you can remove the column you want and change the type of the other. In your new migration file write:
def change
remove_column :reviews, :integer, :string
change_column :reviews, :movie_id, :integer
end
Related
I know I can do this in a change migration and have it be reversible:
add_column :widgets, :color, :string
remove_column :widgets, :flavor, :string
But strangely, change_table->remove does not work like this. Instead of params (name, type), it takes a list of column names. (If you attempt to append a type parameter, it gets interpreted as a column name.)
change_table(:widgets) do |t|
t.column :color, :string
t.remove :flavor, :string # <-- nope! It tries to remove a column named "string"
end
When you try that, you get this error:
remove_columns is only reversible if given a type.
Is there another call I am be overlooking? It seems weird that change_table could be missing such a fundamental use case, but I don't see any calls in the docs that can do it.
While experimenting, I tried this and it works:
change_table(:widgets) do |t|
t.column :color, :string
t.remove :flavor, type: :string
#^^^^^
end
So I guess that's the answer.
ActiveRecord::ConnectionAdapters::Table is generally just a thin wrapper around ActiveRecord::ConnectionAdapters::SchemaStatements - in this case remove_columns which takes a list of columns and an options hash.
type and other column options can be passed to make migration reversible.
remove_columns(:suppliers, :qualification, :experience, type: :string, null: false)
remove really just provides the first argument - which is the table.
Trying to add Timestamps to existing table.
According to Api documenation add_timestamps
Here is my code in migration:
def change
add_timestamps(:products, null: false)
end
Getting error:
*-- add_timestamps(:products, {:null=>false})
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:
SQLite3::SQLException: Cannot add a NOT NULL column with default value NULL: ALTER TABLE "products" ADD "created_at" datetime NOT NULL*
I've also tried all solution in this thread
Same error...
Rails 5.1.4
Ruby 2.4.0
You cannot add columns with not-null constraint to a non-empty table because the existing lines in the table would have empty values right away and therefore the condition fails.
Instead, introduce the columns in three steps:
def change
# add new column but allow null values
add_timestamps :products, null: true
# backfill existing records with created_at and updated_at
# values that make clear that the records are faked
long_ago = DateTime.new(2000, 1, 1)
Product.update_all(created_at: long_ago, updated_at: long_ago)
# change to not null constraints
change_column_null :products, :created_at, false
change_column_null :products, :updated_at, false
end
In my opinion, it is wrong to manipulate existing data with activerecord queries or even SQL in migrations.
The correct rails 5.2+ way to do this is :
class AddTimestampsToCars < ActiveRecord::Migration[5.2]
def change
add_timestamps :cars, null: false, default: -> { 'NOW()' }
end
end
It's a proc so you should be able to set a date in the past if you want to.
Source: https://github.com/rails/rails/pull/20005
I like #spickermann's approach since it takes into account the existing records and probably your migration already went all the way to production, his method ensures data perseverance.
Nevertheless, many of you guys might find yourselves in that situation, but still in development, meaning that there's no real sensitive data you might be afraid of losing... That gives you a bit more freedom on how you can perform the change in the table.
If your code and records only exist locally (if you still have no records created, just skip step 1.) and that table was created in the last migration , my suggestion is:
1.- Delete all the records from that table.
2.- Go to your migration file and edit it by adding t.timestamps so that it looks something like this:
class CreateInstitutionalLegals < ActiveRecord::Migration[5.0]
def change
create_table :institutional_legals do |t|
# Your original migration content goes here
.
.
t.timestamps # This is your addition
end
end
end
3.- Then go to your console and enter rails:db:redo. As explained here, that command is a shortcut for doing a rollback and then migrating back up again.
Now you will see that your schema is updated with the corresponding created_atand updated_at columns.
The concrete benefit of this is that it is super easy to do, you don't create an extra migration file and you learn to use a very handy command ;)
I'm on rails 5.0 and none of these options worked. The rails:db:redo will work but isn't a feasible solution for most.
The only thing that worked was
def change
add_column :products, :created_at, :timestamp
add_column :products, :updated_at, :timestamp
end
I had the same issue. I wanted the end result to be strictly equivalent to add_timestamps :products on an fresh database.
Instead of running a query to backfill, I ended up doing a 3-steps process.
add column with null allowed and default to current time to backfill
change constraint to not null
remove default
And it is reversible.
add_column :products, :created_at, :datetime, precision: 6, null: true, default: -> { "CURRENT_TIMESTAMP" }
add_column :products, :updated_at, :datetime, precision: 6, null: true, default: -> { "CURRENT_TIMESTAMP" }
change_column_null :products, :created_at, false
change_column_null :products, :updated_at, false
change_column_default :products, :created_at, from: -> { "CURRENT_TIMESTAMP" }, to: nil
change_column_default :products, :updated_at, from: -> { "CURRENT_TIMESTAMP" }, to: nil
NB: This is with Rails 6.1 and PostgreSQL
My User_ID miration says interger not integer.
class AddUserIdToPins < ActiveRecord::Migration
def change
add_column :pins, :user_id, :interger
add_index :pins, :user_id
end
end
I'm assuming I just can't change it from "interger" to "integer" using my text editor because it should be in my tables too.
Here is the way :
(A) First grab the specific migration number:
[shreyas#Arup-iMac rails_app_test (master)]$ rake db:migrate:status
database: app_development
Status Migration ID Migration Name
--------------------------------------------------
up 20150219075735 Create people
up 20150219085131 Add likes to persons
up 20150219114058 Add email to people
[shreyas#Arup-iMac rails_app_test (master)]$
(B) Now suppose, you want to edit the migration , 20150219085131, then do :
bin/rake db:migrate:down VERSION=20150219085131
(C) Then edit your migration and fix what you want to fix :
class AddUserIdToPins < ActiveRecord::Migration
def change
add_column :pins, :user_id, :integer
add_index :pins, :user_id
end
end
(D) And finally, again :
rake db:migrate:up VERSION=20150219085131
And you are done!
And If you are not able to run the current migration, then no worry, just change the file content by hand, and run rake db:migrate.
Edit your migration like this:
class AddUserIdToPins < ActiveRecord::Migration
def up
add_reference :pins, :user, index: true
end
def down
remove_index :pins, :user_id
remove_column :pins, :user_id
end
end
You rollback that migration:
bin/rake db:migrate:down VERSION=version_number
And try again:
bin/rake db:migrate:up VERSION=version_number
You can change it to :integer and then you have to run the migration, which will put the column in your db-tables:
rake db:migrate
If you try to run the migration like this it should show an error like:
type "interger" does not exist
We know, rails ActiveRecord::Migration now have a new method
def change
add_column :accounts, :name, :string
add_index :accounts, :name
change_column :my_table, :some_id, :string
end
But my question is for
change_column :my_table, :some_id, :string
rails do not need to know :some_id's previous type is integer or not.
For example assume :some_id was an integer, after this migration it is converted to string.
when I revert this migration :some_id type should be integer again. Am i right ?? but how can rails understand :some_id previous type was integer.
in previous mehtod self.up and self.down it is written in migration file. so it was not problem. rails can easily find that. but in change method how it is recollected?? Does it check the migration for this table in previous migration files where last data type was definded for :some_id or anything else ??
The change_column is an irreversible migration method. So you cannot reverse this migration using change method. To do this you need to write up and down methods. If you just write this in change method, when you run
rake db:rollback
it will throw this exception
ActiveRecord::IrreversibleMigration
You can read more more on:
http://edgeguides.rubyonrails.org/active_record_migrations.html#changing-columns
I tried to create a new Link table and specified the necessary columns under migration.
under db/migrate
class CreateLinks < ActiveRecord::Migration
def change
create_table :links do |t|
t.integer :user_id
t.string :url
t.timestamps
end
end
end
class AddTitleToLink < ActiveRecord::Migration
def change
# add_column :links, :user_id, :integer
add_column :links, :title, :string
end
end
When I ran rails console, Link returned
Link(id: integer, created_at: datetime, updated_at: datetime, title: string)
It seems like user_id (the foreign key) and url are missing. Title, which was added later, is in the table.
Did I do anything wrong?
Did you perhaps run the CreateLinks migration before editing it to add the two fields? If so, you can change that file all day long and rake db:migrate will never re-run it. That would explain there being an empty table links, and the field you then added to it in the next migration.
You can step the database back by running rake db:rollback. Try doing that twice, then migrate again.
Can't see any reason for this not to work. Is it possible that you first ran:
rails g model Link
(which generated a migration AND RAN it)
and then you manually added the :url and :user_id?
Try running twice:
rake db:rollback
Then run again
rake db:migrate
which will catch up your manual modifications