models.rb 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. class Models
  2. include ApplicationLib
  3. =begin
  4. get list of models
  5. result = Models.all
  6. returns
  7. {
  8. 'Some::Classname1' => {
  9. attributes: ['id', 'name', '...']
  10. reflections: ...model.reflections...
  11. },
  12. 'Some::Classname2' => {
  13. attributes: ['id', 'name', '...']
  14. reflections: ...model.reflections...
  15. },
  16. }
  17. =end
  18. def self.all
  19. all = {}
  20. dir = "#{Rails.root}/app/models/"
  21. Dir.glob( "#{dir}**/*.rb" ) do |entry|
  22. next if entry =~ /application_model/i
  23. next if entry =~ %r{channel/}i
  24. next if entry =~ %r{observer/}i
  25. next if entry =~ %r{store/provider/}i
  26. entry.gsub!(dir, '')
  27. entry = entry.to_classname
  28. model_class = load_adapter(entry)
  29. next if !model_class
  30. next if !model_class.respond_to? :new
  31. model_object = model_class.new
  32. next if !model_object.respond_to? :attributes
  33. all[model_class] = {}
  34. all[model_class][:attributes] = model_class.attribute_names
  35. all[model_class][:reflections] = model_class.reflections
  36. #puts model_class
  37. #puts "rrrr #{all[model_class][:attributes]}"
  38. #puts " #{model_class.attribute_names.inspect}"
  39. end
  40. all
  41. end
  42. =begin
  43. get reference list of a models
  44. result = Models.references('User', 2)
  45. returns
  46. {
  47. 'Some::Classname1' => {
  48. attribute1: 12,
  49. attribute2: 6,
  50. },
  51. 'Some::Classname2' => {
  52. updated_by_id: 12,
  53. created_by_id: 6,
  54. },
  55. }
  56. =end
  57. def self.references(object_name, object_id)
  58. # check if model exists
  59. object_model = load_adapter(object_name)
  60. object_model.find(object_id)
  61. list = all
  62. references = {}
  63. # find relations via attributes
  64. ref_attributes = ["#{object_name.downcase}_id"]
  65. # for users we do not define relations for created_by_id &
  66. # updated_by_id - add it here directly
  67. if object_name == 'User'
  68. ref_attributes.push 'created_by_id'
  69. ref_attributes.push 'updated_by_id'
  70. end
  71. list.each {|model_class, model_attributes|
  72. if !references[model_class.to_s]
  73. references[model_class.to_s] = {}
  74. end
  75. next if !model_attributes[:attributes]
  76. ref_attributes.each {|item|
  77. next if !model_attributes[:attributes].include?(item)
  78. count = model_class.where("#{item} = ?", object_id).count
  79. next if count == 0
  80. if !references[model_class.to_s][item]
  81. references[model_class.to_s][item] = 0
  82. end
  83. Rails.logger.debug "FOUND (by id) #{model_class}->#{item} #{count}!"
  84. references[model_class.to_s][item] += count
  85. }
  86. }
  87. # find relations via reflections
  88. list.each {|model_class, model_attributes|
  89. next if !model_attributes[:reflections]
  90. model_attributes[:reflections].each {|_reflection_key, reflection_value|
  91. next if reflection_value.macro != :belongs_to
  92. col_name = "#{reflection_value.name}_id"
  93. next if ref_attributes.include?(col_name)
  94. if reflection_value.options[:class_name] == object_name
  95. count = model_class.where("#{col_name} = ?", object_id).count
  96. next if count == 0
  97. if !references[model_class.to_s][col_name]
  98. references[model_class.to_s][col_name] = 0
  99. end
  100. Rails.logger.debug "FOUND (by ref without class) #{model_class}->#{col_name} #{count}!"
  101. references[model_class.to_s][col_name] += count
  102. end
  103. next if reflection_value.options[:class_name]
  104. next if reflection_value.name != object_name.downcase.to_sym
  105. count = model_class.where("#{col_name} = ?", object_id).count
  106. next if count == 0
  107. if !references[model_class.to_s][col_name]
  108. references[model_class.to_s][col_name] = 0
  109. end
  110. Rails.logger.debug "FOUND (by ref with class) #{model_class}->#{col_name} #{count}!"
  111. references[model_class.to_s][col_name] += count
  112. }
  113. }
  114. # cleanup, remove models with empty references
  115. references.each {|k, v|
  116. next if !v.empty?
  117. references.delete(k)
  118. }
  119. references
  120. end
  121. =begin
  122. get reference total of a models
  123. count = Models.references_total('User', 2)
  124. returns
  125. count # 1234
  126. =end
  127. def self.references_total(object_name, object_id)
  128. references = references(object_name, object_id)
  129. total = 0
  130. references.each {|_model, model_references|
  131. model_references.each {|_col, count|
  132. total += count
  133. }
  134. }
  135. total
  136. end
  137. =begin
  138. merge model references to other model
  139. result = Models.merge('User', 2, 4711) # Object, object_id_of_primary, object_id_which_should_be_merged
  140. returns
  141. true # false
  142. =end
  143. def self.merge(object_name, object_id_primary, object_id_to_merge, force = false)
  144. # if lower x references to update, do it right now
  145. if force
  146. total = references_total(object_name, object_id_to_merge)
  147. if total > 1000
  148. fail "Can't merge object because object has more then 1000 (#{total}) references, please contact your system administrator."
  149. end
  150. end
  151. # update references
  152. references = references(object_name, object_id_to_merge)
  153. references.each {|model, attributes|
  154. model_object = Object.const_get(model)
  155. # collect items and attributes to update
  156. items_to_update = {}
  157. attributes.each {|attribute, _count|
  158. Rails.logger.debug "#{object_name}: #{model}.#{attribute}->#{object_id_to_merge}->#{object_id_primary}"
  159. model_object.where("#{attribute} = ?", object_id_to_merge).each {|item|
  160. if !items_to_update[item.id]
  161. items_to_update[item.id] = item
  162. end
  163. items_to_update[item.id][attribute.to_sym] = object_id_primary
  164. }
  165. }
  166. # update items
  167. ActiveRecord::Base.transaction do
  168. items_to_update.each {|_id, item|
  169. item.save
  170. }
  171. end
  172. }
  173. true
  174. end
  175. end