Returns the associated options for the categorized field
# File vendor/plugins/ubiquo_categories/lib/ubiquo_categories/extensions/active_record.rb, line 186
186: def categorize_options(field)
187: categorized_with_options = self.categorized_with_options_lookup
188: raise UbiquoCategories::CategorizationNotFoundError if categorized_with_options.blank?
189: association_name = field.to_s.pluralize.to_sym
190: categorized_with_options[association_name]
191: end
Class method for ActiveRecord that states that a attribute is categorized
Example:
categorized_with :city
possible options:
:from => CategorySet key(s) where this attribute should feed from.
If it's not provided, will pluralize the attribute name and
use it as the key.
:size => the max number of categories that can be selected.
Can be an integer or :many if there is no limit. Default: 1
:separator => The char(s) that delimite the different categories when
creating them from a string. Defaults to double hash (##)
# File vendor/plugins/ubiquo_categories/lib/ubiquo_categories/extensions/active_record.rb, line 34
34: def categorized_with(field, options = {})
35: options.reverse_merge!(DEFAULT_CATEGORIZED_OPTIONS)
36:
37: association_name = field.to_s.pluralize
38:
39: self.has_many(:category_relations, {
40: :as => :related_object,
41: :class_name => "::CategoryRelation",
42: :dependent => :destroy,
43: :order => "category_relations.position ASC"
44: }) unless self.respond_to?(:category_relations)
45:
46: # TODO: Possible Rails bug? Conditions doesn't get applied
47: # inside the first join (monkey patch applied), correct query below:
48:
49: # SELECT DISTINCT "articles".id FROM "articles"
50: # LEFT OUTER JOIN "category_relations" ON (
51: # "articles"."id" = "category_relations"."related_object_id" AND
52: # "category_relations"."related_object_type" = 'Article' AND
53: # "category_relations"."attr_name" = 'sections') <-- association_name
54: # LEFT OUTER JOIN "categories" ON (
55: # "categories"."id" = "category_relations"."category_id")
56: # ORDER BY categories.name asc LIMIT 11 OFFSET 0;
57: self.has_many(:"#{field}_category_relations", {
58: :as => :related_object,
59: :class_name => "::CategoryRelation",
60: :conditions => ["category_relations.attr_name = ?", association_name],
61: :dependent => :destroy,
62: :order => "category_relations.position ASC"
63: })
64:
65: association_name = field.to_s.pluralize
66: set_key = (options[:from] || association_name).to_s
67:
68: @categorized_with_options ||= {}
69: @categorized_with_options[association_name.to_sym] = options
70:
71: assign_to_set = Proc.new do |categories, object|
72: set = CategorySet.find_by_key(set_key) || CategorySet.find_by_key(set_key.singularize)
73: raise UbiquoCategories::SetNotFoundError unless set
74:
75: categories = uhook_assign_to_set set, categories, object
76: [set, categories]
77: end
78:
79: proc = Proc.new do
80:
81: define_method "<<" do |categories|
82: set, categories = assign_to_set.call(categories, proxy_owner)
83:
84: categories.each do |category|
85: unless has_category? category.to_s
86: raise UbiquoCategories::LimitError if is_full?
87: @reflection.through_reflection.klass.create(
88: :attr_name => association_name,
89: :related_object => proxy_owner,
90: :category => category
91: )
92: end
93: end
94: reset
95: end
96:
97: if options[:size] == 1
98: # Returns directly the instance if only one category is allowed
99: def method_missing(method, *args)
100: if load_target
101: if @target.first.respond_to?(method)
102: if block_given?
103: @target.first.send(method, *args) { |*block_args| yield(*block_args) }
104: else
105: @target.first.send(method, *args)
106: end
107: else
108: super
109: end
110: end
111: end
112: end
113:
114: define_method 'is_full?' do
115: return false if options[:size].to_sym == :many
116: Array(self).size >= options[:size]
117: end
118:
119: define_method 'will_be_full?' do |categories|
120: return false if options[:size].to_sym == :many
121: categories.size > options[:size]
122: end
123:
124: define_method 'has_category?' do |category|
125: if category.is_a? Category
126: Array(self).include? category
127: else
128: Array(self).map(&:to_s).include? category.to_s
129: end
130: end
131:
132: # Automatically set the required attr_name when creating through the through
133: define_method 'construct_owner_attributes' do |reflection|
134: super.merge(:attr_name => association_name.to_s)
135: end
136:
137: end
138:
139: self.has_many(association_name.to_sym, {
140: :through => :"#{field}_category_relations",
141: :class_name => "::Category",
142: :source => :category,
143: :conditions => ["category_relations.attr_name = ?", association_name],
144: :order => "category_relations.position ASC",
145: },&proc)
146:
147: define_method "#{association_name}_with_categories=" do |categories|
148: categories = categories.split(options[:separator]) if categories.is_a? String
149:
150: set, categories = assign_to_set.call(categories, self)
151:
152: raise UbiquoCategories::LimitError if send(association_name).will_be_full? categories
153:
154: CategoryRelation.send(:with_scope, :create => {:attr_name => association_name}) do
155: self.send("#{association_name}_without_categories=", categories)
156: end
157:
158: end
159:
160: alias_method_chain "#{association_name}=", 'categories'
161:
162: named_scope "with_#{association_name}_in", lambda{ |*values|
163: category_conditions_for field, values
164: }
165:
166: if field != association_name
167: alias_method field, association_name
168: alias_method "#{field}=", "#{association_name}="
169: klass = class << self; self; end
170: klass.send :alias_method, "with_#{field}_in", "with_#{association_name}_in"
171: end
172:
173: prepare_categories_join_sql field
174:
175: uhook_categorized_with field, options
176:
177: end
(Not documented)
# File vendor/plugins/ubiquo_categories/lib/ubiquo_categories/extensions/active_record.rb, line 179
179: def categorized_with_options_lookup
180: return {} if self.name == ::ActiveRecord::Base.name
181: @categorized_with_options = {} if @categorized_with_options.blank?
182: return @categorized_with_options.reverse_merge(self.superclass.categorized_with_options_lookup)
183: end
(Not documented)
# File vendor/plugins/ubiquo_categories/lib/ubiquo_categories/extensions/active_record.rb, line 193
193: def category_conditions_for field, category_names
194: association_name = field.to_s.pluralize.to_sym
195:
196: options = categorize_options(association_name)
197: raise UbiquoCategories::CategorizationNotFoundError unless options
198:
199: set = CategorySet.find_by_key "#{options[:from] || association_name}"
200: raise UbiquoCategories::SetNotFoundError unless set
201:
202: value = Array(category_names).map do |category_name|
203: value = set.uhook_category_identifier_for_name category_name
204: end.compact
205:
206: value = [0] if value.blank? # to prevent rails sql bad formation
207:
208: {
209: :conditions => Category.uhook_category_identifier_condition(value, association_name),
210: :readonly => false,
211: :joins => categorize_options(field)[:join_sql]
212: }
213: end
Returns directly the instance if only one category is allowed
# File vendor/plugins/ubiquo_categories/lib/ubiquo_categories/extensions/active_record.rb, line 99
99: def method_missing(method, *args)
100: if load_target
101: if @target.first.respond_to?(method)
102: if block_given?
103: @target.first.send(method, *args) { |*block_args| yield(*block_args) }
104: else
105: @target.first.send(method, *args)
106: end
107: else
108: super
109: end
110: end
111: end
(Not documented)
# File vendor/plugins/ubiquo_categories/lib/ubiquo_categories/extensions/active_record.rb, line 217
217: def prepare_categories_join_sql field
218: association_name = field.to_s.pluralize.to_s
219:
220: relation_table = connection.quote_table_name(CategoryRelation.table_name)
221: category_table = connection.quote_table_name(Category.table_name)
222: relation_alias = connection.quote_table_name(CategoryRelation.alias_for_association(association_name))
223: category_alias = connection.quote_table_name(Category.alias_for_association(association_name))
224:
225: categorize_options(field)[:join_sql] = "INNER JOIN \#{relation_table} \#{relation_alias} ON\n(\#{table_name}.id = \#{relation_alias}.related_object_id AND\n\#{relation_alias}.related_object_type = \#{quote_value(base_class.name)})\nINNER JOIN \#{category_table} \#{category_alias} ON\n(\#{category_alias}.id = \#{relation_alias}.category_id) AND\n\#{relation_alias}.attr_name = \#{quote_value(association_name)}\n"
226: end
Disabled; run with $DEBUG to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.