10

Some time ago we upgraded our application to Rails 4 and switched to JRuby.

Before that change migrations created the default timestamps as NOT NULL. After that change the NOT NULL is missing.

We create these timestamps (created_at, updated_at) as follows:

class Model < ActiveRecord::Migration
  def change
    create_table :model do |t|
      t.belongs_to :user, :null => false

      t.text :content

      t.timestamps
    end
  end
end

The important parts of our application are:

  • ruby '1.9.3', :engine => 'jruby', :engine_version => '1.7.9'
  • gem 'rails', '4.0.2'
  • gem 'activerecord-jdbcpostgresql-adapter', '1.3.4'
  • postgresql: stable 9.3.1

Do you have any idea what might cause the problem and how we can change the default generation back to NOT NULL?

maerzbow
  • 185
  • 1
  • 2
  • 9

2 Answers2

8

I don't know if it is documented anywhere but the source indicates that you can pass the usual column options to t.timestamps:

# Appends <tt>:datetime</tt> columns <tt>:created_at</tt> and
# <tt>:updated_at</tt> to the table.
def timestamps(*args)
  options = args.extract_options!
  column(:created_at, :datetime, options)
  column(:updated_at, :datetime, options)
end

so you can say:

create_table :model do |t|
  #...
  t.timestamps :null => false
end

and your columns should be NOT NULL.

If you look at the 3.2 version, you'll see what's happened:

def timestamps(*args)
  options = { :null => false }.merge(args.extract_options!)
  #...
end

so 3.2 creates the timestamp columns as NOT NULL by default but 4.0 does not.

mu is too short
  • 426,620
  • 70
  • 833
  • 800
  • 1
    Great, thank you. That's it. I am wondering that no one else has a problem with this change. It really has a big impact what to expect from running your migrations. – maerzbow Jan 07 '14 at 09:28
  • The Rails default is `:null => true` (which matches SQL's foolish default) and I get the impression that the `:null => false` on `t.timestamps` wasn't consistently handled. Presumably they opted to make it consistent by making it match the rest of Rails. A lot of AR's interaction with relational databases mystifies me to be honest. – mu is too short Jan 07 '14 at 19:06
  • 3
    FWIW, it looks like timestamps have `null: false` by default was only true in the 3.2 line. It was added in [rails/rails#3334](https://github.com/rails/rails/pull/3334) and then [reverted](https://github.com/rails/rails/commit/fcef728) ahead of 4.0. – Rhett Sutphin Apr 10 '14 at 15:26
0

This issue infuriated me because I had an old app that had been on Rails 3.2 for a couple years, with a large number of usages of this method, hence this initializer:

# Force t.timestamps to always be null: false
module ActiveRecord
  module ConnectionAdapters
    class TableDefinition

      def timestamps_with_non_nullable(*args)
        options = args.extract_options!
        options.merge!(null: false)
        timestamps_without_non_nullable(*args, options)
      end
      alias_method_chain :timestamps, :non_nullable

    end
  end
end
aec
  • 833
  • 1
  • 9
  • 18