如果找不到记录,则返回错误的最佳方法

时间:2014-07-28 13:35:50

标签: ruby-on-rails ruby

我在Ruby on rails网站上有一些脚本来查找位置并将记录保存到我的数据库中。

此时如果找不到位置,它将返回Nil并仍然保存到数据库。

我希望它出错并继续解析文件的其余部分,而不是将nil值保存到数据库中。

将数据库修改为该列上的NOT NIL,或者如果编码中的值为n,则有办法返回Error

如下所示

Begin
  SQL Query
rescue
  return error if Nil
end

模型

class Hotload < ActiveRecord::Base
  attr_accessor :log
  validates :user_id, :uniqueness => {:scope => [:comments, :origin, :dest]}
  attr_accessible :comments, :covered, :delivery, :dest, :equipment_id, :length, :ltl, :origin, :pickup, :rate, :user_id, :weight, :source
  belongs_to :user
  has_one :equipment
  set_rgeo_factory_for_column(:origin, RGeo::Geographic.spherical_factory(:srid => 4326))
  set_rgeo_factory_for_column(:dest, RGeo::Geographic.spherical_factory(:srid => 4326))
  before_save :add_city_and_state
  has_one :company, through: :user

  def self.post(post)

    #convert the post to hash of strings
    post = post.stringify_keys    
    begin
      ['origin','dest'].each do |loc|
        state = post[loc][-2,2]
        city  = post[loc].gsub(%r(, [a-zA-Z]+), '').strip
        post[loc] = LocationFinder.call(city, state, "true")
      end
      post.keys.each do |key|
        if post[key] == ''
          post.delete(key)
        end
      end
      l = Hotload.where(:origin => post['origin'],:dest => post['dest'],:comments => post['comments']).first_or_create do |h|
        h.origin = post['origin']
        h.dest = post['dest']
        h.comments = post['comments']
        h.delivery = post['delivery']
        h.pickup = post['pickup']
        h.equipment_id = post['equipment_id']
        h.source = post['source']
        h.user_id = post['user_id']
        h.length  = post['length']
      end
      l.touch
      l.save # called so that we update the 'updated_at' field if we find the record above

    rescue Exception => e
      puts e unless Rails.env.test?
    end
  end

辅助

#takes in a city and state
# then looks in the database for the locations
# if they are not found, it attempts to find the location using Bing/Google
#
# Is_hotload is a placeholder that is used to determine how we report on unknown locations
#  if we get an unknown location, we try to add it immediately if it is a hotload
#    otherwise we only try to add it if it has been reported 10 times
#
# Returns either NIL or a POINT string representing the Location in the format "POINT (#{origin.coords.x} #{origin.coords.y})"

class LocationFinder

  def self.call(city, state, hotload)
    raise Error if [city,state].include? nil
    LocationFinder.new(city, state, hotload).find_location
  end

  attr_accessor :city, :state, :hotload, :lat, :lng

  def initialize(city, state, hotload)
    @city  =  city.to_s.try(:downcase)
    @state = state.to_s.try(:downcase)
    @hotload = hotload

  end

  # for testing purposes only
  # @lat = "37.208969116210938"
   # @lng = "-93.291557312011719"



  def find_location
    location = validate_location
    location ||= search_database
    location ||= search_levenshtein
    location ||= search_unknown
    unless location.nil? || location.empty?
      location.try(:coords)
    end
  end

  def validate_location
    [city,state].each do |val|
      return "ANYWHERE" if val.blank?
      return "ANYWHERE" if val.upcase == "ANYWHERE"
    end
    # if city =~ /\d{5}/
    #   city =
    # end
    nil
  end

  def search_database
    Location.first(:conditions => {:city => city, :state => state})
  end

  def search_levenshtein
    Location.where("(levenshtein(city, '#{city}') <= 4) AND state = '#{state}'").order("levenshtein(city, '#{city}') ASC").first
  end

  # Tries to find the location using an external API if it
  #  have a value greater than 10 or is a hotload
  def search_unknown
    cs = "#{city}, #{state}"
    Report.check_and_add('unknown_locations', cs) unless hotload == "true"
    report = Report.first( :conditions => { :metric => "unknown_locations", :name => cs } )
    if report.value > 10 || hotload == "true"
      begin
        parse_geo_data
        l = location_insert
        if Location.city_state_exists?("#{city}, #{state}")
          Report.delete(report.id)
        end
      rescue => detail
        Report.new( {:name => cs, :metric => "Could Not Add", :value => '1', :reason => detail.to_s} ).save
      end
    end
  end


  def parse_geo_data
    cs = "#{city}, #{state}"
    puts cs
    google_api_results = HTTParty.get("http://dev.virtualearth.net/REST/v1/Locations/#{cs.gsub(/ /, "%20")}?o=xml&key=AvtYnvs3UjKaIPdG5v1YaVBL_5-Rhg_zgUwoQgvTiTS9dMxJSreIanWVLvTzQc86")
    geo_data = google_api_results.parsed_response
    lat = geo_data["Response"]["ResourceSets"]["ResourceSet"]["Resources"]["Location"]["Point"]["Latitude"]
    lng = geo_data["Response"]["ResourceSets"]["ResourceSet"]["Resources"]["Location"]["Point"]["Longitude"]
    name = geo_data["Response"]["ResourceSets"]["ResourceSet"]["Resources"]["Location"]["Name"]
    city, state = name.downcase.split(",")
    state = state.strip
    self.lat = lat
    self.lng = lng
    self.city = city
    self.state = state

  end

  def location_insert
    Location.create({:city => city, :state => state, :coords => "POINT(#{lng.to_f} #{lat.to_f})", :cs => "#{city}, #{state}"})
  end


end

1 个答案:

答案 0 :(得分:0)

在您的模型中添加状态验证将保持&#34;不良&#34;保存的数据:

validates :origin, :dest, :presence => true

您的l.errors方法中的post可以提供错误消息。如果您返回l,那么您的调用代码可以reference those errors进行显示或记录。

相关问题