Module: Subroutine::AssociationFields

Extended by:
ActiveSupport::Concern
Defined in:
lib/subroutine/association_fields.rb,
lib/subroutine/association_fields/configuration.rb,
lib/subroutine/association_fields/component_configuration.rb,
lib/subroutine/association_fields/association_type_mismatch_error.rb

Defined Under Namespace

Modules: ClassMethods Classes: AssociationTypeMismatchError, ComponentConfiguration, Configuration

Instance Method Summary collapse

Instance Method Details

#clear_field_with_association(field_name) ⇒ Object



144
145
146
147
148
149
150
151
152
153
154
# File 'lib/subroutine/association_fields.rb', line 144

def clear_field_with_association(field_name)
  config = get_field_config(field_name)

  if config&.behavior == :association
    clear_field(config.foreign_type_method) if config.polymorphic?
    clear_field(config.foreign_key_method)
    association_cache.delete(config.field_name)
  else
    clear_field_without_association(field_name)
  end
end

#fetch_association_instance(config) ⇒ Object



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/subroutine/association_fields.rb', line 172

def fetch_association_instance(config)
  klass =
    if config.field_reader?
      config.polymorphic? ? send(config.foreign_type_method) : config.inferred_foreign_type
    else
      get_field(config.foreign_type_method)
    end

  klass = klass.camelize.constantize if klass.is_a?(String)
  return nil unless klass

  foreign_key = config.foreign_key_method
  value = send(foreign_key)
  return nil unless value

  scope = klass.all
  scope = scope.unscoped if config.unscoped?

  if config.raise_on_miss?
    scope.find_by!(config.find_by => value)
  else
    scope.find_by(config.find_by => value)
  end
end

#field_provided_with_association?(field_name) ⇒ Boolean

Returns:

  • (Boolean)


156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/subroutine/association_fields.rb', line 156

def field_provided_with_association?(field_name)
  config = get_field_config(field_name)

  if config&.behavior == :association
    provided = true
    provided &&= field_provided?(config.foreign_type_method) if config.polymorphic?
    provided &&= field_provided?(config.foreign_key_method)
    provided
  elsif config&.behavior == :association_component
    field_provided_without_association?(field_name) ||
      field_provided_without_association?(config.association_name)
  else
    field_provided_without_association?(field_name)
  end
end

#get_field_with_association(field_name) ⇒ Object



130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/subroutine/association_fields.rb', line 130

def get_field_with_association(field_name)
  config = get_field_config(field_name)

  if config&.behavior == :association
    stored_result = association_cache[config.field_name]
    return stored_result unless stored_result.nil?

    result = fetch_association_instance(config)
    association_cache[config.field_name] = result
  else
    get_field_without_association(field_name)
  end
end

#maybe_raise_on_association_type_mismatch!(config, record) ⇒ Object



197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/subroutine/association_fields.rb', line 197

def maybe_raise_on_association_type_mismatch!(config, record)
  return if config.polymorphic?
  return if record.nil?

  klass = config.inferred_foreign_type.constantize

  return if record.class <= klass || record.class >= klass

  message = "#{klass}(##{klass.object_id}) expected, got #{record.class}(##{record.class.object_id})"

  errors.add(:base, message)
  raise Subroutine::AssociationFields::AssociationTypeMismatchError, self
end

#params_with_associationsObject



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/subroutine/association_fields.rb', line 94

def params_with_associations
  association_fields = field_configurations.select { |_name, config| config.behavior == :association }
  return params if association_fields.empty?

  excepts = []
  association_fields.each_pair do |_name, config|
    excepts |= config.related_field_names
  end

  out = params.except(*excepts)
  association_fields.each_pair do |field_name, config|
    next unless field_provided?(field_name)

    out[field_name] = config.field_reader? ? send(field_name) : get_field(field_name)
  end

  out
end

#set_field_with_association(field_name, value, **opts) ⇒ Object



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/subroutine/association_fields.rb', line 113

def set_field_with_association(field_name, value, **opts)
  config = get_field_config(field_name)

  if config&.behavior == :association
    maybe_raise_on_association_type_mismatch!(config, value)
    set_field(config.foreign_type_method, value&.class&.name, **opts) if config.polymorphic?
    set_field(config.foreign_key_method, value&.send(config.find_by), **opts)
    association_cache[config.field_name] = value
  else
    if config&.behavior == :association_component
      clear_field_without_association(config.association_name)
    end

    set_field_without_association(field_name, value, **opts)
  end
end

#setup_fields_with_association(*args) ⇒ Object



89
90
91
92
# File 'lib/subroutine/association_fields.rb', line 89

def setup_fields_with_association(*args)
  @association_cache = {}
  setup_fields_without_association(*args)
end