【问题标题】:How find the distance between two objects?如何找到两个物体之间的距离?
【发布时间】:2019-07-10 07:10:30
【问题描述】:

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

我收到一条错误消息,提示“nil:NilClass 的未定义方法 `latitude'”

就像我说的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

【问题讨论】:

  • 您遇到的错误似乎与地理编码无关,更像是@order 实例变量是nil。因此,您可能需要显示更多代码并改写此问题以使正确答案成为可能。
  • 更新评论抱歉

标签: ruby-on-rails ruby geocoding


【解决方案1】:

您在以下行中设置了@order

@order = current_user.orders.build(order_params)

但是在设置@order 变量之前,您尝试在此之上调用它的longitudelatitude 方法。为了简单地解决这个问题,你可以把这条线向上移动,它甚至可以位于create方法的开头,因为它不依赖于product或类似的东西:

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

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

【讨论】:

    【解决方案2】:

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

    让我们开始为产品距离创建一个验证:

    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"
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-06-19
      • 1970-01-01
      • 2015-08-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多