Проверьте, существует ли запись внутри действия создания - PullRequest
0 голосов
/ 31 октября 2018

Мой сценарий:

У меня есть SaleItem модель, в которой хранится (:sale_id, :product_id, :quantity, :total_price).

class SaleItem < ApplicationRecord
  belongs_to :sale
  belongs_to :product

  before_save :set_unit_price
  before_save :set_total_price
  before_save :set_total_disscounted_price

  def unit_price
    if persisted?
      self[:unit_price]
    else
      product.price_pence
    end
  end

  def total_price
    unit_price * quantity
  end

  private

    def set_unit_price
      self[:unit_price] = unit_price
    end

    def set_total_price
      self[:total_price] = quantity * set_unit_price
    end

    def set_total_disscounted_price
      self[:total_disscounted_price] =self[:total_price] - (self[:total_price] * self.sale.event.event_disscount) / 100
    end
end

Моя проблема в том, что всякий раз, когда я создаю новый объект SaleItem, я хочу проверить, существует ли такая же запись, и если это так, то мне просто нужно сложить :quantity и пересчитать общую стоимость (в модели) в соответствии с на новый :quantity.

Что меня смущает, можно ли проверить это в методе создания? До сих пор я нашел этот метод рельсов first_or_create.

Это мой исходный код от SaleItem контроллера

class SaleItemsController < ApplicationController
  def create
    @sale = @sale_item.sale
    @sale_item = SaleItem.create(sale_item_params)
    @event = @sale.event

    if @sale_item.save
      redirect_to event_sale_path(@event, @sale)
    else
      redirect_to event_sale_path(@event, @sale)

    end
  end

  private

  def sale_item_params
    params.require(:sale_item).permit(:sale_id, :product_id, :quantity)
  end
end

и затем после того, как я нашел first_or_create, я начал менять его на это, но еще не закончил, так как немного застрял:

class SaleItemsController < ApplicationController
  def create

    @sale_item = SaleItem.where(sale_id: params[:sale_id], product_id: sale_item_params[:product_id]).first_or_create do |sale_item|
      sale_item.quantity = sale_item.quantity.to_i + sale_item_params[:quantity].to_i
    end

    @sale = @sale_item.sale
    @sale_item = SaleItem.create(sale_item_params)
    @event = @sale.event

    if @sale_item.save
      redirect_to event_sale_path(@event, @sale)
    else
      redirect_to event_sale_path(@event, @sale)

    end
  end

  private

  def sale_item_params
    params.require(:sale_item).permit(:sale_id, :product_id, :quantity)
  end
end

Я не мог понять, как обновить найденную запись и не изменять вновь созданную запись, поэтому я создал переменную @new_record и первоначально установил ее на false, а затем после создания новой записи, @new_record изменяется на true. Таким образом, я мог отслеживать каждую запись и изменять ее при необходимости.

Это SaleItem Controller обновленный код

class SaleItemsController < ApplicationController
  def create

    @new_record = false

    @sale_item = SaleItem.where(sale_id: params[:sale_id], product_id: sale_item_params[:product_id]).first_or_create do |sale_item|
      sale_item.quantity = sale_item_params[:quantity]
      @new_record = true
    end

    @new_record == false ? @sale_item.quantity = @sale_item.quantity.to_i + sale_item_params[:quantity].to_i : sale_item_params[:quantity].to_i

    @sale = @sale_item.sale
    @event = @sale.event

    if @sale_item.save
      redirect_to event_sale_path(@event, @sale)
    else
      redirect_to event_sale_path(@event, @sale)
    end
  end

  def destroy
    @sale_item = SaleItem.find(params[:id])
    @sale = @sale_item.sale
    @event = @sale.event
    @sale_item.destroy
    redirect_to event_sale_path(@event, @sale)

  end

  private

  def sale_item_params
    params.require(:sale_item).permit(:sale_id, :product_id, :quantity)
  end
end

Ответы [ 3 ]

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

Измените create код действия с этого

def create

  @sale_item = SaleItem.where(sale_id: params[:sale_id], product_id: sale_item_params[:product_id]).first_or_create do |sale_item|
    sale_item.quantity = sale_item.quantity.to_i + sale_item_params[:quantity].to_i
  end

  @sale = @sale_item.sale
  @sale_item = SaleItem.create(sale_item_params)
  @event = @sale.event

  if @sale_item.save
    redirect_to event_sale_path(@event, @sale)
  else
    redirect_to event_sale_path(@event, @sale)
  end
end

к этому

def create

  @sale_item = SaleItem.find_or_create_by(sale_item_params) do |sale_item|
    sale_item.quantity = sale_item.quantity.to_i + sale_item_params[:quantity].to_i
    sale_item.save
  end

  @sale = @sale_item.sale
  @event = @sale.event

  if @sale_item.save
    redirect_to event_sale_path(@event, @sale)
  else
    redirect_to event_sale_path(@event, @sale)
  end
end

find_or_create_by(sale_item_params) сначала найдет sale_item с sale_id, product_id и quantity, а затем, если не найдено ни одной записи sale_item, создаст новую. В обоих случаях вы можете обновить количество.

0 голосов
/ 04 ноября 2018

Я думаю, вы должны определить уникальный ключ, чтобы найти SaleItem

  • например, если sale_id и product_id являются ключами для поиска SaleItem.
  • лучше иметь новый метод сильных параметров для поиска или создания SaleItem для create метода.

пример контроллера:

    class SaleItemsController < ApplicationController
        before_action :initialize_sale_item, only: [:create]

        def create
            @sale_item.assign_attributes(sale_item_params)
            @sale_item.save
            # render or respond_to ...
        end

        private
        def sale_item_params
            params.require(:sale_item).permit(:sale_id, :product_id, :quantity)
        end

        def sale_item_key_params
            params.require(:sale_item).permit(:sale_id, :product_id)
        end

        def initialize_sale_item
            @sale_item = SaleItem.find_or_initialize_by(sale_item_key_params)
        end
    end
0 голосов
/ 31 октября 2018

Полагаю, вы, вероятно, захотите взглянуть на https://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-find_or_create_by

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