Как найти расстояние между двумя объектами? - PullRequest
0 голосов
/ 16 февраля 2019

Я использую геокод.Идея заключается в том, что наши партнеры могут размещать товары с адресом.Когда они это делают, он выбирает широту и долготу.Теперь, когда наши клиенты идут покупать этот продукт, они должны ввести адрес доставки, чтобы сообщить нам, куда доставить продукт.Однако, если адрес доставки не находится в пределах 20 миль от товара, им не разрешается доставлять товар.

Я получаю сообщение об ошибке, говорящее об этом "неопределенном методе" широта "для nil: NilClass"

Как я уже сказал, product.longitude, product.latitude уже установлен, когда пользователи пытаютсяorder.

Не уверен, что это потому, что 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

Ответы [ 2 ]

0 голосов
/ 16 февраля 2019

Вы должны переместить бизнес-логику в модель, к которой она принадлежит.

Итак, давайте начнем с создания проверки для расстояния продукта:

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"

Должен привести к отказу метода.Вы на самом деле тоже не сохраняете запись.Я бы начал все сначала.Напишите провальные тесты для различных возможных условий (недопустимые параметры, допустимые параметры, пользователь является владельцем и т. Д.), А затем напишите код контроллера.Убедитесь, что вы тестируете каждую ветвь кода.

0 голосов
/ 16 февраля 2019

Вы устанавливаете @order в следующей строке:

@order = current_user.orders.build(order_params)

Но вы пытаетесь вызвать его методы longitude и latitude выше этого, прежде чем даже установить переменную @order.Чтобы просто решить эту проблему, вы можете переместить эту строку вверх, она может даже располагаться в начале метода create, поскольку она не зависит от product или чего-либо подобного:

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

Хотя в вашем коде есть ряд проблем, таких как имена методов, начинающиеся с заглавных букв (вы можете сделать это, но не должны, это противоречит соглашению) или общая сложность метода.

...