class AddTimestampsToPosts < ActiveRecord::Migration
def change
add_column :posts, :create_up, :datetime
add_column :posts, :update_at, :datetime
end
end
I need to correct :create_up and :update_at to :created_at and :updated_at
How can I achieve this?
THank you!
def change
rename_column :posts, :create_up, :created_at
rename_column :posts, :update_at, :updated_at
end
The ActiveRecord::Migration documentation lists the available transformations you can use.
Related
Is there any better way to add new columns to rails table than this way
class AddColumnsToUsers < ActiveRecord::Migration[5.1]
def change
add_column :users, :first_name, :string
add_column :users, :last_name, :string
add_column :users, :contact1, :integer
add_column :users, :contact2, :integer
add_column :users, :contact3, :decimal
add_column :users, :contact4, :integer
add_column :users, :contact5, :integer
add_column :users, :contact6, :string
add_column :users, :contact7, :integer
add_column :users, :contact8, :integer
add_column :users, :contact9, :integer
end
end
Can we use change_table method and write these inside a block? instead of repeating the add_column again and again
You can add multiple columns to a same table like this
def change
change_table :users do |t|
t.string :first_name
t.string :last_name
end
end
If you just want to dry, then you can write in following manner also,
{
string: [:first_name, :last_name, :contact6],
integer: [:contact1 ,:contact2 ,:contact4 ,:contact5 ,:contact7 ,:contact8 ,:contact9],
decimal: [:contact3]
}.each do |type, columns|
columns.each { |col| add_column :users, col, type }
end
Right now, the current migration might fail, if the books table doesn't have created_at or updated_at fields:
class AddTimestampIndexes < ActiveRecord::Migration
def up
remove_index :books, :created_at
remove_index :books, :updated_at
add_index :books, :created_at
add_index :books, :updated_at
end
def down
remove_index :books, :created_at
remove_index :books, :updated_at
end
end
Does remove_index take any options to silently proceed if it fails to remove the index rather than raising an error?
You can use the index_exists? method within your migration to test whether the index you need to remove is actually there.
Take a look at the documentation here:
http://apidock.com/rails/ActiveRecord/ConnectionAdapters/SchemaStatements/index_exists%3F
I've not tested it, but you should be able to use something like this:
class AddTimestampIndexes < ActiveRecord::Migration
def up
remove_index :books, :created_at if index_exists?(:books, :created_at)
remove_index :books, :updated_at if index_exists?(:books, :updated_at)
add_index :books, :created_at
add_index :books, :updated_at
end
def down
remove_index :books, :created_at
remove_index :books, :updated_at
end
end
Although, by the looks of things, you really only want to create them if they don't exist?
This might be more appropriate for your migration:
class AddTimestampIndexes < ActiveRecord::Migration
def up
add_index :books, :created_at unless index_exists?(:books, :created_at)
add_index :books, :updated_at unless index_exists?(:books, :updated_at)
end
def down
remove_index :books, :created_at
remove_index :books, :updated_at
end
end
Rails 6.1+ if_exists / if_not_exists options
Rails 6.1 added if_exists option to remove_index in order to not raise an error when the index is already removed.
Rails 6.1 added if_not_exists option to add_index in order to not raise an error when the index is already added.
As a result, your migration can be rewritten in the following way:
class AddTimestampIndexes < ActiveRecord::Migration
def up
remove_index :books, :created_at, if_exists: true
remove_index :books, :updated_at, if_exists: true
add_index :books, :created_at
add_index :books, :updated_at
end
def down
remove_index :books, :created_at, if_exists: true
remove_index :books, :updated_at, if_exists: true
end
end
Here is a list of the links to the corresponding PRs:
Add if_exists option to remove_index,
Fix index options for if_not_exists/if_exists.
There is also index_name_exists?(table_name, index_name) method which let's you check for an index by it's name. It's helpful for checking for existence of multi-column indexes.
Documentation - index_name_exists
I already migrated a table called units with several columns. I was wondering how to migrate in a stand alone 'add_index' to this table using the cmd. Is this code correct:
class AddIndexToUnits < ActiveRecord::Migration
def self.up
add_index :units, :lesson_id
end
def self.down
remove :units
end
end
I have a feeling the self.down could be wrong, I am unsure.
The self.up method is correct. Use this for your self.down:
remove_index :units, :column => :lesson_id
Almost
class AddIndexToUnits < ActiveRecord::Migration
def self.up
add_index :units, :lesson_id, :name=>'lesson_index'
end
def self.down
remove_index :units, 'lesson_index'
end
end
To remove an index, you must use remove_index with the same table and column specification as the self.up's add_index has. So:
def self.down
remove_index :units, :lesson_id
end
A multi-column index example would be:
def self.down
remove_index :units, [:lesson_id, :user_id]
end
I have the following two migrations already in my database:
When I created Prices:
class CreatePrices < ActiveRecord::Migration
def self.up
create_table :prices do |t|
t.string :price_name
t.decimal :price
t.date :date
t.timestamps
end
# add_index :prices (not added)
end
def self.down
drop_table :prices
end
end
and when I added a user_id to Prices:
class AddUserIdToPrices < ActiveRecord::Migration
def self.up
add_column :prices, :user_id, :integer
end
# add_index :user_id (not added)
end
def self.down
remove_column :prices, :user_id
end
end
Is there a way from the command line to add prices and user_id to index? I looked at this question and still was confused on how to go about adding indexes and the parts where I put "not added" seem like they would be error-prone because they were earlier migrations.
My question is, what is the best way for me to add indexing to prices and user_id?
Thank you for the help!
I think one extra migration fits well:
class AddIndexes < ActiveRecord::Migration
def self.up
add_index :prices, :user_id
add_index :prices, :price
end
def self.down
remove_index :prices, :user_id
remove_index :prices, :price
end
end
Or you can use change syntax with newer versions of rails, look at DonamiteIsTnt comment for details:
class AddIndexes < ActiveRecord::Migration
def change
add_index :prices, :user_id
add_index :prices, :price
end
end
Once an app is in production, the intent is that migrations will be applied once.
If you're still developing your app, you can always add them as you've noted followed by a rake db:migrate:reset this will wipe your database and re-create it.
Otherwise, create a new migration rails g migration add_user_id_index.
class AddUserIdIndex < ActiveRecord::Migration
def self.up
add_index :prices, :user_id
end
def self.down
remove_index :prices, :user_id
end
end
FWIW, add_index :prices doesn't make sense. Indexes are per-column, not per-table.
You can always manually create indexes by logging into your database.
CREATE INDEX prices__user_id__idx ON prices (user_id);
Simple solution:
create a new migration
add the indexes there (they don't need to be in the older migrations)
run the migrations
I'm a beginner at Ruby on Rails so I apologize if this is quite obvious, but I'm trying to learn how to write the database migration scripts and I'd like to change the following long_description to a text value instead of string:
class CreateArticles < ActiveRecord::Migration
def self.up
create_table :articles do |t|
t.column "short_description", :string
t.column "long_description", :string
t.timestamps
end
end
end
Any ideas how this is possible?
class CreateArticles < ActiveRecord::Migration
def self.up
create_table :articles do |t|
t.string :short_description
t.text :long_description
t.timestamps
end
end
def self.down
# don't forget the down method
end
end
Also, don't forget the down method.
Migration types are listed here.
:string
:text
:integer
:float
:decimal
:datetime
:timestamp
:time
:date
:binary
:boolean
create_table :articles do |t|
t.column 'long_description', :text
# ...
end
Set it to :text
Here's a good ref for you: Here