models.rb 6.6 KB

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