Неопределенный метод в моем модуле сервисных объектов - PullRequest
0 голосов
/ 16 октября 2018

Я хотел немного очистить и реорганизовать код моего метода create внутри моего контроллера заказов, и я прочитал, что это хорошая практика для использования сервисных объектов.Начиная с этого ужасного кода здесь:

def create
  if current_user.orders.where(paid: false).present?
    order = current_user.orders.last
    order_id = order.id
    product_id = @product.id
    @product.ordinable = false
    @product.save
    order_amount = order.amount
    if order.products << @product
      order.products.each do |x|
        @order_amountnew = order_amount + x.price
      end
      order.amount = @order_amountnew
      order.save
      respond_to do |format|
        format.html { redirect_to products_path, notice: 'Product added to the cart!' }
      end
    else
      respond_to do |format|
        format.html { redirect_to products_path, notice: 'There was a problem while adding the product to the cart!' }
      end
    end
  else
    product_id = @product.id
    order = current_user.orders.new
    order.save
    order_id = order.id
    @product.ordinable = false
    @product.save
    order_amount = order.amount
    if order.products << @product
      order.products.each do |x|
        @order_amountnew = order_amount + x.price
      end
      order.amount = @order_amountnew
      order.save
      respond_to do |format|
        format.html { redirect_to products_path, notice: 'Product added to the cart!' }
      end
      OrderPaidCheckJob.set(wait: 3.minutes).perform_later(order_id)
    else
      respond_to do |format|
        format.html { redirect_to products_path, notice: 'There was a problem while adding the product to the cart!' }
      end
    end
  end
end

Я хотел разделить метод в основном на два сегмента, поэтому я создал два модуля в папке служб следующим образом.Я назвал первый order_present_create_service

module OrderPresentCreateService
  class << self
    def create(params)
      order = current_user.orders.last
      order_id = order.id
      product_id = @product.id
      @product.ordinable = false
      @product.save
      order_amount = order.amount
      if order.products << @product
        order.products.each do |x|
          @order_amountnew = order_amount + x.price
        end
        order.amount = @order_amountnew
        order.save
        respond_to do |format|
          format.html { redirect_to products_path, notice: 'Product added to the cart!' }
        end
      else
        respond_to do |format|
          format.html { redirect_to products_path, notice: 'There was a problem while adding the product to the cart!' }
        end
      end
    end
  end
end

и позвонил второму order_new_create_service

module OrderNewCreateService
  class << self
    def create(params)
      product_id = params[:id]
      order = current_user.orders.new
      order.save
      order_id = order.id
      @product.ordinable = false
      @product.save
      order_amount = order.amount
      if order.products << @product
        order.products.each do |x|
          @order_amountnew = order_amount + x.price
        end
        order.amount = @order_amountnew
        order.save
        respond_to do |format|
          format.html { redirect_to products_path, notice: 'Product added to the cart!' }
        end
        OrderPaidCheckJob.set(wait: 3.minutes).perform_later(order_id)
      else
        respond_to do |format|
          format.html { redirect_to products_path, notice: 'There was a problem while adding the product to the cart!' }
        end
      end
    end
  end
end

здесь мой новый контроллер:

def create
  if current_user.orders.where(paid: false).present?
    OrderPresentCreateService.create(params)
  else
    OrderNewCreateService.create(params)
  end
end

Я просто следовал этомустатья здесь чтобы все заработало.Когда я пытаюсь создать заказ, теперь я получаю эту ошибку:

