Mercurial > hg > soundsoftware-site
comparison app/models/custom_field.rb @ 909:cbb26bc654de redmine-1.3
Update to Redmine 1.3-stable branch (Redmine SVN rev 8964)
author | Chris Cannam |
---|---|
date | Fri, 24 Feb 2012 19:09:32 +0000 |
parents | cbce1fd3b1b7 |
children | 433d4f72a19b |
comparison
equal
deleted
inserted
replaced
908:c6c2cbd0afee | 909:cbb26bc654de |
---|---|
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. |
8 # | 8 # |
9 # This program is distributed in the hope that it will be useful, | 9 # This program is distributed in the hope that it will be useful, |
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 # GNU General Public License for more details. | 12 # GNU General Public License for more details. |
13 # | 13 # |
14 # You should have received a copy of the GNU General Public License | 14 # You should have received a copy of the GNU General Public License |
15 # along with this program; if not, write to the Free Software | 15 # along with this program; if not, write to the Free Software |
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
17 | 17 |
18 class CustomField < ActiveRecord::Base | 18 class CustomField < ActiveRecord::Base |
19 has_many :custom_values, :dependent => :delete_all | 19 has_many :custom_values, :dependent => :delete_all |
20 acts_as_list :scope => 'type = \'#{self.class}\'' | 20 acts_as_list :scope => 'type = \'#{self.class}\'' |
21 serialize :possible_values | 21 serialize :possible_values |
22 | 22 |
23 validates_presence_of :name, :field_format | 23 validates_presence_of :name, :field_format |
24 validates_uniqueness_of :name, :scope => :type | 24 validates_uniqueness_of :name, :scope => :type |
25 validates_length_of :name, :maximum => 30 | 25 validates_length_of :name, :maximum => 30 |
26 validates_inclusion_of :field_format, :in => Redmine::CustomFieldFormat.available_formats | 26 validates_inclusion_of :field_format, :in => Redmine::CustomFieldFormat.available_formats |
27 | 27 |
28 validate :validate_values | |
29 | |
28 def initialize(attributes = nil) | 30 def initialize(attributes = nil) |
29 super | 31 super |
30 self.possible_values ||= [] | 32 self.possible_values ||= [] |
31 end | 33 end |
32 | 34 |
33 def before_validation | 35 def before_validation |
34 # make sure these fields are not searchable | 36 # make sure these fields are not searchable |
35 self.searchable = false if %w(int float date bool).include?(field_format) | 37 self.searchable = false if %w(int float date bool).include?(field_format) |
36 true | 38 true |
37 end | 39 end |
38 | 40 |
39 def validate | 41 def validate_values |
40 if self.field_format == "list" | 42 if self.field_format == "list" |
41 errors.add(:possible_values, :blank) if self.possible_values.nil? || self.possible_values.empty? | 43 errors.add(:possible_values, :blank) if self.possible_values.nil? || self.possible_values.empty? |
42 errors.add(:possible_values, :invalid) unless self.possible_values.is_a? Array | 44 errors.add(:possible_values, :invalid) unless self.possible_values.is_a? Array |
43 end | 45 end |
44 | 46 |
47 if regexp.present? | |
48 begin | |
49 Regexp.new(regexp) | |
50 rescue | |
51 errors.add(:regexp, :invalid) | |
52 end | |
53 end | |
54 | |
45 # validate default value | 55 # validate default value |
46 v = CustomValue.new(:custom_field => self.clone, :value => default_value, :customized => nil) | 56 v = CustomValue.new(:custom_field => self.clone, :value => default_value, :customized => nil) |
47 v.custom_field.is_required = false | 57 v.custom_field.is_required = false |
48 errors.add(:default_value, :invalid) unless v.valid? | 58 errors.add(:default_value, :invalid) unless v.valid? |
49 end | 59 end |
50 | 60 |
51 def possible_values_options(obj=nil) | 61 def possible_values_options(obj=nil) |
52 case field_format | 62 case field_format |
53 when 'user', 'version' | 63 when 'user', 'version' |
54 if obj.respond_to?(:project) && obj.project | 64 if obj.respond_to?(:project) && obj.project |
55 case field_format | 65 case field_format |
56 when 'user' | 66 when 'user' |
57 obj.project.users.sort.collect {|u| [u.to_s, u.id.to_s]} | 67 obj.project.users.sort.collect {|u| [u.to_s, u.id.to_s]} |
58 when 'version' | 68 when 'version' |
59 obj.project.versions.sort.collect {|u| [u.to_s, u.id.to_s]} | 69 obj.project.shared_versions.sort.collect {|u| [u.to_s, u.id.to_s]} |
60 end | 70 end |
61 elsif obj.is_a?(Array) | 71 elsif obj.is_a?(Array) |
62 obj.collect {|o| possible_values_options(o)}.inject {|memo, v| memo & v} | 72 obj.collect {|o| possible_values_options(o)}.inject {|memo, v| memo & v} |
63 else | 73 else |
64 [] | 74 [] |
65 end | 75 end |
66 else | 76 else |
67 read_attribute :possible_values | 77 read_attribute :possible_values |
68 end | 78 end |
69 end | 79 end |
70 | 80 |
71 def possible_values(obj=nil) | 81 def possible_values(obj=nil) |
72 case field_format | 82 case field_format |
73 when 'user', 'version' | 83 when 'user', 'version' |
74 possible_values_options(obj).collect(&:last) | 84 possible_values_options(obj).collect(&:last) |
75 else | 85 else |
76 read_attribute :possible_values | 86 read_attribute :possible_values |
77 end | 87 end |
78 end | 88 end |
79 | 89 |
80 # Makes possible_values accept a multiline string | 90 # Makes possible_values accept a multiline string |
81 def possible_values=(arg) | 91 def possible_values=(arg) |
82 if arg.is_a?(Array) | 92 if arg.is_a?(Array) |
83 write_attribute(:possible_values, arg.compact.collect(&:strip).select {|v| !v.blank?}) | 93 write_attribute(:possible_values, arg.compact.collect(&:strip).select {|v| !v.blank?}) |
84 else | 94 else |
85 self.possible_values = arg.to_s.split(/[\n\r]+/) | 95 self.possible_values = arg.to_s.split(/[\n\r]+/) |
86 end | 96 end |
87 end | 97 end |
88 | 98 |
89 def cast_value(value) | 99 def cast_value(value) |
90 casted = nil | 100 casted = nil |
91 unless value.blank? | 101 unless value.blank? |
92 case field_format | 102 case field_format |
93 when 'string', 'text', 'list' | 103 when 'string', 'text', 'list' |
104 casted = (value.blank? ? nil : field_format.classify.constantize.find_by_id(value.to_i)) | 114 casted = (value.blank? ? nil : field_format.classify.constantize.find_by_id(value.to_i)) |
105 end | 115 end |
106 end | 116 end |
107 casted | 117 casted |
108 end | 118 end |
109 | 119 |
110 # Returns a ORDER BY clause that can used to sort customized | 120 # Returns a ORDER BY clause that can used to sort customized |
111 # objects by their value of the custom field. | 121 # objects by their value of the custom field. |
112 # Returns false, if the custom field can not be used for sorting. | 122 # Returns false, if the custom field can not be used for sorting. |
113 def order_statement | 123 def order_statement |
114 case field_format | 124 case field_format |
115 when 'string', 'text', 'list', 'date', 'bool' | 125 when 'string', 'text', 'list', 'date', 'bool' |
116 # COALESCE is here to make sure that blank and NULL values are sorted equally | 126 # COALESCE is here to make sure that blank and NULL values are sorted equally |
117 "COALESCE((SELECT cv_sort.value FROM #{CustomValue.table_name} cv_sort" + | 127 "COALESCE((SELECT cv_sort.value FROM #{CustomValue.table_name} cv_sort" + |
118 " WHERE cv_sort.customized_type='#{self.class.customized_class.name}'" + | 128 " WHERE cv_sort.customized_type='#{self.class.customized_class.name}'" + |
119 " AND cv_sort.customized_id=#{self.class.customized_class.table_name}.id" + | 129 " AND cv_sort.customized_id=#{self.class.customized_class.table_name}.id" + |
120 " AND cv_sort.custom_field_id=#{id} LIMIT 1), '')" | 130 " AND cv_sort.custom_field_id=#{id} LIMIT 1), '')" |
121 when 'int', 'float' | 131 when 'int', 'float' |
122 # Make the database cast values into numeric | 132 # Make the database cast values into numeric |
123 # Postgresql will raise an error if a value can not be casted! | 133 # Postgresql will raise an error if a value can not be casted! |
124 # CustomValue validations should ensure that it doesn't occur | 134 # CustomValue validations should ensure that it doesn't occur |
125 "(SELECT CAST(cv_sort.value AS decimal(60,3)) FROM #{CustomValue.table_name} cv_sort" + | 135 "(SELECT CAST(cv_sort.value AS decimal(60,3)) FROM #{CustomValue.table_name} cv_sort" + |
126 " WHERE cv_sort.customized_type='#{self.class.customized_class.name}'" + | 136 " WHERE cv_sort.customized_type='#{self.class.customized_class.name}'" + |
127 " AND cv_sort.customized_id=#{self.class.customized_class.table_name}.id" + | 137 " AND cv_sort.customized_id=#{self.class.customized_class.table_name}.id" + |
128 " AND cv_sort.custom_field_id=#{id} AND cv_sort.value <> '' AND cv_sort.value IS NOT NULL LIMIT 1)" | 138 " AND cv_sort.custom_field_id=#{id} AND cv_sort.value <> '' AND cv_sort.value IS NOT NULL LIMIT 1)" |
129 else | 139 else |
130 nil | 140 nil |
132 end | 142 end |
133 | 143 |
134 def <=>(field) | 144 def <=>(field) |
135 position <=> field.position | 145 position <=> field.position |
136 end | 146 end |
137 | 147 |
138 def self.customized_class | 148 def self.customized_class |
139 self.name =~ /^(.+)CustomField$/ | 149 self.name =~ /^(.+)CustomField$/ |
140 begin; $1.constantize; rescue nil; end | 150 begin; $1.constantize; rescue nil; end |
141 end | 151 end |
142 | 152 |
143 # to move in project_custom_field | 153 # to move in project_custom_field |
144 def self.for_all | 154 def self.for_all |
145 find(:all, :conditions => ["is_for_all=?", true], :order => 'position') | 155 find(:all, :conditions => ["is_for_all=?", true], :order => 'position') |
146 end | 156 end |
147 | 157 |
148 def type_name | 158 def type_name |
149 nil | 159 nil |
150 end | 160 end |
151 end | 161 end |