SlideShare uma empresa Scribd logo
1 de 28
Baixar para ler offline
Where’s my SQL?
Designing Databases with ActiveRecord Migrations


                Eleanor McHugh
               Games With Brains
the usual disclaimers

This presentation contains code
That code is probably broken
If that bothers you - fix it
It’s called a learning experience
so who the hell am I?
     Eleanor McHugh
     Games With Brains

     eleanor@games-with-brains.com




RINDR - Rewriting bIND in Ruby
RailsMUD
Confidential Consultancy
on the menu today

a basic development environment
ActiveRecord
Migrations
a simple plug-in
play along at home

you will need:
  one development system
  a standard Ruby install
  the SQLite database
  a current install of Rails
my dev environment

             MacOS X
             TextMate
             kitchen table
             chair
             cups of tea
standard ruby install

visit http://www.ruby-lang.org
  one-click installer for windows
  source code for unix
RubyGems - http://rubygems.org/
SQLite 3

included with MacOS X :)
download from http://www.sqlite.org/
install SWiG? http://www.swig.org/
gem install sqlite3-ruby
Rails


gem install rails --include-dependencies
optional: gem install mongrel
ActiveRecord?
it’s an Object-Relational Mapper
  Ruby objects are database tables
  their attributes are table columns
  each instance is a table row
can be used separately from Rails
  gem install activerecord
using ActiveRecord
intuitive to use
supports popular database backends
rails generators for the lazy
require “rubygems”
gem “activerecord”

ActiveRecord::Base.establish_connection :adapter => “sqlite3”, :database => “test.db”

class User < ActiveRecord::Base
     validates_presence_of :name
     validates_uniqueness_of
     validates_presence_of :password
end

user = User.create :name => “Eleanor McHugh”, :password => “like_duh!”
are tables related?
it wouldn’t be relational if they weren’t!
and here’s an example to prove it...
class User < ActiveRecord::Base
     validates_presence_of :name
     validates_uniqueness_of
     validates_presence_of :password
     has_and_belongs_to_many :roles
end

class Role < ActiveRecord::Base
     has_and_belongs_to_many :users
     validates_presence_of :name
end

Role.create :name => “admin”
User.create :name => “Eleanor McHugh”, :password => “like_duh!”

User.find_by_name(“Eleanor McHugh).roles << Role.find_by_name(“admin”)
Role.find_by_name(“admin”).users.each { |user| puts user.name }
but what about tables?
assumed to exist in your database
class User maps to table users
attribute name maps to column name
each instance of User has a unique id
create table users(
     id int unsigned not null auto_increment primary key,
     name varchar(40) not null,
     password varchar(16) not null
);
in this case...
 roles_users is a join table
 join tables don’t have id columns

create table users(
     id int unsigned not null auto_increment primary key,
     name varchar(40) not null,
     password varchar(16) not null
);

create table roles(
     id int unsigned not null auto_increment primary key,
     name varchar(40) not null
);

create table roles_users(
     users_id int not null,
     roles_id int not null
);
reasons to be tearful

tables defined in SQL schema
have to manually insert the id column
probably database dependent
would much prefer a Ruby solution
Migrations

part of ActiveRecord
support iterative database development
expandable Data Definition Language
independent of database back-end
pure-Ruby solution :)
iterative development?

Ruby encourages agile methods
but SQL is far from agile...
changes to schema have side effects
risk of inconsistent state in database
the basic DDL
in Ruby and database independent :)
only two methods: up and down
class AddUserTable < ActiveRecord::Migration
     def self.up
          create_table :roles, :force => true { |t| t.column :name, :string, :null => false }
          create_table :users, :force => true do |t|
                [:name, :full_name].each { |c| t.column c, :string, :null => false }
                [:email_address_id, :account_status_code_id].each { |c| t.column c, :integer, :null => false }
                [:profile_id, :stylesheet_id].each { |c| t.column c, :integer }
                [:password_hash, :password_salt].each { |c| t.column c, :string, :null => false }
          end
          create_table :roles_users, :force => true do |t|
                [:role_id, :user_id].each { |c| t.column c, :integer, :null => false }
          end
          [:name, :full_name, :account_status_code_id].each { |c| add_index :users, c }
          add_index :roles, :name
          [:role_id, :user_id].each { |c| add_index :roles_users, c }
     end

      def self.down
           [:role_id, :user_id].each { |c| remove_index :roles_users, c }
           remove_index :roles, :name
           [:name, :full_name, :account_status_code_id].each { |c| remove_index :users, c }
           [:roles_users, :roles, :users].each { |t| drop_table t }
      end
end
let’s rev up the pace...
table definitions could be more succinct
# file ‘enhanced_table_definitions.rb’
# inspired by Hobo

module ActiveRecord::ConnectionAdapters
   class TableDefinition
        @@known_column_types = [:integer, :float, :decimal, :datetime, :date, :timestamp, :time, :text, :string, :binary, :boolean ]

          def foreign_key foreign_table, *args
               column foreign_key_name_for(foreign_table).to_sym, :integer, take_options!(args)
          end

          def method_missing name, *args
               @@known_column_types.include?(name) ? args.each {|type| column type, name, take_options!(args) } : super
          end

          def self.foreign_key_name_for table
               quot;#{Inflector.singularize(table)}_idquot;
          end

      private
           def take_options!(args)
                args.last.is_a?(Hash) ? args.pop : {}
           end
      end
