Cannot get will paginate total_entries to work, rails - ruby-on-rails

The problem is I would like to limit the number of results to say 30, so I put in
controller
#users = User.user_search(params[:name], params[:gender]).paginate(page: params[:page], per_page: 20, total_entries: 30)
render 'user_results'
Say I only get 1 or 2 results back, I will still get pagination for two pages. ie will paginate seems to get the result of how many times the total_entries will divide in to the per_page value. So if I set per_page: 20, total_entries: 110 it will give me six links adding the extra 10 as a page also.
My User.user_search method in the User model is
def self.user_search(a, b)
users = User.all
users = User.where('LOWER (name) LIKE LOWER(?)', "%#{a}%") if a.present?
users = users.where('LOWER (gender) LIKE LOWER(?)', "%#{b}%") if b.present?
return users
end
I have seen people with problems about using join models and will paginate but I am just using simple single model paginate. Searched lots about this. From my knowledge will paginate is passing on total_pages method to view and rendering this results. Is there a way to set a limit to my results?

The total_entries option just is a shortcut to avoid will_paginate querying the count for the results. So if you really want to limit the number of results shown in will paginate, but not mess up with the pagination results when there are only a few results you can do something like this:
total_records = User.user_search(params[:name], params[:gender]).count
total_entries = total_records > 30 ? 30 : total_records
#users = User.user_search(params[:name], params[:gender]).paginate(page: params[:page], per_page: 20, total_entries: total_entries)
render 'user_results'
You might think that this adds an additional query, but will_paginate was still going to do the count query in order to do its logic, here we're just overriding the total_entries by setting a max number of records to show.
Note however that by doing this you'll still get more records in the last page (if the result of dividing the total_records between the pages is not exact), or it might even be possible to ask for a higher page number and still get the 'hidden' results.
If you really need to avoid showing results over a certain number, you'll be forced to use a subquery like this:
#users = User.where(id: User.user_search(params[:name], params[:gender]).limit(30).map(&:id)).paginate(page: params[:page], per_page: 20)
However, this might cause issues if instead of 30 you use a very large number.
Previously I was suggesting using ActiveRecord::QueryMethods.limit, on the search result, but will_paginate overwrites this logic when paginating.

Related

Getting the records count at current page in rails with will_paginate gem

I need to get the number of records at current page. I am using will_paginate gem for pagination. When trying to get the collection.count I am getting total number of records?
#collection = User.paginate(page: params[:page], per_page: 10).all
when I try to get the count of collection it returns the total entries. How to get the records count of a current table
If u need total entries in entire query:
#collection.total_entries
If u need entry count in current page:
#collection.size
Meanwhile u dont need to call last .all scope in pagination. Just try:
#collection = User.paginate(page: params[:page], per_page: 10)
Try:
#collection.total_entries
If you want the current number of items on current page the you should do #collection.size.
If you want the total number of items the you should do #collection.count
You can try setting the page to last page to see the difference.
Also use
#collection = User.paginate(page: params[:page], per_page: 10)
as the paginate will return only the corresponding set, configured with page and per_page params.
I also wanted to find the number of records for the current page. But #surveys.size is not returning the number of records in the current page, instead, it's returning the number of records if the current page had been filled.
#collection.length
is the one that provides the needed result.
#collection.entries
is giving you the entries on the current page. If you for example paginate 25 entries, it will show the 25 entries in an Array class

Random record selection and pagination in rails 4

I need to select random 5 records in sqlite3 and paginate them.
def test
add_breadcrumb "Age Test", ages_test_url
#posts = Age.limit(5).order('RANDOM()')
#posts = #posts.page(params[:page]).per_page(2)
end
The above code displays all the record but I need only 5.
Try alternative syntax:
Age.paginate(:page => params[:page], :per_page => 2).order('RANDOM()').limit(5)
However, what is the point of paginating a random set of elements. Every time a user visits the first "page" s/he will see elements other than s/he saw the first. The idea of paginating a randomized elements doesn't seem logical.

Rails 4 - will_paginate: go to last page by default

I have a conversation and messages that belong to a conversation. It would make sense to send users directly to the last page of conversation with the latest messages.
Using .order('created_at DESC') on messages would not be intuitive to users, because it would put latest messages on top of the first page, which is not how most conversations/forums threads work.
Now I have something like this:
#messages = Message.where(conversation_id: params[:id]).paginate(:page => params[:page], :per_page => 15)
will_paginate supports a page option, so you could always give it the latest page as an argument. Ex:
messages.paginate(page: latest_page)
So you just need to implement the latest_page method, counting the number of records and dividing by the number of records per page.
Edit:
Something like this:
def latest_page
messages = Message.where(conversation_id: params[:id])
messages.count / 15
end

Rails paginate array items one-by-one instead of page-by-page

