Advanced Migrations

Most Rails developers use the basic facilities of migrations to create and maintain their database schemas. However, every now and then it’s useful to push migrations just a bit further. This section covers some more advanced migration usage.

Using Native SQL

Migrations give you a database-independent way of maintaining your application’s schema. However, if migrations don’t contain the methods you need to be able to do what you need to do, you’ll need to drop down to database-specific code. Rails provides two ways to do this. One is with options arguments to methods like add_column. The second is the execute method.

When you use options or execute, you might well be tying your migration to a specific database engine, because any SQL you provide in these two locations uses your database’s native syntax.

An example of where you might need to use raw SQL is if you’re creating a custom data type inside your database. Postgres, for example, allows you to specify enumerated types. Enumerated types work just fine with Rails; but to create them in a migration, you have to use SQL and thus execute. Suppose we wanted to create an enumerated type for the various pay types we supported in our checkout form (which we created in Chapter 12, Task G: Check Out!):

 class​ AddPayTypes < ActiveRecord::Migrations[6.0]
 def​ ​up
  execute ​%{
  CREATE TYPE
  pay_type
  AS ENUM (
  'check',
  'credit card',
  'purchase order'
  )
  }
 end
 
 def​ ​down
  execute ​"DROP TYPE pay_type"
 end
 end

Note that if you need to model your database using execute, you should consider changing your schema dump format from “ruby” to “SQL,” as outlined in the Rails Guide.[111] The schema dump is used during tests to create an empty database with the same schema you are using in production.

Custom Messages and Benchmarks

Although not exactly an advanced migration, something that is useful to do within advanced migrations is to output our own messages and benchmarks. We can do this with the say_with_time method:

 def​ ​up
  say_with_time ​"Updating prices..."​ ​do
  Person.​all​.​each​ ​do​ |p|
  p.​update_attribute​ ​:price​, p.​lookup_master_price
 end
 end
 end

say_with_time prints the string passed before the block is executed and prints the benchmark after the block completes.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.137.183