# frozen_string_literal: true module RuboCop module Cop module Rails # Checks the migration for which timestamps are not included # when creating a new table. # In many cases, timestamps are useful information and should be added. # # @example # # bad # create_table :users # # # bad # create_table :users do |t| # t.string :name # t.string :email # end # # # good # create_table :users do |t| # t.string :name # t.string :email # # t.timestamps # end # # # good # create_table :users do |t| # t.string :name # t.string :email # # t.datetime :created_at, default: -> { 'CURRENT_TIMESTAMP' } # end # # # good # create_table :users do |t| # t.string :name # t.string :email # # t.datetime :updated_at, default: -> { 'CURRENT_TIMESTAMP' } # end class CreateTableWithTimestamps < Base include ActiveRecordMigrationsHelper MSG = 'Add timestamps when creating a new table.' RESTRICT_ON_SEND = %i[create_table].freeze def_node_matcher :create_table_with_timestamps_proc?, <<~PATTERN (send nil? :create_table (sym _) ... (block-pass (sym :timestamps))) PATTERN def_node_search :timestamps_included?, <<~PATTERN (send _var :timestamps ...) PATTERN def_node_search :created_at_or_updated_at_included?, <<~PATTERN (send _var :datetime {(sym {:created_at :updated_at})(str {"created_at" "updated_at"})} ...) PATTERN def on_send(node) return unless node.command?(:create_table) parent = node.parent if create_table_with_block?(parent) add_offense(parent) if parent.body.nil? || !time_columns_included?(parent.body) elsif create_table_with_timestamps_proc?(node) # nothing to do else add_offense(node) end end private def time_columns_included?(node) timestamps_included?(node) || created_at_or_updated_at_included?(node) end end end end end