Mercurial > hg > soundsoftware-site
comparison app/models/custom_field.rb @ 1295:622f24f53b42 redmine-2.3
Update to Redmine SVN revision 11972 on 2.3-stable branch
author | Chris Cannam |
---|---|
date | Fri, 14 Jun 2013 09:02:21 +0100 |
parents | 433d4f72a19b |
children |
comparison
equal
deleted
inserted
replaced
1294:3e4c3460b6ca | 1295:622f24f53b42 |
---|---|
1 # Redmine - project management software | 1 # Redmine - project management software |
2 # Copyright (C) 2006-2012 Jean-Philippe Lang | 2 # Copyright (C) 2006-2013 Jean-Philippe Lang |
3 # | 3 # |
4 # This program is free software; you can redistribute it and/or | 4 # This program is free software; you can redistribute it and/or |
5 # modify it under the terms of the GNU General Public License | 5 # modify it under the terms of the GNU General Public License |
6 # as published by the Free Software Foundation; either version 2 | 6 # as published by the Free Software Foundation; either version 2 |
7 # of the License, or (at your option) any later version. | 7 # of the License, or (at your option) any later version. |
27 validates_length_of :name, :maximum => 30 | 27 validates_length_of :name, :maximum => 30 |
28 validates_inclusion_of :field_format, :in => Redmine::CustomFieldFormat.available_formats | 28 validates_inclusion_of :field_format, :in => Redmine::CustomFieldFormat.available_formats |
29 | 29 |
30 validate :validate_custom_field | 30 validate :validate_custom_field |
31 before_validation :set_searchable | 31 before_validation :set_searchable |
32 after_save :handle_multiplicity_change | |
33 | |
34 scope :sorted, lambda { order("#{table_name}.position ASC") } | |
32 | 35 |
33 CUSTOM_FIELDS_TABS = [ | 36 CUSTOM_FIELDS_TABS = [ |
34 {:name => 'IssueCustomField', :partial => 'custom_fields/index', | 37 {:name => 'IssueCustomField', :partial => 'custom_fields/index', |
35 :label => :label_issue_plural}, | 38 :label => :label_issue_plural}, |
36 {:name => 'TimeEntryCustomField', :partial => 'custom_fields/index', | 39 {:name => 'TimeEntryCustomField', :partial => 'custom_fields/index', |
167 end | 170 end |
168 else | 171 else |
169 keyword | 172 keyword |
170 end | 173 end |
171 end | 174 end |
172 | 175 |
173 # Returns a ORDER BY clause that can used to sort customized | 176 # Returns a ORDER BY clause that can used to sort customized |
174 # objects by their value of the custom field. | 177 # objects by their value of the custom field. |
175 # Returns nil if the custom field can not be used for sorting. | 178 # Returns nil if the custom field can not be used for sorting. |
176 def order_statement | 179 def order_statement |
177 return nil if multiple? | 180 return nil if multiple? |
178 case field_format | 181 case field_format |
179 when 'string', 'text', 'list', 'date', 'bool' | 182 when 'string', 'text', 'list', 'date', 'bool' |
180 # COALESCE is here to make sure that blank and NULL values are sorted equally | 183 # COALESCE is here to make sure that blank and NULL values are sorted equally |
181 "COALESCE((SELECT cv_sort.value FROM #{CustomValue.table_name} cv_sort" + | 184 "COALESCE(#{join_alias}.value, '')" |
182 " WHERE cv_sort.customized_type='#{self.class.customized_class.base_class.name}'" + | |
183 " AND cv_sort.customized_id=#{self.class.customized_class.table_name}.id" + | |
184 " AND cv_sort.custom_field_id=#{id} LIMIT 1), '')" | |
185 when 'int', 'float' | 185 when 'int', 'float' |
186 # Make the database cast values into numeric | 186 # Make the database cast values into numeric |
187 # Postgresql will raise an error if a value can not be casted! | 187 # Postgresql will raise an error if a value can not be casted! |
188 # CustomValue validations should ensure that it doesn't occur | 188 # CustomValue validations should ensure that it doesn't occur |
189 "(SELECT CAST(cv_sort.value AS decimal(60,3)) FROM #{CustomValue.table_name} cv_sort" + | 189 "CAST(CASE #{join_alias}.value WHEN '' THEN '0' ELSE #{join_alias}.value END AS decimal(30,3))" |
190 " WHERE cv_sort.customized_type='#{self.class.customized_class.base_class.name}'" + | |
191 " AND cv_sort.customized_id=#{self.class.customized_class.table_name}.id" + | |
192 " AND cv_sort.custom_field_id=#{id} AND cv_sort.value <> '' AND cv_sort.value IS NOT NULL LIMIT 1)" | |
193 when 'user', 'version' | 190 when 'user', 'version' |
194 value_class.fields_for_order_statement(value_join_alias) | 191 value_class.fields_for_order_statement(value_join_alias) |
195 else | 192 else |
196 nil | 193 nil |
197 end | 194 end |
198 end | 195 end |
199 | 196 |
200 # Returns a GROUP BY clause that can used to group by custom value | 197 # Returns a GROUP BY clause that can used to group by custom value |
201 # Returns nil if the custom field can not be used for grouping. | 198 # Returns nil if the custom field can not be used for grouping. |
202 def group_statement | 199 def group_statement |
203 return nil if multiple? | 200 return nil if multiple? |
204 case field_format | 201 case field_format |
205 when 'list', 'date', 'bool', 'int' | 202 when 'list', 'date', 'bool', 'int' |
206 order_statement | 203 order_statement |
207 when 'user', 'version' | 204 when 'user', 'version' |
208 "COALESCE((SELECT cv_sort.value FROM #{CustomValue.table_name} cv_sort" + | 205 "COALESCE(#{join_alias}.value, '')" |
209 " WHERE cv_sort.customized_type='#{self.class.customized_class.base_class.name}'" + | |
210 " AND cv_sort.customized_id=#{self.class.customized_class.table_name}.id" + | |
211 " AND cv_sort.custom_field_id=#{id} LIMIT 1), '')" | |
212 else | 206 else |
213 nil | 207 nil |
214 end | 208 end |
215 end | 209 end |
216 | 210 |
225 " AND #{join_alias}.id = (SELECT max(#{join_alias}_2.id) FROM #{CustomValue.table_name} #{join_alias}_2" + | 219 " AND #{join_alias}.id = (SELECT max(#{join_alias}_2.id) FROM #{CustomValue.table_name} #{join_alias}_2" + |
226 " WHERE #{join_alias}_2.customized_type = #{join_alias}.customized_type" + | 220 " WHERE #{join_alias}_2.customized_type = #{join_alias}.customized_type" + |
227 " AND #{join_alias}_2.customized_id = #{join_alias}.customized_id" + | 221 " AND #{join_alias}_2.customized_id = #{join_alias}.customized_id" + |
228 " AND #{join_alias}_2.custom_field_id = #{join_alias}.custom_field_id)" + | 222 " AND #{join_alias}_2.custom_field_id = #{join_alias}.custom_field_id)" + |
229 " LEFT OUTER JOIN #{value_class.table_name} #{value_join_alias}" + | 223 " LEFT OUTER JOIN #{value_class.table_name} #{value_join_alias}" + |
230 " ON CAST(#{join_alias}.value as decimal(60,0)) = #{value_join_alias}.id" | 224 " ON CAST(CASE #{join_alias}.value WHEN '' THEN '0' ELSE #{join_alias}.value END AS decimal(30,0)) = #{value_join_alias}.id" |
225 when 'int', 'float' | |
226 "LEFT OUTER JOIN #{CustomValue.table_name} #{join_alias}" + | |
227 " ON #{join_alias}.customized_type = '#{self.class.customized_class.base_class.name}'" + | |
228 " AND #{join_alias}.customized_id = #{self.class.customized_class.table_name}.id" + | |
229 " AND #{join_alias}.custom_field_id = #{id}" + | |
230 " AND #{join_alias}.value <> ''" + | |
231 " AND #{join_alias}.id = (SELECT max(#{join_alias}_2.id) FROM #{CustomValue.table_name} #{join_alias}_2" + | |
232 " WHERE #{join_alias}_2.customized_type = #{join_alias}.customized_type" + | |
233 " AND #{join_alias}_2.customized_id = #{join_alias}.customized_id" + | |
234 " AND #{join_alias}_2.custom_field_id = #{join_alias}.custom_field_id)" | |
235 when 'string', 'text', 'list', 'date', 'bool' | |
236 "LEFT OUTER JOIN #{CustomValue.table_name} #{join_alias}" + | |
237 " ON #{join_alias}.customized_type = '#{self.class.customized_class.base_class.name}'" + | |
238 " AND #{join_alias}.customized_id = #{self.class.customized_class.table_name}.id" + | |
239 " AND #{join_alias}.custom_field_id = #{id}" + | |
240 " AND #{join_alias}.id = (SELECT max(#{join_alias}_2.id) FROM #{CustomValue.table_name} #{join_alias}_2" + | |
241 " WHERE #{join_alias}_2.customized_type = #{join_alias}.customized_type" + | |
242 " AND #{join_alias}_2.customized_id = #{join_alias}.customized_id" + | |
243 " AND #{join_alias}_2.custom_field_id = #{join_alias}.custom_field_id)" | |
231 else | 244 else |
232 nil | 245 nil |
233 end | 246 end |
234 end | 247 end |
235 | 248 |
260 begin; $1.constantize; rescue nil; end | 273 begin; $1.constantize; rescue nil; end |
261 end | 274 end |
262 | 275 |
263 # to move in project_custom_field | 276 # to move in project_custom_field |
264 def self.for_all | 277 def self.for_all |
265 find(:all, :conditions => ["is_for_all=?", true], :order => 'position') | 278 where(:is_for_all => true).order('position').all |
266 end | 279 end |
267 | 280 |
268 def type_name | 281 def type_name |
269 nil | 282 nil |
270 end | 283 end |
321 errs << ::I18n.t('activerecord.errors.messages.inclusion') unless possible_values.include?(value) | 334 errs << ::I18n.t('activerecord.errors.messages.inclusion') unless possible_values.include?(value) |
322 end | 335 end |
323 end | 336 end |
324 errs | 337 errs |
325 end | 338 end |
339 | |
340 # Removes multiple values for the custom field after setting the multiple attribute to false | |
341 # We kepp the value with the highest id for each customized object | |
342 def handle_multiplicity_change | |
343 if !new_record? && multiple_was && !multiple | |
344 ids = custom_values. | |
345 where("EXISTS(SELECT 1 FROM #{CustomValue.table_name} cve WHERE cve.custom_field_id = #{CustomValue.table_name}.custom_field_id" + | |
346 " AND cve.customized_type = #{CustomValue.table_name}.customized_type AND cve.customized_id = #{CustomValue.table_name}.customized_id" + | |
347 " AND cve.id > #{CustomValue.table_name}.id)"). | |
348 pluck(:id) | |
349 | |
350 if ids.any? | |
351 custom_values.where(:id => ids).delete_all | |
352 end | |
353 end | |
354 end | |
326 end | 355 end |