Skip to content

Commit 1e4f28b

Browse files
authored
Merge pull request #1266 from ccutrer/inspect_change_table_for_not_null_column
Rails/NotNullColumn: Inspect change_table calls for offenses
2 parents 7e691de + 5fcfda4 commit 1e4f28b

File tree

3 files changed

+193
-6
lines changed

3 files changed

+193
-6
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* [#1266](https://github.com/rubocop/rubocop-rails/pull/1266): Check `change_table` calls for offenses. ([@ccutrer][])

lib/rubocop/cop/rails/not_null_column.rb

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,16 @@ module Rails
1515
# # bad
1616
# add_column :users, :name, :string, null: false
1717
# add_reference :products, :category, null: false
18+
# change_table :users do |t|
19+
# t.string :name, null: false
20+
# end
1821
#
1922
# # good
2023
# add_column :users, :name, :string, null: true
2124
# add_column :users, :name, :string, null: false, default: ''
25+
# change_table :users do |t|
26+
# t.string :name, null: false, default: ''
27+
# end
2228
# add_reference :products, :category
2329
# add_reference :products, :category, null: false, default: 1
2430
class NotNullColumn < Base
@@ -35,6 +41,22 @@ class NotNullColumn < Base
3541
(send nil? :add_reference _ _ (hash $...))
3642
PATTERN
3743

44+
def_node_matcher :change_table?, <<~PATTERN
45+
(block (send nil? :change_table ...) (args (arg $_)) _)
46+
PATTERN
47+
48+
def_node_matcher :add_not_null_column_in_change_table?, <<~PATTERN
49+
(send (lvar $_) :column _ $_ (hash $...))
50+
PATTERN
51+
52+
def_node_matcher :add_not_null_column_via_shortcut_in_change_table?, <<~PATTERN
53+
(send (lvar $_) $_ _ (hash $...))
54+
PATTERN
55+
56+
def_node_matcher :add_not_null_reference_in_change_table?, <<~PATTERN
57+
(send (lvar $_) :add_reference _ _ (hash $...))
58+
PATTERN
59+
3860
def_node_matcher :null_false?, <<~PATTERN
3961
(pair (sym :null) (false))
4062
PATTERN
@@ -48,16 +70,25 @@ def on_send(node)
4870
check_add_reference(node)
4971
end
5072

73+
def on_block(node)
74+
check_change_table(node)
75+
end
76+
alias on_numblock on_block
77+
5178
private
5279

80+
def check_column(type, pairs)
81+
if type.respond_to?(:value)
82+
return if type.value == :virtual || type.value == 'virtual'
83+
return if (type.value == :text || type.value == 'text') && database == MYSQL
84+
end
85+
86+
check_pairs(pairs)
87+
end
88+
5389
def check_add_column(node)
5490
add_not_null_column?(node) do |type, pairs|
55-
if type.respond_to?(:value)
56-
return if type.value == :virtual || type.value == 'virtual'
57-
return if (type.value == :text || type.value == 'text') && database == MYSQL
58-
end
59-
60-
check_pairs(pairs)
91+
check_column(type, pairs)
6192
end
6293
end
6394

@@ -67,6 +98,41 @@ def check_add_reference(node)
6798
end
6899
end
69100

101+
def check_add_column_in_change_table(node, table)
102+
add_not_null_column_in_change_table?(node) do |receiver, type, pairs|
103+
next unless receiver == table
104+
105+
check_column(type, pairs)
106+
end
107+
end
108+
109+
def check_add_column_via_shortcut_in_change_table(node, table)
110+
add_not_null_column_via_shortcut_in_change_table?(node) do |receiver, type, pairs|
111+
next unless receiver == table
112+
113+
check_column(type, pairs)
114+
end
115+
end
116+
117+
def check_add_reference_in_change_table(node, table)
118+
add_not_null_reference_in_change_table?(node) do |receiver, pairs|
119+
next unless receiver == table
120+
121+
check_pairs(pairs)
122+
end
123+
end
124+
125+
def check_change_table(node)
126+
change_table?(node) do |table|
127+
children = node.body.begin_type? ? node.body.children : [node.body]
128+
children.each do |child|
129+
check_add_column_in_change_table(child, table)
130+
check_add_column_via_shortcut_in_change_table(child, table)
131+
check_add_reference_in_change_table(child, table)
132+
end
133+
end
134+
end
135+
70136
def check_pairs(pairs)
71137
return if pairs.any? { |pair| default_option?(pair) }
72138

spec/rubocop/cop/rails/not_null_column_spec.rb

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,126 @@ def change
8787
end
8888
end
8989

90+
context 'with change_table call' do
91+
context 'with shortcut column call' do
92+
context 'with null: false' do
93+
it 'reports an offense' do
94+
expect_offense(<<~RUBY)
95+
def change
96+
change_table :users do |t|
97+
t.string :name, null: false
98+
^^^^^^^^^^^ Do not add a NOT NULL column without a default value.
99+
end
100+
end
101+
RUBY
102+
end
103+
104+
it 'reports multiple offenses' do
105+
expect_offense(<<~RUBY)
106+
def change
107+
change_table :users do |t|
108+
t.string :name, null: false
109+
^^^^^^^^^^^ Do not add a NOT NULL column without a default value.
110+
t.string :address, null: false
111+
^^^^^^^^^^^ Do not add a NOT NULL column without a default value.
112+
end
113+
end
114+
RUBY
115+
end
116+
end
117+
118+
context 'with default option' do
119+
it 'does not register an offense' do
120+
expect_no_offenses(<<~RUBY)
121+
def change
122+
change_table :users do |t|
123+
t.string :name, null: false, default: ""
124+
end
125+
end
126+
RUBY
127+
end
128+
end
129+
130+
context 'without any options' do
131+
it 'does not register an offense' do
132+
expect_no_offenses(<<~RUBY)
133+
def change
134+
change_table :users do |t|
135+
t.string :name
136+
end
137+
end
138+
RUBY
139+
end
140+
end
141+
end
142+
143+
context 'with column call' do
144+
context 'with null: false' do
145+
it 'reports an offense' do
146+
expect_offense(<<~RUBY)
147+
def change
148+
change_table :users do |t|
149+
t.column :name, :string, null: false
150+
^^^^^^^^^^^ Do not add a NOT NULL column without a default value.
151+
end
152+
end
153+
RUBY
154+
end
155+
end
156+
157+
context 'with default option' do
158+
it 'does not register an offense' do
159+
expect_no_offenses(<<~RUBY)
160+
def change
161+
change_table :users do |t|
162+
t.column :name, :string, null: false, default: ""
163+
end
164+
end
165+
RUBY
166+
end
167+
end
168+
169+
context 'without any options' do
170+
it 'does not register an offense' do
171+
expect_no_offenses(<<~RUBY)
172+
def change
173+
change_table :users do |t|
174+
t.column :name, :string
175+
end
176+
end
177+
RUBY
178+
end
179+
end
180+
end
181+
182+
context 'with reference call' do
183+
context 'with null: false' do
184+
it 'reports an offense' do
185+
expect_offense(<<~RUBY)
186+
def change
187+
change_table :users do |t|
188+
t.references :address, null: false
189+
^^^^^^^^^^^ Do not add a NOT NULL column without a default value.
190+
end
191+
end
192+
RUBY
193+
end
194+
end
195+
196+
context 'without any options' do
197+
it 'does not register an offense' do
198+
expect_no_offenses(<<~RUBY)
199+
def change
200+
change_table :users do |t|
201+
t.references :address
202+
end
203+
end
204+
RUBY
205+
end
206+
end
207+
end
208+
end
209+
90210
context 'with add_reference call' do
91211
context 'with null: false' do
92212
it 'reports an offense' do

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy