DivideByHero
DivideByHero

Reputation: 20335

How to save datetime fields with validations? [Ruby / Rails 4 / Postgres]

Ok, so I need help with datetime database fields.

Let's say my table is called "events" and has a datetime field named "starts_at". I have confirmed this in my schema.rb file (technically I am using Postgres):

create_table "events", force: true do |t|
  t.string   "name",                        null: false
  t.datetime "created_at"
  t.datetime "updated_at"
  t.datetime "starts_at
  ...
end

In my event.rb model, I have a validation to make sure the starts_at datetime is set:

attr_accessor :starts_at
validates :starts_at, presence: true

I'm testing this via the rails console and I can't get it to save any value, let alone create any validation errors. What gives? For example:

e = Event.new
e.name = 'Post 1'
e.starts_at = DateTime.now.utc
e.save

It appears to save, but there is no validation error, no mention of "starts_at" in the displayed query. Starts_at is nil in the database. My schema defines it as a "datetime" field but it ignores my DateTime variable. I thought, ok, maybe it is technically a string field and rails doesn't auto-convert for me:

e = Event.new
e.name = 'Post 2'
e.starts_at = DateTime.now.utc.to_s
e.save

Same thing. Thinking that the resulting format is being rejected in Postgres, I try this:

e = Event.new
e.name = 'Post 3'
e.starts_at = DateTime.now.utc.strftime('%Y-%m-%d %H:%M:%S')
e.save

I thought it might work with:

e.starts_at = Time.now.utc

Or, for Unix timestamp integer style:

e.starts_at = DateTime.now.utc.to_i

Nope, nothing works. What am I doing wrong?

Some questions:

  1. How do I get a datetime field to accept my input -- any input! -- and actually save it to the database? Do I need to know which time format is ultimately being used by the database type (Postgres, MySQL, etc) and adjust accordingly? i.e. How does database agnosticism apply?

  2. How can I update my validation to check if the database actually accepted my input? It's counterintuitive that I am validating the presence of my starts_at variable, but it will in fact allow it to be saved as nil.

Upvotes: 0

Views: 1236

Answers (2)

spickermann
spickermann

Reputation: 106882

Remove this line:

attr_accessor :starts_at

It masks the original setter that comes with Rails and sets a instance variable instead.

If there is a column (like the starts_at column here) in the database then there is no need to define a getter oder setter method on your own.

Upvotes: 1

Raj
Raj

Reputation: 22926

Probable issue is that Rails is protecting you from mass assignment of variables.

You need to remove attr_accessor on that columns that are saved as NULL in the database.

Explained really well here - What is attr_accessor in Ruby? and Difference between attr_accessor and attr_accessible

Upvotes: 0

Related Questions