Module: ActiveRecord::ClassMethods

Included in:
Base
Defined in:
lib/reactive_record/active_record/class_methods.rb

Constant Summary collapse

SERVER_METHODS =

ignore any of these methods if they get called on the client. This list should be trimmed down to include only methods to be called as “macros” such as :after_create, etc…

[
  :regulate_relationship, :regulate_scope,
  :attribute_type_decorations, :defined_enums, :_validators, :timestamped_migrations, :lock_optimistically, :lock_optimistically=,
  :local_stored_attributes=, :lock_optimistically?, :attribute_aliases?, :attribute_method_matchers?, :defined_enums?,
  :has_many_without_reactive_record_add_changed_method, :has_many_with_reactive_record_add_changed_method,
  :belongs_to_without_reactive_record_add_changed_method, :belongs_to_with_reactive_record_add_changed_method,
  :cache_timestamp_format, :composed_of_with_reactive_record_add_changed_method, :schema_format, :schema_format=,
  :error_on_ignored_order_or_limit, :error_on_ignored_order_or_limit=, :timestamped_migrations=, :dump_schema_after_migration,
  :dump_schema_after_migration=, :dump_schemas, :dump_schemas=, :warn_on_records_fetched_greater_than=,
  :belongs_to_required_by_default, :default_connection_handler, :connection_handler=, :default_connection_handler=,
  :skip_time_zone_conversion_for_attributes, :skip_time_zone_conversion_for_attributes=, :time_zone_aware_types,
  :time_zone_aware_types=, :protected_environments, :skip_time_zone_conversion_for_attributes?, :time_zone_aware_types?,
  :partial_writes, :partial_writes=, :composed_of_without_reactive_record_add_changed_method, :logger, :partial_writes?,
  :after_initialize, :record_timestamps, :record_timestamps=, :after_find, :after_touch, :before_save, :around_save,
  :belongs_to_required_by_default=, :default_connection_handler?, :before_create, :around_create, :before_update, :around_update,
  :after_save, :before_destroy, :around_destroy, :after_create, :after_destroy, :after_update, :_validation_callbacks,
  :_validation_callbacks?, :_validation_callbacks=, :_initialize_callbacks, :_initialize_callbacks?, :_initialize_callbacks=,
  :_find_callbacks, :_find_callbacks?, :_find_callbacks=, :_touch_callbacks, :_touch_callbacks?, :_touch_callbacks=, :_save_callbacks,
  :_save_callbacks?, :_save_callbacks=, :_create_callbacks, :_create_callbacks?, :_create_callbacks=, :_update_callbacks,
  :_update_callbacks?, :_update_callbacks=, :_destroy_callbacks, :_destroy_callbacks?, :_destroy_callbacks=, :record_timestamps?,
  :pre_synchromesh_scope, :pre_synchromesh_default_scope, :do_not_synchronize, :do_not_synchronize?,
  :logger=, :maintain_test_schema, :maintain_test_schema=, :scope, :time_zone_aware_attributes, :time_zone_aware_attributes=,
  :default_timezone, :default_timezone=, :_attr_readonly, :warn_on_records_fetched_greater_than, :configurations, :configurations=,
  :_attr_readonly?, :table_name_prefix=, :table_name_suffix=, :schema_migrations_table_name=, :internal_metadata_table_name,
  :internal_metadata_table_name=, :primary_key_prefix_type, :_attr_readonly=, :pluralize_table_names=, :protected_environments=,
  :ignored_columns=, :ignored_columns, :index_nested_attribute_errors, :index_nested_attribute_errors=, :primary_key_prefix_type=,
  :table_name_prefix?, :table_name_suffix?, :schema_migrations_table_name?, :internal_metadata_table_name?, :protected_environments?,
  :pluralize_table_names?, :ignored_columns?, :store_full_sti_class, :store_full_sti_class=, :nested_attributes_options,
  :nested_attributes_options=, :store_full_sti_class?, :default_scopes, :default_scope_override, :default_scopes=, :default_scope_override=,
  :nested_attributes_options?, :cache_timestamp_format=, :cache_timestamp_format?, :reactive_record_association_keys, :_validators=,
  :has_many, :belongs_to, :composed_of, :belongs_to_without_reactive_record_add_is_method, :_rollback_callbacks, :_commit_callbacks,
  :_before_commit_callbacks, :attribute_type_decorations=, :_commit_callbacks=, :_commit_callbacks?, :_before_commit_callbacks?,
  :_before_commit_callbacks=, :_rollback_callbacks=, :_before_commit_without_transaction_enrollment_callbacks?,
  :_before_commit_without_transaction_enrollment_callbacks=, :_commit_without_transaction_enrollment_callbacks,
  :_commit_without_transaction_enrollment_callbacks?, :_commit_without_transaction_enrollment_callbacks=, :_rollback_callbacks?,
  :_rollback_without_transaction_enrollment_callbacks?, :_rollback_without_transaction_enrollment_callbacks=,
  :_rollback_without_transaction_enrollment_callbacks, :_before_commit_without_transaction_enrollment_callbacks, :aggregate_reflections,
  :_reflections=, :aggregate_reflections=, :pluralize_table_names, :public_columns_hash, :attributes_to_define_after_schema_loads,
  :attributes_to_define_after_schema_loads=, :table_name_suffix, :schema_migrations_table_name, :attribute_aliases,
  :attribute_method_matchers, :connection_handler, :attribute_aliases=, :attribute_method_matchers=, :_validate_callbacks,
  :_validate_callbacks?, :_validate_callbacks=, :_validators?, :_reflections?, :aggregate_reflections?, :include_root_in_json,
  :_reflections, :include_root_in_json=, :include_root_in_json?, :local_stored_attributes, :default_scope, :table_name_prefix,
  :attributes_to_define_after_schema_loads?, :attribute_type_decorations?, :defined_enums=, :suppress, :has_secure_token,
  :generate_unique_secure_token, :store, :store_accessor, :_store_accessors_module, :stored_attributes, :reflect_on_aggregation,
  :reflect_on_all_aggregations, :_reflect_on_association, :reflect_on_all_associations, :clear_reflections_cache, :reflections,
  :reflect_on_association, :reflect_on_all_autosave_associations, :no_touching, :transaction, :after_commit, :after_rollback, :before_commit,
  :before_commit_without_transaction_enrollment, :after_create_commit, :after_update_commit, :after_destroy_commit,
  :after_commit_without_transaction_enrollment, :after_rollback_without_transaction_enrollment, :raise_in_transactional_callbacks,
  :raise_in_transactional_callbacks=, :accepts_nested_attributes_for, :has_secure_password, :has_one, :has_and_belongs_to_many,
  :before_validation, :after_validation, :serialize, :primary_key, :dangerous_attribute_method?, :get_primary_key, :quoted_primary_key,
  :define_method_attribute, :reset_primary_key, :primary_key=, :define_method_attribute=, :attribute_names, :initialize_generated_modules,
  :column_for_attribute, :define_attribute_methods, :undefine_attribute_methods, :instance_method_already_implemented?, :method_defined_within?,
  :dangerous_class_method?, :class_method_defined_within?, :attribute_method?, :has_attribute?, :generated_attribute_methods,
  :attribute_method_prefix, :attribute_method_suffix, :attribute_method_affix, :attribute_alias?, :attribute_alias, :define_attribute_method,
  :update_counters, :locking_enabled?, :locking_column, :locking_column=, :reset_locking_column, :decorate_attribute_type,
  :decorate_matching_attribute_types, :attribute, :define_attribute, :reset_counters, :increment_counter, :decrement_counter,
  :validates_absence_of, :validates_length_of, :validates_size_of, :validates_presence_of, :validates_associated, :validates_uniqueness_of,
  :validates_acceptance_of, :validates_confirmation_of, :validates_exclusion_of, :validates_format_of, :validates_inclusion_of,
  :validates_numericality_of, :define_callbacks, :normalize_callback_params, :__update_callbacks, :get_callbacks, :set_callback,
  :set_callbacks, :skip_callback, :reset_callbacks, :deprecated_false_terminator, :define_model_callbacks, :validate, :validators,
  :validates_each, :validates_with, :clear_validators!, :validators_on, :validates, :_validates_default_keys, :_parse_validates_options,
  :validates!, :_to_partial_path, :sanitize, :sanitize_sql, :sanitize_conditions, :quote_value, :sanitize_sql_for_conditions, :sanitize_sql_array,
  :sanitize_sql_for_assignment, :sanitize_sql_hash_for_assignment, :sanitize_sql_for_order, :expand_hash_conditions_for_aggregates, :sanitize_sql_like,
  :replace_named_bind_variables, :replace_bind_variables, :raise_if_bind_arity_mismatch, :replace_bind_variable, :quote_bound_value, :all,
  :default_scoped, :valid_scope_name?, :scope_attributes?, :before_remove_const, :ignore_default_scope?, :unscoped, :build_default_scope,
  :evaluate_default_scope, :ignore_default_scope=, :current_scope, :current_scope=, :scope_attributes, :base_class, :abstract_class?,
  :finder_needs_type_condition?, :sti_name, :descends_from_active_record?, :abstract_class, :compute_type, :abstract_class=, :table_name, :columns,
  :table_exists?, :columns_hash, :column_names, :attribute_types, :prefetch_primary_key?, :sequence_name, :quoted_table_name, :_default_attributes,
  :type_for_attribute, :inheritance_column, :attributes_builder, :inheritance_column=, :reset_table_name, :table_name=, :reset_column_information,
  :full_table_name_prefix, :full_table_name_suffix, :reset_sequence_name, :sequence_name=, :next_sequence_value, :column_defaults, :content_columns,
  :readonly_attributes, :attr_readonly, :create, :create!, :instantiate, :find, :type_caster, :arel_table, :find_by, :find_by!, :initialize_find_by_cache,
  :generated_association_methods, :arel_engine, :arel_attribute, :predicate_builder, :collection_cache_key, :relation_delegate_class,
  :initialize_relation_delegate_cache, :enum, :collecting_queries_for_explain, :exec_explain, :i18n_scope, :lookup_ancestors, :human_attribute_name,
  :references, :uniq, :maximum, :none, :exists?, :second, :limit, :order, :eager_load, :update, :delete_all, :destroy, :ids, :many?, :pluck, :third,
  :delete, :fourth, :fifth, :forty_two, :second_to_last, :third_to_last, :preload, :sum, :take!, :first!, :last!, :second!, :offset, :select, :fourth!,
  :third!, :third_to_last!, :fifth!, :where, :first_or_create, :second_to_last!, :forty_two!, :first, :having, :any?, :one?, :none?, :find_or_create_by,
  :from, :first_or_create!, :first_or_initialize, :except, :find_or_create_by!, :find_or_initialize_by, :includes, :destroy_all, :update_all, :or,
  :find_in_batches, :take, :joins, :find_each, :last, :in_batches, :reorder, :group, :left_joins, :left_outer_joins, :rewhere, :readonly, :create_with,
  :distinct, :unscope, :calculate, :average, :count_by_sql, :minimum, :lock, :find_by_sql, :count, :cache, :uncached, :connection, :connection_pool,
  :establish_connection, :connected?, :clear_cache!, :clear_reloadable_connections!, :connection_id, :connection_config, :clear_all_connections!,
  :remove_connection, :connection_specification_name, :connection_specification_name=, :retrieve_connection, :connection_id=, :clear_active_connections!,
  :sqlite3_connection, :direct_descendants, :benchmark, :model_name, :with_options, :attr_protected, :attr_accessible
]

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &block) ⇒ Object