I have a group of assets, let's call them "practitioners".
I'm displaying these practitioners in the header of a calendar interface.
There are 7 columns to the calendar. 7 columns = 7 practitioners per view/page.
Right now:
if the first page shows you practitioners 1-7, when you go the next page you will see practitioners 8-15, next page 16-23, etc. etc.
i am wondering how to page the practitioners so that if the first page shows you practitioners 1-7, the next page will show you practitioners 2-8, then 3-9, etc. etc.
i would greatly appreciate any help you can offer.
here is the rails code i am working with.
best regards,
harris novick
# get the default sort order
sort_order = RESOURCE_SORT_ORDER
# if we've been given asset ids, start our list with them
unless params[:asset_ids].blank?
params[:asset_ids] = params[:asset_ids].values unless params[:asset_ids].is_a?(Array)
sort_order = "#{params[:asset_ids].collect{|id| "service_provider_resources.id = #{id} DESC"}.join(",")}, #{sort_order}"
end
#asset_set = #provider.active_resources(:include => {:active_services => :latest_approved_version}).paginate(
:per_page => RESOURCES_IN_DAY_VIEW,
:page => params[:page],
:order => sort_order
)
Good question! I guess this is one thing WillPaginate doesn't really account for. I'm going by looking at WillPaginate's code here, but I didn't actually test this solution. If you intend to try it, let me know if it worked for you.
The logic is well separated, in WillPaginate::Collection. You need to change the behavior of the offset and total_entries= methods. You can do this with subclassing, but that means you can no longer use the special paginate finder, unfortunately. (It has WillPaginate::Collection hardcoded.)
You could have something like the following, perhaps in your lib/:
class SlidingWindowCollection < WillPaginate::Collection
def offset
current_page - 1
end
def total_entries=(number)
#total_entries = number.to_i
#total_pages = [#total_entries - per_page, 1].max
end
end
And then, your example code would look like:
#asset_set_scope = #provider.active_resources(:include => {:active_services => :latest_approved_version})
#asset_set = SlidingWindowCollection.create(params[:page], RESOURCES_IN_DAY_VIEW, #asset_set_scope.count) do |pager|
pager.replace(#asset_set_scope.all(:offset => pager.offset, :limit => pager.per_page, :order => sort_order))
end
Usage is a bit more complicated, I suppose. All the extra stuff is normally taken care of by the special finder paginate, such as figuring out the total number of entries and selecting the right entries. I suppose you could create a helper if it's something you intend to do often.
I think LIMIT will work for you. I don't know using pagination but you can try following
LIMIT params[:page], 7
Where params[:page] is number of the page,
So for page 1 it will show 7 rows from 1 i.e. 1-7
Smilarly,
for page 2 it will show 7 rows from 2 i.e. 2-8

Using will_paginate with multiple models (Rails)

Pretty sure that I'm missing something really simple here:
I'm trying to display a series of pages that contain instances of two different models - Profiles and Groups. I need them ordering by their name attribute. I could select all of the instances for each model, then sort and paginate them, but this feels sloppy and inefficient.
I'm using mislav-will_paginate, and was wondering if there is any better way of achieving this? Something like:
[Profile, Group].paginate(...)
would be ideal!
Good question, I ran into the same problem a couple of times. Each time, I ended it up by writing my own sql query based on sql unions (it works fine with sqlite and mysql). Then, you may use will paginate by passing the results (http://www.pathf.com/blogs/2008/06/how-to-use-will_paginate-with-non-activerecord-collectionarray/). Do not forget to perform the query to count all the rows.
Some lines of code (not tested)
my_query = "(select posts.title from posts) UNIONS (select profiles.name from profiles)"
total_entries = ActiveRecord::Base.connection.execute("select count(*) as count from (#{my_query})").first['count'].to_i
results = ActiveRecord::Base.connection.select_rows("select * from (#{my_query}) limit #{limit} offset #{offset}")
Is it overkilled ? Maybe but you've got the minimal number of queries and results are consistent.
Hope it helps.
Note: If you get the offset value from a http param, you should use sanitize_sql_for_conditions (ie: sql injection ....)
You can get close doing something like:
#profiles, #groups = [Profile, Group].map do |clazz|
clazz.paginate(:page => params[clazz.to_s.downcase + "_page"], :order => 'name')
end
That will then paginate using page parameters profile_page and group_page. You can get the will_paginate call in the view to use the correct page using:
<%= will_paginate #profiles, :page_param => 'profile_page' %>
....
<%= will_paginate #groups, :page_param => 'group_page' %>
Still, I'm not sure there's a huge benefit over setting up #groups and #profiles individually.
in my last project i stuck into a problem, i had to paginate multiple models with single pagination in my search functionality.
it should work in a way that the first model should appear first when the results of the first model a second model should continue the results and the third and so on as one single search feed, just like facebook feeds.
this is the function i created to do this functionality
def multi_paginate(models, page, per_page)
WillPaginate::Collection.create(page, per_page) do |pager|
# set total entries
pager.total_entries = 0
counts = [0]
offsets = []
for model in models
pager.total_entries += model.count
counts << model.count
offset = pager.offset-(offsets[-1] || 0)
offset = offset>model.count ? model.count : offset
offsets << (offset<0 ? 0 : offset)
end
result = []
for i in 0...models.count
result += models[i].limit(pager.per_page-result.length).offset(offsets[i]).to_a
end
pager.replace(result)
end
end
try it and let me know if you have any problem with it, i also posted it as an issue to will_paginate repository, if everyone confirmed that it works correctly i'll fork and commit it to the library.
https://github.com/mislav/will_paginate/issues/351
Have you tried displaying two different sets of results with their own paginators and update them via AJAX? It is not exactly what you want, but the result is similar.

Resources