Class: ActiveRecordAutoValidations::AutoValidateModelClass

Inherits:
Object
  • Object
show all
Defined in:
app/services/active_record_auto_validations/auto_validate_model_class.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(model_class:, ignore_column_names: []) ⇒ AutoValidateModelClass

Returns a new instance of AutoValidateModelClass.



8
9
10
11
# File 'app/services/active_record_auto_validations/auto_validate_model_class.rb', line 8

def initialize(model_class:, ignore_column_names: [])
  @ignore_column_names = ignore_column_names
  @model_class = model_class
end

Instance Attribute Details

#ignore_column_namesObject (readonly)

Returns the value of attribute ignore_column_names.



2
3
4
# File 'app/services/active_record_auto_validations/auto_validate_model_class.rb', line 2

def ignore_column_names
  @ignore_column_names
end

#model_classObject (readonly)

Returns the value of attribute model_class.



2
3
4
# File 'app/services/active_record_auto_validations/auto_validate_model_class.rb', line 2

def model_class
  @model_class
end

Class Method Details

.execute!Object



4
5
6
# File 'app/services/active_record_auto_validations/auto_validate_model_class.rb', line 4

def self.execute!(...)
  ActiveRecordAutoValidations::AutoValidateModelClass.new(...).perform
end

Instance Method Details

#auto_validate_max_length_on_column!(column) ⇒ Object



107
108
109
110
# File 'app/services/active_record_auto_validations/auto_validate_model_class.rb', line 107

def auto_validate_max_length_on_column!(column)
  Rails.logger.info { "AutoValidate: Adding maxlength of #{column.limit} validation to #{model_class.table_name}##{column.name}" }
  model_class.validates column.name.to_sym, allow_blank: true, length: {maximum: column.limit}
end

#auto_validate_max_length_on_column?(column) ⇒ Boolean

Returns:

  • (Boolean)


103
104
105
# File 'app/services/active_record_auto_validations/auto_validate_model_class.rb', line 103

def auto_validate_max_length_on_column?(column)
  column.type == :string && column.limit && !max_length_validation_exists_on_column?(column)
end

#auto_validate_pesence_on_column!(column) ⇒ Object



98
99
100
101
# File 'app/services/active_record_auto_validations/auto_validate_model_class.rb', line 98

def auto_validate_pesence_on_column!(column)
  Rails.logger.info { "AutoValidate: Adding presence validation to #{model_class.table_name}##{column.name}" }
  model_class.validates column.name.to_sym, presence: true
end

#auto_validate_presence_on_column?(column) ⇒ Boolean

Returns:

  • (Boolean)


94
95
96
# File 'app/services/active_record_auto_validations/auto_validate_model_class.rb', line 94

def auto_validate_presence_on_column?(column)
  !column.null && !column.name.end_with?("_id") && column.default.nil? && column.default_function.nil? && !presence_validation_exists_on_column?(column)
end

#check_if_already_loaded_on_model_class!Object



30
31
32
33
34
# File 'app/services/active_record_auto_validations/auto_validate_model_class.rb', line 30

def check_if_already_loaded_on_model_class!
  auto_validations_loaded = model_class.instance_variable_get(:@_active_record_auto_validations_loaded)

  raise "AutoValidations already loaded for #{model_class.name}" if auto_validations_loaded
end

#columnsObject



40
41
42
# File 'app/services/active_record_auto_validations/auto_validate_model_class.rb', line 40

def columns
  @columns ||= model_class.columns
end

#ignore_column?(column_name) ⇒ Boolean

Returns:

  • (Boolean)


44
45
46
47
48
# File 'app/services/active_record_auto_validations/auto_validate_model_class.rb', line 44

def ignore_column?(column_name)
  return true if column_name == "id" || column_name == "created_at" || column_name == "updated_at"

  ignore_column_names.include?(column_name)
end

#ignore_index?(index) ⇒ Boolean

Returns:

  • (Boolean)


50
51
52
53
54
# File 'app/services/active_record_auto_validations/auto_validate_model_class.rb', line 50

def ignore_index?(index)
  return true unless index.unique

  index.columns.any? { |index_column_name| ignore_column?(index_column_name) }
end

#indexesObject



56
57
58
# File 'app/services/active_record_auto_validations/auto_validate_model_class.rb', line 56

def indexes
  @indexes ||= model_class.connection.indexes(model_class.table_name)
end

#insert_active_record_auto_validations_from_columns!Object



60
61
62
63
64
65
66
67
# File 'app/services/active_record_auto_validations/auto_validate_model_class.rb', line 60

def insert_active_record_auto_validations_from_columns!
  columns.each do |column|
    next if ignore_column?(column.name)

    auto_validate_pesence_on_column!(column) if auto_validate_presence_on_column?(column)
    auto_validate_max_length_on_column!(column) if auto_validate_max_length_on_column?(column)
  end
end

#insert_active_record_auto_validations_from_indexes!Object



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'app/services/active_record_auto_validations/auto_validate_model_class.rb', line 69

def insert_active_record_auto_validations_from_indexes!
  indexes.each do |index|
    next if ignore_index?(index)

    # Dont add uniqueness validation to ActsAsList position columns
    if index.columns.include?("position") && model_class.respond_to?(:acts_as_list_top)
      Rails.logger.info do
        "AutoValidate: Skipping unique validation on #{model_class.table_name}##{index.columns.join(",")} because it looks like ActsAsList"
      end

      next
    end

    ActiveRecordAutoValidations::AutoUniqueIndex.execute!(columns: columns, model_class: model_class, index: index)
  end
end

#max_length_validation_exists_on_column?(column) ⇒ Boolean

Returns:

  • (Boolean)


112
113
114
115
116
117
118
# File 'app/services/active_record_auto_validations/auto_validate_model_class.rb', line 112

def max_length_validation_exists_on_column?(column)
  model_class.validators_on(column.name.to_sym).each do |validator|
    return true if validator.kind == :length
  end

  false
end

#performObject



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'app/services/active_record_auto_validations/auto_validate_model_class.rb', line 13

def perform
  check_if_already_loaded_on_model_class!
  register_loaded_on_model_class!

  begin
    columns
    indexes
  rescue ActiveRecord::StatementInvalid => e
    # Database is probably not running - we need to ignore this to make stuff like db:migrate, db:schema:load work
    Rails.logger.info { "AutoValidate: Ignoring error while loading columns, because database might not be initialized: #{e.message}" }
    return
  end

  insert_active_record_auto_validations_from_columns!
  insert_active_record_auto_validations_from_indexes!
end

#presence_validation_exists_on_column?(column) ⇒ Boolean

Returns:

  • (Boolean)


86
87
88
89
90
91
92
# File 'app/services/active_record_auto_validations/auto_validate_model_class.rb', line 86

def presence_validation_exists_on_column?(column)
  model_class.validators_on(column.name.to_sym).each do |validator|
    return true if validator.kind == :presence
  end

  false
end

#register_loaded_on_model_class!Object



36
37
38
# File 'app/services/active_record_auto_validations/auto_validate_model_class.rb', line 36

def register_loaded_on_model_class!
  model_class.instance_variable_set(:@_active_record_auto_validations_loaded, true)
end