1

私はモデルDownloadとテーブルを持っていますdownloads。には、IP アドレスを整数として格納するdownloadsというフィールドがあります。ip_addressモデルをセットアップしたいのですIpAddressが、ip_addresses テーブルがないので、次のようなことができます

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'

次のように動作させたい:

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

しかし、無駄な IP アドレスのテーブルはありません。

これは可能ですか?

編集

ruby にはすでにIPAddr クラスがあることがわかりました。

だから私はこれをしました:

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

それから私はたくさんのクールなことをすることができます

Download.new(:ip => '127.0.0.1').save
Download.for_ip('127.0.0.1').first.ip.to_i # 2130706433
4

3 に答える 3

3

belongs_to2 つのテーブル内のオブジェクト間の関連付けを指定するためのものです。しかし、その通りです。他の関連データを保存する必要がない限り、テーブルに IP アドレスを保存してもほとんど役に立ちません。

ただし、スコープを使用して目的を達成することはできます。Download モデルに次のようなものを含めることができます。

class Download < ActiveRecord::Base
  scope :for_ip, lambda { |x| where(:ip_address => x) }
end

それからあなたは電話するでしょう

Download.for_ip(2130706433)

その IP のダウンロードのリストを取得するには。

代わりにクラス メソッドを追加することもできます。

class Download < ActiveRecord::Base
  def self.for_ip(x)
    where(:ip_address => x)  
  end  
end

これは、文字列から数値の IP アドレスに変換する場合に便利です。

また、IPAddress クラスが必要な場合は、次のようなメソッドを追加できます。

class IPAddress
  def initialize(ip)
    #presumably do some stuff here
    @ip = ip
  end

  def downloads
    Download.for_ip(@ip)
  end
end
于 2012-08-10T14:50:39.447 に答える
2
IpAddress.find(2130706433).downloads # SELECT * FROM downloads WHERE ip_address='2130706433'

これは完全にセマンティクスの問題ですが、IpAddress テーブルがない場合はおそらく変更されるはずです (つまり、IpAddress テーブルがない場合、データベースで IpAddress オブジェクト 2130706433 を見つけるにはどうすればよいでしょうか - IpAddress を特定の単一の IP アドレスではなくコンテナーにしない限り)。 、それ以外の場合は、のようなコンストラクターで新しいものをインスタンス化するなどのことを行いますIpAddress(2130706433).downloads)。

それ以外の場合は、IpAddress テーブルがなくても問題はないと思います。belongs_to単なる別の列ではなく、なぜそれが必要なのですか?

同様の方法でアクセスしたい場合は、モデル/オブジェクトを保持できます。

class Download < ActiveRecord::Base
  ##Whatever Download-model-specific code you have...
  def ip_address
    #If nil, initialize new object. Return object.
    @ip_address ||= IpAddress(ip_address_val)
  end
end

class IpAddress
  def initialize(address)
    @value = address
  end
  def downloads
    Download.where(:ip_address_val => self.value)
  end
end

編集: あなたが求めているように、アクセサーをオーバーライドできます。求めているものに特に注意を払う必要があるだけです。このドキュメントを参照してください:http://ar.rubyonrails.org/classes/ActiveRecord/Base.html セクション「デフォルトアクセサーの上書き」の下

基本的に、値をオーバーライドする場合、および DB 値にアクセスする場合は を使用するread_attribute(attr_name)ため、コードは次のようになります。

class Download < ActiveRecord::Base
  ##Whatever Download-model-specific code you have...
  def ip_address
    #If nil, initialize new object. Return object.
    @ip_address ||= IpAddress(read_attribute(:ip_address))
  end
end

class IpAddress
  def initialize(address)
    @value = address
  end
  def downloads
    Download.where(:ip_address => self.value)
  end
end

注意しないと、コードが少し混乱する可能性があります。

于 2012-08-10T14:52:28.750 に答える
0

set_table_name "downloads" を IpAddress に追加し、列名 ip_address が既にある 2 つの間の関係を削除します。

これにより、次の方法でクエリが提供されます

Download.find(1).ip_address.to_s # '127.0.0.1'
Download.find(1).ip_address.to_i # 2130706433
IpAddress.find(Download.find(1).ip_address) # SELECT * FROM downloads WHERE ip_address='2130706433'
IpAddress.find(2130706433) # SELECT * FROM downloads WHERE ip_address='2130706433'
于 2012-08-10T14:49:48.457 に答える