Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoid Rails converting PostgreSQL inet type to an IPAddr object?

I have a problem in my Rails project. In previous projects (not Rails) I just used the "inet" type in PostgreSQL to store an IP address with a subnet, something like this:

 192.168.1.0/30 
 192.168.1.1/30
 192.168.1.2/30
 192.168.1.3/30

This was a good method to store the IP and the subnet in one field. Now I am using the inet type in Rails (4.0.1) and Ruby (2.0.0 p247), but as I read and tried, Rails converts it to the IPAddr object. But this IPAddr Object is destroying my format. It converts the four examples above to the following:

 192.168.1.0/30

Is there a way to prevent Rails doing that or is there a way to substitute it with a string? Or maybe another gem?

The problem occurs when I try to store something, and even when I try to read an existing value from the database.

Just to be more granular:

 IPAddr.new("192.168.1.2/255.255.255.252") 

Creates the database entry:

 192.168.1.0/24
like image 617
user2699706 Avatar asked Mar 31 '14 21:03

user2699706


1 Answers

If I remember right, 192.168.1.0/30 is technically correct.

Here's a couple things that might help:

  • In addition to IPAddr, a very good gem for working with IPv4 and IPv6 is IPAddress. It won't help much if Active Record has passed the value to IPAddr already, and it has changed the value, so you'll need to tell Active Record to use IPAddress instead.
  • Storing your addresses as PostgreSQL "inet" type is fine, if you intend to use PostgreSQL to handle your subnetting needs via its built-in IP functions. It's a bad idea if you want to simply store the IP address and retrieve it, as you found out. Active Record tries to honor the field type, and map it to the closest Ruby class, which is IPAddr. Instead, I always store my IPs both as a string, for fast retrieval in the form I want, and as a suitably sized integer, so I can do all my subnetting manipulations and matches in binary.

    It might help if, in your query, you tell PostgreSQL to cast your value to a string before returning it to Active Record. At that point you could use IPAddress to work with the value after parsing it. How to tell Active Record to tell PostgreSQL to do that is a different question.

like image 137
the Tin Man Avatar answered Oct 28 '22 16:10

the Tin Man