Область применения метода класса в Rails 3

На основе Rails 3 API разница между областью действия и методом класса почти не существует.

class Shipment < ActiveRecord::Base
  def self.unshipped
    where(:shipped => false)
  end
end

совпадает с

scope :unshipped, where(:shipped => false)

Однако, я нахожу, что иногда получаю разные результаты, используя их.

Хотя оба они генерируют одинаковый правильный SQL-запрос, область не всегда возвращает правильные значения при вызове. Похоже, эта проблема возникает только тогда, когда она называется так же дважды, хотя и на другой стороне, в методе. Во второй раз, когда он вызывал, при использовании области видимости он возвращал то же самое, что и в первый раз. Если я использую метод класса, он работает правильно.

Существует ли какое-то кеширование запросов при использовании области видимости?

Edit:

order.line_items.unshipped

Вышеуказанная строка - это то, как вызывается область. Заказы имеют много строк.

Метод generate_multiple_shipments вызывается дважды, потому что тест создает порядок и генерирует отгрузки, чтобы узнать, сколько их есть. Затем он вносит изменения в заказ и регенерирует поставки. Однако group_by_ship_date возвращает те же результаты, что и в первой итерации порядка.

def generate_multiple_shipments(order)
  line_items_by_date = group_by_ship_date(order.line_items.unshipped)

  line_items_by_date.keys.sort.map do |date|
    shipment = clone_from_order(order)
    shipment.ship_date = date
    line_items_by_date[date].each { |line_item| shipment.line_items << line_item }
    shipment
  end
end

def group_by_ship_date(line_items)    
  hash = {}
  line_items.each do |line_item|
    hash[line_item.ship_date] ||= []
    hash[line_item.ship_date] << line_item
  end
  hash
end

Ответы

Ответ 1

Я думаю, что ваш вызов неверен. Вы должны добавить так называемый метод запроса для выполнения области действия, например all, first, last, т.е.:

order.line_items.unshipped.all

Я заметил некоторые несоответствия, особенно в rspec, которых можно избежать, добавив метод запроса.

Вы не опубликовали свой тестовый код, так что трудно сказать точно, но, по моему опыту, после изменения связанных записей вам необходимо принудительно перезагрузить, поскольку кеш запросов не всегда достаточно умен, чтобы обнаружить изменение. Передав true в ассоциацию, вы можете принудительно перезагрузить ассоциацию и повторить запрос:

order.line_items(true).unshipped.all

Ответ 2

Предполагая, что вы ссылаетесь на Rails 3.1, на область видимости может влиять область по умолчанию, которая может быть определена на вашей модели, тогда как метод класса не будет.