Class: Ekylibre::Record::Base

Inherits:
ActiveRecord::Base
  • Object
show all
Extended by:
Enumerize
Defined in:
lib/ekylibre/record/base.rb

Direct Known Subclasses

Account, AccountBalance, Activity, ActivityBudget, ActivityBudgetItem, ActivityDistribution, ActivityInspectionCalibrationNature, ActivityInspectionCalibrationScale, ActivityInspectionPointNature, ActivityProduction, Affair, Analysis, AnalysisItem, Attachment, BankStatement, BankStatementItem, Campaign, CapIslet, CapLandParcel, CapStatement, Cash, CashSession, CashTransfer, Catalog, CatalogItem, Crumb, CultivableZone, CustomField, CustomFieldChoice, Dashboard, Delivery, DeliveryTool, Deposit, District, Document, DocumentTemplate, Entity, EntityAddress, EntityLink, Event, EventParticipation, FinancialYear, FixedAsset, FixedAssetDepreciation, Gap, GapItem, Georeading, Guide, GuideAnalysis, GuideAnalysisPoint, Identifier, Import, IncomingPayment, IncomingPaymentMode, Inspection, InspectionCalibration, InspectionPoint, Intervention, InterventionParameter, InterventionParameterReading, InterventionWorkingPeriod, Inventory, InventoryItem, Issue, Journal, JournalEntry, JournalEntryItem, Listing, ListingNode, ListingNodeItem, Loan, LoanRepayment, ManureManagementPlan, ManureManagementPlanZone, MapBackground, NetService, Notification, Observation, OutgoingPayment, OutgoingPaymentMode, Parcel, ParcelItem, PlantCounting, PlantCountingItem, PlantDensityAbacus, PlantDensityAbacusItem, PostalZone, Preference, Prescription, Product, ProductEnjoyment, ProductLink, ProductLinkage, ProductLocalization, ProductMembership, ProductMovement, ProductNature, ProductNatureCategory, ProductNatureCategoryTaxation, ProductNatureVariant, ProductNatureVariantReading, ProductOwnership, ProductPhase, ProductReading, Purchase, PurchaseItem, PurchaseNature, Role, Sale, SaleItem, SaleNature, Sensor, Sequence, Subscription, SubscriptionNature, Supervision, SupervisionItem, TargetDistribution, Task, Tax, Team, Tracking, User

Constant Summary collapse

@@readonly_counter =
0

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.attr_readonly_with_conditions(*args) ⇒ Object

Permits to add conditions on attr_readonly


187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/ekylibre/record/base.rb', line 187

def attr_readonly_with_conditions(*args)
  options = args.extract_options!
  return attr_readonly_without_conditions(*args) unless options[:if]
  if options[:if].is_a?(Symbol)
    method_name = options[:if]
  else
    method_name = "readonly_#{@@readonly_counter += 1}?"
    send(:define_method, method_name, options[:if])
  end
  code = ''
  code << "before_update do\n"
  code << "  if self.#{method_name}\n"
  code << "    old = #{name}.find(self.id)\n"
  args.each do |attribute|
    code << "  self['#{attribute}'] = old['#{attribute}']\n"
  end
  code << "  end\n"
  code << "end\n"
  class_eval code
end

.columns_definitionObject


98
99
100
# File 'lib/ekylibre/record/base.rb', line 98

def columns_definition
  Ekylibre::Schema.tables[table_name] || {}.with_indifferent_access
end

.complex_scopesObject


106
107
108
# File 'lib/ekylibre/record/base.rb', line 106

def complex_scopes
  scopes.select { |x| !x.arity.zero? }
end

.customizable?Boolean

Returns:

  • (Boolean)

48
49
50
# File 'lib/ekylibre/record/base.rb', line 48

def self.customizable?
  respond_to?(:custom_fields)
end

.has_picture(options = {}) ⇒ Object


82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/ekylibre/record/base.rb', line 82

def has_picture(options = {})
  default_options = {
    url: '/backend/:class/:id/picture/:style',
    path: ':tenant/:class/:attachment/:id_partition/:style.:extension',
    styles: {
      thumb: ['64x64>', :jpg],
      identity: ['180x180>', :jpg]
    },
    convert_options: {
      thumb:    '-background white -gravity center -extent 64x64',
      identity: '-background white -gravity center -extent 180x180'
    }
  }
  has_attached_file :picture, default_options.deep_merge(options)
end

.human_attribute_name_with_id(attribute, options = {}) ⇒ Object

Permits to consider something and something_id like the same


181
182
183
# File 'lib/ekylibre/record/base.rb', line 181

def human_attribute_name_with_id(attribute, options = {})
  human_attribute_name_without_id(attribute.to_s.gsub(/_id\z/, ''), options)
end

.nomenclature_reflectionsObject


132
133
134
# File 'lib/ekylibre/record/base.rb', line 132

def nomenclature_reflections
  @nomenclature_reflections ||= {}.with_indifferent_access
end

.refers_to(name, *args) ⇒ Object

Link to nomenclature


137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/ekylibre/record/base.rb', line 137