end
let’s rev up the pace...
# file ‘expanded_ddl.rb’
require ‘enhanced_table_definitions’

module ExpandedDDL
    def create_timestamped_table table, options = {}
          create_table table, :force => !options[:no_force] do |t|
                [:created_at, :modified_at].each { |c| t.datetime c }
                yield t if block_given?
          end
          [:created_at, :modified_at].each { |c| add_index table, c }
    end

      def drop_timestamped_table table
            [:created_at, :modified_at].each { |c| remove_index table, c }
            drop_table table
      end

      def create_join_table primary_table, secondary_table, options = {}
            table = join_table_name(primary_table, secondary_table)
            create_timestamped_table(table, options) { |t| t.foreign_key key, :null => false }
            [primary_key, secondary_key].each { |c| add_foreign_key_index table, c }
      end

      def drop_join_table primary_table, secondary_table
            table = join_table_name(primary_table, secondary_table)
            [primary_table, secondary_table].each { |c| remove_foreign_key_index table, c }
            drop_table table
      end

      def add_foreign_key_index table, key, options = {}
            add_index table, foreign_key_name_for(key), options
      end

      def remove_foreign_key_index table, key
            remove_index table, foreign_key_name_for(key)
      end

      def join_table_name primary_table, secondary_table
            (primary_table.to_s < secondary_table.to_s) ? quot;#{primary_table}_#{secondary_table}quot; : quot;#{secondary_table}_#{primary_table}quot;
      end

      def foreign_key_name_for table
            “#{Inflector.singularize(table)}_id”
      end
end
...and see the benefits
require ‘expanded_ddl’

class AddUserTable < ActiveRecord::Migration
     extend ExpandedDDL

      def self.up
           create_timestamped_table :users, :force => true do |t|
                [:name, :full_name].each { |c| t.string c, :null => false }
                [:email_addresses, :account_status_codes].each { |key| t.foreign_key key, :null => false }
                [:profiles, :stylesheets].each { |key| t.foreign_key key }
                [:password_hash, :password_salt].each { |c| t.string c, :null => false }
           end
           add_index :users, :name, :unique => true
           add_index :users, :full_name
           add_foreign_key_index :users, :account_status_codes

            create_table :roles, :force => true { |t| t.column :name, :string, :null => false }
            add_index :roles, :name

            create_join_table :roles, :users, :force => true
            [:role_id, :user_id].each { |c| add_index :roles_users, c }
      end

      def self.down
           [:role_id, :user_id].each { |c| remove_index :roles_users, c }
           drop_join_table :roles, :users
           remove_index :roles, :name
           remove_foreign_key_index :users, :account_status_codes
           [:name, :full_name].each { |c| remove_index :users, c }
           [:roles, :users].each { |t| drop_timestamped_table t }
      end
end
run in sequence
rake db:migrate
each migration has a sequence number
migrations are run in this order
a hypothetical example from RailsMUD
001_add_account_tables
002_add_character_tables
003_add_action_tables
004_alter_account_tables
005_add_creature_tables
fun with plug-ins


playing with DDLs is fun
but what about the data model?
plug-ins are great for this
what’s in a name?
this plug-in adds names to a model
ActiveRecord::Base.send(:include, ActiveRecord::Acts::Named)

module ActiveRecord
   module Acts #:nodoc:
        module Named #:nodoc:
             def self.included(base)
                  base.extend(ClassMethods)
             end

               module ClassMethods
                  def acts_as_named(options = {})
                       write_inheritable_attribute(:acts_as_named_options, {:from => options[:from]})
                       class_inheritable_reader :acts_as_named_options
                       validates_presence_of :name
                       validates_uniqueness_of :name unless options[:duplicate_names]

                           include ActiveRecord::Acts::Named::InstanceMethods
                           extend ActiveRecord::Acts::Named::SingletonMethods
                     end
               end

               module SingletonMethods
               end

               module InstanceMethods
               end
         end
      end
end
some DDL goodies

module ExpandedDDL
=begin
    add the following to the module
=end

      def create_named_table table, options
           create_timestamped_table table, take_options!(options) do |t|
                t.column :name, :string, :null => false
                yield t if block_given?
           end
           add_index table, :name, :unique => !options[:duplicate_names_allowed]
      end

      def drop_named_table table
           remove_index table, :name
           drop_table table
      end
end
an updated migration
require ‘expanded_ddl’

class AddUserTable < ActiveRecord::Migration
     extend ExpandedDDL

      def self.up
           create_named_table :roles, :force => true
           create_named_table :users, :force => true do |t|
                 t.string :full_name, :null => false
                 [:email_addresses, :account_status_codes].each { |key| t.foreign_key key, :null => false }
                 [:profiles, :stylesheets].each { |key| t.foreign_key key }
                 [:password_hash, :password_salt].each { |c| t.string c, :null => false }
           end
           add_index :users, :full_name
           add_foreign_key_index :users, :account_status_codes
           create_join_table :roles, :users, :force => true
           [:role_id, :user_id].each { |c| add_index :roles_users, c }
      end

      def self.down
           [:role_id, :user_id].each { |c| remove_index :roles_users, c }
           drop_join_table :roles, :users
           remove_foreign_key_index :users, :account_status_codes
           remove_index :users, :full_name
           [:roles, :users].each { |t| drop_named_table t }
      end
