ac360
ac360

Reputation: 7835

Sort Array By Date Attribute, Ordered By Nearest to Current Time

I have an Array of Contact objects...

[#<Contact id: 371, full_name: "Don Hofton", birthday: "2013-11-07">,...]

And I need to order them by birthdays nearest to the current time AND remove objects from the array that have birthdays greater than 4 months away. Here is what I've got so far, but it's not working....

@contacts_with_birthday_data = Contact.where(:user_id => current_user.id).where("birthday IS NOT NULL")
        @current_time = Time.now
        @contacts_with_birthday_data.each do |c|
            c.birthday = c.birthday[0..4]
            c.birthday = Date.parse(c.birthday)
        end
        @contacts_with_birthday_data = @contacts_with_birthday_data.sort! { |a,b| b[:birthday] <=> a[:birthday] }
        @contacts_with_birthday_data = @contacts_with_birthday_data.sort! { |a| a.birthday < DateTime.now }

Upvotes: 0

Views: 2142

Answers (1)

Kyle
Kyle

Reputation: 1278

I think you can do this all with one query:

Contact \
  .where(:user_id => current_user.id)
  .where("birthday > ?", 4.months.ago)
  .order("birthday desc")

If 4.months.ago is used in a scope, make sure to wrap it in a lambda or Proc, or it will be calculated when the class is loaded and not on subsequent calls. This has bit me more than once!

Alternatively, in a non-Rails world, you could use the reject and sort_by methods on Enumerable:

contacts = [#your array of contacts]
contacts.reject { |c| c.birthday < 4.months.ago }.sort_by(&:birthday).reverse

If you haven't seen the syntax used in sort_by, that's actually equivalent to sort_by { |c| c.birthday }. That syntax tells Ruby to convert the birthday method to a Proc object, then call the Proc against each instance in your array.

Upvotes: 1

Related Questions