Class: Enumeration

Inherits:
Sequel::Model
  • Object
show all
Defined in:
backend/app/model/enumeration.rb,
frontend/app/models/enumeration.rb

Constant Summary collapse

CSV_HEADERS =
["Enumeration code", "Enumeration", "Value code", "Value", "Position", "Read-only"]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(hash = {}) ⇒ Enumeration

Returns a new instance of Enumeration.



5
6
7
8
9
10
# File 'frontend/app/models/enumeration.rb', line 5

def initialize(hash = {})
  if hash
    @enum_name = hash["enum_name"]
    @enum_value = hash["enum_value"]
  end
end

Instance Attribute Details

#enum_nameObject

Returns the value of attribute enum_name



2
3
4
# File 'frontend/app/models/enumeration.rb', line 2

def enum_name
  @enum_name
end

#enum_valueObject

Returns the value of attribute enum_value



3
4
5
# File 'frontend/app/models/enumeration.rb', line 3

def enum_value
  @enum_value
end

Class Method Details

.apply_values(obj, json, opts = {}) ⇒ Object

Update the allowable values of the current enumeration.



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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'backend/app/model/enumeration.rb', line 81

def self.apply_values(obj, json, opts = {})
  # don't allow update of an non-editable enumeration
  # make sure the DB mapping has been converted.
  obj.reload
  is_editable = ( obj.editable === 1 or obj.editable == true )


  incoming_values = Array(json['values'])
  existing_values = obj.enumeration_value.select {|val| val[:suppressed] != 1 }.map {|val| val[:value] }
  # we need to keep suppressed values in mind for positioning
  existing_length = obj.enumeration_value.length

  added_values = incoming_values - existing_values
  removed_values = existing_values - incoming_values

  # if it's not editable, we cannot add or remove values, but we can set the
  # default...
  if (( !is_editable and added_values.length > 0 ) or ( !is_editable and removed_values.length > 0 )) and opts[:default_value].nil?
    raise AccessDeniedException.new("Cannot modify a non-editable enumeration: #{obj.name} with #{ json['values'].join(' , ') }. Only allowed values are : #{ obj.enumeration_value.join(' , ')} ")
  end

  # Make sure we're not being asked to remove read-only values.
  if EnumerationValue.filter(:enumeration_id => obj.id,
                             :value => removed_values,
                             :readonly => 1).count > 0

    raise AccessDeniedException.new("Can't remove read-only enumeration values")
  end


  added_values.each_with_index do |value, i|
    obj.add_enumeration_value(:value => value, :position => (existing_length + i + 1) )
  end

  removed_values.each do |value|
    DB.attempt {
      EnumerationValue.filter(:enumeration_id => obj.id,
                              :value => value, :suppressed => 0 ).delete
    }.and_if_constraint_fails {
      raise ConflictException.new("Can't delete a value that's in use: #{value}")
    }
  end


  enum_vals = EnumerationValue.filter( :enumeration_id => obj.id ).order(:position)
  enum_vals.update(:position => Sequel.lit('position + 9999' ))
  enum_vals.each_with_index do |ev, i|
    ev.position = i
    ev.save
  end

  broadcast_changes

  obj.refresh

  existing_default = obj.default_value.nil? ? nil : obj.default_value[:value]

  if opts[:default_value] != existing_default
    if opts[:default_value]
      new_default = EnumerationValue[:value => opts[:default_value]]
      return obj if new_default.nil? #just move along if the default isn't in the values table
      obj.default_value = new_default[:id]
    else
      obj.default_value = nil
    end

    obj.save
  end


  obj
end

.broadcast_changesObject



194
195
196
# File 'backend/app/model/enumeration.rb', line 194

def self.broadcast_changes
  Notifications.notify("ENUMERATION_CHANGED")
end

.create_from_json(json, opts = {}) ⇒ Object



155
156
157
158
159
160
# File 'backend/app/model/enumeration.rb', line 155

def self.create_from_json(json, opts = {})
  default_value = json['default_value']
  json['default_value'] = nil

  self.apply_values(super, json, opts.merge({:default_value => default_value}))
end

.csvObject



199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# File 'backend/app/model/enumeration.rb', line 199