end
and its model
this model invokes acts_as_named
the default is for unique names only
:duplicate_names =>true
indices in the DDL become relations
class User < ActiveRecord::Base
     acts_as_named
     validates_presence_of :full_name
     belongs_to :account_status_code
     validates_presence_of :account_status_code
     has_one :profile
     has_one :stylesheet
     has_one :email_address
     validates_presence_of :email_address
     has_and_belongs_to_many :roles
end
conclusions?


Migrations simplify data definition
plug-ins simplify model definition
together they open many possibilities

Mais conteúdo relacionado

Mais procurados

Jython: Python para la plataforma Java (JRSL 09)
Jython: Python para la plataforma Java (JRSL 09)Jython: Python para la plataforma Java (JRSL 09)
Jython: Python para la plataforma Java (JRSL 09)Leonardo Soto
 
Web2py tutorial to create db driven application.
Web2py tutorial to create db driven application.Web2py tutorial to create db driven application.
Web2py tutorial to create db driven application.fRui Apps
 
Magicke metody v Pythonu
Magicke metody v PythonuMagicke metody v Pythonu
Magicke metody v PythonuJirka Vejrazka
 
[FT-7][snowmantw] How to make a new functional language and make the world be...
[FT-7][snowmantw] How to make a new functional language and make the world be...[FT-7][snowmantw] How to make a new functional language and make the world be...
[FT-7][snowmantw] How to make a new functional language and make the world be...Functional Thursday
 
Active Record Inheritance in Rails
Active Record Inheritance in RailsActive Record Inheritance in Rails
Active Record Inheritance in RailsSandip Ransing
 
Drupal csu-open atriumname
Drupal csu-open atriumnameDrupal csu-open atriumname
Drupal csu-open atriumnameEmanuele Quinto
 
JavaOne 2017 | JShell: The Ultimate Missing Tool
 JavaOne 2017 | JShell: The Ultimate Missing Tool JavaOne 2017 | JShell: The Ultimate Missing Tool
JavaOne 2017 | JShell: The Ultimate Missing ToolHakan Özler
 
Eureka - elegant iOs form builder in swift (johnp - mingle)
Eureka - elegant iOs form builder in swift (johnp - mingle)Eureka - elegant iOs form builder in swift (johnp - mingle)
Eureka - elegant iOs form builder in swift (johnp - mingle)John Pham
 
Command-Oriented Architecture
Command-Oriented ArchitectureCommand-Oriented Architecture
Command-Oriented ArchitectureLuiz Messias
 
A Few of My Favorite (Python) Things
A Few of My Favorite (Python) ThingsA Few of My Favorite (Python) Things
A Few of My Favorite (Python) ThingsMichael Pirnat
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ EtsyNishan Subedi
 
Miniproject on Employee Management using Perl/Database.
Miniproject on Employee Management using Perl/Database.Miniproject on Employee Management using Perl/Database.
Miniproject on Employee Management using Perl/Database.Sanchit Raut
 
Everything About PowerShell
Everything About PowerShellEverything About PowerShell
Everything About PowerShellGaetano Causio
 
rails-migrations_1
rails-migrations_1rails-migrations_1
rails-migrations_1brecke
 
PofEAA and SQLAlchemy
PofEAA and SQLAlchemyPofEAA and SQLAlchemy
PofEAA and SQLAlchemyInada Naoki
 
David Grudl: Novinky v Nette
David Grudl: Novinky v NetteDavid Grudl: Novinky v Nette
David Grudl: Novinky v NetteDevelcz
 

Mais procurados (19)

Jython: Python para la plataforma Java (JRSL 09)
Jython: Python para la plataforma Java (JRSL 09)Jython: Python para la plataforma Java (JRSL 09)
Jython: Python para la plataforma Java (JRSL 09)
 
Web2py tutorial to create db driven application.
Web2py tutorial to create db driven application.Web2py tutorial to create db driven application.
Web2py tutorial to create db driven application.
 
Magicke metody v Pythonu
Magicke metody v PythonuMagicke metody v Pythonu
Magicke metody v Pythonu
 
Sqlite perl
Sqlite perlSqlite perl
Sqlite perl
 
jQuery
jQueryjQuery
jQuery
 
[FT-7][snowmantw] How to make a new functional language and make the world be...
[FT-7][snowmantw] How to make a new functional language and make the world be...[FT-7][snowmantw] How to make a new functional language and make the world be...
[FT-7][snowmantw] How to make a new functional language and make the world be...
 
Active Record Inheritance in Rails
Active Record Inheritance in RailsActive Record Inheritance in Rails
Active Record Inheritance in Rails
 
Drupal csu-open atriumname
Drupal csu-open atriumnameDrupal csu-open atriumname
Drupal csu-open atriumname
 
JavaOne 2017 | JShell: The Ultimate Missing Tool
 JavaOne 2017 | JShell: The Ultimate Missing Tool JavaOne 2017 | JShell: The Ultimate Missing Tool
JavaOne 2017 | JShell: The Ultimate Missing Tool
 
Sparklyr
SparklyrSparklyr
Sparklyr
 
Eureka - elegant iOs form builder in swift (johnp - mingle)
Eureka - elegant iOs form builder in swift (johnp - mingle)Eureka - elegant iOs form builder in swift (johnp - mingle)
Eureka - elegant iOs form builder in swift (johnp - mingle)
 
Command-Oriented Architecture
Command-Oriented ArchitectureCommand-Oriented Architecture
Command-Oriented Architecture
 
