Random record selection and pagination in rails 4 - ruby-on-rails

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.

Related

Cannot get will paginate total_entries to work, 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.

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

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 :order by date in Postgres returning incorrect order

I have a model called Story that I'm trying to order by the created_at date. Since I've hosted my app on Heroku, which uses Postgresql, I have the following in my controller:
#stories = Story.find( :all, :order => "DATE(created_at) DESC" , :limit => 11)
I would expect this to give the first 11 of my stories, ordered by the creation date, with the newest story first.
Unfortunately, this doesn't work. Most of the stories return ordered correctly, but the first two are flipped. That is, the latest story appears second in the list.
Why would this be? I have a sneaky suspicion that my results aren't ordered at all or are being ordered on the wrong column (maybe id?) and that until now it just happened to be ordered like I expected when displayed on my index page. How can I get it to order as I expect it to?
In case anyone cares, the index view is simply displaying the stories, in order. That is (HAML):
- #stories.each do |story|
= render :partial => "event", :locals => { :event => story }
EDIT
I am suspicious that the created_at is a datetime column and the DATE(...) function disregards the time portion. So it returns the elements created on the same date in a random order. Since the first two stories were created on the same day, but several hours apart, which would explain why they seem to be 'reversed'. If this is the case, what would be the correct syntax to order by both date and time?
I believe you want:
#stories = Story.find(:all, :order => "created_at DESC" , :limit => 11)
Update for Rails 3+:
#stories = Story.order(created_at: :desc).limit(11)
If you are using Rails 3, I would also encourage you to use the cool new query syntax which would be:
#stories = Story.order('created_at DESC').limit(11)
See Active Record Query Interface for more information.

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

Resources