How About A Date? Dealing With Datetime Columns
DATETIME_SELECT
More than likely, you will be dealing with datetime columns in the context of a form.
As such, the best way is to use Rails' own form.datetime_select method, like this:
More than likely, you will be dealing with datetime columns in the context of a form.
As such, the best way is to use Rails' own form.datetime_select method, like this:
<%= form.datetime_select :published_at, include_blank: true %>
The include_blank option is, um, optional, but I used it here because I deliberately did not set a default on this column. That way, a blog post remains in what amounts to a draft state until it is scheduled with a published_at value.
With the above in place, you will see something like this:
Without "include_blank: true", that first select field would automatically be set to a year sometime in the past. In 2024, that ends up being 2019:
For our use case, having dates in the past is pretty useless. We either want to publish our blog posts immediately, or at some future time.
The good news is that form.datetime_select allows you to set the starting year. You do so by adding a start_year option, like this:
<%= form.datetime_select :published_at, include_blank: true, start_year: Time.now.year %>
In fact, you'll want to use something like this, so that the start_year only applies to new records, in case you ever come back to edit an older post:
<% if form.object.persisted? %> <%= form.datetime_select :published_at, include_blank: true %> <% else %> <%= form.datetime_select :published_at, include_blank: true, start_year: Time.now.year %> <% end %>
ADDING A DEFAULT
Another option is if you want to always have this column default to the current date and time, and thus be live instantly whenever you decide not to set a future time.
You can do that with a migration:
class AddDefaultPublishedAtToBlogPosts < ActiveRecord::Migration[7.0] def up change_column_default :blog_posts, :published_at, -> { 'CURRENT_TIMESTAMP' } end def down change_column_default :blog_posts, :published_at, from: -> { 'CURRENT_TIMESTAMP' }, to: nil end end
The CURRENT_TIMESTAMP lambda is what does the magic here, speaking directly to the database at the time the record is created.
You might be tempted to set this to something like Time.now.
DON'T DO IT!
No, really. I mean, it's not going to break anything, but you'll see some other weird issues since Time.now always generates a different value. Of course, CURRENT_TIMESTAMP does, too, but in a way that Postgres understands. Did I mention I'm using Postgres? I'm using Postgres. If you're using something else, your mileage may vary with this method, since I haven't tested it in anything else.