Rails - using `rails generate model` to specify non-nullable field type
Asked Answered
S

4

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.

Springspringboard answered 20/1, 2014 at 1:56 Comment(3)
This post (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 (github.com/rails/rails/blob/master/railties/lib/rails/…), it looks like the extra options are index, uniq and polymorphic, all which are mentioned in that post.Weldonwelfare
Yeah, agree with @mrrogers null doesn't appear to be an option in the code that handles generating the attributes for a new model.Soft
Aw. Well that was unfortunate and misleading. Thanks for the help!Springspringboard
C
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.

Charleton answered 11/4, 2016 at 23:22 Comment(1)
The column modifiers are now mentioned in Column Modifiers.Geraldo
L
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

Lovel answered 28/8, 2014 at 14:29 Comment(0)
D
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
Depraved answered 21/1, 2023 at 9:39 Comment(0)
S
-2

You can do it in your model class like this-

class TestModel < ActiveRecord::Base
  validates_presence_of :non_nullable
end
Sherrill answered 24/8, 2015 at 19:2 Comment(2)
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 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/2Garceau
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/2Garceau

© 2022 - 2024 — McMap. All rights reserved.