Rails :order by date in Postgres returning incorrect order - ruby-on-rails

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.

Related

will_paginate reporting too many entries and pages

I'm using will_paginate to display data returned from a query that includes both a joins and a select statement. When I paginate the data the number of entries is equal to the number of entries before executing the select statement, even though paginate is being called after the query, and the query contains fewer elements than paginate reports.
#sales = Sale.joins(:line_items).where(company_id: company_id, status: ['Complete', 'Voided'], time: (midnight_1..midnight_2)).order('id DESC')
puts #sales.length
14
#sales = #sales.select('distinct sales.*')
puts #sales.length
4
#sales.paginate(:per_page => 4, :page => params[page])
puts #sales.total_entries
14
This leads to displaying links to empty pages.
It's always going to be slightly harder to paginate and join in has_many or has_and_belongs_to_many associations with will_paginate, or indeed any pagination solution.
If you don't need to query on the joined in association you can remove it. You lose the benefit of getting the associated line items in one query but you don't lose that much.
If you need to query on it, and presumably you want sales that only have line items, you'll need to pass in a :count option to the paginate call which specifies additional options that are used for the call to count how many items there are. In your case:
#sales.paginate(:per_page => 4,
:page => params[page],
:count => {:group => 'sales.id' })
Assuming that your Sale model has_many :line_items, by joining you're going to get a 'sales' entry for every related 'line_item'.

how to paginate records from multiple models? (do I need a polymorphic join?)

After quite a bit of searching, I'm still a bit lost. There are a few other similar questions out there that deal with paginating multiple models, but they are either unanswered or they pagainate each model separately.
I need to paginate all records of an Account at once.
class Account
:has_many :emails
:has_many :tasks
:has_many :notes
end
So, I'd like to find the 30 most recent "things" no matter what they are. Is this even possible with the current pagination solutions out there?
Like using some combination of eager loading and Kaminari or will_paginate?
Or, should I first set up a polymorphic join of all these things, called Items. Then paginate the most recent 30 items, then do a lookup of the associated records of those items.
And if so, I'm not really sure what that code should look like. Any suggestions?
Which way is better? (or even possible)
Rails 3.1, Ruby 1.9.2, app not in production.
with will_paginate :
#records = #do your work and fetch array of records you want to paginate ( various types )
then do the following :
current_page = params[:page] || 1
per_page = 10
#records = WillPaginate::Collection.create(current_page, per_page, records.size) do |pager|
pager.replace(#records)
end
then in your view :
<%=will_paginate #records%>
Good question... I'm not sure of a "good" solution, but you could do a hacky one in ruby:
You'd need to first fetch out the 30 latest of each type of "thing", and put them into an array, indexed by created_at, then sort that array by created_at and take the top 30.
A totally non-refactored start might be something like:
emails = Account.emails.all(:limit => 30, :order => :created_at)
tasks = Account.tasks.all(:limit => 30, :order => :created_at)
notes = Account.notes.all(:limit => 30, :order => :created_at)
thing_array = (emails + tasks + notes).map {|thing| [thing.created_at, thing] }
# sort by the first item of each array (== the date)
thing_array_sorted = thing_array.sort_by {|a,b| a[0] <=> b[0] }
# then just grab the top thirty
things_to_show = thing_array_sorted.slice(0,30)
Note: not tested, could be full of bugs... ;)
emails = account.emails
tasks = account.tasks
notes = account.notes
#records = [emails + tasks + notes].flatten.sort_by(&:updated_at).reverse
#records = WillPaginate::Collection.create(params[:page] || 1, 30, #records.size) do |pager|
pager.replace(#records)
end
Thats it... :)

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

How do I create a 'Most Recently Popular' bar for content in Ruby on Rails?

I'm a noob so please forgive if this is an easy question but I'm trying to create a 'Most Recently Popular' output for specific content on a rails project.
Right now the object I am pulling from has an attribute revision.background_title. I want to calculate popularity by finding the number of specific background_title's added over the past seven days then put them in order. For example if there are 4 background_title's named 'awesomecontent' then that would be above one that has 1 background_title named 'less awesome content'
This pulls all of them:
#revisions = Revision.find(:all, :order => "created_at desc")
Thanks.
You can use the basic ActiveRecord find method to do this. The code would end up looking something like this:
#revisions = Revision.all(
:select => "background_title, count(*) count", # Return title and count
:group => 'background_title', # Group by the title
:order => '2 desc' # Order by the count descending
)
To see the output, you could then do something like this:
#revisions.each do |revision|
puts "Revision #{revision.background_title} appears #{revision.count} times"
end
giving
Revision z appears 10 times
Revision a appears 3 times
Revision b appears 2 times
Another option would be to take a look at ActiveRecord::Calculations:
http://api.rubyonrails.org/classes/ActiveRecord/Calculations/ClassMethods.html
Calculations supports a count method that also supports the group option. However, going this route will give you back a hash containing the background_title as the key and the count as the value. Personally, find the first method more useful.

Rails, Get a random record when using :group

How do I get a random record when using :group?
#paintings = Painting.all(:group => "user_id", :order => "created_at DESC")
This gives me the latest painting for each user. Now I would like to select a random painting from each user instead of the latest. The order of the paintings should still be the same, so that the user that have been the most active will get his/her random painting displayed first.
painting150 (user1)
painting200 (user2)
painting231 (user3)
Is this possible?
Best regards.
Asbjørn Morell.
This answer is specific to Rails, but since you are using ActiveRecord, I am assuming it should be fine.
unique_paintings = []
#paintings.group_by(&:user_id).each do |user_id, paintings|
unique_paintings << paintings[rand(paintings.size-1)]
end
unique_paintings.sort_by(&:created_at)
The group_by most certainly messes up the created_at sort you did in the query, so I did a sort_by as the last step. You might want to get rid of it in the query since you'll have to do it anyway here.
#painting = #paintings[rand(#paintings.size-1)]
(or paintings.count, dont know the right method yet)
Assuming you have MySQL, you can try:
#paintings = Painting.all(:group => "user_id", :order => "RAND()")
you could do something like this but it will suffer as your number of records grow
#paintings = Painting.find(:all, :order => 'RAND()').map{ |i| i.user_id }.uniq

Resources