A Few of My Favorite (Python) Things
A Few of My Favorite (Python) ThingsA Few of My Favorite (Python) Things
A Few of My Favorite (Python) Things
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ Etsy
 
Miniproject on Employee Management using Perl/Database.
Miniproject on Employee Management using Perl/Database.Miniproject on Employee Management using Perl/Database.
Miniproject on Employee Management using Perl/Database.
 
Everything About PowerShell
Everything About PowerShellEverything About PowerShell
Everything About PowerShell
 
rails-migrations_1
rails-migrations_1rails-migrations_1
rails-migrations_1
 
PofEAA and SQLAlchemy
PofEAA and SQLAlchemyPofEAA and SQLAlchemy
PofEAA and SQLAlchemy
 
David Grudl: Novinky v Nette
David Grudl: Novinky v NetteDavid Grudl: Novinky v Nette
David Grudl: Novinky v Nette
 

Semelhante a Where's My SQL? Designing Databases with ActiveRecord Migrations

Say Goodbye to Procedural Programming - Nick Sutterer
Say Goodbye to Procedural Programming - Nick SuttererSay Goodbye to Procedural Programming - Nick Sutterer
Say Goodbye to Procedural Programming - Nick SuttererRuby Meditation
 
Engines: Team Development on Rails (2005)
Engines: Team Development on Rails (2005)Engines: Team Development on Rails (2005)
Engines: Team Development on Rails (2005)lazyatom
 
A Tour to MySQL Commands
A Tour to MySQL CommandsA Tour to MySQL Commands
A Tour to MySQL CommandsHikmat Dhamee
 
Using Scala Slick at FortyTwo
Using Scala Slick at FortyTwoUsing Scala Slick at FortyTwo
Using Scala Slick at FortyTwoEishay Smith
 
Ruby Language - A quick tour
Ruby Language - A quick tourRuby Language - A quick tour
Ruby Language - A quick touraztack
 
RubyEnRails2007 - Dr Nic Williams - DIY Syntax
RubyEnRails2007 - Dr Nic Williams - DIY SyntaxRubyEnRails2007 - Dr Nic Williams - DIY Syntax
RubyEnRails2007 - Dr Nic Williams - DIY SyntaxDr Nic Williams
 
DBIx-DataModel v2.0 in detail
DBIx-DataModel v2.0 in detail DBIx-DataModel v2.0 in detail
DBIx-DataModel v2.0 in detail Laurent Dami
 
RubyBarCamp “Полезные gems и plugins”
RubyBarCamp “Полезные gems и plugins”RubyBarCamp “Полезные gems и plugins”
RubyBarCamp “Полезные gems и plugins”apostlion
 
Desarrollando aplicaciones web en minutos
Desarrollando aplicaciones web en minutosDesarrollando aplicaciones web en minutos
Desarrollando aplicaciones web en minutosEdgar Suarez
 
Valeriy Prokopchuk: Validators in Migrations.
Valeriy Prokopchuk: Validators in Migrations.Valeriy Prokopchuk: Validators in Migrations.
Valeriy Prokopchuk: Validators in Migrations.Sphere Consulting Inc
 
Venturing Into The Wild: A .NET Developer's Experience As A Ruby Developer
Venturing Into The Wild: A .NET Developer's Experience As A Ruby DeveloperVenturing Into The Wild: A .NET Developer's Experience As A Ruby Developer
Venturing Into The Wild: A .NET Developer's Experience As A Ruby DeveloperJon Kruger
 
PyCon 2010 SQLAlchemy tutorial
PyCon 2010 SQLAlchemy tutorialPyCon 2010 SQLAlchemy tutorial
PyCon 2010 SQLAlchemy tutorialjbellis
 
Intermediate SQL with Ecto - LoneStar ElixirConf 2018
Intermediate SQL with Ecto - LoneStar ElixirConf 2018Intermediate SQL with Ecto - LoneStar ElixirConf 2018
Intermediate SQL with Ecto - LoneStar ElixirConf 2018wreckoning
 
Postgres & Redis Sitting in a Tree- Rimas Silkaitis, Heroku
Postgres & Redis Sitting in a Tree- Rimas Silkaitis, HerokuPostgres & Redis Sitting in a Tree- Rimas Silkaitis, Heroku
Postgres & Redis Sitting in a Tree- Rimas Silkaitis, HerokuRedis Labs
 
Ruby on rails
Ruby on rails Ruby on rails
Ruby on rails Mohit Jain
 

Semelhante a Where's My SQL? Designing Databases with ActiveRecord Migrations (20)

Say Goodbye to Procedural Programming - Nick Sutterer
Say Goodbye to Procedural Programming - Nick SuttererSay Goodbye to Procedural Programming - Nick Sutterer
Say Goodbye to Procedural Programming - Nick Sutterer
 
Engines: Team Development on Rails (2005)
Engines: Team Development on Rails (2005)Engines: Team Development on Rails (2005)
Engines: Team Development on Rails (2005)
 
Django - sql alchemy - jquery
Django - sql alchemy - jqueryDjango - sql alchemy - jquery
Django - sql alchemy - jquery
 
A Tour to MySQL Commands
A Tour to MySQL CommandsA Tour to MySQL Commands
A Tour to MySQL Commands
 
Using Scala Slick at FortyTwo
Using Scala Slick at FortyTwoUsing Scala Slick at FortyTwo
Using Scala Slick at FortyTwo
 
Ruby Language - A quick tour
Ruby Language - A quick tourRuby Language - A quick tour
Ruby Language - A quick tour
 
