Module: DattsRight::Base
- Defined in:
- lib/datts_right/base.rb
Class Method Summary collapse
-
.create_definitions! ⇒ Object
Used when you have already existing records that have don’t have definitions, and you want them to.
- .defined? ⇒ Boolean
- .defined_by?(arg) ⇒ Boolean
- .defines ⇒ Object
- .defines?(klass = nil) ⇒ Boolean
- .method_missing(method_id, *arguments) ⇒ Object
Instance Method Summary collapse
- #has_dynamic_attributes(options = {}) ⇒ Object (also: #has_datts)
-
#respond_to?(method_id, include_private = false) ⇒ Boolean
Override AR::Base#respond_to? so we can return the matchers even if the attribute doesn’t exist in the actual columns.
Class Method Details
.create_definitions! ⇒ Object
Used when you have already existing records that have don’t have definitions, and you want them to
72 73 74 75 76 |
# File 'lib/datts_right/base.rb', line 72 def self.create_definitions! self.all.each do |record| record.create_dynamic_attribute_definition_if_needed end end |
.defined? ⇒ Boolean
94 95 96 |
# File 'lib/datts_right/base.rb', line 94 def self.defined? [:of] end |
.defined_by?(arg) ⇒ Boolean
98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/datts_right/base.rb', line 98 def self.defined_by?(arg) return false unless self.defined? symbol = if arg.is_a?(Class) arg.name.underscore.to_sym elsif arg.is_a?(Symbol) arg else # should be an instance arg.class.name.underscore.to_sym end [:of] == symbol end |
.defines ⇒ Object
90 91 92 |
# File 'lib/datts_right/base.rb', line 90 def self.defines [:defines] if defines? end |
.defines?(klass = nil) ⇒ Boolean
78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/datts_right/base.rb', line 78 def self.defines?(klass=nil) return false unless ![:defines].nil? && ![:defines].empty? #puts "There is [:defines], and it's not empty" if klass klass = klass.class unless klass.is_a?(Class) klass_symbol = klass.name.downcase.to_sym [:defines].include?(klass_symbol) else true end end |
.method_missing(method_id, *arguments) ⇒ Object
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/datts_right/base.rb', line 112 def self.method_missing(method_id, *arguments) # TODO better way to hook this into the rails code, and not define my own begin # Prioritize ActiveRecord's method_missing super(method_id, *arguments) rescue NoMethodError => e if method_id.to_s =~ /^find_(all_|last_)?by_(dynamic_attribute|datt)_([_a-z]\w*)$/ all_or_last = $1 attributes = $3.split("_and_") results = self attributes.each_with_index do |attribute, i| results = results.where_dynamic_attribute(attribute.to_sym => arguments[i]) end case all_or_last when "all_" results when "last_" results.last when nil results.first else nil end else raise e end end end |
Instance Method Details
#has_dynamic_attributes(options = {}) ⇒ Object Also known as: has_datts
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/datts_right/base.rb', line 3 def has_dynamic_attributes(={}) include DattsRight::InstanceMethods cattr_accessor :dynamic_attributes_options self. = has_many :dynamic_attributes, :as => :attributable, :dependent => :destroy has_one :dynamic_attribute_definition, :as => :attribute_defineable, :dependent => :destroy after_save :save_dynamic_attribute_definition after_create :create_dynamic_attribute_definition_if_needed, :inherit_definition! delegate :definition, :definition=, :to => :dynamic_attribute_definition # Carry out delayed actions before save before_save :build_dynamic_attributes after_find :cache_dynamic_attributes default_scope includes(:dynamic_attributes).includes(:dynamic_attribute_definition) #validate :must_be_reflected_by_definer # scope :scope_self when looking through attributes so we don't look through all dynamic_attributes # Why? What if you have Friend and Page models. # * Some Phone records have a dynamic_attribute :price # * Some Page records have a dynamic_attribute :price # # When we do Page.find_by_price(400) we want to search only the dynamic_attributes that belong to Page # and we want to disregard the rest of the dynamic_attributes. scope :scope_self, lambda { joins(:dynamic_attributes).where("dynamic_attributes.attributable_type = :klass", :klass => self.name) } scope :with_datt_key, lambda { |args| with_dynamic_attribute_key(args) } scope :with_dynamic_attribute_key, lambda { |datt_key| scope_self.joins(:dynamic_attributes).where("dynamic_attributes.attr_key = :datt_key", :datt_key => datt_key)} scope :with_datt_type, lambda { |args| with_dynamic_attribute_type(args) } scope :with_dynamic_attribute_type, lambda { |object_type| scope_self.joins(:dynamic_attributes).where("object_type = :object_type", :object_type => object_type) } scope :order_by_datt, lambda { |attr_key_with_order, object_type| order_by_dynamic_attribute(attr_key_with_order, object_type) } scope :order_by_dynamic_attribute, lambda { |attr_key_with_order, object_type| # possible attr_key_with_order forms: "field_name", "field_name ASC", "field_name DESC" split_attr_key_with_order = attr_key_with_order.split(" ") attr_key = split_attr_key_with_order.first order_by = split_attr_key_with_order.last if split_attr_key_with_order.size > 1 order_value = "dynamic_attributes.#{object_type}_value" order_value << " #{order_by}" if order_by scope_self.with_dynamic_attribute_key(attr_key).joins(:dynamic_attributes).with_dynamic_attribute_type(object_type).order(order_value) } scope :where_datt, lambda { |opts| where_dynamic_attribute(opts) } scope :where_datts, lambda { |opts| where_dynamic_attribute(opts) } scope :where_dynamic_attributes, lambda { |opts| where_dynamic_attribute(opts) } scope :where_dynamic_attribute, lambda { |opts| # TODO accept stuff other than the normal hash # Lifted from AR::Relation#build_where attributes = case opts when String, Array self.(opts) when Hash opts end results = self attributes.each do |k, v| conditions = "exists (" + "select 1 from dynamic_attributes dynamic_attribute where " + "#{self.table_name}.id = dynamic_attribute.attributable_id " + "and dynamic_attribute.attributable_type = :attributable_type " + "and dynamic_attribute.attr_key = :attr_key and dynamic_attribute.#{DynamicAttribute.attr_column(v)} = :value" + ")" results = results.where(conditions, :attributable_type => self.name, :attr_key => k.to_s, :value => v) end results } # Used when you have already existing records that have don't have definitions, and you want them to def self.create_definitions! self.all.each do |record| record.create_dynamic_attribute_definition_if_needed end end def self.defines?(klass=nil) return false unless ![:defines].nil? && ![:defines].empty? #puts "There is [:defines], and it's not empty" if klass klass = klass.class unless klass.is_a?(Class) klass_symbol = klass.name.downcase.to_sym [:defines].include?(klass_symbol) else true end end def self.defines [:defines] if defines? end def self.defined? [:of] end def self.defined_by?(arg) return false unless self.defined? symbol = if arg.is_a?(Class) arg.name.underscore.to_sym elsif arg.is_a?(Symbol) arg else # should be an instance arg.class.name.underscore.to_sym end [:of] == symbol end private def self.method_missing(method_id, *arguments) # TODO better way to hook this into the rails code, and not define my own begin # Prioritize ActiveRecord's method_missing super(method_id, *arguments) rescue NoMethodError => e if method_id.to_s =~ /^find_(all_|last_)?by_(dynamic_attribute|datt)_([_a-z]\w*)$/ all_or_last = $1 attributes = $3.split("_and_") results = self attributes.each_with_index do |attribute, i| results = results.where_dynamic_attribute(attribute.to_sym => arguments[i]) end case all_or_last when "all_" results when "last_" results.last when nil results.first else nil end else raise e end end end # Override AR::Base#respond_to? so we can return the matchers even if the # attribute doesn't exist in the actual columns. Is this expensive? def respond_to?(method_id, include_private=false) # TODO perhaps we could save a cache somewhere of all methods used by # any of the records of this class. that way, we can make this method # act a bit more like AR::Base#respond_to? # Ex: # return true if all_attributes_exists?(match.attribute_names) || all_dynamic_attributes_exists?(match.attribute_names) if match = ActiveRecord::DynamicFinderMatch.match(method_id) return true elsif match = ActiveRecord::DynamicScopeMatch.match(method_id) return true end super end end |
#respond_to?(method_id, include_private = false) ⇒ Boolean
Override AR::Base#respond_to? so we can return the matchers even if the attribute doesn’t exist in the actual columns. Is this expensive?
143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/datts_right/base.rb', line 143 def respond_to?(method_id, include_private=false) # TODO perhaps we could save a cache somewhere of all methods used by # any of the records of this class. that way, we can make this method # act a bit more like AR::Base#respond_to? # Ex: # return true if all_attributes_exists?(match.attribute_names) || all_dynamic_attributes_exists?(match.attribute_names) if match = ActiveRecord::DynamicFinderMatch.match(method_id) return true elsif match = ActiveRecord::DynamicScopeMatch.match(method_id) return true end super end |