I'm trying to get back into RoR after a long hiatus, and was getting an error when I tried to rails db:migrate:
rails aborted!
StandardError: An error has occurred, this and all later migrations canceled:
Directly inheriting from ActiveRecord::Migration is not supported. Please specify the Rails release the migration was written for:
the errors continue...
I'm thinking its because of the gem ratyrate.
In one of the migration files:
class CreateRatingCaches < ActiveRecord::Migration
def self.up
create_table :rating_caches do |t|
t.belongs_to :cacheable, :polymorphic => true
t.float :avg, :null => false
t.integer :qty, :null => false
t.string :dimension
t.timestamps
end
add_index :rating_caches, [:cacheable_id, :cacheable_type]
end
def self.down
drop_table :rating_caches
end
end
is it because rails 5 don't use def self.up / def self.down? and instead should be using def change?
If that's the case, is it okay for me to just change the def setf.up to def change and then remove the def self.down block?
In addition to this, why is there even a def self.down calling to drop the table when its creating the table? Does it not get executed, only when you db:rollback the database?
Thanks
Since you are inheriting from ActiveRecord::Migration the migration is cancelled.
You should therefore inherit from ActiveRecord::Migration[5.1] and the migration should work. Change the first line to:
class CreateRatingCaches < ActiveRecord::Migration[5.1]
(5.1 specifies the rails version, adapt acordingly, e.g. ActiveRecord::Migration[4.2] etc.)
See this answer for more information about change vs. up/down in migrations or read this part in the official guide for detail information about the different aspects about them.
Related
Disclaimer: I don't know ruby.
I've been trying to setup this ruby application. I'm trying to debug why I get an uninitialized constant error:
rake aborted!
StandardError: An error has occurred, all later migrations canceled:
uninitialized constant CreateSyncsTable::Syncs/var/rails/cycs/cycs/db/migrate/20100818122117_create_syncs_table.rb:8:in `up'
Below is the file contents of 20100818122117_create_syncs_table.rb.
class CreateSyncsTable < ActiveRecord::Migration
def self.up
create_table :syncs do |t|
t.timestamps
t.integer :remedy_query_low
t.integer :remedy_query_high
end
Sync.create :remedy_query_low => 0, :remedy_query_high => 0
end
def self.down
drop_table :syncs
end
end
To my understanding, line 8 is trying to create a new entry into the syncs table. I don't know exactly why the syntax for doing so is as follows:
Sync.create :remedy_query_low => 0, :remedy_query_high => 0
Nor do I understand why or where "Sync" comes from. Moreover, I don't know what constant is uninitialized.
Any help to debug this is appreciated. For the record, I am using centOS 7, Maria DB and ActiveRecord version 3.2.18.
I reviewed the API to see if that would help. Since I don't know ruby, I don't find it of much help.
Try adding in a call to ActiveRecord::ModelSchema.reset_column_information as it "resets all the cached information about columns, which will cause them to be reloaded on the next request", allowing you to create Sync entries immediately after creating the table in the migration:
class CreateSyncsTable < ActiveRecord::Migration
def self.up
create_table :syncs do |t|
t.timestamps
t.integer :remedy_query_low
t.integer :remedy_query_high
end
Sync.reset_column_information
Sync.create :remedy_query_low => 0, :remedy_query_high => 0
end
def self.down
drop_table :syncs
end
end
Personally, I would recommend removing the Sync.create :remedy_query_low => 0, :remedy_query_high => 0 statement altogether since I think Rails migrations are best used for schema migrations only, and data migrations are best put in rake tasks (a great reason why can be found here).
In this case, Sync is referring to a model. You should have a file in app/models/ called sync.rb, which is the model definition for the Sync class. This is a Rails convention for defining models.
You can use models in your migrations (you've been looking at a migration). However, it's generally not recommended to use your app's models in the migration, because you can end up with conflicts.
What's recommended is to define a proxy model in your migration, which takes the place of the app model for the purposes of the migration. You declare the proxy model at the top of your migration file, so that it's local to the migration.
Try this code:
class Sync < ActiveRecord::Base
end
class CreateSyncsTable < ActiveRecord::Migration
def self.up
create_table :syncs do |t|
t.timestamps
t.integer :remedy_query_low
t.integer :remedy_query_high
end
# Reset ActiveRecord cache of Sync details
Sync.reset_column_information
Sync.create :remedy_query_low => 0, :remedy_query_high => 0
end
def self.down
drop_table :syncs
end
end
The additional call to Sync.reset_column_information tells Rails to reset the cache of information about the model because the table structure has changed. This will prevent issues, such as trying to access the new columns added in the migration.
This is a Ruby non-web project that uses ActiveRecord to talk to the database.
There is a single file which contains the db connection code, migration, and model. See here (but it's not necessary to read this to answer the question)
require 'sqlite3'
require 'active_record'
require 'yaml'
require 'active_support/all'
require 'securerandom'
BasePath = "#{File.dirname(__FILE__)}/.."
DATABASE_FILENAME = "database.sqlite"
DATABASE_PATH = "#{BasePath}/#{DATABASE_FILENAME}"
SQLite3::Database.new(DATABASE_PATH)
ActiveRecord::Base.establish_connection(
adapter: 'sqlite3',
database: DATABASE_PATH
)
class Migrations < ActiveRecord::Migration
def up
create_table :todos do |t|
t.string :content
t.boolean :completed
t.timestamps null: false
end
end
def down
puts "backing up database".red_on_black if File.file?(DATABASE_PATH)
loop { (`cp #{DATABASE_PATH} #{DATABASE_PATH}-#{SecureRandom.urlsafe_base64}.backup`; break) rescue next }
sleep 0.5
drop_table :todos
puts "dropped todos table"
end
end # Migrations
class Todo < ActiveRecord::Base
end
The question is about this line:
class Migrations < ActiveRecord::Migration
When I run the migration with Migrations.migrate(:up), I get a deprecation warning:
DEPRECATION WARNING: Directly inheriting from ActiveRecord::Migration is deprecated.
Please specify the Rails release the migration was written for:
class Migrations < ActiveRecord::Migration[4.2]
Like it advises I change my class definition to
class Migrations < ActiveRecord::Migration[4.2]
And then I no longer get the warning.
I'm wondering if anyone can explain the purpose of this.
My app doesn't depend on any version of Rails. Why would I need
to specify a Rails version?
Because Active Record wants to know in which version the migrations were generated. Sometimes a default in a migration can change between Rails releases (when I say Rails releases I'm talking about the release of Rails the framework, not rails the gem).
So let's say you have a migration like:
create_table :todos do |t|
t.string :content
end
And it was generated with Active Record 4.2 (and thus Rails 4.2 release). In Rails 4.2, strings columns have the default size of 4 bytes.
In Rails 5.0, the Rails team decided to change the default size to 8 bytes. If you upgrade the gem to 5.0 rollback this migration and run again now your database will have a string column with 8 bytes of size.
If you specify the version in the migration, no matter which version of Active Record you are using the column will always be generated with the size that were the default in the version of Rails that it was generated. In my example, if you specify 4.2 as the version it will be always a 4 bytes string column.
If upgrading from rails 4 to rails 5, you can just add the version number to the migration like so after rollback or drop:
Rails 4.2.6
class CreateStudents < ActiveRecord::Migration
def change
create_table :students do |t|
t.belongs_to :user, index: true
t.string :first_name
t.string :last_name
t.string :phone
t.timestamps null: false
end
end
end
Rails 5.1.3
class CreateStudents < ActiveRecord::Migration[5.1]
def change
create_table :students do |t|
t.belongs_to :user, index: true
t.string :first_name
t.string :last_name
t.string :phone
t.timestamps null: false
end
end
end
I have a migration file called [timestamp]_create_posts.rb.
I found that I made the column with a wrong data type. I need to make t.text :content instead of t.string :content.
I include the code from the above file:
class CreatePosts < ActiveRecord::Migration
def change
create_table :posts do |t|
t.string :title
t.string :content
t.timestamps null: false
end
end
end
I kinda know that I should not directly change the file but rollback migration and change the schema and do the migration again. But I wasn't sure whether that's a right way to do it. It would be really nice if someone can guide me through this. I'm not really familiar with Rails.
You should not rollback anything. You should create a new migration, that will change a column with following content:
class UpdatePostsChangeContentColumn < ActiveRecord::Migration
def change
change_column :posts, :content, :text, limit: 60000 # or whatever
end
end
or, even better, to supply the reasonable rollback of this migration:
class UpdatePostsChangeContentColumn < ActiveRecord::Migration
def up
change_column :posts, :content, :text, limit: 60000 # or whatever
end
# back to previous version
def down
change_column :posts, :content, :string
end
end
The other option if you are just in the development is just to Drop you database and recreate it. Then you can modify that file, but THIS IS NOT ADVISED. I have done this again in development where i didn't care about recreating my database
rake db:drop
rake db:create
rake db:migrate
There are two ways to change the column in table:
You can use rake db:rollback VERSION=file_version and then after that you can change datatype manually.
Generate another migration file. e.g rails g migration RemoveColumnToPost and the you can add following codes:
def up
change_column :posts, :content, :text
end
def down
change_column :posts, :content, :string
end
And then use rake db:migrate
I have what I think is a pretty simple migration. For some reason I get an IrreversibleMigration error when I try to db:rollback or db:migrate:redo.
The migration runs smoothly, but I'd rather keep it reversible. I can't figure out why it's not as written. Any ideas?
Here's the migration:
class AddWhyHypAndWhyHypeToStatements < ActiveRecord::Migration
def change
change_table :statements do |t|
t.rename :description, :why_hypocritical
t.text :why_hypothetical
end
end
end
If it matters, "description" column is a text column. I'm using Rails 3.1/Ruby 1.9.2/PostgreSQL. Thanks for any help.
Looks like Rails has troubles reverting change_table method. Try doing it that way instead:
class AddWhyHypAndWhyHypeToStatements < ActiveRecord::Migration
def change
rename_column :statements, :description, :why_hypocritical
add_column :statements, :why_hypothetical, :text
end
end
You can see the list of commands that can be inverted in the docs or in Rails Guides.
I'm reading Rails 3 in Action and following the commands verbatim. However, when I run the commands
rails new things_i_bought
cd things_i_bought
bundle install
rails generate scaffold purchase name:string cost:float
The book says I should get this code:
class CreatePurchases < ActiveRecord::Migration
def self.up #not created in my code
create_table :purchases do |t|
t.string :name
t.float :cost
t.timestamps
end
end
def self.down # not created in my code
drop_table :purchases
end
end
I get this code instead:
class CreatePurchases < ActiveRecord::Migration
def change
create_table :purchases do |t|
t.string :name
t.float :cost
t.timestamps
end
end
end
Why are the class methods up and down not being created for me? I'm using
rails 3.1.1 and ruby 1.9.2.
thanks for reading my book!
As JacobM and dbalatero have already explained, this is a new feature in Rails 3.1. This particular feature was added by Aaron Patterson as a way to simplify the migration syntax. In earlier versions of Rails, you would have to do as the book shows:
class CreatePurchases < ActiveRecord::Migration
def self.up
create_table :purchases do |t|
t.string :name
t.float :cost
t.timestamps
end
end
def self.down
drop_table :purchases
end
end
But that's kind of repeating yourself. Aaron created a migration syntax that looks good and is simpler, calling only the methods necessary for migrating forward, but also allowing the migrations backwards (known as a "rollback") too. The same migration written with the Rails 3.1 syntax is this:
class CreatePurchases < ActiveRecord::Migration
def change
create_table :purchases do |t|
t.string :name
t.float :cost
t.timestamps
end
end
end
So when this migration runs "forwards", Rails will create the purchases table with the fields. When you roll it back (or run it "backwards") then Rails will know to drop the table.
This syntax isn't entirely perfect however, and you'll run into problems with methods such as change_column. When that happens, it's best to stick with defining both the def up and def down methods in the migrations:
class CreatePurchases < ActiveRecord::Migration
def up
change_column :purchases, :cost, :integer
end
def down
change_column :purchases, :cost, :float
end
end
That's because in this example Rails won't know how to switch it back to the previous type. I hope this explains it better!
This is a new feature in Rails 3.1. For changes that Rails can figure out how to reverse, such as creating a table, you simply create a "change" method with the code that would have gone in "up", and it figures out how to do "down" on it's own.
You can also define "up" and "down" methods yourself -- for some changes (such as dropping a column) Rails won't be able to figure it out -- but the syntax is a bit different; it's not just def up instead of def self.up (they're now instance methods instead of class methods).
I believe in the new Rails 3.1, the database migration methods are self-aware about how to run an up/down migration.
Therefore, if you define a def change method, it will try to use those self-aware methods: in this case, create_table knows to do DROP TABLE in a down context, and CREATE TABLE in an up context.
If you want the old style, you can probably keep using it and define your own self.down and self.up methods as the book describes.
Edit: here's a link to the blog post on this, called "Reversible Migrations": http://www.edgerails.info/articles/what-s-new-in-edge-rails/2011/05/06/reversible-migrations/index.html