RubyEnRails2007 - Dr Nic Williams - DIY Syntax
RubyEnRails2007 - Dr Nic Williams - DIY SyntaxRubyEnRails2007 - Dr Nic Williams - DIY Syntax
RubyEnRails2007 - Dr Nic Williams - DIY Syntax
 
Sequel
SequelSequel
Sequel
 
DataMapper
DataMapperDataMapper
DataMapper
 
DBIx-DataModel v2.0 in detail
DBIx-DataModel v2.0 in detail DBIx-DataModel v2.0 in detail
DBIx-DataModel v2.0 in detail
 
RubyBarCamp “Полезные gems и plugins”
RubyBarCamp “Полезные gems и plugins”RubyBarCamp “Полезные gems и plugins”
RubyBarCamp “Полезные gems и plugins”
 
Desarrollando aplicaciones web en minutos
Desarrollando aplicaciones web en minutosDesarrollando aplicaciones web en minutos
Desarrollando aplicaciones web en minutos
 
ABAP Cheat sheet
ABAP Cheat sheetABAP Cheat sheet
ABAP Cheat sheet
 
Valeriy Prokopchuk: Validators in Migrations.
Valeriy Prokopchuk: Validators in Migrations.Valeriy Prokopchuk: Validators in Migrations.
Valeriy Prokopchuk: Validators in Migrations.
 
Venturing Into The Wild: A .NET Developer's Experience As A Ruby Developer
Venturing Into The Wild: A .NET Developer's Experience As A Ruby DeveloperVenturing Into The Wild: A .NET Developer's Experience As A Ruby Developer
Venturing Into The Wild: A .NET Developer's Experience As A Ruby Developer
 
PyCon 2010 SQLAlchemy tutorial
PyCon 2010 SQLAlchemy tutorialPyCon 2010 SQLAlchemy tutorial
PyCon 2010 SQLAlchemy tutorial
 
Intermediate SQL with Ecto - LoneStar ElixirConf 2018
Intermediate SQL with Ecto - LoneStar ElixirConf 2018Intermediate SQL with Ecto - LoneStar ElixirConf 2018
Intermediate SQL with Ecto - LoneStar ElixirConf 2018
 
Postgres & Redis Sitting in a Tree- Rimas Silkaitis, Heroku
Postgres & Redis Sitting in a Tree- Rimas Silkaitis, HerokuPostgres & Redis Sitting in a Tree- Rimas Silkaitis, Heroku
Postgres & Redis Sitting in a Tree- Rimas Silkaitis, Heroku
 
Ruby on rails
Ruby on rails Ruby on rails
Ruby on rails
 
SOLID Ruby, SOLID Rails
SOLID Ruby, SOLID RailsSOLID Ruby, SOLID Rails
SOLID Ruby, SOLID Rails
 

Mais de Eleanor McHugh

[2023] Putting the R! in R&D.pdf
[2023] Putting the R! in R&D.pdf[2023] Putting the R! in R&D.pdf
[2023] Putting the R! in R&D.pdfEleanor McHugh
 
Generics, Reflection, and Efficient Collections
Generics, Reflection, and Efficient CollectionsGenerics, Reflection, and Efficient Collections
Generics, Reflection, and Efficient CollectionsEleanor McHugh
 
The Relevance of Liveness - Biometrics and Data Integrity
The Relevance of Liveness - Biometrics and Data IntegrityThe Relevance of Liveness - Biometrics and Data Integrity
The Relevance of Liveness - Biometrics and Data IntegrityEleanor McHugh
 
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]Eleanor McHugh
 
The Browser Environment - A Systems Programmer's Perspective
The Browser Environment - A Systems Programmer's PerspectiveThe Browser Environment - A Systems Programmer's Perspective
The Browser Environment - A Systems Programmer's PerspectiveEleanor McHugh
 
Go for the paranoid network programmer, 3rd edition
Go for the paranoid network programmer, 3rd editionGo for the paranoid network programmer, 3rd edition
Go for the paranoid network programmer, 3rd editionEleanor McHugh
 
An introduction to functional programming with Go [redux]
An introduction to functional programming with Go [redux]An introduction to functional programming with Go [redux]
An introduction to functional programming with Go [redux]Eleanor McHugh
 
An introduction to functional programming with go
An introduction to functional programming with goAn introduction to functional programming with go
An introduction to functional programming with goEleanor McHugh
 
Implementing virtual machines in go & c 2018 redux
Implementing virtual machines in go & c 2018 reduxImplementing virtual machines in go & c 2018 redux
Implementing virtual machines in go & c 2018 reduxEleanor McHugh
 
Identity & trust in Monitored Spaces
Identity & trust in Monitored SpacesIdentity & trust in Monitored Spaces
Identity & trust in Monitored SpacesEleanor McHugh
 
Don't Ask, Don't Tell - The Virtues of Privacy By Design
Don't Ask, Don't Tell - The Virtues of Privacy By DesignDon't Ask, Don't Tell - The Virtues of Privacy By Design
Don't Ask, Don't Tell - The Virtues of Privacy By DesignEleanor McHugh
 
Don't ask, don't tell the virtues of privacy by design
Don't ask, don't tell   the virtues of privacy by designDon't ask, don't tell   the virtues of privacy by design
Don't ask, don't tell the virtues of privacy by designEleanor McHugh
 