177
178
179
180
181
182
183
184
185
186
187
# File 'lib/reactive_record/active_record/class_methods.rb', line 177

def method_missing(name, *args, &block)
  if args.count == 1 && name.start_with?("find_by_") && !block
    find_by(_dealias_attribute(name.sub(/^find_by_/, "")) => args[0])
  elsif [].respond_to?(name)
    all.send(name, *args, &block)
  elsif name.end_with?('!')
    send(name.chop, *args, &block).send(:reload_from_db) rescue nil
  elsif !SERVER_METHODS.include?(name)
    raise "#{self.name}.#{name}(#{args}) (called class method missing)"
  end
end

Instance Method Details

#_all_filterObject



239
240
241
242
243
244
245
246
247
248
249
250
# File 'lib/reactive_record/active_record/class_methods.rb', line 239

def _all_filter
  # provides a filter for the all scopes taking into account STI subclasses
  # note: within the lambda `self` will be the model instance
  defining_class_is_base_class = base_class == self
  defining_model_name = model_name.to_s
  lambda do
    # have to delay computation of inheritance column since it might
    # not be defined when class is first defined
    ic = self.class.inheritance_column
    defining_class_is_base_class || !ic || self[ic] == defining_model_name
  end
end

#_attribute_aliasesObject



80
81
82
# File 'lib/reactive_record/active_record/class_methods.rb', line 80

