##// END OF EJS Templates
Rails3: model: replace deprecated before_validation method at CustomField model...
Toshi MARUYAMA -
r8071:f1994ea9c082
parent child
Show More
@@ -1,163 +1,164
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 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.
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 include Redmine::SubclassFactory
19 include Redmine::SubclassFactory
20
20
21 has_many :custom_values, :dependent => :delete_all
21 has_many :custom_values, :dependent => :delete_all
22 acts_as_list :scope => 'type = \'#{self.class}\''
22 acts_as_list :scope => 'type = \'#{self.class}\''
23 serialize :possible_values
23 serialize :possible_values
24
24
25 validates_presence_of :name, :field_format
25 validates_presence_of :name, :field_format
26 validates_uniqueness_of :name, :scope => :type
26 validates_uniqueness_of :name, :scope => :type
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_values
30 validate :validate_values
31 before_validation :set_searchable
31
32
32 def initialize(attributes = nil)
33 def initialize(attributes = nil)
33 super
34 super
34 self.possible_values ||= []
35 self.possible_values ||= []
35 end
36 end
36
37
37 def before_validation
38 def set_searchable
38 # make sure these fields are not searchable
39 # make sure these fields are not searchable
39 self.searchable = false if %w(int float date bool).include?(field_format)
40 self.searchable = false if %w(int float date bool).include?(field_format)
40 true
41 true
41 end
42 end
42
43
43 def validate_values
44 def validate_values
44 if self.field_format == "list"
45 if self.field_format == "list"
45 errors.add(:possible_values, :blank) if self.possible_values.nil? || self.possible_values.empty?
46 errors.add(:possible_values, :blank) if self.possible_values.nil? || self.possible_values.empty?
46 errors.add(:possible_values, :invalid) unless self.possible_values.is_a? Array
47 errors.add(:possible_values, :invalid) unless self.possible_values.is_a? Array
47 end
48 end
48
49
49 if regexp.present?
50 if regexp.present?
50 begin
51 begin
51 Regexp.new(regexp)
52 Regexp.new(regexp)
52 rescue
53 rescue
53 errors.add(:regexp, :invalid)
54 errors.add(:regexp, :invalid)
54 end
55 end
55 end
56 end
56
57
57 # validate default value
58 # validate default value
58 v = CustomValue.new(:custom_field => self.clone, :value => default_value, :customized => nil)
59 v = CustomValue.new(:custom_field => self.clone, :value => default_value, :customized => nil)
59 v.custom_field.is_required = false
60 v.custom_field.is_required = false
60 errors.add(:default_value, :invalid) unless v.valid?
61 errors.add(:default_value, :invalid) unless v.valid?
61 end
62 end
62
63
63 def possible_values_options(obj=nil)
64 def possible_values_options(obj=nil)
64 case field_format
65 case field_format
65 when 'user', 'version'
66 when 'user', 'version'
66 if obj.respond_to?(:project) && obj.project
67 if obj.respond_to?(:project) && obj.project
67 case field_format
68 case field_format
68 when 'user'
69 when 'user'
69 obj.project.users.sort.collect {|u| [u.to_s, u.id.to_s]}
70 obj.project.users.sort.collect {|u| [u.to_s, u.id.to_s]}
70 when 'version'
71 when 'version'
71 obj.project.shared_versions.sort.collect {|u| [u.to_s, u.id.to_s]}
72 obj.project.shared_versions.sort.collect {|u| [u.to_s, u.id.to_s]}
72 end
73 end
73 elsif obj.is_a?(Array)
74 elsif obj.is_a?(Array)
74 obj.collect {|o| possible_values_options(o)}.inject {|memo, v| memo & v}
75 obj.collect {|o| possible_values_options(o)}.inject {|memo, v| memo & v}
75 else
76 else
76 []
77 []
77 end
78 end
78 else
79 else
79 read_attribute :possible_values
80 read_attribute :possible_values
80 end
81 end
81 end
82 end
82
83
83 def possible_values(obj=nil)
84 def possible_values(obj=nil)
84 case field_format
85 case field_format
85 when 'user', 'version'
86 when 'user', 'version'
86 possible_values_options(obj).collect(&:last)
87 possible_values_options(obj).collect(&:last)
87 else
88 else
88 read_attribute :possible_values
89 read_attribute :possible_values
89 end
90 end
90 end
91 end
91
92
92 # Makes possible_values accept a multiline string
93 # Makes possible_values accept a multiline string
93 def possible_values=(arg)
94 def possible_values=(arg)
94 if arg.is_a?(Array)
95 if arg.is_a?(Array)
95 write_attribute(:possible_values, arg.compact.collect(&:strip).select {|v| !v.blank?})
96 write_attribute(:possible_values, arg.compact.collect(&:strip).select {|v| !v.blank?})
96 else
97 else
97 self.possible_values = arg.to_s.split(/[\n\r]+/)
98 self.possible_values = arg.to_s.split(/[\n\r]+/)
98 end
99 end
99 end
100 end
100
101
101 def cast_value(value)
102 def cast_value(value)
102 casted = nil
103 casted = nil
103 unless value.blank?
104 unless value.blank?
104 case field_format
105 case field_format
105 when 'string', 'text', 'list'
106 when 'string', 'text', 'list'
106 casted = value
107 casted = value
107 when 'date'
108 when 'date'
108 casted = begin; value.to_date; rescue; nil end
109 casted = begin; value.to_date; rescue; nil end
109 when 'bool'
110 when 'bool'
110 casted = (value == '1' ? true : false)
111 casted = (value == '1' ? true : false)
111 when 'int'
112 when 'int'
112 casted = value.to_i
113 casted = value.to_i
113 when 'float'
114 when 'float'
114 casted = value.to_f
115 casted = value.to_f
115 when 'user', 'version'
116 when 'user', 'version'
116 casted = (value.blank? ? nil : field_format.classify.constantize.find_by_id(value.to_i))
117 casted = (value.blank? ? nil : field_format.classify.constantize.find_by_id(value.to_i))
117 end
118 end
118 end
119 end
119 casted
120 casted
120 end
121 end
121
122
122 # Returns a ORDER BY clause that can used to sort customized
123 # Returns a ORDER BY clause that can used to sort customized
123 # objects by their value of the custom field.
124 # objects by their value of the custom field.
124 # Returns false, if the custom field can not be used for sorting.
125 # Returns false, if the custom field can not be used for sorting.
125 def order_statement
126 def order_statement
126 case field_format
127 case field_format
127 when 'string', 'text', 'list', 'date', 'bool'
128 when 'string', 'text', 'list', 'date', 'bool'
128 # COALESCE is here to make sure that blank and NULL values are sorted equally
129 # COALESCE is here to make sure that blank and NULL values are sorted equally
129 "COALESCE((SELECT cv_sort.value FROM #{CustomValue.table_name} cv_sort" +
130 "COALESCE((SELECT cv_sort.value FROM #{CustomValue.table_name} cv_sort" +
130 " WHERE cv_sort.customized_type='#{self.class.customized_class.name}'" +
131 " WHERE cv_sort.customized_type='#{self.class.customized_class.name}'" +
131 " AND cv_sort.customized_id=#{self.class.customized_class.table_name}.id" +
132 " AND cv_sort.customized_id=#{self.class.customized_class.table_name}.id" +
132 " AND cv_sort.custom_field_id=#{id} LIMIT 1), '')"
133 " AND cv_sort.custom_field_id=#{id} LIMIT 1), '')"
133 when 'int', 'float'
134 when 'int', 'float'
134 # Make the database cast values into numeric
135 # Make the database cast values into numeric
135 # Postgresql will raise an error if a value can not be casted!
136 # Postgresql will raise an error if a value can not be casted!
136 # CustomValue validations should ensure that it doesn't occur
137 # CustomValue validations should ensure that it doesn't occur
137 "(SELECT CAST(cv_sort.value AS decimal(60,3)) FROM #{CustomValue.table_name} cv_sort" +
138 "(SELECT CAST(cv_sort.value AS decimal(60,3)) FROM #{CustomValue.table_name} cv_sort" +
138 " WHERE cv_sort.customized_type='#{self.class.customized_class.name}'" +
139 " WHERE cv_sort.customized_type='#{self.class.customized_class.name}'" +
139 " AND cv_sort.customized_id=#{self.class.customized_class.table_name}.id" +
140 " AND cv_sort.customized_id=#{self.class.customized_class.table_name}.id" +
140 " AND cv_sort.custom_field_id=#{id} AND cv_sort.value <> '' AND cv_sort.value IS NOT NULL LIMIT 1)"
141 " AND cv_sort.custom_field_id=#{id} AND cv_sort.value <> '' AND cv_sort.value IS NOT NULL LIMIT 1)"
141 else
142 else
142 nil
143 nil
143 end
144 end
144 end
145 end
145
146
146 def <=>(field)
147 def <=>(field)
147 position <=> field.position
148 position <=> field.position
148 end
149 end
149
150
150 def self.customized_class
151 def self.customized_class
151 self.name =~ /^(.+)CustomField$/
152 self.name =~ /^(.+)CustomField$/
152 begin; $1.constantize; rescue nil; end
153 begin; $1.constantize; rescue nil; end
153 end
154 end
154
155
155 # to move in project_custom_field
156 # to move in project_custom_field
156 def self.for_all
157 def self.for_all
157 find(:all, :conditions => ["is_for_all=?", true], :order => 'position')
158 find(:all, :conditions => ["is_for_all=?", true], :order => 'position')
158 end
159 end
159
160
160 def type_name
161 def type_name
161 nil
162 nil
162 end
163 end
163 end
164 end
General Comments 0
You need to be logged in to leave comments. Login now