method names in Rails migrations - ruby-on-rails

I'm using Agile Web Development with Rails to learn about Rails. In an early chapter, the author created scaffolding and then started looking at the Migration. In his Migration, there is an "up" and and "down" method, whereas I only have a "change" method in my Migration. The author is using Rails 3.05 (or something like that) and I am using 3.1, however, I don't think that's the explanation, because using another book but same version of Rails I remember creating a migration that had the "up" and "down" methods...
So, two questions,
a) What's the reason why I have different method names in my migration?
b) is it going to affect functionality?
My Migration
class CreateProducts < ActiveRecord::Migration
def change
create_table :products do |t|
t.string : title
t.text :description
t.string :image_url
t.decimal :price, :precision => 8, :scale => 2
t.timestamps
end
end
end
Books Migration
class CreateProducts < ActiveRecord::Migration
def self.up
create_table :products do |t|
t.string :title
t.text :description
t.string :image_url
t.decimal :price, :precision => 8, :scale => 2
t.timestamps
end
end
def self.down
drop_table :products
end
end

Rails 3.1 did away with both the "up" and "down" part of migrations. Now they are called "reversible migrations" that use the change method. So your first code example is correct for Rails 3.1, second is correct for 3.0.x and earlier. Here are the change notes for 3.1 that skim over this update:
https://gist.github.com/958283
The important line: Migration files generated from model and constructive migration generators (for example, add_name_to_users) use the reversible migration's change method instead of the ordinary up and down methods.
The update makes sense if you think about it... you no longer have to define all the steps to "up" your database as well as type out the same steps in reverse to "down" your database. The change method is smart enough to go back and forth given the singe set of instructions.
To answer your second question, no it won't change how the migration works. It will still update your data store per your instructions, keep track of the migration, etc. It's just a more efficient way of describing those changes to your Model.

Same code really, just more dry (and slightly less customizeable).
Theres a good description here:
http://edgerails.info/articles/what-s-new-in-edge-rails/2011/05/06/reversible-migrations/index.html

Related

Ruby on Rails Migrating Databases Inconsistencies (Ruby on Rails 3 Essential Training Chapter 6)

I'm doing the Lynda course and am up to migrating databases. So first it seems like there are some syntax differences between what is default in my newer version of Rails (3.2.6) than are in the video, but I took a look at the Ruby website and figured out that it likely doesn't matter.
However where I'm stuck is that when creating my UsersModel that defines columns(attribs) to put things in, it creates it all, except that the ones I define myself (first name, last name, email and password) won't get created. Only the date created, date modified and ID do, I assume because they are the default ones and just work out of the box.
Here is the code the video tells you to use:
class CreateUsers < ActiveRecord::Migration
def self.up
create_table :users do |t|
t.string "first_name", :limit => 25
t.string "last_name", :limit => 50
t.string "email", :default => "", :null => false
t.string "password", :limit => 40
t.timestamps
end
end
def down
drop_table :users
end
end
I have put two asteriks around the differences below, the main one being a default that is def up in my version but in the video version it is def self.up. The other thing I noticed when I read the documentation on the Rails site was that instead of quotes you are supposed to use the :. Since the code as given by the video didn't work, I tried the code below as well. But I got the same result, with none of the t.strings actually being created in the table.
class CreateUsers < ActiveRecord::Migration
**def up**
create_table :users do |t|
t.string **:**first_name, :limit => 25
t.string **:**last_name, :limit => 50
t.string **:**email, :default => "", :null => false
t.string **:**"password", :limit => 40
t.timestamps
end
end
**def down**
drop_table :users
end
end
So two questions:
Am I not using the proper syntax?
After the first time you 'set up' a table, if you do it again will it override the old configuration? Do I have to create a whole new database again? I'm not sure that by changing the 'users' file and rearranging the syntax, and then doing rake db:migrate that I can override what is there at all.
Thanks so much for your help.
-Dave
Symbols versus strings shouldn't matter. Self.up versus up is the older style but also shouldn't matter. Rails tracks which migrations it has already run in the schema migrations table. A consequence of this is that once a migration has been run rails won't run it again, even if you have changed it.
You can do
rake db:rollback
To have rails run the down method for the last migration that was run (and so it will be run again when you next run db:migrate)
It can be more appropriate to create a new migration to add extra columns - if you have already pushed the original migration to your repository I would usually do this

Should we use the abstracted rails polymorphic migration syntax?