def _attribute_aliases
  @_attribute_aliases ||= {}
end

#_dealias_attribute(new) ⇒ Object



72
73
74
75
76
77
78
# File 'lib/reactive_record/active_record/class_methods.rb', line 72

def _dealias_attribute(new)
  if self == base_class
    _attribute_aliases[new] || new
  else
    _attribute_aliases[new] ||= superclass._dealias_attribute(new)
  end
end

#_new_without_sti_type_castObject



5
# File 'lib/reactive_record/active_record/class_methods.rb', line 5

alias _new_without_sti_type_cast new

#_react_param_conversion(param, opt = nil) ⇒ Object



357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
# File 'lib/reactive_record/active_record/class_methods.rb', line 357

def _react_param_conversion(param, opt = nil)
  param = Native(param)
  param = JSON.from_object(param.to_n) if param.is_a? Native::Object
  result =
    if param.is_a? self
      param
    elsif param.is_a? Hash
      if opt == :validate_only
        klass = ReactiveRecord::Base.infer_type_from_hash(self, param)
        klass == self || klass < self
      else
        # TODO: investigate saving .changes here and then replacing the
        # TODO: changes after the load is complete.  In other words preserve the
        # TODO: changed values as changes while just updating the synced values.
        target =
          if param[primary_key]
            find(param[primary_key])
          else
            new
          end

        associations = reflect_on_all_associations

        param = param.collect do |key, value|
          assoc = associations.detect do |association|
            association.association_foreign_key == key
          end

          if assoc
            if value
              [assoc.attribute, { id: [value] }]
            else
              [assoc.attribute, [nil]]
            end
          else
            [key, [value]]
          end
        end
        # TODO: verify wrapping with load_data was added so broadcasting works in 1.0.0.lap28
        ReactiveRecord::Base.load_data do
          ReactiveRecord::ServerDataCache.load_from_json(Hash[param], target)
        end
        target.cast_to_current_sti_type
      end
    end

  result
