11

According to the rails documentation

http://guides.rubyonrails.org/migrations.html

2.3 Supported Type Modifiers says it should be possible to modify fields to allow or disallow NULL in the column, and that it's possible to do this on the terminal

This is what I want to appear in the migration file

class CreateTestModels < ActiveRecord::Migration
  def change
    create_table :test_models do |t|
      t.string:non_nullable, :null => false

      t.timestamps
    end
  end
end

On the terminal, I've tried

rails generate model TestModel non_nullable:string{null}
rails generate model TestModel 'non_nullable:string{null: false}'

I can't think of any other way to express it

Note: I already know you can go into the migration file and manually add it. That's not what I'm looking for.

Andrew Grimm
  • 78,473
  • 57
  • 200
  • 338
Alan
  • 297
  • 3
  • 12
  • 5
    This post (http://railsguides.net/2013/06/29/advanced-rails-model-generators/) has a lot of nice stuff about generator options. He doesn't mention setting the null value, sadly. And if you dig into the rails source code (https://github.com/rails/rails/blob/master/railties/lib/rails/generators/generated_attribute.rb), it looks like the *extra* options are `index`, `uniq` and `polymorphic`, all which are mentioned in that post. – mr rogers Jan 20 '14 at 02:18
  • Yeah, agree with @mrrogers null doesn't appear to be an option in the code that handles generating the attributes for a new model. – Shadwell Jan 20 '14 at 02:23
  • 1
    Aw. Well that was unfortunate and misleading. Thanks for the help! – Alan Jan 20 '14 at 02:33

4 Answers4

3

The docs mention that

Some commonly used type modifiers can be passed directly on the command line. They are enclosed by curly braces and follow the field type

but they don't give details about which "commonly used" modifiers willl work.

As pointed out by mr rogers there are only three supported options:

  • length for string/text/binary/integer (name:string{255})
  • precision,scale for decimal (dollar_fragment:decimal{3,2})
  • polymorphic for references/belongs_to (agent:references{polymorphic})

As mentioned by user2903934 it may be possible to make this work from the command line as a hack.

NOTE: this is a hack. i wouldn't recommend doing this but it does answer your question.

rails generate model TestModel 'non_nullable, null => false:string'

It looks like it splits on the first colon, so we can use a hashrocket syntax to sneak options in there. This yields:

class CreateTestModels < ActiveRecord::Migration
  def change
    create_table :test_models do |t|
      t.string :non_nullable, null => false

      t.timestamps
    end
  end
end

That obviously isn't officially supported, it just happens to work.

devpuppy
  • 822
  • 9
  • 8
  • The column modifiers are now mentioned in [Column Modifiers](http://edgeguides.rubyonrails.org/active_record_migrations.html#column-modifiers). – Sushil Aug 17 '16 at 06:46
0

The closest I can get to your solution is something like this:

rails generate model TestModel non_nullable,null:string

I couldn't work out what comes after the , but that should give you a start

Andrew Grimm
  • 78,473
  • 57
  • 200
  • 338
user2903934
  • 59
  • 1
  • 11
0

You can open editor by utilising https://github.com/rails/rails/pull/38870 (available for Rails versions > 6.1.0)

To create migration with null: false from command line, first you need to enable EDITOR_FOR_GENERATOR

# config/application.rb
    # https://github.com/rails/rails/pull/38870#issuecomment-609018444
    config.generators.after_generate do |files|
      if ENV["EDITOR_FOR_GENERATOR"]
        files.each do |file|
          system("#{ENV["EDITOR_FOR_GENERATOR"]} #{file}")
        end
      end
    end

Than use sed to append to specific columns.

For example that you want to create a model with jti and exp columns with not null constrains and add index to them (index is supported on command line using :index). We need to match line t.string :jti and append to it so end result is t.string :jti, null: false

Here is command I use:

# rails g model CreateJwtDenylist jti:index exp:datetime:index

# replace jti and exp with your column names
EDITOR_FOR_GENERATOR='sed -i "" -r -e "/^[[:space:]]*t.*(jti|exp)$/ s/$/, null: false/"' rails g model CreateJwtDenylist jti:index exp:datetime:index

This works both for rails g migration and rails g model.

Resulting migration is

# db/migrate/20230121091319_create_jwt_denylist.rb
class CreateJwtDenylist < ActiveRecord::Migration[7.0]
  def change
    create_table :jwt_denylists do |t|
      t.string :jti, null: false
      t.datetime :exp, null: false

      t.timestamps
    end
    add_index :jwt_denylists, :jti
    add_index :jwt_denylists, :exp
  end
end
duleorlovic
  • 432
  • 4
  • 15
-2

You can do it in your model class like this-

class TestModel < ActiveRecord::Base
  validates_presence_of :non_nullable
end
pyron_orion
  • 545
  • 5
  • 18
  • It would be more performant to handle this at the schema level; sadly, even as of Rails 7.0.1, there does not appear to be generator-CLI support for `null: false`. That's what editing the migration before running it is for.That manual editing also defeats attempts at automation. We have a [template](https://edgeguides.rubyonrails.org/rails_application_templates.html) that generates the (relatively) bare app. We also have (a subset of each app's) database tables that always have the same fields, including non-nullable fields. 1/2 – Jeff Dickey Jan 10 '22 at 06:10
  • it would be Very Handy if we could automate setting those up with CLI model generation rather than generating the migration (without `null: false`) and then replacing lines in the migration using automation. See where I'm trying to go with this? (And yes, I know I'm commenting on an _ancient_ answer. Isn't that SO in a nutshell?) 2/2 – Jeff Dickey Jan 10 '22 at 06:17