Rails: How to add add_index to existing table - ruby-on-rails

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

Related

How to create a migration to remove an index only if it exists, rather than throwing an exception if it doesn't?

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

Change a column name in rails database.

I'm having this table
class CreateEvents < ActiveRecord::Migration
def self.up
create_table :events do |t|
t.integer :subcategory
t.string :event_name
t.text :description
t.string :location
t.date :date
t.decimal :price
t.timestamps
end
end
def self.down
drop_table :events
end
end
and i want to change the subcategory to subcategory_id. I tries this one but is not working
ruby script/generate migration RenameDatabaseColumn and then i went to the file which is in db\migrate and edited to look like this
class RenameDatabaseColumn < ActiveRecord::Migration
def self.up
rename_column :events, :subgategory, :subgategory_id
end
def self.down
# rename back if you need or do something else or do nothing
end
end
then i run the command rake db:migrate put the column is still subcategory. Can you help me please? I'm using rails 2.0
Thank you
Did you misspell the column name? isn't it :subcategory? You wrote :subgategory.
class RenameDatabaseColumn < ActiveRecord::Migration
def self.up
rename_column :events, :subcategory, :subcategory_id
end
def self.down
# rename back if you need or do something else or do nothing
end
end

Best way to add_index to database

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

How do I remove a model and its table in Ruby on Rails?

I'm diving into RoR and I need to remove a model and its table, as well as update the other models that reference it. I did a search on google and SO and the best answer I found was this, but the answer is unclear to me. The final consensus was to use the ruby script/destroy model method and then "manually edit any migrations that might contain refs to these deleted models" It's this last part that I'm unclear about. I want to delete the models for my user and profile models and tables...
class CreateUsers < ActiveRecord::Migration
def self.up
create_table :users do |t|
t.string :email
t.string :password
t.timestamps
end
end
def self.down
drop_table :users
end
end
class CreateProfiles < ActiveRecord::Migration
def self.up
create_table :profiles do |t|
t.string :name
t.integer :user_id
t.timestamps
end
end
def self.down
drop_table :profiles
end
end
and update the article model and table that references them...
class CreateArticles < ActiveRecord::Migration
def self.up
create_table :articles do |t|
t.string :title
t.text :body
t.datetime :published_at
t.string :image
t.timestamps
end
end
def self.down
drop_table :articles
end
end
class AddUserIdToArticles < ActiveRecord::Migration
def self.up
add_column :articles, :user_id, :integer
end
def self.down
remove_column :articles, :user_id
end
end
Can I just do ruby script/destroy user and then call the self.down methods in the article migrations? If so, how do I call the 'self.down` methods and in what order?
Thanks so much in advance for your help!
Yep. Just delete it with
ruby script/destroy model user
ruby script/destroy model profile
And then rollback your database, or self.down with this :
rake db:rollback
Now you can safely delete your migration file.

Activerecode HABTM primary key problem

I have to tables that have a many to many relationship. I have created the correct table codesecure_project_tst_definition and it works. I can join rows together by calling the codesecure_projects << method on a TstDefinition object. The problem is that for some reason active record wants to use Codesecure_project_id as the id value for the codesecure_project_tst_definition table. What am I doing wrong? How do I fix it so that when I call the codesecure_projects << method it does not try to set the id of the codesecure_project_tst_definition table?
I have posted the migrations below
class CreateCodesecureProjects < ActiveRecord::Migration
def self.up
create_table :codesecure_projects do |t|
t.string :name
t.string :lang
t.timestamps
end
end
def self.down
drop_table :codesecure_projects
end
end
class CreateTstDefinitions < ActiveRecord::Migration
def self.up
create_table :tst_definitions do |t|
t.string :test_name
t.timestamps
end
end
def self.down
drop_table :tst_definitions
end
end
class CreateCodesecureProjectsTstDefinitions < ActiveRecord::Migration
def self.up
create_table :codesecure_projects_tst_definitions do |t|
t.references :codesecure_project
t.references :tst_definition
t.timestamps
end
end
def self.down
drop_table :codesecure_projects_tst_definitions
end
end
The relevant parts of the models:
class TstDefinition < ActiveRecord::Base
has_and_belongs_to_many :codesecure_projects
has_many :tst_datas
class CodesecureProject < ActiveRecord::Base
has_many :input_abstractions
has_and_belongs_to_many :tst_definitions
After some searching I actually found the answer, thanks to this blog post http://jimcortez.com/blog/?p=9. I simply needed to remove the id column from the codesecure_projects_tst_definitions table. So the migration now looks like this:
class CreateCodesecureProjectsTstDefinitions < ActiveRecord::Migration
def self.up
create_table :codesecure_projects_tst_definitions, :id => false do |t|
t.references :codesecure_project
t.references :tst_definition
t.timestamps
end
end
def self.down
drop_table :codesecure_projects_tst_definitions
end
end

Resources