Maven, JRuby and Rails Migrations

Here’s how I managed to get Rails Migrations working with a Maven build process, enabling me to leverage Migrations to maintain the RDBMS schema of a Java application.

Add JRuby and Database dependencies

Add the following dependencies to your pom.xml (adjust for whatever is latest version of jruby and whatever your database is).

  <dependency>
   <groupId>org.jruby</groupId>
   <artifactId>jruby-complete</artifactId>
   <version>1.3.0RC1</version>
  </dependency>
  <dependency>
   <groupId>oracle</groupId>
   <artifactId>jdbc</artifactId>
   <version>11.1.0</version>
  </dependency>

Add a goal to install required Ruby gems

To get Rails migrations running we’ll need the following gems:

  • activerecord
  • activerecord-jdbc-adapter
  • your database specific jdbc adapter

We’ll set up a profile to install these gems if they are missing (based on a approach used by Binil Thomas):

<profiles>
  <profile>
   <id>first.time</id>
   <activation>
    <file>
     <missing>${user.home}/.gem/jruby/1.8/gems/activerecord-2.3.2</missing>
    </file>
   </activation>
   <build>
    <plugins>
     <plugin>
      <groupId>org.codehaus.mojo</groupId>
      <artifactId>exec-maven-plugin</artifactId>
      <executions>
       <execution>
        <id>install-active-record-gem</id>
        <phase>initialize</phase>
        <goals>
         <goal>java</goal>
        </goals>
        <configuration>
         <mainClass>org.jruby.Main</mainClass>
         <arguments>
          <argument>-S</argument>
          <argument>gem</argument>
          <argument>install</argument>
          <argument>activerecord</argument>
          <argument>activerecord-jdbc-adapter</argument>
          <argument>activerecord-oracle_enhanced-adapter</argument>
          <argument>--no-ri</argument>
          <argument>--no-rdoc</argument>
          <argument>--no-test</argument>
         </arguments>
        </configuration>
       </execution>
      </executions>
     </plugin>
    </plugins>
   </build>
  </profile>
 </profiles>

Replace activerecord-oracle_enhanced-adapter with the name of your chosen database’s jdbc adapter.

Add a goal to run the migration

 <build>
  <plugins>
   <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>exec-maven-plugin</artifactId>
    <executions>
     <execution>
      <id>run-migrate</id>
      <phase>install</phase>
      <goals>
       <goal>java</goal>
      </goals>
      <configuration>
       <mainClass>org.jruby.Main</mainClass>
       <arguments>
        <argument>-S</argument>
        <argument>rake</argument>
        <argument>-f</argument>
        <argument>${basedir}/Rakefile</argument>
       </arguments>
      </configuration>
     </execution>
    </executions>
   </plugin>
  </plugins>
 </build>

Create a Rakefile

You’ll need a Rakefile to carry out the migration, in my case I wanted to avoid depending on all of Rails so I just used the following:

require 'active_record'
require 'yaml'

RAILS_ROOT = "#{File.dirname(__FILE__)}" unless defined?(RAILS_ROOT)

task :default => :migrate

task :migrate => :environment do
  ActiveRecord::Migrator.migrate('db/migrate', ENV["VERSION"] ? ENV["VERSION"].to_i : nil )
end

task :environment do
  ActiveRecord::Base.establish_connection(YAML::load(File.open("#{RAILS_ROOT}/config/database.yml")))
  ActiveRecord::Base.logger = Logger.new(File.open('database.log', 'a'))
end

Write your migrations

Create your migrations in db/migrate.

Apply database changes

Finally type:

mvn install

to deploy your database changes.

The full POM

<project>
 <modelVersion>4.0.0</modelVersion>
 <groupId>org.example</groupId>
 <artifactId>schema</artifactId>
 <name>Example POM for doing Rails Migrations</name>
 <packaging>pom</packaging>
 <dependencies>
  <dependency>
   <groupId>org.jruby</groupId>
   <artifactId>jruby-complete</artifactId>
   <version>1.3.0RC1</version>
  </dependency>
  <dependency>
   <groupId>oracle</groupId>
   <artifactId>jdbc</artifactId>
   <version>11.2.0</version>
  </dependency>
 </dependencies>
 <build>
  <plugins>
   <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>exec-maven-plugin</artifactId>
    <executions>
     <execution>
      <id>run-migrate</id>
      <phase>install</phase>
      <goals>
       <goal>java</goal>
      </goals>
      <configuration>
       <mainClass>org.jruby.Main</mainClass>
       <arguments>
        <argument>-S</argument>
        <argument>rake</argument>
        <argument>-f</argument>
        <argument>${basedir}/Rakefile</argument>
       </arguments>
      </configuration>
     </execution>
    </executions>
   </plugin>
  </plugins>
 </build>
 <profiles>
  <profile>
   <id>first.time</id>
   <activation>
    <file>
     <missing>${user.home}/.gem/jruby/1.8/gems/activerecord-2.3.2</missing>
    </file>
   </activation>
   <build>
    <plugins>
     <plugin>
      <groupId>org.codehaus.mojo</groupId>
      <artifactId>exec-maven-plugin</artifactId>
      <executions>
       <execution>
        <id>install-active-record-gem</id>
        <phase>initialize</phase>
        <goals>
         <goal>java</goal>
        </goals>
        <configuration>
         <mainClass>org.jruby.Main</mainClass>
         <arguments>
          <argument>-S</argument>
          <argument>gem</argument>
          <argument>install</argument>
          <argument>activerecord</argument>
          <argument>activerecord-jdbc-adapter</argument>
          <argument>activerecord-oracle_enhanced-adapter</argument>
          <argument>--no-ri</argument>
          <argument>--no-rdoc</argument>
          <argument>--no-test</argument>
         </arguments>
        </configuration>
       </execution>
      </executions>
     </plugin>
    </plugins>
   </build>
  </profile>
 </profiles>
</project>
Advertisements