end

#abstract_class=(val) ⇒ Object



272
273
274
# File 'lib/reactive_record/active_record/class_methods.rb', line 272

def abstract_class=(val)
  @abstract_class = val
end

#abstract_class?Boolean

Returns:

  • (Boolean)


23
24
25
# File 'lib/reactive_record/active_record/class_methods.rb', line 23

def abstract_class?
  defined?(@abstract_class) && @abstract_class == true
end

#alias_attribute(new_name, old_name) ⇒ Object



84
85
86
87
88
89
# File 'lib/reactive_record/active_record/class_methods.rb', line 84

def alias_attribute(new_name, old_name)
  ['', '=', '_changed?'].each do |variant|
    define_method("#{new_name}#{variant}") { |*args, &block| send("#{old_name}#{variant}", *args, &block) }
  end
  _attribute_aliases[new_name] = old_name
end

#allObject



227
228
229
230
231
232
233
234
235
236
237
# File 'lib/reactive_record/active_record/class_methods.rb', line 227

def all
  ReactiveRecord::Base.default_scope[self] ||=
    begin
    root = ReactiveRecord::Collection
           .new(self, nil, nil, self, 'all')
           .extend(ReactiveRecord::UnscopedCollection)
    (@_default_scopes || [{ client: _all_filter }]).inject(root) do |scope, opts|
      scope.build_child_scope(ReactiveRecord::ScopeDescription.new(self, :all, opts))
    end
  end