Anonymity, identity, trust
Anonymity, identity, trustAnonymity, identity, trust
Anonymity, identity, trustEleanor McHugh
 
Going Loopy - Adventures in Iteration with Google Go
Going Loopy - Adventures in Iteration with Google GoGoing Loopy - Adventures in Iteration with Google Go
Going Loopy - Adventures in Iteration with Google GoEleanor McHugh
 
Distributed Ledgers: Anonymity & Immutability at Scale
Distributed Ledgers: Anonymity & Immutability at ScaleDistributed Ledgers: Anonymity & Immutability at Scale
Distributed Ledgers: Anonymity & Immutability at ScaleEleanor McHugh
 
Go for the paranoid network programmer, 2nd edition
Go for the paranoid network programmer, 2nd editionGo for the paranoid network programmer, 2nd edition
Go for the paranoid network programmer, 2nd editionEleanor McHugh
 
Going Loopy: Adventures in Iteration with Go
Going Loopy: Adventures in Iteration with GoGoing Loopy: Adventures in Iteration with Go
Going Loopy: Adventures in Iteration with GoEleanor McHugh
 
Finding a useful outlet for my many Adventures in go
Finding a useful outlet for my many Adventures in goFinding a useful outlet for my many Adventures in go
Finding a useful outlet for my many Adventures in goEleanor McHugh
 
Anonymity, trust, accountability
Anonymity, trust, accountabilityAnonymity, trust, accountability
Anonymity, trust, accountabilityEleanor McHugh
 

Mais de Eleanor McHugh (20)

[2023] Putting the R! in R&D.pdf
[2023] Putting the R! in R&D.pdf[2023] Putting the R! in R&D.pdf
[2023] Putting the R! in R&D.pdf
 
Generics, Reflection, and Efficient Collections
Generics, Reflection, and Efficient CollectionsGenerics, Reflection, and Efficient Collections
Generics, Reflection, and Efficient Collections
 
The Relevance of Liveness - Biometrics and Data Integrity
The Relevance of Liveness - Biometrics and Data IntegrityThe Relevance of Liveness - Biometrics and Data Integrity
The Relevance of Liveness - Biometrics and Data Integrity
 
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
The Browser Environment - A Systems Programmer's Perspective [sinatra edition]
 
The Browser Environment - A Systems Programmer's Perspective
The Browser Environment - A Systems Programmer's PerspectiveThe Browser Environment - A Systems Programmer's Perspective
The Browser Environment - A Systems Programmer's Perspective
 
Go for the paranoid network programmer, 3rd edition
Go for the paranoid network programmer, 3rd editionGo for the paranoid network programmer, 3rd edition
Go for the paranoid network programmer, 3rd edition
 
An introduction to functional programming with Go [redux]
An introduction to functional programming with Go [redux]An introduction to functional programming with Go [redux]
An introduction to functional programming with Go [redux]
 
An introduction to functional programming with go
An introduction to functional programming with goAn introduction to functional programming with go
An introduction to functional programming with go
 
Implementing virtual machines in go & c 2018 redux
Implementing virtual machines in go & c 2018 reduxImplementing virtual machines in go & c 2018 redux
Implementing virtual machines in go & c 2018 redux
 
Identity & trust in Monitored Spaces
Identity & trust in Monitored SpacesIdentity & trust in Monitored Spaces
Identity & trust in Monitored Spaces
 
Don't Ask, Don't Tell - The Virtues of Privacy By Design
Don't Ask, Don't Tell - The Virtues of Privacy By DesignDon't Ask, Don't Tell - The Virtues of Privacy By Design
Don't Ask, Don't Tell - The Virtues of Privacy By Design
 
Don't ask, don't tell the virtues of privacy by design
Don't ask, don't tell   the virtues of privacy by designDon't ask, don't tell   the virtues of privacy by design
Don't ask, don't tell the virtues of privacy by design
 
Anonymity, identity, trust
Anonymity, identity, trustAnonymity, identity, trust
Anonymity, identity, trust
 
Going Loopy - Adventures in Iteration with Google Go
Going Loopy - Adventures in Iteration with Google GoGoing Loopy - Adventures in Iteration with Google Go
Going Loopy - Adventures in Iteration with Google Go
 
Distributed Ledgers: Anonymity & Immutability at Scale
Distributed Ledgers: Anonymity & Immutability at ScaleDistributed Ledgers: Anonymity & Immutability at Scale
Distributed Ledgers: Anonymity & Immutability at Scale
 
Hello Go
Hello GoHello Go
Hello Go
 
Go for the paranoid network programmer, 2nd edition
Go for the paranoid network programmer, 2nd editionGo for the paranoid network programmer, 2nd edition
Go for the paranoid network programmer, 2nd edition
 
Going Loopy: Adventures in Iteration with Go
Going Loopy: Adventures in Iteration with GoGoing Loopy: Adventures in Iteration with Go
Going Loopy: Adventures in Iteration with Go
 
Finding a useful outlet for my many Adventures in go
Finding a useful outlet for my many Adventures in goFinding a useful outlet for my many Adventures in go
Finding a useful outlet for my many Adventures in go
 
Anonymity, trust, accountability
Anonymity, trust, accountabilityAnonymity, trust, accountability
Anonymity, trust, accountability
 

Último

Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESmohitsingh558521
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxLoriGlavin3
 
Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rick Flair
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsNathaniel Shimoni
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxLoriGlavin3
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embeddingZilliz
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024Lonnie McRorey
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsPixlogix Infotech
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxLoriGlavin3
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersNicole Novielli
 
