New solution
Add an integer column named batch_id to the animals table.
class AddBatchIdToPhotos < ActiveRecord::Migration def self.up add_column :photos, :batch_id, :integer set_batch_id change_column :photos, :batch_id, :integer, :nil => false add_index :photos, :batch_id end def self.down remove_column :photos, :batch_id end def self.set_batch_id # set the batch id to existing rows # implement this end end
Now add before_create to the Photo model to set the batch identifier.
class Photo belongs_to :animal before_create :batch_photo_add after_update :batch_photo_update after_destroy :batch_photo_remove private def batch_photo_add self.batch_id = next_batch_id_for_animal(animal_id) true end def batch_photo_update return true unless animal_id_changed? batch_photo_remove(batch_id, animal_id_was) batch_photo_add end def batch_photo_remove(b_id=batch_id, a_id=animal_id) Photo.update_all("batch_id = batch_id- 1", ["animal_id = ? AND batch_id > ?", a_id, b_id]) true end def next_batch_id_for_animal(a_id) (Photo.maximum(:batch_id, :conditions => {:animal_id => a_id}) || 0) + 1 end end
Now you can get the desired result by issuing a simple paginate command
@animal_photos = Photo.paginate(:page => 1, :per_page => 10, :order => :batch_id)
How it works?
Consider that we have the data indicated below:
id Photo Description Batch Id 1 Cat_photo_1 1 2 Cat_photo_2 2 3 Dog_photo_1 1 2 Cat_photo_3 3 4 Dog_photo_2 2 5 Lion_photo_1 1 6 Cat_photo_4 4
Now, if we execute the query ordered with batch_id , we get this
# batch 1 (cat, dog, lion) Cat_photo_1 Dog_photo_1 Lion_photo_1
The distribution of the batch is not random; the animals are filled from above. The number of animals displayed per page is determined by the per_page parameter passed to the paginate method (and not the batch size).
Old decision
Have you tried this?
If you use the will_paginate gem:
# assuming you want to order by animal name animal_photos = Photo.paginate(:include => :animal, :page => 1, :order => "animals.name") animal_photos.each do |animal_photo| puts animal_photo.file_name puts animal_photo.animal.name end