Module: Motor::Resources::FetchConfiguredModel
- Defined in:
- lib/motor/resources/fetch_configured_model.rb
Constant Summary collapse
- CACHE_HASH =
HashWithIndifferentAccess.new
- HAS_AND_BELONGS_TO_MANY_JOIN_MODEL_PREFIX =
'HABTM_'
Class Method Summary collapse
- .build_configured_model(model, config) ⇒ Object
- .build_configured_model_from_configs(model, configs) ⇒ Object
- .call(model, cache_key:) ⇒ Object
- .configure_reflection_class?(ref) ⇒ Boolean
- .configure_reflection_classes(klass, cache_key) ⇒ Object
- .define_association(klass, name, options, filters) ⇒ Object
- .define_associations(klass, config) ⇒ Object
- .define_belongs_to_reflection(klass, config) ⇒ Object
- .define_class_name_method(klass, model) ⇒ Object
- .define_column_reflections(klass, config) ⇒ Object
- .define_columns_hash(klass, config) ⇒ Object
- .define_default_scope(klass, config) ⇒ Object
- .define_has_one_reflection(klass, config) ⇒ Object
- .maybe_fetch_from_cache(model, cache_key, miss_cache_block, postprocess_block) ⇒ Object
- .normalize_association_params(params) ⇒ Object
- .sti_model?(model) ⇒ Boolean
Class Method Details
.build_configured_model(model, config) ⇒ Object
26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/motor/resources/fetch_configured_model.rb', line 26 def build_configured_model(model, config) klass = Class.new(model) klass.inheritance_column = nil if model.superclass.abstract_class define_class_name_method(klass, model) define_columns_hash(klass, config) define_default_scope(klass, config) define_column_reflections(klass, config) define_associations(klass, config) klass end |
.build_configured_model_from_configs(model, configs) ⇒ Object
204 205 206 207 208 209 210 211 212 |
# File 'lib/motor/resources/fetch_configured_model.rb', line 204 def build_configured_model_from_configs(model, configs) resource_config = configs.find { |r| r.name == model.name.underscore } if resource_config build_configured_model(model, resource_config.preferences) else define_class_name_method(Class.new(model), model) end end |
.call(model, cache_key:) ⇒ Object
12 13 14 15 16 17 18 19 20 21 22 23 24 |
# File 'lib/motor/resources/fetch_configured_model.rb', line 12 def call(model, cache_key:) configs = Motor::Configs::LoadFromCache.load_resources(cache_key: cache_key) return model if model.name == 'ActiveStorage::Attachment' return model if configs.blank? || sti_model?(model) maybe_fetch_from_cache( model, cache_key.to_s + model.object_id.to_s, -> { build_configured_model_from_configs(model, configs) }, ->(klass) { configure_reflection_classes(klass, cache_key) } ) end |
.configure_reflection_class?(ref) ⇒ Boolean
214 215 216 217 218 219 220 221 222 223 224 225 |
# File 'lib/motor/resources/fetch_configured_model.rb', line 214 def configure_reflection_class?(ref) begin return false unless ref.klass rescue StandardError return false end return false if ref.klass.anonymous? return false if ref.klass.name.demodulize.starts_with?(HAS_AND_BELONGS_TO_MANY_JOIN_MODEL_PREFIX) true end |
.configure_reflection_classes(klass, cache_key) ⇒ Object
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/motor/resources/fetch_configured_model.rb', line 139 def configure_reflection_classes(klass, cache_key) klass._reflections.each do |key, ref| next unless configure_reflection_class?(ref) ref_dup = ref.dup if ref.klass.name == klass.name ref_dup.instance_variable_set(:@klass, klass) else ref_dup.instance_variable_set(:@klass, call(ref.klass, cache_key: cache_key)) end klass.reflections[key] = ref_dup end klass._reflections = klass.reflections klass end |
.define_association(klass, name, options, filters) ⇒ Object
171 172 173 174 175 176 177 178 179 |
# File 'lib/motor/resources/fetch_configured_model.rb', line 171 def define_association(klass, name, , filters) if [:class_name] == 'ActiveStorage::Attachment' klass.has_many_attached name.delete_suffix('_attachments').to_sym elsif filters.present? klass.has_many(name.to_sym, -> { filter(filters).tap(&:arel) }, **.symbolize_keys) else klass.has_many(name.to_sym, **.symbolize_keys) end end |
.define_associations(klass, config) ⇒ Object
159 160 161 162 163 164 165 166 167 168 169 |
# File 'lib/motor/resources/fetch_configured_model.rb', line 159 def define_associations(klass, config) config.fetch(:associations, []).each do |association| next unless association[:virtual] = normalize_association_params(association) filters = .delete(:filters) define_association(klass, association[:name], , filters) end end |
.define_belongs_to_reflection(klass, config) ⇒ Object
114 115 116 117 118 119 120 121 |
# File 'lib/motor/resources/fetch_configured_model.rb', line 114 def define_belongs_to_reflection(klass, config) klass.belongs_to(config[:name].to_sym, class_name: config[:model_name]&.classify, foreign_key: config[:foreign_key], polymorphic: config[:polymorphic], primary_key: config[:primary_key], optional: true) end |
.define_class_name_method(klass, model) ⇒ Object
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/motor/resources/fetch_configured_model.rb', line 54 def define_class_name_method(klass, model) klass.instance_variable_set(:@__motor_model_name, model.name) klass.instance_eval do def name @__motor_model_name end def inspect super.gsub(/\#<Class:0x\w+>/, name) end def to_s super.gsub(/\#<Class:0x\w+>/, name) end def anonymous? true end end klass end |
.define_column_reflections(klass, config) ⇒ Object
99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/motor/resources/fetch_configured_model.rb', line 99 def define_column_reflections(klass, config) config.fetch(:columns, []).each do |column| reference = column[:reference] next if reference.blank? next unless reference[:virtual] if reference[:reference_type] == 'belongs_to' define_belongs_to_reflection(klass, reference) else define_has_one_reflection(klass, reference) end end end |
.define_columns_hash(klass, config) ⇒ Object
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/motor/resources/fetch_configured_model.rb', line 78 def define_columns_hash(klass, config) return klass if config[:custom_sql].blank? columns = Resources::CustomSqlColumnsCache.call(config[:custom_sql]) columns_hash = columns.each_with_object({}) do |column, acc| acc[column[:name]] = ActiveRecord::ConnectionAdapters::Column.new(column[:name], nil) end klass.instance_variable_set(:@__motor_custom_sql_columns_hash, columns_hash) # rubocop:disable Naming/MemoizedInstanceVariableName klass.instance_eval do def columns_hash @__motor__columns_hash ||= @__motor_custom_sql_columns_hash.merge(super) end end # rubocop:enable Naming/MemoizedInstanceVariableName end |
.define_default_scope(klass, config) ⇒ Object
40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/motor/resources/fetch_configured_model.rb', line 40 def define_default_scope(klass, config) return klass if config[:custom_sql].blank? klass.instance_variable_set(:@__motor_custom_sql, config[:custom_sql].squish) klass.instance_eval do default_scope do from(Arel.sql("(#{self.klass.instance_variable_get(:@__motor_custom_sql)})").as(table_name)) end end klass end |
.define_has_one_reflection(klass, config) ⇒ Object
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/motor/resources/fetch_configured_model.rb', line 123 def define_has_one_reflection(klass, config) = { class_name: config[:model_name].classify, foreign_key: config[:foreign_key], primary_key: config[:primary_key] } = .merge(config[:options] || {}) if config[:model_name] == 'active_storage/attachment' klass.has_one_attached config[:name].delete_suffix('_attachment').to_sym else klass.has_one(config[:name].to_sym, **.symbolize_keys) end end |
.maybe_fetch_from_cache(model, cache_key, miss_cache_block, postprocess_block) ⇒ Object
190 191 192 193 194 195 196 197 198 199 200 201 202 |
# File 'lib/motor/resources/fetch_configured_model.rb', line 190 def maybe_fetch_from_cache(model, cache_key, miss_cache_block, postprocess_block) return miss_cache_block.call unless cache_key if CACHE_HASH[model.name] && CACHE_HASH[model.name][:key] == cache_key CACHE_HASH[model.name][:value] else result = miss_cache_block.call CACHE_HASH[model.name] = { key: cache_key, value: result } postprocess_block.call(result) end end |
.normalize_association_params(params) ⇒ Object
181 182 183 184 185 186 187 188 |
# File 'lib/motor/resources/fetch_configured_model.rb', line 181 def normalize_association_params(params) = params.slice(:foreign_key, :primary_key).merge(dependent: :destroy) [:class_name] = params[:model_name].classify [:as] = params[:foreign_key].delete_suffix('_id') if params[:polymorphic] .merge(params[:options] || {}) end |
.sti_model?(model) ⇒ Boolean
227 228 229 |
# File 'lib/motor/resources/fetch_configured_model.rb', line 227 def sti_model?(model) !model.superclass.abstract_class && model.columns_hash[model.inheritance_column.to_s] end |