Skip to content

Commit 2f92b1c

Browse files
authored
Add not-null modifier to migrations (rails#52327)
* Add migration type modifier for not-null attributes * Explain change * Appease rubocop by using AS helper * Deal with nil
1 parent 26575aa commit 2f92b1c

File tree

3 files changed

+58
-8
lines changed

3 files changed

+58
-8
lines changed

railties/CHANGELOG.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,25 @@
1+
* Add not-null type modifier to migration attributes.
2+
3+
4+
# Generating with...
5+
bin/rails generate migration CreateUsers email_address:string!:uniq password_digest:string!
6+
7+
# Produces:
8+
class CreateUsers < ActiveRecord::Migration[8.0]
9+
def change
10+
create_table :users do |t|
11+
t.string :email_address, null: false
12+
t.string :password_digest, null: false
13+
14+
t.timestamps
15+
end
16+
add_index :users, :email_address, unique: true
17+
end
18+
end
19+
20+
21+
*DHH*
22+
123
* Add script folder and generator
224

325
Add a new script default folder to hold your one-off or general purpose

railties/lib/rails/generators/generated_attribute.rb

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# frozen_string_literal: true
22

33
require "active_support/time"
4+
require "active_support/core_ext/string/starts_ends_with"
45

56
module Rails
67
module Generators
@@ -89,20 +90,24 @@ def reference?(type)
8990
def parse_type_and_options(type)
9091
case type
9192
when /(text|binary)\{([a-z]+)\}/
92-
return $1, size: $2.to_sym
93+
parsed_type, parsed_options = $1, { size: $2.to_sym }
9394
when /(string|text|binary|integer)\{(\d+)\}/
94-
return $1, limit: $2.to_i
95+
parsed_type, parsed_options = $1, { limit: $2.to_i }
9596
when /decimal\{(\d+)[,.-](\d+)\}/
96-
return :decimal, precision: $1.to_i, scale: $2.to_i
97+
parsed_type, parsed_options = :decimal, { precision: $1.to_i, scale: $2.to_i }
9798
when /(references|belongs_to)\{(.+)\}/
98-
type = $1
99+
parsed_type = $1
99100
provided_options = $2.split(/[,.-]/)
100-
options = Hash[provided_options.map { |opt| [opt.to_sym, true] }]
101-
102-
return type, options
101+
parsed_options = Hash[provided_options.map { |opt| [opt.to_sym, true] }]
103102
else
104-
return type, {}
103+
parsed_type, parsed_options = type&.remove("!"), {}
104+
end
105+
106+
if type&.ends_with?("!")
107+
parsed_options[:null] = false
105108
end
109+
110+
return parsed_type, parsed_options
106111
end
107112
end
108113

railties/test/generators/migration_generator_test.rb

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,29 @@ def test_remove_migration_with_virtual_attributes
455455
end
456456
end
457457

458+
def test_create_table_migration_with_required_attributes
459+
run_generator ["create_books", "title:string!", "content:text!"]
460+
assert_migration "db/migrate/create_books.rb" do |content|
461+
assert_method :change, content do |change|
462+
assert_match(/create_table :books/, change)
463+
assert_match(/ t\.string :title, null: false/, change)
464+
assert_match(/ t\.text :content, null: false/, change)
465+
end
466+
end
467+
end
468+
469+
def test_add_migration_with_required_attributes
470+
migration = "add_title_body_to_posts"
471+
run_generator [migration, "title:string!", "body:text!"]
472+
473+
assert_migration "db/migrate/#{migration}.rb" do |content|
474+
assert_method :change, content do |change|
475+
assert_match(/add_column :posts, :title, :string, null: false/, change)
476+
assert_match(/add_column :posts, :body, :text, null: false/, change)
477+
end
478+
end
479+
end
480+
458481
private
459482
def with_singular_table_name
460483
old_state = ActiveRecord::Base.pluralize_table_names

0 commit comments

Comments
 (0)