Rails创建一个或从范围创建多个记录

时间:2014-07-27 23:20:55

标签: ruby-on-rails ruby

我有一个名为IP的类,具有:address属性和两个虚拟属性::start_ip:end_ip

class IP < ActiveRecord::Base
  # address attribute is saved in database
  # start_ip and end_ip are virtual attribute, used in my form
  attr_accessor :start_ip, :end_ip
end

我有一个表单可以让我输入一个IP(进入:地址字段)或一系列地址进入我的虚拟属性的字段(:start_ip和:end_ip)。

如果我在:address字段中输入单个IP,那么一切正常。

如果我输入一系列地址(假设它跨越5个地址),那么我想为该范围内的每个地址创建IP记录,并且我认为最好拒绝当前记录,因为它赢了&因为我输入了一个范围,所以在其地址栏中有一个条目。

所以我想我需要一个before_save回调:

before_save :range_given?

def range_given?
  create!([@start_ip..@end_ip])
end

但它并不完全正确。

如何告诉rails忘记当前实例化(和验证)的记录,而是创建5条新记录,将每个地址属性设置为该范围内的IP?

2 个答案:

答案 0 :(得分:0)

在您create行动的控制器中,您可以写下这样的内容:

(params[:start_ip]..params[:end_ip]).each do |ip|
  IP.create!(address: ip)
end

添加您需要的代码。

PD。也许您应该重新考虑您的域模型,因为IP地址不同于IP范围

答案 1 :(得分:0)

很容易解决这个问题:

def create_from_range      
  # We are dealing with a range, so lets
  # turn both ends into IPAddr objects
  # so that we can do some Ruby magic on them
  start_addr = IPAddr.new(start_ip)
  end_addr   = IPAddr.new(end_ip)

  # Now that we have the start and end points of
  # of our range, we can call "to_a" on it, which
  # will give us a list of all the IPs from start to end
  range = (start_addr..end_addr).to_a

  # We need to shift the first value off the array, 
  # and assign it's address to the record we are
  # currently in the middle of creating, as it does 
  # not have an address yet
  #
  # No need to call save on this as we are in a 
  # before_save filter but you might need to do
  # that, depending on your domain
  first_ip   = range.shift
  self.address = first_ip.to_s

  # Now we loop through the remaining items in our range  
  # (array of IPs) and create a new record for each one
  range.each{ |ip| IPcreate! address: ip.to_s } 
end

容易,没有搞乱。