end

#base_classObject



11
12
13
14
15
16
17
18
19
20
21
# File 'lib/reactive_record/active_record/class_methods.rb', line 11

def base_class
  unless self < Base
    raise ActiveRecordError, "#{name} doesn't descend from ActiveRecord"
  end

  if superclass == Base || superclass.abstract_class?
    self
  else
    superclass.base_class
  end
end

#column_namesObject



321
322
323
# File 'lib/reactive_record/active_record/class_methods.rb', line 321

def column_names
  ReactiveRecord::Base.public_columns_hash.keys
end

#columns_hashObject



325
326
327
# File 'lib/reactive_record/active_record/class_methods.rb', line 325

def columns_hash
  ReactiveRecord::Base.public_columns_hash[name] || {}
end

#composed_of(name, opts = {}) ⇒ Object



310
311
312
313
314
315
316
317
318
319
# File 'lib/reactive_record/active_record/class_methods.rb', line 310

def composed_of(name, opts = {})
  reflection = Aggregations::AggregationReflection.new(base_class, :composed_of, name, opts)
  if reflection.klass < ActiveRecord::Base
    define_method(name) { @backing_record.get_ar_aggregate(reflection, nil) }
    define_method("#{name}=") { |val| @backing_record.set_ar_aggregate(reflection, val) }
  else
    define_method(name) { @backing_record.get_non_ar_aggregate(name, nil) }
    define_method("#{name}=") { |val| @backing_record.set_non_ar_aggregate(reflection, val) }
  end
end

#create(*args, &block) ⇒ Object

alias pre_synchromesh_method_missing method_missing

def method_missing(name, *args, &block)

return all.send(name, *args, &block) if [].respond_to?(name)
if name.end_with?('!')
  return send(name.chop, *args, &block).send(:reload_from_db) rescue nil
end
pre_synchromesh_method_missing(name, *args, &block)

end



206
207
208
# File 'lib/reactive_record/active_record/class_methods.rb', line 206

def create(*args, &block)
  new(*args).save(&block)
end

#default_scope(*args, &block) ⇒ Object



221
222
223
224
225
# File 'lib/reactive_record/active_record/class_methods.rb', line 221

def default_scope(*args, &block)
  opts = _synchromesh_scope_args_check([*block, *args])
  @_default_scopes ||= []
  @_default_scopes << opts
end

#define_attribute_methodsObject



345
346
347
348
349
350
351
352
353
354
355
# File 'lib/reactive_record/active_record/class_methods.rb', line 345

def define_attribute_methods
  columns_hash.each do |name, column_hash|
    next if name == primary_key
    define_method(name) { @backing_record.get_attr_value(name, nil) }
    define_method("#{name}!") { @backing_record.get_attr_value(name, true) }
    define_method("#{name}=") { |val| @backing_record.set_attr_value(name, val) }
    define_method("#{name}_changed?") { @backing_record.changed?(name) }
    define_method("#{name}?") { @backing_record.get_attr_value(name, nil).present? }
  end
  self.inheritance_column = nil if inheritance_column && !columns_hash.key?(inheritance_column)
end

#enum(*args) ⇒ Object



64
65
66
# File 'lib/reactive_record/active_record/class_methods.rb', line 64

def enum(*args)
  # when we implement schema validation we should also implement value checking
end

#find(id) ⇒ Object



54
55
56
# File 'lib/reactive_record/active_record/class_methods.rb', line 54

def find(id)
  ReactiveRecord::Base.find(self, primary_key => id)
end

#find_by(opts = {}) ⇒ Object



58
59
60
61
62
# File 'lib/reactive_record/active_record/class_methods.rb', line 58

def find_by(opts = {})
  dealiased_opts = {}
  opts.each { |attr, value| dealiased_opts[_dealias_attribute(attr)] = value }
  ReactiveRecord::Base.find(self, dealiased_opts)
