Как использовать области для фильтрации данных по частичной переменной - PullRequest
0 голосов
/ 22 января 2020

У меня есть рабочий скрипт, фильтрующий мои результаты с помощью Active Record Scoping. Все отлично работает, когда я хочу фильтровать, сравнивая параметры с данными из базы данных.

Но у меня есть некоторая функция, подсчитывающая цену автомобиля внутри _car. html .erb частичная, результат этой функции зависит от результата параметров.

Как я могу отображать результаты поиска по результатам этой функции и показывать только автомобили по цене ниже определенной (определенной в параметрах).

Некоторый код, чтобы сделать его более понятным:

car.rb (файл модели)

  scope :price_leasing, -> (price_leasing) { where('price_leasing <= ?', price_leasing) }
  # for now price_leasing is getting price from database
  scope :brand, -> (brand) { where brand: brand }
  scope :car_model, -> (car_model) { where car_model: car_model }
  scope :category, -> (category) { where category: category }

cars_controller.rb (файл контроллера)

def index
  @cars = Car.where(nil)
  @cars = @cars.price_leasing(params[:price_leasing]) if params[:price_leasing].present?
  @cars = @cars.brand(params[:brand]) if params[:brand].present?
  @cars = @cars.car_model(params[:car_model]) if params[:car_model].present?
  @cars = @cars.category(params[:category]) if params[:category].present?

  @brands = Brand.all # importing all car brands into filters
end 

в индексе. html .erb У меня есть код "render @cars"

<%= 
  if @cars.size > 0
    render @cars.where(:offer_status => 1)
  else
    render html: '<p>Nie znaleziono  pasujących wyników.</p>'.html_safe
  end
 %>

внутри _car. html .erb-файла У меня есть функция из помощника

<h3 class="car-cell__price"><%= calculate_car_price(car.price, car.id) %> <span class="car-cell__light-text">zł/mc</span></h3>

моя функция Calculate_car_price () внутри помощника

def calculate_car_price(car_price, car_id)
  car = Car.find(car_id)
  fullprice = car_price

  if params[:price_leasing].present?
    owncontribution = params[:price_leasing].to_i
  else
    owncontribution = car.owncontribution
  end 
  pv = fullprice - owncontribution + (0.02 * fullprice)

  if params[:period].present?
    carperiod = params[:period].to_i
    carprice = (Exonio.pmt(0.0522/60, carperiod, pv)) * -1
  else
    carprice = (Exonio.pmt(0.0522/60, 60, pv)) * -1
  end
  p number_with_precision(carprice, precision: 0)
end

Я бы хотел, чтобы область видимости в результате этой функции. Является ли это возможным?

1 Ответ

0 голосов
/ 23 января 2020

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

Чтобы сделать то, что вы хотите на уровне БД, вам потребуется виртуальный столбец в базе данных, реализация будет меняться в зависимости от того, какой продукт базы данных вы используете ( Я бы не ожидал, что определение виртуального столбца в postgreSQL будет таким же, как определение виртуального столбца в mySQL)

Так что я не уверен, что существует оптимальный способ сделать это.

Я бы предложил вам создать собственный метод класса и метод экземпляра в вашей модели Car. Это будет менее производительно, но проще для понимания и реализации.

def self.car_price_under(target_price, params)
  select { |v| v.car_price_under?(target_price, params) }
end


def car_price_under?(target_price, params)
  full_price = price
  if params[:price_leasing].present?
     my_own_contribution = params[:price_leasing].to_i
   else
    my_own_contribution = owncontribution
  end 
  pv = full_price - my_own_contribution + (0.02 * full_price)
  if params[:period].present?
    car_period = params[:period].to_i
    new_car_price = (Exonio.pmt(0.0522/60, car_period, pv)) * -1
  else
    new_car_price = (Exonio.pmt(0.0522/60, 60, pv)) * -1
  end
  new_car_price <= target_price
end

Это позволит вам сделать ...

 @cars = Car.where(nil)
 @cars = @cars.brand(params[:brand]) if params[:brand].present?
 @cars = @cars.car_model(params[:car_model]) if params[:car_model].present?
 @cars = @cars.category(params[:category]) if params[:category].present?
 @cars = @cars.car_price_under(target_price, params) if target_price.present?

Обратите внимание, что это происходит в рельсах, а не в базе данных , поэтому метод car_price_under следует вызывать после всех других областей, чтобы минимизировать количество записей, которые необходимо изучить. Вы не можете связывать дополнительные области, так как @cars будет массивом ... если вы хотите иметь возможность связывать дополнительные области (или вы хотите иметь отношение активной записи, а не массив), вы можете сделать что-то вроде @cars = Car.where(id: @cars.pluck(:id))

...