Module: ValidationStateGuard

Included in:
Sample
Defined in:
app/models/validation_state_guard.rb

Overview

It’s such a common pattern in the code to have a guard on some our validations that this module provides that facility. You can declare a guard with:

extend ValidationStateGuard
validation_guard(:guard_name)

This then gives you private methods of guard_name, guard_name=, and guard_name? It also adds an after_save callback that ensures that guard_name is false so it doesn’t leak.

If you have a method that should enable a guard and then disable it afterwards then you can do:

validation_guarded_by(:method_that_needs_guard_enabled, :guard_name)

This will set the guard_name to true before the method is called and return it to false afterwards.

JG: This pattern has been pretty much eliminated. It seems to just be used to control Sample renaming

Instance Method Summary collapse

Instance Method Details

#validation_guard(guard) ⇒ Object

rubocop:todo Metrics/MethodLength



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'app/models/validation_state_guard.rb', line 19

def validation_guard(guard) # rubocop:todo Metrics/MethodLength
  guard = guard.to_sym

  line = __LINE__ + 1
  class_eval(
    "
    attr_accessor #{guard.inspect}
    alias_method(#{guard.inspect}?, #{guard.inspect})
    private #{guard.inspect}, #{guard.inspect}?
    # This used to be protected, looks like rails attribute assignment implementation changed.
    public #{guard.inspect}=

    # Do not remove the 'true' from this otherwise the return value is false, which will fail the save!
    after_save { |record| record.send(#{guard.inspect}=, false) ; true }
  ",
    __FILE__,
    line
  )
end

#validation_guarded_by(method, guard) ⇒ Object

rubocop:todo Metrics/MethodLength



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'app/models/validation_state_guard.rb', line 39

def validation_guarded_by(method, guard) # rubocop:todo Metrics/MethodLength
  # Method name could end in ! or ?, in which case the unguarded name needs to be correct.
  method.to_s =~ /^([^!?]+)([!?])?$/
  core_name, extender = $1, $2
  unguarded_name = :"#{core_name}_unguarded_by_#{guard}#{extender}"

  line = __LINE__ + 1
  class_eval(
    "
    alias_method(#{unguarded_name.inspect}, #{method.to_sym.inspect})
    def #{method}(*args, &block)
      send(#{guard.to_sym.inspect}=, true)
      #{unguarded_name}(*args, &block)
    ensure
      send(#{guard.to_sym.inspect}=, false)
    end
  ",
    __FILE__,
    line
  )
end