ReefPointsBlog

postgres_ext: Adding Postgres data types to Rails

Dan McClain

Over the past few weeks, I have been working on a new gem which adds support to Rail's ActiveRecord for PostgreSQL's native data types. I am happy to announce that I have released the postgres_ext gem.

postgres_ext supports for ActiveRecord version 3.2 and above (at this time). Parallel to my development, I plan to submit pull request to Rails master, so that postgres_ext will not be needed in Rails 4.0.

Features

Migration/Schema support

postgres_ext adds migration and schema.rb support for the following PostgresSQL type:

You can create columns with the following migration methods:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
create_table :examples do |t|
  t.inet :ip_address
  # INET Column

  t.cidr :subnet
  # CIDR Column

  t.macaddr :mac_address
  # MACADDR Column

  t.uuid :unique_id
  # UUID Column

  t.integer :int_array, :array => true
  # Integer[] Column
end

These migrations will be captured in your schema.rb file, so you don't have to use the structure.sql file if these types are your only reason. In fact, if you are using these only supported types with structure.sql, including the postgres_ext gem should allow you to correctly rake db:schema:dump your database.

Migration/Schema.rb support documentation

Type Casting

postgres_ext converts INET and CIDR values to IPAddr instances, and coverts arrays to array objects of the column type (integer arrays are cast as an array of integers, INET arrays to are cast to an array of IPAddrs).

INET Type Casting example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
create_table :inet_examples do |t|
  t.inet :ip_address
end

class InetExample < ActiveRecord::Base
end

inetExample = InetExample.new
inetExample.ip_address = '127.0.0.0/24'
inetExample.ip_address
# => #<IPAddr: IPv4:127.0.0.0/255.255.255.0>
inetExample.save

inet_2 = InetExample.first
inet_2.ip_address
# => #<IPAddr: IPv4:127.0.0.0/255.255.255.0>

Array Type Casting example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
create_table :people do |t|
  t.integer :favorite_numbers, :array => true
end

class Person < ActiveRecord::Base
end

person = Person.new
person.favorite_numbers = [1,2,3]
person.favorite_numbers
# => [1,2,3]
person.save

person_2 = Person.first
person_2.favoite_numbers
# => [1,2,3]
person_2.favoite_numbers.first.class
# => Fixnum

Type casting documentation

Another gem born out of necessity

I have also released pg_array_parser, a C extension which parses PostgreSQL array values and returns an array of strings. This gem is used by postgres_ext to retrieve the array values before casting them to the required type.

Plans for postgres_ext

INET, CIDR and MACADDR support has already been added to Rails 4. My next step is to submit a pull request to add UUID migration support and Array support to Rails master. Then I plan to backport Rails 4's hstore support back to postgres_ext. After adding support for the other PostgreSQL types, I plan to add support to arel for PostgreSQL type specific where clauses (ie ANY for array comparison, << and >> for INET and CIDR comparisons.