class RuboCop::Cop::Rails::NotNullColumn
change_column_null :products, :category_id, false
add_reference :products, :category
end
t.string :name, null: false, default: ”
change_table :users do |t|
add_column :users, :name, :string, null: false, default: ”
add_column :users, :name, :string, null: true
# good
end
t.string :name, null: false
change_table :users do |t|
add_reference :products, :category, null: false
add_column :users, :name, :string, null: false
# bad
@example
is MySQL, this cop ignores offenses for ‘TEXT` columns.
`DATABASE_URL` when the `Database` option is not set. If the database
environment in `config/database.yml` or the environment variable
The cop will automatically detect an adapter from `development`
`TEXT` cannot have a default value in MySQL.
and then use `change_column_default` to remove the default.
default first to have the database automatically backfill existing rows,
`change_column_null`. Alternatively, you could add the column with a
it as nullable first, back-fill the data, and then use
If you need to add a NOT NULL column to an existing table, you must add
records that could violate the constraint.
can freely use NOT NULL columns without defaults, since there are no
existing records will not have a value for the new column. New tables
This cop only applies when adding a column to an existing table, since
value.
Checks for add_column calls with a NOT NULL constraint without a default
def check_add_column(node)
def check_add_column(node) add_not_null_column?(node) do |type, pairs| check_column(type, pairs) end end
def check_add_column_in_change_table(node, table)
def check_add_column_in_change_table(node, table) add_not_null_column_in_change_table?(node) do |receiver, type, pairs| next unless receiver == table check_column(type, pairs) end end
def check_add_column_via_shortcut_in_change_table(node, table)
def check_add_column_via_shortcut_in_change_table(node, table) add_not_null_column_via_shortcut_in_change_table?(node) do |receiver, type, pairs| next unless receiver == table check_column(type, pairs) end end
def check_add_reference(node)
def check_add_reference(node) add_not_null_reference?(node) do |pairs| check_pairs(pairs) end end
def check_add_reference_in_change_table(node, table)
def check_add_reference_in_change_table(node, table) add_not_null_reference_in_change_table?(node) do |receiver, pairs| next unless receiver == table check_pairs(pairs) end end
def check_change_table(node)
def check_change_table(node) change_table?(node) do |table| next unless node.body children = node.body.begin_type? ? node.body.children : [node.body] children.each do |child| check_add_column_in_change_table(child, table) check_add_column_via_shortcut_in_change_table(child, table) check_add_reference_in_change_table(child, table) end end end
def check_column(type, pairs)
def check_column(type, pairs) if type.respond_to?(:value) return if VIRTUAL_TYPE_VALUES.include?(type.value) return if TEXT_TYPE_VALUES.include?(type.value) && database == MYSQL end check_pairs(pairs) end
def check_pairs(pairs)
def check_pairs(pairs) return if pairs.any? { |pair| default_option?(pair) } null_false = pairs.find { |pair| null_false?(pair) } return unless null_false add_offense(null_false) end
def on_block(node)
def on_block(node) check_change_table(node) end
def on_send(node)
def on_send(node) check_add_column(node) check_add_reference(node) end