aboutsummaryrefslogtreecommitdiff
path: root/app/models/resource_form.rb
blob: 14275a48750283fb7856789053739297a042db53 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
class ResourceForm
  include ActiveModel::Model

  attr_accessor :agent, :resource
  attr_accessor :agent_id, :uuid, :name, :summary, :description, :email,
                :website, :phone_number, :address, :postal_code, :city,
                :entry_number, :latitude, :longitude, :section_ids, :source

  with_options presence: true do
    validates :name
    validates :email, allow_blank: true
#    validates :source
    validates :phone_number, allow_blank: true
    validates :website, allow_blank: true
  end

  validate :validate_models

  def initialize(agent, attributes = nil)
    @agent = agent
    @attributes = attributes || default_attributes

    raise ArgumentError "Attributes must be permitted" unless @attributes.permitted?

    # We use an empty hidden field to ensure this is always set, even if no
    # section is selected, so let's remove the empty value
    @section_ids = @attributes.extract!(:section_ids)[:section_ids].filter_map { |x| x.presence } rescue []
    # We may have an existing and correct source, but anyway we must have one
    @resource = @agent.resources.build({ source: @agent.name }.merge(@attributes))
  end

  def new_record?
    resource&.new_record? || true
  end

  # New forms can provide an existing classification,
  # and updates can prefer passed arguments to ensure correct changes
  def section_ids
    resource.present? && @section_ids.empty? ? resource.section_ids : @section_ids
  end

  # Ensure field values stick around
  # OMG this is ugly
  # TODO: use delegator or metaprog
  def name
    @name ||= resource&.name
  end
  def summary
    @summary ||= resource&.summary
  end
  def description
    @description ||= resource&.description
  end
  def email
    @email ||= resource&.email
  end
  def website
    @website ||= resource&.website
  end
  def phone_number
    @phone_number ||= resource&.phone_number
  end
  def address
    @address ||= resource&.address
  end
  def postal_code
    @postal_code ||= resource&.postal_code
  end
  def city
    @city ||= resource&.city
  end
  def longitude
    @longitude ||= resource&.longitude
  end
  def latitude
    @latitude ||= resource&.latitude
  end


  def save
    Rails.logger.info "--- Calling SAVE ---"
    return false if invalid?

    ActiveRecord::Base.transaction do
      resource.save! && \
      @section_ids.each do |sec_id|
        Rails.logger.info("section " + sec_id)
        resource.categories << resource.classifications.find_or_create_by!(section_id: sec_id)
      end

      true
    rescue ActiveRecord::StatementInvalid => e
      errors.add(:base, e.message)
      false
    end

  rescue Exception => e
    Rails.logger.info "Unhandled Exception #{e.class}: #{e.message}"
    false
  end

  private

  def default_attributes
    ActionController::Parameters.new(
      {
        agent_id: @agent.id,
        uuid: '',
        name: '',
        summary: '',
        description: '',
        email: '',
        website: '',
        phone_number: '',
        address: '',
        postal_code: '',
        city: '',
        entry_number: nil,
        latitude: 0.0,
        longitude: 0.0,
        source: @agent.name,
        section_ids: []
      }).permit!
  end

  # Validate underlying models
  def validate_models
    Rails.logger.info('--- validate_models ---')
    resource.valid? || promote_errors(resource.errors)
  end

  # Promote an error from the Model to the Form
  def promote_errors(model_errors)
    model_errors.each do |attribute, error|
      errors.add(attribute, error.full_message)
    end
  end
end