Drop mysql tables in Rails - mysql

How do I drop selected tables in Rails? I want to drop all tables from a database with a given prefix. PHPMyAdmin would be very useful at this point.
Thanks

You could install phpMyAdmin and manually delete your tables, or if you wanted to do it from within the rails framework and keep you migrations in sync, why not create a new migration that drops the tables on self.up and creates the tables on self.down.
class DropOldTablesMigration < ActiveRecord::Migration
def self.up
drop_table :prefix_table1
drop_table :prefix_table2
end
def self.down
create_table :prefix_table1 do |t|
t.column :name, :string
end
create_table :prefix_table2 do |t|
t.column :name, :string
end
end
end
EDIT:
Just to follow up, if the issue is that there are a lot of tables and you don't want to type them all, you could do something like this:
class DropOldTablesMigration < ActiveRecord::Migration
def self.up
ActiveRecord::Base.connection.tables.each do |t|
unless t.index('yourprefix_') == nil
drop_table t
end
end
end
end
Of course you would not be able to recreate the tables when you migrate down that way, but depending on what is going on in your app, that may not be a concern.
EDIT IN RESPONSE TO YOUR COMMENT:
To create a new migration, from the root of your app run the following command:
script/generate migration YourMigrationName
The migration file will be created for you in db/migrate. Add the code you want to run and save it. To run the new file enter the following at the command line
rake db:migrate

Related

In a Rails migration on a MySQL database, how to add a new column of type tinyint?

I have a Ruby on Rails application backed by a MySQL database. I want to add a new column of the MySQL type tinyint to one of my existing database tables.
After creating a new ActiveRecord migration class (via the command-line generator rails generate migration), what's the syntax to use in my add_column method call in my change method to add the new tinyint-type column? That is:
class MyMigration < ActiveRecord::Migration
def change
add_column :my_existing_table_name, :my_new_column_name, # Q: What goes here?
end
end
Just use a value of :boolean for the type parameter in the add_column call. For example:
class MyMigration < ActiveRecord::Migration
def change
add_column :my_existing_table_name, :my_new_column_name, :boolean
end
end
Reference: https://apidock.com/rails/ActiveRecord/ConnectionAdapters/SchemaStatements/add_column

Modifying old Rails migrations then adding a new migration that calls the old ones

MySQL 5.7 began failing old migrations that set a default for columns of type text.
After editing the migration, dropping the development db and re-running all migrations, all worked fine in development.
For production:
1. Is my below understanding correct? Is this the main and/or only issue (besides editing old migrations being frowned upon)
The issue to look out for is that since you can't drop a production db, these migrations will not be run and not reflected in db/schema.rb. As a result, your code will be error prone because it was written to work with a slightly different schema in development.
2. My solution is to essentially force the migration to re-run by calling its up method in a new migration. (See below code). Is this a reasonable solution? ie. Will it work in all cases (no critical downfalls).
This is the original migration, made years ago in Rails 2
class AddZipWarpableResHistory < ActiveRecord::Migration[5.2]
def self.up
add_column :warpables, :history, :text, :default => "", :null => false
add_column :warpables, :cm_per_pixel, :float, :default => 0, :null => false
Warpable.find(:all).each do |w|
r = w.get_cm_per_pixel
w.cm_per_pixel = r if r != nil
w.save
end
end
def self.down
remove_column :warpables, :history
remove_column :warpables, :cm_per_pixel
end
end
after edits (only including the edited lines below) in Rails 5
class AddZipWarpableResHistory < ActiveRecord::Migration[5.2]
def self.up
add_column :warpables, :history, :text, :null => false
Warpable.all.each do |w| # edited this bc find(:all) was broken as well
r = w.get_cm_per_pixel
w.cm_per_pixel = r if r != nil
w.save
end
end
end
new migration to ensure it works in production:
Note that none of the changes in that migration have any subsequent changes in other migrations before this one to account for
require_relative '20111005211631_add_zip_warpable_res_history'
class EnsureNoWarpableCorruption < ActiveRecord::Migration[5.2]
def self.up
AddZipWarpableResHistory.down
AddZipWarpableResHistory.up
msg = 'MySQL 5.7 began throwing errors on migrations that set a default for columns of type text.' +
'We edited that migration and rerun it here to ensure no data corruption in production'
change_table_comment(:warpables, msg)
end
def self.down
raise ActiveRecord::IrreversibleMigration
end
end
Would just editing the production DB manually in MySQL before merging this be an alternative solution if the model code wasn't updated as well?
MySQL doesn't support transactional migrations. Is this the simple solution when working with other databases?
Notes
I didn't execute SQL directly because then we would probably need to start storing db/structure.sql instead of db/schema.rb.
I didn't try to fix any model code or other logic.

Migration to create table raises Mysql2::Error: Table doesn't exist

