How to create “Upcoming birthdays” module in Rails?

后端 未结 9 2186
栀梦
栀梦 2020-12-29 17:46

I have a table \"users\" with a column \"date_of_birth\" (DATE format with day, month, year). In frontend I need to list 5 upcoming birthdays.

Spent ages trying to w

相关标签:
9条回答
  • 2020-12-29 18:04

    Thanks to this post in my rails 3 app i use:

     u = User.where("strftime('%m%d', date_of_birth) = ?", Date.today.strftime('%m%d'))
    

    Update:

    To use this with Postgresql:

    u = User.where("extract(month from date_of_birth) = ? AND extract(day from date_of_birth) = ?", Date.today.strftime('%m'), Date.today.strftime('%d'))
    
    0 讨论(0)
  • 2020-12-29 18:04

    Here's how I find today's birthdays:

    User.find_by_sql("select * from users where date_format(date_of_birth, '%m%d') = date_format(now(), '%m%d')")

    I run this once a day. It takes less than a second from about 100,000 rows. (It doesn't properly handle people born on Feb 29th.)

    0 讨论(0)
  • 2020-12-29 18:09

    I'd have a before_save callback that calculates and stores to the day of the year in the database alongside the birthday.

    You then have a simple query to pull back the next 5 birthdays. Make sure to handle the boundary condition where you are at the end of the year (I'd check if you don't get 5 results in RoR and then run a new query for the 1st Jan to get some extra birthdays to make it up to 5).

    You will probably want to cache the results so you don't keep rerunning the query if it is on a common page.

    0 讨论(0)
  • 2020-12-29 18:11

    I too thought that day of year would be the way to go, but the fact that it is different for most of the year depending on whether it is a leap year or not makes it tricky.

    Better is to store the month and day as a string: d.strftime('%m%d'). You can then use that as (possibly) two queries (assuming new column is 'monthday')

    First,

    User.find(:all,
              :condition => [:monthday > Date.now.strftime('%m%d')],
              :select => "DISTINCT monthday",
              :limit => 5)
    

    If you don't get 5 results, do the query again, except use "0101" instead of the date calculation and lower the limit.

    This gets you a list of monthday strings that you then have to turn back into dates.

    If you want users, remove the :select line.

    0 讨论(0)
  • 2020-12-29 18:18

    It's better to use SQL to make this query:

    next_month = (Date.today + 1.month).month # or use any other integer
    
    users_having_birhtday_next_month = 
      User.where("EXTRACT(MONTH FROM date_of_birth) = ?", next_month)
    

    Note: EXTRACT - PostgreSQL function

    0 讨论(0)
  • 2020-12-29 18:18

    If your database is mysql, the following is probably faster:

    scope :birthday_next_week, (lambda {
      where('DayOfYear(date_of_birth) >= 7
         And DayOfYear(date_of_birth) - DayOfYear(curdate()) Between 0 and 6) Or
       (MOD(YEAR(curDate()),4) = 0) And MOD(YEAR(curDate()),100) != 0
        And (DayOfYear(date_of_birth) + 366 - DayOfYear(curdate())) % 366 < 7) Or
         (DayOfYear(date_of_birth) + 365 - DayOfYear(curdate())) % 365 < 7').
        order('DATE_FORMAT( date_of_birth, "%m-%d" ) ASC')
    })
    

    Edit: changed to make it work in the week before new years eve / leap years.

    0 讨论(0)
提交回复
热议问题