简体   繁体   中英

select! always returns nil on heroku

Everything works fine on local. This doesn't work on Heroku:

class Ticket
  def self.how_many_today
    todays_tickets = Ticket.all.to_a.select!{ |t| t.created_at.to_date == Date.today }
    todays_tickets == nil ? 0 : todays_tickets.count
  end

  # This method is scheduled with cron
  def self.reset_todays_nr
    @todays_nr = nil
  end

  def self.set_todays_nr
    if @todays_nr.nil?
      @todays_nr = how_many_today + 1
    else
      @todays_nr += 1
    end
  end
end

Namely, playing on heroku run console reveals this inconsistency:

irb(main):023:0* set_todays_nr
=> 1
irb(main):024:0> set_todays_nr
=> 2
irb(main):025:0> set_todays_nr
=> 3
irb(main):026:0> Ticket.all.to_a.select!{ |t| t.created_at.to_date == Date.today }
=> nil
irb(main):028:0> Ticket.first.created_at
=> Sat, 20 Dec 2014 16:19:31 UTC +00:00
irb(main):029:0> Ticket.first.created_at.to_date
=> Sat, 20 Dec 2014
irb(main):030:0> Date.today
=> Sat, 20 Dec 2014
irb(main):031:0> Date.today.to_date
=> Sat, 20 Dec 2014
irb(main):032:0> Date.today == Ticket.first.created_at.to_date
=> true
irb(main):033:0> Date.today.to_date == Ticket.first.created_at.to_date
=> true
irb(main):034:0> 
irb(main):035:0* Ticket.all.to_a.select!{ |t| t.created_at.to_date == Date.today }
=> nil
irb(main):036:0> Ticket.all.map(&:created_at)
=> [Sat, 20 Dec 2014 16:19:31 UTC +00:00, Sat, 20 Dec 2014 16:21:12 UTC +00:00]
irb(main):037:0> _[0].to_date == Date.today
=> true

It looks like the condition for select! is properly parsed, manual check shows there are some elements to that condition, but select! does not return any array. Once again, this does work locally.

Database has been migrated and fixtures loaded just as on local. Although self.reset_todays_nr is scheduled with cron which might cause problems, this method is not triggered in this case, so it's rather irrelevant for the problem, but I posted it here just in case this problem is more advanced than I suppose. Could anyone help me out here, please?

That is weird indeed. Particularly because I ran some commands in my Rails console just now and array.select!{} shouldn't return nil unless the array was empty to begin with.

[1].select!{ |t| false } #=> []
[].select!{ |t| false } #=> nil

So recheck what the output of Ticket.all.to_a is.

Also, your select condition can be set simply as:

var = Ticket.select{ |t| t.created_at.to_date == Date.today }

That will select all tickets itself and then filter.

But it would be preferable to filter and count in the query rather than load up everything in memory and then do further operations for comparisons. Check this out:

Ticket.where("DATE(created_at) = DATE(?)", Date.today).count

Or change the DATE(?) part with your SQL's "get today's date" function.

Alternatively, you could:

now = DateTime.now
range = (today.beginning_of_day)..(today.end_of_day)
Ticket.where(created_at: range).count

Keep the possible discrepancy of time-zone in mind ie the created_at column might have a different time-zone than generated by DateTime.now . You'll have to check.

@Humza, thank you very much! It isn't the precise solution, but helped me to solve the case. Thanks a lot for Ticket.where("DATE(created_at) = DATE(?)", Date.today).count - I was thinking exactly the same, ie not to load the entire array and only then evaluate it, so thanks for a way of doing it. If you look at my code, you see that in set_todays_nr I purposedly place how_many_today in a condition so as to run the search at most as often as cron is scheduled to reset @todays_nr . After changing it, bug became more visible: because of the flow of the app, the new how_many_today was returning 1 - the ticket is created before this method is called. Though the mystery of strange heroku behaviour remains unsolved, I didn't sleuth further as changing the method to the below form solved the problem. Now it looks like this:

  def self.how_many_today
    Ticket.where("DATE(created_at) = DATE(?)", Date.today).count
  end

  # This method is scheduled with cron; check config/schedule.rb
  def self.reset_todays_nr
    @todays_nr = nil
  end

  def self.set_todays_nr
    if @todays_nr.nil?
      @todays_nr = how_many_today
    else
      @todays_nr += 1
    end
  end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM