I have a model Download, with a table downloads. downloads has a field called ip_address, which stores an ip address as an integer. I want to set up an IpAddress model, but without a ip_addresses table, so I can do stuff like
Download.find(1).ip_address.to_s # '127.0.0.1'
Download.find(1).ip_address.to_i # 2130706433
Download.find(1).ip_address.downloads # SELECT * FROM downloads WHERE ip_address='2130706433'
IpAddress.find(2130706433).downloads # SELECT * FROM downloads WHERE ip_address='2130706433'
I want it to behave like:
class Download < ActiveRecord::Base
belongs_to :ip_address, :foreign_key => :ip_address
end
class IpAddress < ActiveRecord::Base
set_primary_key :ip_address
has_many :downloads, :foreign_key => :ip_address
end
but without having a useless table of ip addresses.
Is this possible?
EDIT
I found that ruby already has a IPAddr class.
So I did this:
require 'ipaddr'
class Download < ActiveRecord::Base
attr_accessible :ip, ...
def ip
@ip ||= IPAddr.new(read_attribute(:ip), Socket::AF_INET)
end
def ip=(addr)
@ip = IPAddr.new(addr, Socket::AF_INET)
write_attribute(:ip, @ip.to_i)
end
def self.for_ip(addr)
where(:ip => IPAddr.new(addr, Socket::AF_INET).to_i)
end
end
Then I can do lots of cool stuff
Download.new(:ip => '127.0.0.1').save
Download.for_ip('127.0.0.1').first.ip.to_i # 2130706433
This is totally a semantics issue, but this should probably change if you have no IpAddress table (i.e. how can we find the IpAddress object 2130706433 in the database if there is no IpAddress table – unless you make IpAddress a container rather than a specific single ipaddress, otherwise do something like instantiate new ones with a constructer like
IpAddress(2130706433).downloads).Otherwise, though, I don’t see any problems in not having the IpAddress table. Why do you need it to be
belongs_to, rather than just another column?You can keep the models/objects if you wish to access them in similar ways:
EDIT:
You can override the accessor, like you’re asking. You just have to be careful in your code to be particular about what you’re asking for.
See this doc: http://ar.rubyonrails.org/classes/ActiveRecord/Base.html
Under section “Overwriting default accessors”
Basically, if you do override the value, and if you wish to access the DB value, you use
read_attribute(attr_name), so the code might look like this:Though things might get a little confusing in your code if you aren’t careful.