Как реализовать ActiveRecord "scoped" для моделей MongoMapper в Rails 3? - PullRequest
1 голос
/ 26 апреля 2011

Обратите внимание, что я новичок в Ruby, поэтому многие очевидные вещи не так очевидны для меня;)

Я получил много параметров, отправленных на мой контроллер (res, page, с тех пор). Используя эти параметры, я пытаюсь составить запрос для моих моделей на основе MongoMapper.

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

Например

if (params[:res] && params[:page] && params[:since]) 
  @movies = Movie.where(:FirstReleasedYear.gt => params[:since].to_i-1).sort(:DateModified.desc).paginate(:per_page => params[:res], :page => params[:page])
  @total_results = Movie.where(:FirstReleasedYear.gt => params[:since].to_i-1).count
elsif (params[:res] && params[:page])
  @movies = Movie.sort(:DateModified.desc).paginate(:per_page => params[:res], :page => params[:page])
  @total_results = Movie.count
elsif (params[:since]) # Too slow request
  @movies = Movie.where(:FirstReleasedYear.gt => params[:since].to_i-1).sort(:DateModified.desc)
  @total_results = Movie.where(:FirstReleasedYear.gt => params[:since].to_i-1).count
else # default request 
@year_now = Time.new.year
  @movies = Movie.limit(30).offset(0).where(:FirstReleasedYear.gt => @year_now-1).sort(:DateModified.desc).order.all
  @total_results = Movie.where(:FirstReleasedYear.gt => @year_now).count
end 

Это полная катастрофа - если я хочу добавить какой-то новый параметр, мне придется добавить еще ifs.

Я хотел бы использовать это следующим образом

@movies = Movie.scoped # I've found this in example for ActiveRecord model

if (params[:since])
  @movies.where(:FirstReleasedYear.gt => params[:since].to_i-1)
end
# Some other params like sort and so on 
if (params[:res] && params[:page])
  @movies.paginate(:per_page => params[:res], :page => params[:page])
end 

Пожалуйста, дайте мне совет, как справиться с такой ситуацией

1 Ответ

3 голосов
/ 27 апреля 2011

Я сосредоточусь на этом коде:

@movies = Movie.where(:FirstReleasedYear.gt => params[:since].to_i-1).sort(:DateModified.desc)
@total_results = Movie.where(:FirstReleasedYear.gt => params[:since].to_i-1).count

Цели:

  1. Использование именованных областей для повышения читабельности
  2. Не выполнятьзапрос дважды, чтобы получить счет

В вашей модели:

class Movie
  include MongoMapper::Document
  scope :released_in, :lambda{|year| where(:FirstReleasedYear.gt=>(year.to_i -1)}
end

Теперь ваша секция контроллера будет выглядеть:

@movies = Movie.released_in(params[:year]).sort(:DateModified.desc)
@total_results = @movies.count

Другие рекомендации:

  • Не беспокойтесь о params [: res], просто установите его как значения по умолчанию
  • Не проверяйте, существует ли params [: page] - will_paginate установит значение 1, если выне устанавливайте его
  • Если вы используете will_paginate, вы можете получить общее количество результатов из него, не делайте дополнительного запроса, чтобы получить счет
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...