Не уверен, как оптимизировать ассоциацию активных записей

#ruby-on-rails #ruby #activerecord #data-access

#ruby-on-rails #ruby #activerecord #доступ к данным

Вопрос:

У меня есть фрагмент кода, который получает связанный объект по идентификатору, в противном случае он инициализирует новый объект.

 def pick_for_game(game_id)
   picks.find_or_initialize_by_game_id(game_id)
end
  

Коллекция picks обычно содержит несколько сотен элементов. Два варианта использования:

  1. Я хочу вызвать этот метод для 15-30 игр

  2. Я хочу вызвать этот метод для всех игр

Похоже, что текущий подход подходит для варианта использования a, но абсолютно ужасен для варианта использования b. Я мог бы усложнить этот метод в зависимости от того, был ли picks загружен с готовностью, например, следующим образом:

 def pick_for_game(game_id)
  if picks.loaded?
    new_pick = proc {
      Pick.new do |p|
        p.game_id = game_id
      end
    }
    picks.detect(new_pick) do |p|
      p.game_id == game_id
    end
  else
    picks.find_or_initialize_by_game_id(game_id)
  end
end
  

Однако, будет ли выбор одного подхода вместо другого для всех случаев иметь какие-либо преимущества, кроме как сделать код немного чище? Есть другие решения этой проблемы?

Ответ №1:

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

 def picks_for_games( game_ids )
  existing_picks = Pick.all( :conditions => { :game_id => game_ids } )
  game_ids_without_picks = game_ids - existing_picks.map{ |x| x.game_id }
  new_picks = game_ids_without_picks.map { 
                |game_id| Pick.initialize_by_game_id( game_id ) 
              }
  return picks   new_picks
end
  

Вы могли бы переключаться между двумя реализациями в зависимости от:

 if game_ids.is_a?( Array )
  

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

 Game.all( :conditions => { :picks => nil } ).map { |game| Pick.initialize_by_game_id( game.id ) }