Ruby on rails 地理编码器轨道,检查是否有效

Ruby on rails 地理编码器轨道,检查是否有效,ruby-on-rails,ruby,rails-geocoder,Ruby On Rails,Ruby,Rails Geocoder,下面是我正在使用geocoder的类。我无法检查通过地理编码器输入的地址是否有效。当我添加一家公司/编辑一家公司时,这段代码非常有效,该公司的地址通过geocoder提供纬度和经度。但我需要代码来工作,这样当用户试图在编辑或创建公司时,将一个没有给出经度和纬度的地址放入时,就会弹出一个错误,并通知用户该地址无效 型号 class Company < ActiveRecord::Base validates :name, presence: true, length: { maxim

下面是我正在使用geocoder的类。我无法检查通过地理编码器输入的地址是否有效。当我添加一家公司/编辑一家公司时,这段代码非常有效,该公司的地址通过geocoder提供纬度和经度。但我需要代码来工作,这样当用户试图在编辑或创建公司时,将一个没有给出经度和纬度的地址放入时,就会弹出一个错误,并通知用户该地址无效

型号

class Company < ActiveRecord::Base
    validates :name, presence: true, length: { maximum: 30 }
    validates :website, presence: true
    validates :address, presence: true
    validates :description, presence: true
    validates :primary_field, presence: true

    geocoded_by :address
    before_save :geocode, if: ->(obj){ obj.address.present? and obj.address_changed? }

    after_save :set_popup_value

    private

     ...

end
class公司(obj){obj.address.present?和obj.address_changed?}
保存后:设置弹出值
私有的
...
结束
查看

<% provide(:title, 'Add Company') %>
<h1>Add Company</h1>
<div class="row">
  <div class="span6 offset3">
    <%= form_for(@company) do |f| %>
      <%= render 'shared/error_messages' %>

      <%= f.label :name %>
      <%= f.text_field :name %>

      <%= f.label :website %>
      <%= f.text_field :website %>

      <%= f.label :primary_field %>
      <%= f.select :primary_field, @primary_field %>

      <%= f.label :address %>
      <%= f.text_field :address, :placeholder => '123 Test St, City State Zip'%>

      <%= f.label :description %>
      <%= f.text_area :description, :size => "30x5" %>

      <%= f.submit "Add Company", class: "btn btn-large btn-primary" %>
    <% end %>
  </div>
</div>

添加公司
'123测试街,城市州邮政编码''>
“30x5”%>

您可能需要对geocoder服务进行web/服务调用。你如何做到这一点取决于你想要什么:ajaxy请求或背景工作,等等

这是一个相当普遍的问题,因此,您可能会在programmers.stackexchange.com中获得更好的关注

但是,这里有一些链接可以帮助您:

谷歌地理编码API:


OpenStreetMap:

因为您使用的是Geocoder,所以在保存之前,您只需要有机会检查Geocoder的结果。这一过程在it手册的“高级地理编码”一节中进行了解释。仅举一个例子,您可以这样做:

geocoded_by :address do |obj,results|
  ....
end
验证结果后,如果尚未获得坐标,则可以进行例外/添加验证错误/无论什么


当然,这意味着,你必须打电话给web服务,看看地址是否合适——就像其他人说的那样,在这之前进行一些基本的验证会很好。

因此,经过几天的努力,我想出了一些解决方案。第一个是真正的黑客,但完成了我需要的。我的第二个解决方案更加优雅,从目前为止我所知道的情况来看,效果非常好!我希望其他人觉得这很有用

我只需几行代码就可以处理控制器中的所有逻辑

geocoded_by :address
after_validation :geocode, if: ->(obj){ obj.address.present? and obj.address_changed? }
after_validation :lat_changed?

after_save :set_popup_value

private

# This is used to make sure that our address is actually parsed properly and we
# get a valuable lat/long
def lat_changed?
    if (self.address_changed?)
        if !(self.latitude_changed?)
            self.errors.add(:address, "is not valid")
            return false
        end
    end
    return true
end
通过在我的地理编码之后创建另一个
,我可以检查适当的值是否发生了变化,以及它们是否以某种方式发生了变化,而我知道地理编码中存在问题

如果地址改变了,但纬度没有改变,那么当地址通过地理编码器输入时,就不会得到返回的lat/long。如果是这种情况,那么我们只需添加一个错误,向用户抛出并返回false,这将停止对数据库的保存


我希望其他有这个问题的人都能找到这个帖子

肖恩·卡拉汉说的没问题。您可以通过以下方式改进代码:

def lat_changed?
  if address_changed? && !latitude_changed?
    self.errors.add(:address, "is not valid")
  end
end

不必返回真/假

您可以在如下示例中的模型中进行设置,以验证
地址
地址更改时,
地理编码
仅调用一次。 在
geocoded\u by
方法中,我们显式设置为写入
纬度
经度
,以便在找不到地址时,这些列将设置为

class Company < ActiveRecord::Base
   geocoded_by :address do |object, results|
    if results.present?
     object.latitude = results.first.latitude
     object.longitude = results.first.longitude
    else
     object.latitude = nil
     object.longitude = nil
    end
  end

  before_validation :geocode, if: :address_changed?

  validates :address, presence: true
  validates :found_address_presence

  def found_address_presence
    if latitude.blank? || longitude.blank?
      errors.add(:address, "We couldn't find the address")
    end
  end
end
class公司
您是否要求SO为您编写地址验证代码?不,我只是不知道在哪里/如何检查地址是否有效。因此,基本上,当用户点击“添加公司”按钮时,如果用户输入了一个地址,而地理编码器无法从中获取lat/long,那么我需要提出一个错误。但我不知道如何做到这一点。您可以改进它:
def lat\u changed?
`if address\u changed?&!latitude\u已更改?`self.errors.add(:address,“无效”)`end`
end
我认为在验证回调后添加错误不是一个好主意。这是在假设如果地址发生更改,则必须更改latitude。这一定是真的吗?