[英]How to end each loop after a particular condition in ruby
我已包含给定的代码
def check_ip
start_ip = IPAddr.new(myip).to_i
end_ip = IPAddr.new(endip).to_i
ip_pool = IpTab.all
p '!!!!!!!!!!!!!!!!!!!!!!!'
p ip_pool
ip_pool.each do |ip|
low = IPAddr.new(ip.start_ip).to_i
high = IPAddr.new(ip.end_ip).to_i
p '-------------------------------'
p ((low..high)===start_ip)
p ((low..high)===start_ip)
p '******************************'
break if (low..high)===start_ip
break if (low..high)===end_ip
p '*******************************'
self.errors.add(:start_ip, I18n.t('errors.start_ip'))
end
end
我得到的输出:
"!!!!!!!!!!!!!!!!!!!!!!!"
IpPool Load (0.1ms) SELECT `ip_pools`.* FROM `ip_pools`
#<ActiveRecord::Relation [#<IpPool id: 1, start_ip: "10.10.10.10", end_ip: "10.10.10.20", user_id: 1, created_at: "2015-09-08 05:12:34", updated_at: "2015-09-08 05:12:34">, #<IpPool id: 4, start_ip: "11.12.12.13", end_ip: "11.12.12.16", user_id: 1, created_at: "2015-09-08 06:08:38", updated_at: "2015-09-08 06:08:38">]>
"-------------------------------"
true
true
"******************************"
但是它不能正常工作,如果我的start_ip或end_ip位于数据库中给定的ips之间,则它不允许保存ip。 即如果(low..high)===start_ip
或(low..high)===end_ip
为true,则不允许保存。
指导我如何解决此问题,因为我的代码不起作用指导我如何编写此代码。
如果
(low..high)===start_ip
或if (low..high)===end_ip
为true
则不允许保存
您的循环无法正常工作。 假设(low..high)===start_ip
为true
。 您的循环变为:
ip_pool.each do |ip|
low = IPAddr.new(ip.start_ip).to_i
high = IPAddr.new(ip.end_ip).to_i
break if true # loop exits here
break if (low..high)===end_ip # not called
self.errors.add(:start_ip, I18n.t('errors.start_ip')) # not called either
end
如果if (low..high)===end_ip
为true
,它将变为:
ip_pool.each do |ip|
low = IPAddr.new(ip.start_ip).to_i
high = IPAddr.new(ip.end_ip).to_i
break if (low..high)===start_ip # nothing happens
break if true # loop exits here
self.errors.add(:start_ip, I18n.t('errors.start_ip')) # not called
end
无论哪种方式,都不会调用self.errors.add
。 然而, 被称为如果两个条件都false
,可能不是你想要的。
为了解决您的问题,您可以编写:
ip_pool.each do |ip|
low = IPAddr.new(ip.start_ip).to_i
high = IPAddr.new(ip.end_ip).to_i
if (low..high).include?(start_ip) || (low..high).include?(end_ip)
errors.add(:start_ip, I18n.t('errors.start_ip'))
break
end
end
或有单独的错误:
ip_pool.each do |ip|
low = IPAddr.new(ip.start_ip).to_i
high = IPAddr.new(ip.end_ip).to_i
if (low..high).include?(start_ip)
errors.add(:start_ip, I18n.t('errors.start_ip'))
break
elsif (low..high).include?(end_ip)
errors.add(:end_ip, I18n.t('errors.end_ip'))
break
end
end
请注意,我已将rng===obj
替换为rng.include?(obj)
。
此外,我认为您的before_save :check_ip
应该是validate :check_ip
,如执行自定义验证中所示。 该文档还显示了如何实现可应用于多个属性的EachValidator
。
您真正需要做的是,当验证失败时返回false。 我想你应该试试这个
def check_ip
start_ip = IPAddr.new(self.start_ip).to_i
end_ip = IPAddr.new(self.end_ip).to_i
ip_pool = IpPool.all
p '!!!!!!!!!!!!!!!!!!!!!!!'
p ip_pool
begin
ip_pool.each do |ip|
low = IPAddr.new(ip.start_ip).to_i
high = IPAddr.new(ip.end_ip).to_i
p '-------------------------------'
p ((low..high)===start_ip)
p ((low..high)===start_ip)
p '******************************'
raise ArgumentError, I18n.t('errors.start_ip') if ((low..high)===start_ip or (low..high)===end_ip
p '*******************************'
end
rescue ArgumentError => msg
p msg
self.errors.add(:start_ip, msg)
return false
end
return true
end
如果您是我,我会向Ip
模型添加自定义验证检查:
validate :validate_pool_existence!
def validate_pool_existence
# DRY by taste
errors.add(:start_ip, I18n.t('errors.start_ip')) if IpPool.contains_ip?(start_ip)
errors.add(:end_ip, I18n.t('errors.end_ip')) if IpPool.contains_ip?(end_ip)
end
现在,您需要向IpPool
添加一些有用的方法以支持ip范围查询:
# Check if any IpPool in database contains passed ip
# `all` usage maybe slow if you have lots of records in IpPool table
def self.contains_ip?(ip)
all.any? { |pool| pool.contains?(ip) }
end
# Check if current IpPool contains passed ip
def contains_ip?(ip)
to_addr.include? ip
end
# This returns an IPAddr range like this:
# #<IPAddr: IPv4:10.10.10.10/255.255.255.255>..#<IPAddr: IPv4:10.10.10.20/255.255.255.255>
def to_addr
AddrIP.new(start_ip)..AddrIP.new(end_ip)
end
就是这样。 这是IPAddr
因为IPAddr
支持范围,并且您可以通过简单的include?
来查询ip是否在范围内include?
校验:
>> range = IPAddr.new('10.10.10.10')..IPAddr.new('10.10.10.20')
=> #<IPAddr: IPv4:10.10.10.10/255.255.255.255>..#<IPAddr: IPv4:10.10.10.20/255.255.255.255>
>> range.include? '10.10.10.15'
=> true
>> range.include? '10.10.10.25'
=> false
请享用! :)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.