def refers_to(name, *args)
  options = args.extract_options!
  scope = args.shift
  Rails.logger.warn 'Cannot support Proc scope' unless scope.nil?
  column = ["#{name}_tid".to_sym, "#{name}_name".to_sym, name].detect { |c| columns_definition[c] }
  options[:foreign_key] ||= column
  reflection = Nomen::Reflection.new(self, name, options)
  @nomenclature_reflections ||= {}.with_indifferent_access
  @nomenclature_reflections[reflection.name] = reflection
  enumerize reflection.foreign_key, in: reflection.all(reflection.scope),
                                    i18n_scope: ["nomenclatures.#{reflection.nomenclature}.items"]

  if reflection.foreign_key != reflection.name
    define_method name do
      reflection.klass.find(self[reflection.foreign_key])
    end
  else
    define_method "#{name}_name" do
      item = reflection.klass.find(self[reflection.foreign_key])
      item ? item.name : nil
    end
  end

  define_method "human_#{name}_name" do
    item = reflection.klass.find(self[reflection.foreign_key])
    item ? item.human_name : nil
  end

  define_method "#{name}=" do |value|
    self[reflection.foreign_key] = value.is_a?(Nomen::Item) ? value.name : value
  end

  # Define a default scope "of_<name>"
  scope "of_#{name}".to_sym, proc { |*items|
    where(reflection.foreign_key => items.map { |i| reflection.klass.all(i) }.flatten.uniq)
  }

  define_method "of_#{name}?" do |item_or_name|
    item = item_or_name.is_a?(Nomen::Item) ? item_or_name : reflection.klass.find(item_or_name)
    item >= self[reflection.foreign_key]
  end
end

.scope_with_registration(name, body, &block) ⇒ Object

Permits to consider something and something_id like the same


111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/ekylibre/record/base.rb', line 111

def scope_with_registration(name, body, &block)
  # Check body.is_a?(Relation) to prevent the relation actually being
  # loaded by respond_to?
  if body.is_a?(::ActiveRecord::Relation) || !body.respond_to?(:call)
    ActiveSupport::Deprecation.warn('Using #scope without passing a callable object is deprecated. For ' \
                                    "example `scope :red, where(color: 'red')` should be changed to " \
                                    "`scope :red, -> { where(color: 'red') }`. There are numerous gotchas " \
                                    'in the former usage and it makes the implementation more complicated ' \
                                    'and buggy. (If you prefer, you can just define a class method named ' \
                                    "`self.red`.)\n" + caller.join("\n"))
  end
  arity = begin
            body.arity
          rescue
            0
          end
  scopes << Scope.new(name.to_sym, arity)
  scope_without_registration(name, body, &block)
end

.simple_scopesObject


102
103
104
# File 'lib/ekylibre/record/base.rb', line 102

def simple_scopes
  scopes.select { |x| x.arity.zero? }
end

Instance Method Details

#already_updated?Boolean

Returns:

  • (Boolean)

75
76
77
# File 'lib/ekylibre/record/base.rb', line 75

def already_updated?
  self.class.where(id: id, lock_version: lock_version).empty?
end

#check_if_destroyable?Boolean

Returns:

  • (Boolean)

30
31
32
33
34
# File 'lib/ekylibre/record/base.rb', line 30

def check_if_destroyable?
  unless destroyable?
    raise RecordNotDestroyable, "#{self.class.name} ID=#{id} is not destroyable"
  end
end

#check_if_updateable?Boolean

Returns:

  • (Boolean)

25
26
27
28
# File 'lib/ekylibre/record/base.rb', line 25

def check_if_updateable?
  true
  # raise RecordNotUpdateable unless self.updateable?
end

#customizable?Boolean

Returns:

  • (Boolean)

52
53
54
# File 'lib/ekylibre/record/base.rb', line 52

def customizable?
  self.class.customizable?
end

#customized?Boolean

Returns:

  • (Boolean)

56
57
58
# File 'lib/ekylibre/record/base.rb', line 56

def customized?
  customizable? && self.class.custom_fields.any?
end

#destroyable?Boolean

Returns:

  • (Boolean)

36
37
38
# File 'lib/ekylibre/record/base.rb', line 36

def destroyable?
  true
end

#editable?Boolean

Returns:

  • (Boolean)

44
45
46
# File 'lib/ekylibre/record/base.rb', line 44

def editable?
  updateable?
end

#human_attribute_name(*args) ⇒ Object


60
61
62
# File 'lib/ekylibre/record/base.rb', line 60

def human_attribute_name(*args)
  self.class.human_attribute_name(*args)
end

#old_recordObject

Returns a relation for the old record in DB


70
71
72
73
# File 'lib/ekylibre/record/base.rb', line 70

def old_record
  return nil if new_record?
  self.class.find_by(id: id)
end

#othersObject

Returns a relation for all other records


65
66
67
# File 'lib/ekylibre/record/base.rb', line 65

def others
  self.class.where.not(id: (id || -1))
end

#updateable?Boolean

Returns:

  • (Boolean)

40
41
42
# File 'lib/ekylibre/record/base.rb', line 40

def updateable?
  true
end