неопределенная локальная переменная или метод `current_user 'для OrderNewCreateService: Module

В начале я получаланалогичная ошибка с product_id = @ product.id, поэтому я изменил ее в product_id = params [: id] и заставил работать как-то.Где я делаю это неправильно?

Ответы [ 2 ]

0 голосов
/ 16 октября 2018

Мне кажется, что вы можете реорганизовать ваше действие create без использования служб.(Я большой поклонник сервисов. Я просто не думаю, что они вам здесь нужны.)

Во-первых, я бы добавил пару методов к вашей модели User, что-то вроде этого:

class User < ApplicationRecord

  def unpaid_orders
    orders.where(paid: false)
  end

  def unpaid_orders?
    unpaid_orders.any?
  end

end

Затем я бы сделал amount метод вместо атрибута, что-то вроде:

class Order < ApplicationRecord 

  def amount
    products.sum(&:price)
  end

end

Затем в вашем контроллере вы можете сделать что-то вроде:

delegate *%w(
  unpaid_orders?
  orders
), to: :current_user

def create
  order = unpaid_orders? ? orders.last : orders.create!
  @product.update(ordinable: false)
  if order.products << @product 
    @notice = 'Product added to the Cart!'
    OrderPaidCheckJob.set(wait: 3.minutes).perform_later(order.id) unless unpaid_orders?
  else 
    @notice = 'There was a problem while adding the product to the cart!'
  end
  redirect_to products_path, notice: @notice
end

Если вы не хотите делать amount методом для Order, тогда вы можете сделать:

delegate *%w(
  unpaid_orders?
  orders
), to: :current_user

def create
  order = unpaid_orders? ? orders.last : orders.create!
  @product.update(ordinable: false)
  if order.products << @product 
    order.update(amount: order.products.sum(&:price))
    @notice = 'Product added to the Cart!'
    OrderPaidCheckJob.set(wait: 3.minutes).perform_later(order.id) unless unpaid_orders?
  else 
    @notice = 'There was a problem while adding the product to the cart!'
  end
  redirect_to products_path, notice: @notice
end
0 голосов
/ 16 октября 2018

Если я правильно понимаю, задача заключается в рефакторинге оригинального действия с контроллера.В вашем рефакторированном коде есть список проблем, поэтому, чтобы сократить ответ, позвольте мне пропустить его и сосредоточиться на исходном действии.

Я вижу следующие проблемы:

  • product_id переменнаяинициализируется, но не используется
  • order_id переменная в 1-й ветви if условие инициализируется, но не используется
  • respond_to блок имеет условие только для формата html.Поскольку нет кода для других форматов, его можно упростить, метод
  • OrderPaidCheckJob.set ставится после redirect_to, поэтому он никогда не будет вызываться.Чтобы заставить его работать, поместите его перед redirect_to
  • Несмотря на условия if, действие заканчивается на redirect_to по тому же пути, только notice изменяется.Таким образом, вы можете просто установить notice и переместить redirect_to из if s
  • @product.ordinable = false; @product.save, что можно упростить до @product.update(ordinable: false).Поскольку он находится в обеих ветвях if, его можно убрать из этого блока.
  • Не знаю, почему if order.products << @product.Как вы думаете, когда это состояние ложное?В случае возникновения проблемы при добавлении его в базу данных будет выдано исключение. Блок
  • order.products.each do |x| и т. Д. Можно упростить до order.amount = @order_amountnew = order_amount + order.products.last.price (я подозреваю, что у вас здесь ошибка, поскольку вы выполняете итерацию по productsно сохраните результат только для последнего продукта)
  • вы инициализируете переменную экземпляра @order_amountnew, но не используете ее позже из-за перенаправления.Его можно удалить, я думаю,

Предварительный результат:

def create
  @product.update(ordinable: false)

  if current_user.orders.where(paid: false).present?
    order = current_user.orders.last
    order_amount = order.amount
    if order.products << @product
      order.amount = @order_amountnew = order_amount + order.products.last.price
      order.save

      notice = 'Product added to the cart!'
    else
      notice = 'There was a problem while adding the product to the cart!'
    end

  else
    order = current_user.orders.new
    order.save
    order_id = order.id
    order_amount = order.amount
    if order.products << @product
      order.amount = @order_amountnew = order_amount + order.products.last.price
      order.save

      OrderPaidCheckJob.set(wait: 3.minutes).perform_later(order_id)

      notice = 'Product added to the cart!'
    else
      notice = 'There was a problem while adding the product to the cart!'
    end
  end

  redirect_to products_path, notice: notice
end

Выглядит лучше и удобочитаемее?Поскольку он все еще имеет повторяющийся код, он может быть высушен еще больше.Но я бы порекомендовал справиться с проблемами, на которые я указал, прежде чем рефакторинг.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...