What is Artificial Intelligence?????????
What is Artificial Intelligence?????????What is Artificial Intelligence?????????
What is Artificial Intelligence?????????blackmambaettijean
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionDilum Bandara
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 

Último (20)

Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptx
 
Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directions
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embedding
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and Cons
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software Developers
 
What is Artificial Intelligence?????????
What is Artificial Intelligence?????????What is Artificial Intelligence?????????
What is Artificial Intelligence?????????
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An Introduction
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 

Where's My SQL? Designing Databases with ActiveRecord Migrations

  • 1. Where’s my SQL? Designing Databases with ActiveRecord Migrations Eleanor McHugh Games With Brains
  • 2. the usual disclaimers This presentation contains code That code is probably broken If that bothers you - fix it It’s called a learning experience
  • 3. so who the hell am I? Eleanor McHugh Games With Brains eleanor@games-with-brains.com RINDR - Rewriting bIND in Ruby RailsMUD Confidential Consultancy
  • 4. on the menu today a basic development environment ActiveRecord Migrations a simple plug-in
  • 5. play along at home you will need: one development system a standard Ruby install the SQLite database a current install of Rails
  • 6. my dev environment MacOS X TextMate kitchen table chair cups of tea
  • 7. standard ruby install visit http://www.ruby-lang.org one-click installer for windows source code for unix RubyGems - http://rubygems.org/
  • 8. SQLite 3 included with MacOS X :) download from http://www.sqlite.org/ install SWiG? http://www.swig.org/ gem install sqlite3-ruby
  • 9. Rails gem install rails --include-dependencies optional: gem install mongrel
  • 10. ActiveRecord? it’s an Object-Relational Mapper Ruby objects are database tables their attributes are table columns each instance is a table row can be used separately from Rails gem install activerecord
  • 11. using ActiveRecord intuitive to use supports popular database backends rails generators for the lazy require “rubygems” gem “activerecord” ActiveRecord::Base.establish_connection :adapter => “sqlite3”, :database => “test.db” class User < ActiveRecord::Base validates_presence_of :name validates_uniqueness_of validates_presence_of :password end user = User.create :name => “Eleanor McHugh”, :password => “like_duh!”
  • 12. are tables related? it wouldn’t be relational if they weren’t! and here’s an example to prove it... class User < ActiveRecord::Base validates_presence_of :name validates_uniqueness_of validates_presence_of :password has_and_belongs_to_many :roles end class Role < ActiveRecord::Base has_and_belongs_to_many :users validates_presence_of :name end Role.create :name => “admin” User.create :name => “Eleanor McHugh”, :password => “like_duh!” User.find_by_name(“Eleanor McHugh).roles << Role.find_by_name(“admin”) Role.find_by_name(“admin”).users.each { |user| puts user.name }
  • 13. but what about tables? assumed to exist in your database class User maps to table users attribute name maps to column name each instance of User has a unique id create table users( id int unsigned not null auto_increment primary key, name varchar(40) not null, password varchar(16) not null );
  • 14. in this case... roles_users is a join table join tables don’t have id columns create table users( id int unsigned not null auto_increment primary key, name varchar(40) not null, password varchar(16) not null ); create table roles( id int unsigned not null auto_increment primary key, name varchar(40) not null ); create table roles_users( users_id int not null, roles_id int not null );
  • 15. reasons to be tearful tables defined in SQL schema have to manually insert the id column probably database dependent would much prefer a Ruby solution
  • 16. Migrations part of ActiveRecord support iterative database development expandable Data Definition Language independent of database back-end pure-Ruby solution :)
  • 17. iterative development? Ruby encourages agile methods but SQL is far from agile... changes to schema have side effects risk of inconsistent state in database
  • 18. the basic DDL in Ruby and database independent :) only two methods: up and down class AddUserTable < ActiveRecord::Migration def self.up create_table :roles, :force => true { |t| t.column :name, :string, :null => false } create_table :users, :force => true do |t| [:name, :full_name].each { |c| t.column c, :string, :null => false } [:email_address_id, :account_status_code_id].each { |c| t.column c, :integer, :null => false } [:profile_id, :stylesheet_id].each { |c| t.column c, :integer } [:password_hash, :password_salt].each { |c| t.column c, :string, :null => false } end create_table :roles_users, :force => true do |t| [:role_id, :user_id].each { |c| t.column c, :integer, :null => false } end [:name, :full_name, :account_status_code_id].each { |c| add_index :users, c } add_index :roles, :name [:role_id, :user_id].each { |c| add_index :roles_users, c } end def self.down [:role_id, :user_id].each { |c| remove_index :roles_users, c } remove_index :roles, :name [:name, :full_name, :account_status_code_id].each { |c| remove_index :users, c } [:roles_users, :roles, :users].each { |t| drop_table t } end end
  • 19. let’s rev up the pace... table definitions could be more succinct # file ‘enhanced_table_definitions.rb’ # inspired by Hobo module ActiveRecord::ConnectionAdapters class TableDefinition @@known_column_types = [:integer, :float, :decimal, :datetime, :date, :timestamp, :time, :text, :string, :binary, :boolean ] def foreign_key foreign_table, *args column foreign_key_name_for(foreign_table).to_sym, :integer, take_options!(args) end def method_missing name, *args @@known_column_types.include?(name) ? args.each {|type| column type, name, take_options!(args) } : super end def self.foreign_key_name_for table quot;#{Inflector.singularize(table)}_idquot; end private def take_options!(args) args.last.is_a?(Hash) ? args.pop : {} end end end
  • 20. let’s rev up the pace... # file ‘expanded_ddl.rb’ require ‘enhanced_table_definitions’ module ExpandedDDL def create_timestamped_table table, options = {} create_table table, :force => !options[:no_force] do |t| [:created_at, :modified_at].each { |c| t.datetime c } yield t if block_given? end [:created_at, :modified_at].each { |c| add_index table, c } end def drop_timestamped_table table [:created_at, :modified_at].each { |c| remove_index table, c } drop_table table end def create_join_table primary_table, secondary_table, options = {} table = join_table_name(primary_table, secondary_table) create_timestamped_table(table, options) { |t| t.foreign_key key, :null => false } [primary_key, secondary_key].each { |c| add_foreign_key_index table, c } end def drop_join_table primary_table, secondary_table table = join_table_name(primary_table, secondary_table) [primary_table, secondary_table].each { |c| remove_foreign_key_index table, c } drop_table table end def add_foreign_key_index table, key, options = {} add_index table, foreign_key_name_for(key), options end def remove_foreign_key_index table, key remove_index table, foreign_key_name_for(key) end def join_table_name primary_table, secondary_table (primary_table.to_s < secondary_table.to_s) ? quot;#{primary_table}_#{secondary_table}quot; : quot;#{secondary_table}_#{primary_table}quot; end def foreign_key_name_for table “#{Inflector.singularize(table)}_id” end end
  • 21. ...and see the benefits require ‘expanded_ddl’ class AddUserTable < ActiveRecord::Migration extend ExpandedDDL def self.up create_timestamped_table :users, :force => true do |t| [:name, :full_name].each { |c| t.string c, :null => false } [:email_addresses, :account_status_codes].each { |key| t.foreign_key key, :null => false } [:profiles, :stylesheets].each { |key| t.foreign_key key } [:password_hash, :password_salt].each { |c| t.string c, :null => false } end add_index :users, :name, :unique => true add_index :users, :full_name add_foreign_key_index :users, :account_status_codes create_table :roles, :force => true { |t| t.column :name, :string, :null => false } add_index :roles, :name create_join_table :roles, :users, :force => true [:role_id, :user_id].each { |c| add_index :roles_users, c } end def self.down [:role_id, :user_id].each { |c| remove_index :roles_users, c } drop_join_table :roles, :users remove_index :roles, :name remove_foreign_key_index :users, :account_status_codes [:name, :full_name].each { |c| remove_index :users, c } [:roles, :users].each { |t| drop_timestamped_table t } end end
  • 22. run in sequence rake db:migrate each migration has a sequence number migrations are run in this order a hypothetical example from RailsMUD 001_add_account_tables 002_add_character_tables 003_add_action_tables 004_alter_account_tables 005_add_creature_tables
  • 23. fun with plug-ins playing with DDLs is fun but what about the data model? plug-ins are great for this
  • 24. what’s in a name? this plug-in adds names to a model ActiveRecord::Base.send(:include, ActiveRecord::Acts::Named) module ActiveRecord module Acts #:nodoc: module Named #:nodoc: def self.included(base) base.extend(ClassMethods) end module ClassMethods def acts_as_named(options = {}) write_inheritable_attribute(:acts_as_named_options, {:from => options[:from]}) class_inheritable_reader :acts_as_named_options validates_presence_of :name validates_uniqueness_of :name unless options[:duplicate_names] include ActiveRecord::Acts::Named::InstanceMethods extend ActiveRecord::Acts::Named::SingletonMethods end end module SingletonMethods end module InstanceMethods end end end end
  • 25. some DDL goodies module ExpandedDDL =begin add the following to the module =end def create_named_table table, options create_timestamped_table table, take_options!(options) do |t| t.column :name, :string, :null => false yield t if block_given? end add_index table, :name, :unique => !options[:duplicate_names_allowed] end def drop_named_table table remove_index table, :name drop_table table end end
  • 26. an updated migration require ‘expanded_ddl’ class AddUserTable < ActiveRecord::Migration extend ExpandedDDL def self.up create_named_table :roles, :force => true create_named_table :users, :force => true do |t| t.string :full_name, :null => false [:email_addresses, :account_status_codes].each { |key| t.foreign_key key, :null => false } [:profiles, :stylesheets].each { |key| t.foreign_key key } [:password_hash, :password_salt].each { |c| t.string c, :null => false } end add_index :users, :full_name add_foreign_key_index :users, :account_status_codes create_join_table :roles, :users, :force => true [:role_id, :user_id].each { |c| add_index :roles_users, c } end def self.down [:role_id, :user_id].each { |c| remove_index :roles_users, c } drop_join_table :roles, :users remove_foreign_key_index :users, :account_status_codes remove_index :users, :full_name [:roles, :users].each { |t| drop_named_table t } end end
  • 27. and its model this model invokes acts_as_named the default is for unique names only :duplicate_names =>true indices in the DDL become relations class User < ActiveRecord::Base acts_as_named validates_presence_of :full_name belongs_to :account_status_code validates_presence_of :account_status_code has_one :profile has_one :stylesheet has_one :email_address validates_presence_of :email_address has_and_belongs_to_many :roles end
  • 28. conclusions? Migrations simplify data definition plug-ins simplify model definition together they open many possibilities