如何找到两个物体之间的距离?

问题描述 投票:-2回答:2

我正在使用地理编码。我们的合作伙伴可以发布带有地址的产品。当他们这样做时,它获取纬度和经度。现在,当我们的客户去购买该产品时,他们必须输入一个送货地址,告诉我们在哪里交付产品。但是,如果他们的送货地址不在产品20英里范围内,则不允许他们交付产品。

我收到一条错误消息,说这是“未定义的方法`纬度'为nil:NilClass”

就像我说的那样,当用户试图订购时,product.longitude,product.latitude已经设置好了。

不确定是不是因为order.delivery_address(lat,long)尚未提交到数据库中并且它试图检查距离。这是我的代码如下

所以我的问题是如何才能找到产品地址和订单地址之间的距离,如果两者之间的距离超过20英里,我想向用户显示警告信息。

 def create
        product = Product.find(params[:product_id])
        if current_user == product.user
            flash[:alert] = "You cannot purchase your own property"

        elsif current_user.stripe_id.blank? || current_user.phone_number.blank?
            flash[:alert] = " Please update your payment method and verify phone number please"
            return redirect_to payment_method_path
        elsif Geocoder::Calculations.distance_between([product.latitude, product.longitude], [@order.latitude, @order.longitude]) < 20
            flash[:alert] = "The delivery address you provided is outside the delivery zone. Please choose a different product."        
        else
            quantity = order_params[:quantity].to_i 

        @order = current_user.orders.build(order_params)
        @order.product = product
        @order.price = product.price
        @order.total = product.price * quantity + product.delivery_price

        # @order.save

        if @order.Waiting!
            if product.Request?
                flash[:notice] = "Request sent successfully... Sit back and relax while our licensed dispensary fulfil your order :)"
            else
                @order.Approved!
                flash[:notice] = "Your order is being filled and it will delivered shortly:)"
            end
        else
            flash[:alert] = "Our licensed dispensary cannot fulfil your order at this time :( "
        end

        end
        redirect_to product
    end
ruby-on-rails ruby geocoding
2个回答
2
投票

您在以下行中设置@order

@order = current_user.orders.build(order_params)

但是在你设置longitude变量之前,你试着在它之上调用它的latitude@order方法。要简单地解决这个问题,你可以移动这一行,它甚至可以位于create方法的开头,因为它不依赖于product或类似的东西:

def create
  @order = current_user.orders.build(order_params)
  # ...
end

虽然,您的代码中存在许多问题,例如以大写字母开头的方法名称(您可以这样做,但您不应该,这违反惯例)或方法的整体复杂性。


1
投票

您应该将业务逻辑移动到它所属的模型。

因此,我们首先创建产品距离验证:

class Order < ApplicationRecord

  validates :product_is_within_range, 
    if: -> { product.present? } # prevents nil errors

  # our custom validation method
  def product_is_within_range
    errors.add(:base, "The delivery address you provided is outside the delivery zone. Please choose a different product.") if product_distance < 20
  end

  def product_distance
    Geocoder::Calculations.distance_between(product.coordinates, self.coordinates)
  end
end

然后将总计算移动到模型中:

class Order < ApplicationRecord
  before_validation :calculate_total!, if: ->{ product && total.nil? }

  def calculate_total!
    self.total = product.price * self.quantity + product.delivery_price
  end
end

但是你仍然需要处理控制器非常破碎的事实。例如:

if current_user == product.user
  flash[:alert] = "You cannot purchase your own property"

应该导致该方法保释。你实际上也没有保存记录。我会重新开始。为不同的可能条件(无效参数,有效参数,用户是所有者等)编写失败测试,​​然后编写控制器代码。确保测试每个代码分支。

© www.soinside.com 2019 - 2024. All rights reserved.