I wrote a migration with the following:
class CreateTableSomeTable < ActiveRecord::Migration[5.1]
def change
create_table :some_tables do |t|
t.references :user, foreign_key: true
t.references :author, references: :user, foreign_key: true
t.text :summary
end
end
end
It is a basic migration that is creating a database table. However: when I run rails db:migrate a very odd error message aborts the migration:
Mysql2::Error: Table 'my_database.some_tables' doesn't exist: SHOW FULL FIELDS FROM 'some_tables'
It is as if the error is saying it can't create the table because the table does exist, which doesn't make sense.
Things I have looked at and tried:
reviewed the database.yml which seems fine. Nothing has changed, and I have recently run other migrations just fine (though no migrations that created database tables)
ran bundle to ensure all gems were installed
deleted the schema.rb file, recreated the database with data from another copy, and I ran rake db:schema:dump to recreate the schema.rb file. I attempted to run the migration again and still got the same error.
I am using rails 5.1.1 as well as mysql2 0.4.6
Any tips on how I can get the migration to run?
I got a similar error when trying to create a new model that has a reference to an existing model that was created before migrating to Rails 5.1.
Although the error message was not very clear about that, in my case it turned out that the problem was data type mismatch between the primary key of the old model and the foreign key of the new model (MySQL does not permit that). It was so because since Rails 5.1 the default data type of all the primary and foreign keys is bigint, but for the old model the primary key type was still integer.
I solved this by converting all the primary and foreign keys of the current models to bigint, so I can use the Rails new defaults and forget about it.
A workaround could also be specifying integer type for the new foreign keys so that they match the primary keys type of the old models. Something like the following:
class CreateUserImages < ActiveRecord::Migration[5.1]
def change
create_table :user_images do |t|
t.references :user, type: :integer, foreign_key: true
t.string :url
end
end
end
The big issue with the ActiveRecord migration 5.1 is that now the id are expected to be BIGINT instead of INT, so when you adding a column referring another table created before rails 5.1 it expect the column type to be BIGINT but instead is just an INT, hence the error.
The best solution is just modify your migration and change the type of the column to int.
class CreateTableSomeTable < ActiveRecord::Migration[5.1]
def change
create_table :some_tables do |t|
t.references :user, foreign_key: true, type: :int
t.references :author, references: :user, foreign_key: true
t.text :summary
end
end
that should work.
I figured out a work around, but it is still very puzzling to me.
The error message in the log file was not exactly pointing to the issue. For some reason, it might be rails 5.1.1 or it might be mysql2 0.4.6, but it doesn't like using references within the create_table block for some reason. Very odd because it has worked for me in the past.
So I changed the migration from this:
class CreateTableSomeTable < ActiveRecord::Migration[5.1]
def change
create_table :some_tables do |t|
t.references :user, foreign_key: true
t.references :author, references: :user, foreign_key: true
t.text :summary
end
end
end
To this:
class CreateTableSomeTable < ActiveRecord::Migration[5.1]
def change
create_table :some_tables do |t|
t.integer :user_id
t.integer :author_id
t.text :summary
end
end
end
And it worked.
It is very odd because references works just fine with sqlite3 (I tested this by generating a dummy app, ran a scaffold command with a references column, and ran rails db:migrate and it all worked).
This drove me nuts, I think I was seeing a different reason for this than what others suggested. In my case it happened because my migration file names didn't exactly match the migration class therein. For example, I had a migration file named 20171205232654_bonus.rb but inside the class was declared as class CreateBonus < ActiveRecord::Migration[5.1]. Once I changed the file name to 20171205232654_create_bonus.rb everything worked.
This might have something to do with the fact that I've been creating migrations only, not full scaffolds, and maybe I did something wrong. I really don't know how I wound up with that mismatch.

Set default value based on column in another table during migration

Trying to change my database a little bit. I have two tables one called User and one called Plan. I want to perform a migration that will add a column to my User table and set the default value of that column based on the value of a column in the Plan table. Then drop the Plan table along with any other columns in the User table that were associated with Plan. The following is the code that I have so far, but I am not sure if it is the best approach.
class DropPlansAddPurchasedAuctionsToCompany < ActiveRecord::Migration
def up
add_column :users, :purchased_items, :integer, default: 0, after: :legal_name
User.update_all(:purchased_items => -1).where("plan_id IS NOT NULL")
remove_column :users, :plan_id
remove_column :users, :plan_started_at
remove_column :users, :disable_plan_limits
drop_table :plans
end
def down
raise ActiveRecord::IrreversibleMigration, "Can't recover plans table"
end
end
I think this is the right direction but when I run the migration i get the following error message: NoMethodError: undefined method 'where' for 3:Fixnum
Any insight or suggestions? If you need more info I can provide it.
update_all returns the number of records that were updated, which is a number, not a relation.
You should do the where before the update_all:
User.where("plan_id IS NOT NULL").update_all(:purchased_items => -1)

Redmine Not Recognizing Migration File to Change DB

Essentially I am trying to add a new column to an existing Redmine database table through a plugin.
To my knowledge, the main command for migrating to the database through a plugin is:
rake redmine:plugins:migrate
yet when I run that command, on my local machine it says that it is migrating all the plugins i have installed, however it is not updating the database. Are there any checks I can do to make sure that redmine is recognizing which database to migrate to?
For example, in one of my plugins I simple want to add a new field :foo of type :datetime to the users table with the following migration file:
class AddColumnIssuePosition < ActiveRecord::Migration
def self.up
change_table :user do |t|
t.column :foo, :datetime
end
end
def self.down
change_table :user do |t|
t.remove :foo
end
end
end
I run the migration rake command and it says that it has migrated the plugin, however it doesnt give any details on the new column addition "foo" to the "users" table...
Migrating user_foo (User Foo Plugin)...
It just spouts out that line and it ends there. No changes found on the users table.
Forgive me as I am somewhat new to rails.
Change your migration to look like below:
class AddColumnIssuePosition < ActiveRecord::Migration
def change
add_column :users, :foo, :datetime
end
end