1
votes

I have a custom model (not mapping by any tables under database). This custom model is just the result of union many other table's data. I want to use kaminari for paginate this.

for example:

def index
   @custom_models = find_all_items # result is an array
   render
end

And then i paginate those items on view:

  = paginate @custom_models

When I run this, I meet exception:

undefined method `total_pages' for Array:0x007fb4dde63c70

My question is: how can I use Kaminari for custom model file.

@Edit I can use Kaminari now, just use this line:

  @custom_models = Kaminari.paginate_array(@custom_models)
                  .page(params[:page]).per(params[:per_page])

But now I meet problem: because this is custom model, I'm using custom query. I use raw sql query and paginate by myself using offset and limit keyword.

For example I return 25 records, and default of Kaminari is displaying 25 records each pages so I can only see 1 page. I can make query for returning total necessary records (for example 1000 records) but I don't know how to make Kaminari understand this and show me enough pages.

thanks

1

1 Answers

2
votes

To start with, I presume that fetch_all_items.is an array.

You could insert pagination at the controller, though this means that database will load the entire collection and then filter the results, using the array pagination method.

@custom_models =  Kaminari.paginate_array(fetch_all_items).page(params[:page])

But I think the best way is to control the offset/limit (pagination) within your model. To show you how to do that, it would be helpful to have the code that produces fetch_all_items.

You can find more in Kaminari wiki page

update - hacky!!!

So, now we are looking at a different thing. Not 100% certain this will be enough, but this should be the way to go, if you want to go radical and paginate in the model:

In your model, you should have something like this (which you will have, of course, to adjust to your needs):

def fetch_all_items(page, per_page)
    offset = page*per_page
    items = SomeSqlMethod("select .... offset #{offset}, limit #{per_page}") # your sql statement
    total_rows = SomeSqlMethod("select count(..) ....") # to get the total number of records
    total_pages = (total_rows.to_f / per_page).ceil # to get the total pages
    items.class.module_eval { 
        attr_accessor :total_pages, :current_page
    } # to add some variables to make Kaminari happy
    items.total_pages = total_pages
    items.current_page = page
    items # to return this
end

In your controller, then, you should have:

@custom_model = fetch_all_items(params[:page].to_i, params[:per_page].to_i) # cast to integer to avoid injections and misfunctions

Apart from :total_pages, :current_page, Kaminari might also want some other variables, like next_page, prev_page, I don't know. Use the same block, items.class.module_eval, to inject them.