Set default value based on column in another table during migration - mysql

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)

Related

Rails Migration: Adding comment to column without changing type

I'm currently working on a task to add a large number of comments to the columns in a database. I currently am approaching it trying to use the change_column function like the code below; however I'm running into some errors and worried I could accidentally change some types when I actually want to leave them alone.
change_column :tablename, :id, :bigint, comment: "id"
This results in the following error when the column in question is a foreign key.:
Mysql2::Error: Cannot change column 'id': used in a foreign key
constraint 'fk_rails_(8 character series of numbers and letters)' of
table 'databasename.tablename'
I also tried the following approach,
change_column_comment :tablename, :id, comment:'ID'
it results in the following error:
change_column_comment(:tablename, :id, {:comment=>"ID"})
rails aborted! NotImplementedError:
ActiveRecord::ConnectionAdapters::Mysql2Adapter does not support
changing column comments
I got the same error message too:
NotImplementedError: ActiveRecord::ConnectionAdapters::Mysql2Adapter does not support changing column comments
When it occurs , you can change:
From:
def change
change_column :tablename, :id, :bigint, comment: "id"
To:
def up
change_column :tablename, :id, :bigint, comment: "id"
end
def down
change_column :tablename, :id, :bigint, comment: ""
end
My Rails version: 5.1.5
I dont get you, but why didn't you use add_column instead of change_column
add_column :tablename, :comment, :text, default: "ID"
The foreign keys is still an issue, but I've managed to get a reasonable result by extracting the current data types and using them in the following statement structure for each column.
connection.execute("ALTER TABLE `tablename` MODIFY `id` bigint(20) comment 'ID'")

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.

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

Rails 3, changing field in model from string to datetime type

When making my model, I made row type as string (I wasn't aware of datetime at the time). Currently I have plenty of records that have that row filled. Is there a safe way to convert the model's row to datetime through a migration - besides just removing it, and then adding it back?
Thanks!
Accordingly to the documentation this is an example of migration that transforms a string in datetime. I'm not sure it will work so you may want to try it out on a dev/stage env before going to the prod env.
class ChangeColumnToUsers < ActiveRecord::Migration
def self.up
change_column :users, :created_at, :datetime
end
def self.down
change_column :users, :created_at, :string
end
end
I think what you are looking for is change_column
http://apidock.com/rails/v3.0.0/ActiveRecord/ConnectionAdapters/SchemaStatements/change_column

Drop mysql tables in Rails

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