WHat object is passed into create_table block in Ruby on Rails - 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).

Related

Where does the block variable in create_table come from in a Rails migration?

rails generate model User email:string password:string
Looking into the migration that was created:
class CreateUsers < ActiveRecord::Base
def change
create_table :users do |t|
t.string :email
t.string :password
t.timestamps
end
end
end
From the book "Beginning Rails 4": "This is a standard migration fare. In the change definition, you use create_table method to create a new users table. The new table object is yielded to the block variable t, on which you call the string method to create each column"
I'd like a more detailed explanation of exactly where the block variable t comes from. Is it returned by the create_table method (I think not, but I can't think of anything else)?
From the docs:
# create_table() passes a TableDefinition object to the block.
# This form will not only create the table, but also columns for the
# table.
So the t you are seeing is actually an object of the TableDefinition class. You can read more about this class here: http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html
A block is what you see between the do and the end. The block variable in this case was declared here create_table :users do |t| between the | in that line.

Why does explicitly passing a hash allow heroku postgres to set primary keys as I want it to

Spent the past hour running migrate on heroku wondering why the following migrate doesn't set the primary key from id to what I want it to be:
class CreateProducts < ActiveRecord::Migration
def change
create_table :products, :primary_key => :product_id do |t|
t.string :name
end
end
end
Then I figured there might be something wrong with the way I'm passing in the arguments so I changed it to
class CreateProducts < ActiveRecord::Migration
def change
create_table :products, {:primary_key => :product_id} do |t|
t.string :name
end
end
end
And all of a sudden Rails wasn't trying to look for the id column anymore when performing joins.
This might be a little vague but why do the braces matter? I was under the impression that trailing named parameters passed into a method are automatically treated as a hash as of Ruby 2.0.0 (during deployment, it says I was using ruby 2.0.0)
(I'm assuming create_table ... is a method call)

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

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