我正在使用地理编码。我们的合作伙伴可以发布带有地址的产品。当他们这样做时,它获取纬度和经度。现在,当我们的客户去购买该产品时,他们必须输入一个送货地址,告诉我们在哪里交付产品。但是,如果他们的送货地址不在产品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
您在以下行中设置@order
:
@order = current_user.orders.build(order_params)
但是在你设置longitude
变量之前,你试着在它之上调用它的latitude
和@order
方法。要简单地解决这个问题,你可以移动这一行,它甚至可以位于create
方法的开头,因为它不依赖于product
或类似的东西:
def create
@order = current_user.orders.build(order_params)
# ...
end
虽然,您的代码中存在许多问题,例如以大写字母开头的方法名称(您可以这样做,但您不应该,这违反惯例)或方法的整体复杂性。
您应该将业务逻辑移动到它所属的模型。
因此,我们首先创建产品距离验证:
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"
应该导致该方法保释。你实际上也没有保存记录。我会重新开始。为不同的可能条件(无效参数,有效参数,用户是所有者等)编写失败测试,然后编写控制器代码。确保测试每个代码分支。