Оптимизация запросов на покупку в Rails - PullRequest
3 голосов
/ 03 февраля 2012

Я внедряю онлайн-магазин приложений с Rails. Его модель данных показана следующим образом:

class User < ActiveRecord::Base
  has_many purchase_records
  has_many items, :through => purchase_records
end

class Item < ActiveRecord::Base
  has_many purchase_records
  has_many users, :through => purchase_records
end

class PurchaseRecord < ActiveRecord::Base
  belongs_to :user
  belongs_to :item
end

У него есть страница, показывающая доступные товары и цены на них, и если пользователь приобрел товар, цена будет ссылкой для скачивания, как в App Store. Помощник вида написан, чтобы помочь сгенерировать такие ссылки:

def download_link(item)
  # generate a download link
end

def item_link(item)
  if current_user and current_user.items.where(:id => item.id).first != nil
    # User already purchased it
    download_link(item, 'book-price')
  else
    # Not purchased yet, show price and link to its details
    link_to item.price, item
  end
end

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

Ответы [ 3 ]

1 голос
/ 04 февраля 2012

Я только что реализовал загружаемый контент для клиента.

Я написал метод экземпляра для класса пользователя, который извлекает приобретенные пользователем товары, например ::100100

class User < ActiveRecord::Base
  ...
  def downloads
    self.orders.collect { |o| o.products }.flatten
  end
end

Вы могли бы использовать включить? способ проверить, купил ли пользователь товар, например ::10000

def item_link(item)
  if current_user && current_user.downloads.include?(item)
    download_link(item, 'book-price')
  else
    link_to item.price, item
  end
end    

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

Низкоуровневый кеш Rails может выглядеть так:

def downoads
  Rails.cache.fetch("user-downloads-#{self.id}") do
    self.orders.collect { |o| o.products }.flatten
  end
end

И вызовите следующее, чтобы очистить кеш:

Rails.cache.delete("user-downloads-#{self.id}")
1 голос
/ 04 февраля 2012

Вы можете установить приобретенные пользователем предметы в качестве переменной экземпляра в контроллере.Тогда вы попадаете в базу данных только один раз:

# app/controllers/items_controller.rb
def index
  @purchased_items = current_user.items
end

# app/helpers/items_helper.rb
def item_link(item)
  if @purchased_items.include?(item)
    download_link(...)
  else
    link_to ...
  end
end
0 голосов
/ 03 февраля 2012

Ну, вы не пишете это в помощнике вида.В пользовательской модели вы создаете область видимости под названием paid_items , в которой вы будете проверять все предметы, приобретенные пользователем.

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

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