From 2e478d8537de717595193b5534476c131fc83e19 Mon Sep 17 00:00:00 2001 From: Dan Johnson Date: Mon, 24 Jun 2013 18:30:32 -0400 Subject: [PATCH] TopicLinkClick: convert 'ip' (bigint) -> 'ip_address' (inet) When accessed over IPv6, the ip address of the user is a 128-bit number, too big for PostgreSQL's bigint data type. Since PostgresSQL has the built-in inet type, which handles both IPv4 and IPv6 addresses, we should use that instead. Where this is done elsewhere in the codebase, the column is called ip_address, so we should follow that convention as well. This migration uses a SQL command to populate the new field from the old one, so as not to rely on the TopicLinkClick model class, which should keep the migration from failing if that class is modified in the future. --- app/models/topic_link_click.rb | 8 +++---- ..._change_ip_to_inet_in_topic_link_clicks.rb | 21 +++++++++++++++++++ spec/models/topic_link_click_spec.rb | 4 ++-- spec/models/topic_link_spec.rb | 2 +- 4 files changed, 27 insertions(+), 8 deletions(-) create mode 100644 db/migrate/20130624203206_change_ip_to_inet_in_topic_link_clicks.rb diff --git a/app/models/topic_link_click.rb b/app/models/topic_link_click.rb index 560450525..174122b6c 100644 --- a/app/models/topic_link_click.rb +++ b/app/models/topic_link_click.rb @@ -5,10 +5,8 @@ class TopicLinkClick < ActiveRecord::Base belongs_to :topic_link, counter_cache: :clicks belongs_to :user - has_ip_address :ip - validates_presence_of :topic_link_id - validates_presence_of :ip + validates_presence_of :ip_address # Create a click from a URL and post_id def self.create_from(args={}) @@ -28,7 +26,7 @@ class TopicLinkClick < ActiveRecord::Base rate_key = "link-clicks:#{link.id}:#{args[:user_id] || args[:ip]}" if $redis.setnx(rate_key, "1") $redis.expire(rate_key, 1.day.to_i) - create!(topic_link_id: link.id, user_id: args[:user_id], ip: args[:ip]) + create!(topic_link_id: link.id, user_id: args[:user_id], ip_address: args[:ip]) end args[:url] @@ -43,9 +41,9 @@ end # id :integer not null, primary key # topic_link_id :integer not null # user_id :integer -# ip :integer not null # created_at :datetime not null # updated_at :datetime not null +# ip_address :string not null # # Indexes # diff --git a/db/migrate/20130624203206_change_ip_to_inet_in_topic_link_clicks.rb b/db/migrate/20130624203206_change_ip_to_inet_in_topic_link_clicks.rb new file mode 100644 index 000000000..a0c3924bf --- /dev/null +++ b/db/migrate/20130624203206_change_ip_to_inet_in_topic_link_clicks.rb @@ -0,0 +1,21 @@ +require 'ipaddr' + +class ChangeIpToInetInTopicLinkClicks < ActiveRecord::Migration + def up + add_column :topic_link_clicks, :ip_address, :inet + + execute "UPDATE topic_link_clicks SET ip_address = inet( + (ip >> 24 & 255) || '.' || + (ip >> 16 & 255) || '.' || + (ip >> 8 & 255) || '.' || + (ip >> 0 & 255) + );" + + change_column :topic_link_clicks, :ip_address, :inet, { :null => false } + remove_column :topic_link_clicks, :ip + end + + def down + raise ActiveRecord::IrreversibleMigration + end +end diff --git a/spec/models/topic_link_click_spec.rb b/spec/models/topic_link_click_spec.rb index fce47cb59..1580de1ac 100644 --- a/spec/models/topic_link_click_spec.rb +++ b/spec/models/topic_link_click_spec.rb @@ -26,7 +26,7 @@ describe TopicLinkClick do context 'create' do before do - TopicLinkClick.create(topic_link: @topic_link, ip: '192.168.1.1') + TopicLinkClick.create(topic_link: @topic_link, ip_address: '192.168.1.1') end it 'creates the forum topic link click' do @@ -39,7 +39,7 @@ describe TopicLinkClick do end it 'serializes and deserializes the IP' do - TopicLinkClick.first.ip.to_s.should == '192.168.1.1' + TopicLinkClick.first.ip_address.to_s.should == '192.168.1.1' end end diff --git a/spec/models/topic_link_spec.rb b/spec/models/topic_link_spec.rb index 820d45b59..29d7422a2 100644 --- a/spec/models/topic_link_spec.rb +++ b/spec/models/topic_link_spec.rb @@ -236,7 +236,7 @@ describe TopicLink do it 'has the correct results' do TopicLink.extract_from(post) topic_link = post.topic.topic_links.first - TopicLinkClick.create(topic_link: topic_link, ip: '192.168.1.1') + TopicLinkClick.create(topic_link: topic_link, ip_address: '192.168.1.1') counts_for[post.id].should be_present counts_for[post.id].find {|l| l[:url] == 'http://google.com'}[:clicks].should == 0