First I am agreed with the comments above seems like you don't really need that extra column, instead of that you could define a function within your model that returns the value when needed:
def book_status
date = booking_time&.strftime('%H:%M:%S')&.to_time&.utc
date < Time.current ? 'no_show' : 'booked'
end
Then to any instance of your book model, you can access his status like this: my_book.book_status
.
But if you really need/want that extra column there is a way to speed up the process, the problem you have in your code is that you perform n SQL queries to update each item plus if you use the update function you are also triggering all the ActiveRecord callbacks for each instance of book, a possible workaround is to use the update_all, but take into account that if you need callbacks then you need to keep it the way you have it, in any case, this is how to do it with update_all (should speed up the process):
books_ids = Booking.where(booking_status: 'booked').
where('booking_date = ?', Date.current).
select { |book_i| book_i.booking_time&.strftime('%H:%M:%S')&.to_time&.utc < Time.current }.map(&:id)
Book.where(id: books_ids).update_all(booking_status: 'no_show')
The above code will generate 2 queries instead of n one to get the books_ids that you want to update and the second one to really update those books (without trigger callbacks), in any case, I recommend the first approach instead of this.
A third option is to do it as needed like below:
def book_status
date = booking_time&.strftime('%H:%M:%S')&.to_time&.utc
if date < Time.current
self.update(booking_status: 'no_show')
booking_status
else
booking_status
end
end
if you don't want/need callbacks then use update_column instead.
EDITED:
If what you want is to parse the format this is how you can do it:
require 'time'
p Time.parse('16:20:00').utc
You can test the above snippet here.