def self.csv
  out = CSV_HEADERS.to_csv
  Enumeration.sequel_to_jsonmodel(Enumeration.all).sort_by { |e| e.name }.each do |enum|
    enum.enumeration_values.reject { |v| v.suppressed == 1 }.sort_by { |v| v.position }.each do |val|
      out << [
              enum.name,
              I18n.t("enumeration_names.#{enum.name}", :default => enum.name),
              val.value,
              I18n.t("enumerations.#{enum.name}.#{val.value}", :default => val.value),
              val.position,
              val.readonly,
             ].to_csv
    end
  end

  out
end

.dependants_of(enum_name) ⇒ Object



25
26
27
# File 'backend/app/model/enumeration.rb', line 25

def self.dependants_of(enum_name)
  @enumeration_dependants[enum_name]
end

.register_enumeration_dependant(definition, model) ⇒ Object

Record the fact that ‘model’ uses ‘enum_name’.



17
18
19
20
21
22
# File 'backend/app/model/enumeration.rb', line 17

def self.register_enumeration_dependant(definition, model)
  Array(definition[:uses_enum]).each do |enum_name|
    @enumeration_dependants[enum_name] ||= []
    @enumeration_dependants[enum_name] << [definition, model]
  end
end

.sequel_to_jsonmodel(objs, opts = {}) ⇒ Object



171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'backend/app/model/enumeration.rb', line 171

def self.sequel_to_jsonmodel(objs, opts = {})
  jsons = super

  jsons.zip(objs).each do |json, obj|

    # we're keeping the values as just the not suppressed values.
    # enumeration_values are only needed in situations where we are
    # editing/updating the lists.
    json['values'] = obj.enumeration_value.select {|v| v[:suppressed] != 1 }.map {|v| v[:value] }
    json['readonly_values'] = obj.enumeration_value.map {|v| v[:value] if ( v[:readonly] != 0 && v[:suppressed] != 1 )}.compact
    json['enumeration_values'] = EnumerationValue.sequel_to_jsonmodel(obj.enumeration_value)
    # this tells us where the enum is used.
    json["relationships"] = obj.dependants.collect { |d| d.first[:property] }.uniq

    if obj.default_value
      json['default_value'] = EnumerationValue[:id => obj.default_value][:value]
    end
  end

  jsons
end

Instance Method Details

#dependantsObject



29
30
31
# File 'backend/app/model/enumeration.rb', line 29

def dependants
  self.class.dependants_of(self.name) || []
end

#migrate(old_value, new_value) ⇒ Object

Find all database records that refer to the enumeration value identified by ‘source_id’ and repoint them to ‘destination_id’.



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
# File 'backend/app/model/enumeration.rb', line 35

def migrate(old_value, new_value)
  is_editable = ( self.editable === 1 or self.editable == true )
  if !is_editable
    raise EnumerationMigrationFailed.new("Can't migrate values for non-editable enumeration #{self.id}")
  end

  old_enum_value = self.enumeration_value.find {|val| val[:value] == old_value}

  if old_enum_value.nil?
    raise NotFoundException.new("Can't find a value '#{old_value}' in enumeration #{self.id}")
  end

  if old_enum_value.readonly != 0
    raise EnumerationMigrationFailed.new("Can't transfer from a read-only enumeration value")
  end

  new_enum_value = self.enumeration_value.find {|val| val[:value] == new_value}

  if new_enum_value.nil?
    raise NotFoundException.new("Can't find a value '#{new_value}' in enumeration #{self.id}")
  end

  dependants = self.class.dependants_of(self.name) ? self.class.dependants_of(self.name) : []
  dependants.each do |definition, model|
    property_id = "#{definition[:property]}_id".intern
    records = model.filter(property_id => old_enum_value.id)
    if model.included_modules.include?(ActiveAssociation)
      # update and check each record for a related record to reindex
      records.each do |rec|
        rec.update(property_id => new_enum_value.id, :system_mtime => Time.now)
        rec.broadcast_reindex
      end
    else
      # update in one go
      records.update(property_id => new_enum_value.id, :system_mtime => Time.now)
    end
  end

  old_enum_value.delete
  self.reload
  self.enumeration_value.each_with_index { |ev, i| ev.position = i; ev.save }
  self.class.broadcast_changes
end

#update_from_json(json, opts = {}, apply_nested_records = true) ⇒ Object



163
164
165
166
167
168
# File 'backend/app/model/enumeration.rb', line 163

def update_from_json(json, opts = {}, apply_nested_records = true)
  default_value = json['default_value']
  json['default_value'] = nil

  self.class.apply_values(super, json, opts.merge({:default_value => default_value}))
end