#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 обычно содержит несколько сотен элементов. Два варианта использования:
-
Я хочу вызвать этот метод для 15-30 игр
-
Я хочу вызвать этот метод для всех игр
Похоже, что текущий подход подходит для варианта использования 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 ) }