end

#finder_method(name) ⇒ Object



263
264
265
266
267
268
269
270
# File 'lib/reactive_record/active_record/class_methods.rb', line 263

def finder_method(name)
  ReactiveRecord::ScopeDescription.new(self, "_#{name}", {})
  [name, "#{name}!"].each do |method|
    singleton_class.send(:define_method, method) do |*vargs|
      all.apply_scope("_#{method}", *vargs).first
    end
  end
end

#inheritance_columnObject



35
36
37
38
39
40
41
42
43
# File 'lib/reactive_record/active_record/class_methods.rb', line 35

def inheritance_column
  return nil if @no_inheritance_column
  @inheritance_column_value ||=
    if self == base_class
      @inheritance_column_value || 'type'
    else
      superclass.inheritance_column.tap { |v| @no_inheritance_column = !v }
    end
end

#inheritance_column=(name) ⇒ Object



45
46
47
48
# File 'lib/reactive_record/active_record/class_methods.rb', line 45

def inheritance_column=(name)
  @no_inheritance_column = !name
  @inheritance_column_value = name
end

#model_nameObject



50
51
52
# File 'lib/reactive_record/active_record/class_methods.rb', line 50

def model_name
  @model_name ||= ActiveModel::Name.new(self)
end

#new(*args, &block) ⇒ Object



7
8
9
# File 'lib/reactive_record/active_record/class_methods.rb', line 7

def new(*args, &block)
  _new_without_sti_type_cast(*args, &block).cast_to_current_sti_type
end

#primary_keyObject



27
28
29
# File 'lib/reactive_record/active_record/class_methods.rb', line 27

def primary_key
  @primary_key_value ||= (self == base_class) ? :id : base_class.primary_key
end

#primary_key=(val) ⇒ Object



31
32
33
# File 'lib/reactive_record/active_record/class_methods.rb', line 31

def primary_key=(val)
  @primary_key_value = val.to_s
end

#scope(name, *args) ⇒ Object



210
211
212
213
214
215
216
217
218
219
# File 'lib/reactive_record/active_record/class_methods.rb', line 210

def scope(name, *args)
  opts = _synchromesh_scope_args_check(args)
  scope_description = ReactiveRecord::ScopeDescription.new(self, name, opts)
  singleton_class.send(:define_method, name) do |*vargs|
    all.build_child_scope(scope_description, *name, *vargs)
  end
  # singleton_class.send(:define_method, "#{name}=") do |_collection|
  #   raise 'NO LONGER IMPLEMENTED - DOESNT PLAY WELL WITH SYNCHROMESH'
  # end
end

#serialize(attr, *args) ⇒ Object



68
69
70
# File 'lib/reactive_record/active_record/class_methods.rb', line 68

def serialize(attr, *args)
  ReactiveRecord::Base.serialized?[self][attr] = true
end

#server_method(name, default: nil) ⇒ Object



333
334
335
336
337
338
339
340
341
342
343
# File 'lib/reactive_record/active_record/class_methods.rb', line 333

def server_method(name, default: nil)
  server_methods[name] = { default: default }
  define_method(name) do |*args|
    vector = args.count.zero? ? name : [[name] + args]
    @backing_record.get_server_method(vector, nil)
  end
  define_method("#{name}!") do |*args|
    vector = args.count.zero? ? name : [[name] + args]
    @backing_record.get_server_method(vector, true)
  end
end

#server_methodsObject



329
330
331
# File 'lib/reactive_record/active_record/class_methods.rb', line 329

def server_methods
  @server_methods ||= {}
end

#unscopedObject

def all=(_collection)

raise "NO LONGER IMPLEMENTED DOESNT PLAY WELL WITH SYNCHROMESH"

end



256
257
258
259
260
261
# File 'lib/reactive_record/active_record/class_methods.rb', line 256

def unscoped
  ReactiveRecord::Base.unscoped[self] ||=
    ReactiveRecord::Collection
    .new(self, nil, nil, self, 'unscoped')
    .extend(ReactiveRecord::UnscopedCollection)
end