There are two ways to write a polymorphic migration in Rails. Generally, I've done this:
class CreateFeatures < ActiveRecord::Migration
def change
create_table :features do |t|
t.integer :featureable_id
t.string :featurable_type
t.timestamps
end
end
end
However, we can also do this:
class CreateFeatures < ActiveRecord::Migration
def change
create_table :features do |t|
t.references :featureable, :polymorphic => true
t.timestamps
end
end
end
The two are, for all practical purposes, identical. My question: Is one better than another? Is one better for future maintainability?
This would likely be an issue only if one of two things changed:
The polymorphic abstraction version (Version #2) goes away or the syntax changes
The method of working a polymorphic relationship (using id and type) changes- unlikely
Just wondering if there's a preference, or if it's "Meh, doesn't really matter either way"
For an all rails app, where you are generating all tables via migrations, there is no difference functionally.
Here is the code for references:
def references(*args)
options = args.extract_options!
polymorphic = options.delete(:polymorphic)
args.each do |col|
#base.add_column(#table_name, "#{col}_id", :integer, options)
#base.add_column(#table_name, "#{col}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) unless polymorphic.nil?
end
end
This is all well and good but if your foreign keys on the referenced table are not _id, method one is the only choice.
references just saves you one line of code...

Why are the methods up and down not being created with my subclass of ActiveRecord::Migration?

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

WHat object is passed into create_table block in Ruby on Rails

when you generate a model in rails, and it creates a skeleton migration file.
in has
create_table :model_names do |t|
t.string :name
t.string :address
t.timestamps
end
What object is being passed in as t.
When I read this part of the book I wondered what t was, but it never explained. Then later I learned in the form_for helper which passes an |f| into its block, that the f was a FormBuilder object, and this made me come here and ask. I mean, it obviously isn't important, but it bugs me when knowledge is missing.
the answer is ActiveRecord::ConnectionAdapters::TableDefinition
how do I know?
class CreateFoos < ActiveRecord::Migration
def change
create_table :foos do |t|
puts "the answer is: " + t.class.to_s
t.string :foo
t.timestamps
end
end
end
Playing with pry (or the ruby debugger) is a fun, easy way to explore.
class CreateFoos < ActiveRecord::Migration
def change
create_table :foos do |t|
binding.pry
end
end
end
Things like the apidock docs often provide answers in actual text. When they don't, viewing the source often leads to the answer in relatively short order (it does, in this case).

id field without autoincrement option in migration

I have a DB migration like so:
class CreateParticipations < ActiveRecord::Migration
def self.up
create_table(:participations, :primary_key => 'Seat') do |t|
t.integer :Seat
t.string :Nickname
t.string :Clan
t.string :FirstName
t.string :LastName
t.string :Email
t.boolean :Payed
t.timestamps
end
end
def self.down
drop_table :participations
end
end
Now, seat is created with an Auto increment. However, I do not want that. I want it without an auto increment. I will define Seat myself in my Logic.
I have been looking around but I cannot find how to disable auto_increment.
How do I do this? Except for manually doing it in MySQL.
For the record, if you absolutely need to do this (it shouldn't happen often), here's the way to do a non-autoincrementing primary key with the Rails migration DSL:
create_table(:table_name, :id => false) do |t|
t.integer :id, :options => 'PRIMARY KEY'
end
That will work for MySQL anyway, if your DB uses different syntax to specify a primary key, replace the :options => 'PRIMARY KEY' with whatever that is.
This question is 3 years old, but incase anyone is wondering 3 years later, like I was, all you do is "change_column" in the event the table is already created:
change_column(:table_name, :id, :integer, :null => false)
This should work in Rails 2.x and 3.x.
O
Not saying its a good idea, but here's how I did it for SQLite3 - just replace that SQLiteAdapter with your DB's adapter - you might do this cleaner/short with a call to define_method
class AbstractAdapter
end
module ActiveRecord
module ConnectionAdapters
class SQLiteAdapter < AbstractAdapter
def supports_autoincrement?
false
end
end
end
end
<then you migration>
or
class SomeMigration < ActiveRecord::Migration
def change
create_table :table do |t|
ActiveRecord::ConnectionAdapters::SQLiteAdapter.send :define_method, :supports_autoincrement? do false end
t.integer etc
end
end
end
Of course just change the adapter for other db's
Is there a reason you can't use rails' id key and manually add an index called Seat?
I've seen some hacks just to get rails to -work- on non-increment-pk databases. I don't think it's an option. If I recall, that's how rails accesses all its per-row functionality.
Honestly, how -absolutely- do you need that slight boost in efficiency of ignoring rails' structure?
I think the real answer is "you can't." Activerecord has a few things it will not bend on.

Resources