N+1 проблема для пользовательского метода в рельсах

В моем приложении рельсы у меня есть User модель с методом под названием price_tier:

def price_tier
  Spree::PriceTier.by_code[read_attribute(:price_tier)]
end

Тем не менее, когда у меня есть коллекция @users и вызовите price_tier один за другим, он загрузит PriceTier запрос для каждого экземпляра, который вызывает проблему N+1.

includes здесь не работает, так как это не ассоциация.

@users.map { |user| user.price_tier }

Есть ли способ изменить код, который исправляет проблему N+1?

1 ответ

Вы действительно должны установить отношения между моделями напрямую, например, user has_one :price_tier, Это сделает код здесь бризом.

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

tiers = Spree::PriceTier.where(code: @users.pluck(:price_tier))
                        .each_with_object({}) { |tier, hash| hash[tier[code]] = tier }

@users.map { |user| tiers[user.price_tier] }

NB. Вышесказанное предполагает удаление метода экземпляра. :price_tier и используя атрибут.

Я не уверен, что действительно стоит включить вышесказанное - вы собираете пользовательский Price_tier, нажимаете на БД (только один раз, а не для каждого пользователя) для уровней, итерируете их все, чтобы создать хэш для быстрого доступа, затем итерируете через пользователей, чтобы сопоставить их. Это большая работа для чего-то, что легко решается путем установления отношений.

Надеюсь, что это поможет, и действительно надеюсь, что тон выше в приведенном выше смысле - в основном означает, что вы могли бы сделать что-то подобное выше, хотя реальный совет был бы: пожалуйста, не устанавливайте отношения и работайте с традиционным подходом здесь:)

Другие вопросы по тегам