module CustomFields::Source::ClassMethods
Public Instance Methods
Enhance a referenced collection OR the instance itself (by passing self) by providing methods to manage custom fields.
@param [ String, Symbol ] name The name of the relation.
@example
class Company embeds_many :employees custom_fields_for :employees end class Employee embedded_in :company, inverse_of: :employees field :name, String end company.employees_custom_fields.build label: 'His/her position', name: 'position', kind: 'string' company.save company.employees.build name: 'Michael Scott', position: 'Regional manager'
# File lib/custom_fields/source.rb, line 256 def custom_fields_for(name) declare_embedded_in_definition_in_custom_field(name) # stores the relation name _custom_fields_for << name.to_s extend_for_custom_fields(name) end
Determines if the relation is enhanced by the custom fields
@example the Person class has somewhere in its code this: “custom_fields_for :addresses”
Person.custom_fields_for?(:addresses)
@param [ String, Symbol ] name The name of the relation.
@return [ true, false ] True if enhanced, false if not.
# File lib/custom_fields/source.rb, line 233 def custom_fields_for?(name) _custom_fields_for.include?(name.to_s) end
Protected Instance Methods
An embedded relationship has to be defined on both side in order for it to work properly. But because custom_field can be embedded in different models that it’s not aware of, we have to declare manually the definition once we know the target class.
@param [ String, Symbol ] name The name of the relation.
@return [ Field
] The new field class.
# File lib/custom_fields/source.rb, line 337 def declare_embedded_in_definition_in_custom_field(name) klass_name = dynamic_custom_field_class_name(name).split('::').last # Use only the class, ignore the modules source = safe_module_parents.size > 1 ? safe_module_parents.first : Object return if source.const_defined?(klass_name) (klass = Class.new(::CustomFields::Field)).class_eval <<-EOF, __FILE__, __LINE__ + 1 embedded_in :#{self.name.demodulize.underscore}, inverse_of: :#{name}_custom_fields, class_name: '#{self.name}' EOF source.const_set(klass_name, klass) end
Returns the class name of the custom field which is based both on the parent class name and the name of the relation in order to avoid name conflicts (with other classes)
@param [ Metadata ] metadata The relation’s old metadata.
@return [ String ] The class name
# File lib/custom_fields/source.rb, line 324 def dynamic_custom_field_class_name(name) "#{self.name}#{name.to_s.singularize.camelize}Field" end
Extends / Decorates the current class in order to be fully custom_fields compliant. it declares news fields, adds new callbacks, …etc
@param [ String, Symbol ] name The name of the relation.
# File lib/custom_fields/source.rb, line 272 def extend_for_custom_fields(name) class_eval do field :"#{name}_custom_fields_version", type: ::Integer, default: 0 embeds_many :"#{name}_custom_fields", class_name: dynamic_custom_field_class_name(name) # , cascade_callbacks: true # FIXME ????? accepts_nested_attributes_for :"#{name}_custom_fields", allow_destroy: true end class_eval <<-EOV, __FILE__, __LINE__ + 1 after_initialize :refresh_#{name}_metadata before_update :bump_#{name}_custom_fields_version before_update :collect_#{name}_custom_fields_diff after_update :apply_#{name}_custom_fields_diff after_update :apply_#{name}_custom_fields_localize_diff def ordered_#{name}_custom_fields self.ordered_custom_fields('#{name}') end protected def refresh_#{name}_metadata self.refresh_metadata_with_custom_fields('#{name}') end def bump_#{name}_custom_fields_version self.bump_custom_fields_version('#{name}') end def collect_#{name}_custom_fields_diff self.collect_custom_fields_diff(:#{name}, self.#{name}_custom_fields) end def apply_#{name}_custom_fields_diff self.apply_custom_fields_diff(:#{name}) end def apply_#{name}_custom_fields_localize_diff self.apply_custom_fields_localize_diff(:#{name}) end EOV end
# File lib/custom_fields/source.rb, line 351 def safe_module_parents respond_to?(:module_parents) ? module_parents : parents end