Нахождение следующего объекта модели ActiveRecord в базе данных с использованием заданного объекта - PullRequest
4 голосов
/ 13 января 2010

У меня есть объект модели ActiveRecord @gallery, который представляет строку в таблице MYSQL Galleries. Могу ли я попросить @gallery дать мне идентификатор следующего объекта галереи в таблице?

Очевидный способ сделать это:

@galleries = Gallery.find(:all)
index = @galleries.index(@gallery)

@nextgallery = @galleries[index+1]

но тогда я должен это сделать nilsafe, и я без необходимости делаю еще один вызов БД, чтобы получить все записи. Есть другой выход?

Ответы [ 5 ]

8 голосов
/ 16 января 2012

Я был в подобной ситуации, и в итоге я нашел пару решений, использующих Rails 3.1.3, с методами класса или областью действия (named_scope в Rails 2.x). Этот подход будет работать даже с непоследовательными идентификаторами.

Пример методов класса с использованием модели Post:

def next
  Post.where("posts.id > ?", self.id).order("posts.id ASC").limit(1)
end

def previous
  Post.where("posts.id < ?", self.id).order("posts.id DESC").limit(1)
end

Это может быть использовано как:

post = Post.find(5)

next_post = post.next
 => [#<Post id: 6, ...]

previous_post = post.previous
 => [#<Post id: 4, ...]

А для областей применения лямбда должна выглядеть примерно так:

  scope :next, lambda { |i| {:conditions => ["#{self.table_name}.id > ?", i.id], :order => "#{self.table_name}.id ASC", :limit => 1} }
  scope :previous, lambda { |i| {:conditions => ["#{self.table_name}.id < ?", i.id], :order => "#{self.table_name}.id DESC", :limit => 1} }
2 голосов
/ 13 января 2010

Прежде всего вы должны определить некоторые критерии для определения порядка ваших галерей. В MySQL, когда вы будете делать

 SELECT * FROM galeries

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

 @nextgallery = Gallery.find(
                   :first, 
                   :order => "created_at ASC", 
                   :conditions => "created_at > #{@gallery.created_at}"
                 )

В этом примере вы должны быть осторожны с @gallery.created_at, потому что Rails хранит в базе данных время в формате времени GMT +0, но в @gallery.created_at это с вашей локальной конфигурацией (например, +2 ч). Чтобы изменить его, используйте: @gallery.created_at.gmtime.to_s

2 голосов
/ 13 января 2010

Вы действительно уверены, что делаете второй вызов БД? Если так, это действительно имеет значение? Это глубоко в 4х вложенном цикле, где каждый вызов имеет значение?

Если нет, то предоптимизация может быть вашим провалом. AR: B выполняет много операций кэширования, а iirc find (: all) возвращает массив или Hash, поэтому индекс +1 должен быть в порядке

0 голосов
/ 13 января 2010

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

Однако вы можете попасть в базу данных только один раз, если сделаете что-то вроде

@galleries = Gallery.find(:all)
@gallery = @galleries.detect{|g| g.id == params[:gallery_id]}
index = @galleries.index(@gallery)
@nextgallery = @galleries[index+1]

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

0 голосов
/ 13 января 2010

Код, который вы представили, полезен. Метод find(:all) по умолчанию извлекает все записи таблицы галерей следующим образом (это можно увидеть при запуске WEBrick в режиме разработки)

SELECT * FROM galleries

Результаты этого запроса кэшируются и используются повторно каждый раз, когда вы обращаетесь к @galaeries, это также видно (при запуске WEBrick), поскольку другие вызовы базы данных не выполняются.

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