##// END OF EJS Templates
Update the new custom field form with remotely....
Jean-Philippe Lang -
r9980:599736aca7b9
parent child
Show More
@@ -0,0 +1,1
1 $('#content').html('<%= escape_javascript(render :template => 'custom_fields/new', :layout => nil, :formats => [:html]) %>')
@@ -1,288 +1,292
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2012 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 class CustomField < ActiveRecord::Base
19 19 include Redmine::SubclassFactory
20 20
21 21 has_many :custom_values, :dependent => :delete_all
22 22 acts_as_list :scope => 'type = \'#{self.class}\''
23 23 serialize :possible_values
24 24
25 25 validates_presence_of :name, :field_format
26 26 validates_uniqueness_of :name, :scope => :type
27 27 validates_length_of :name, :maximum => 30
28 28 validates_inclusion_of :field_format, :in => Redmine::CustomFieldFormat.available_formats
29 29
30 30 validate :validate_custom_field
31 31 before_validation :set_searchable
32 32
33 33 def set_searchable
34 34 # make sure these fields are not searchable
35 35 self.searchable = false if %w(int float date bool).include?(field_format)
36 36 # make sure only these fields can have multiple values
37 37 self.multiple = false unless %w(list user version).include?(field_format)
38 38 true
39 39 end
40 40
41 41 def validate_custom_field
42 42 if self.field_format == "list"
43 43 errors.add(:possible_values, :blank) if self.possible_values.nil? || self.possible_values.empty?
44 44 errors.add(:possible_values, :invalid) unless self.possible_values.is_a? Array
45 45 end
46 46
47 47 if regexp.present?
48 48 begin
49 49 Regexp.new(regexp)
50 50 rescue
51 51 errors.add(:regexp, :invalid)
52 52 end
53 53 end
54 54
55 55 if default_value.present? && !valid_field_value?(default_value)
56 56 errors.add(:default_value, :invalid)
57 57 end
58 58 end
59 59
60 60 def possible_values_options(obj=nil)
61 61 case field_format
62 62 when 'user', 'version'
63 63 if obj.respond_to?(:project) && obj.project
64 64 case field_format
65 65 when 'user'
66 66 obj.project.users.sort.collect {|u| [u.to_s, u.id.to_s]}
67 67 when 'version'
68 68 obj.project.shared_versions.sort.collect {|u| [u.to_s, u.id.to_s]}
69 69 end
70 70 elsif obj.is_a?(Array)
71 71 obj.collect {|o| possible_values_options(o)}.reduce(:&)
72 72 else
73 73 []
74 74 end
75 75 when 'bool'
76 76 [[l(:general_text_Yes), '1'], [l(:general_text_No), '0']]
77 77 else
78 78 possible_values || []
79 79 end
80 80 end
81 81
82 82 def possible_values(obj=nil)
83 83 case field_format
84 84 when 'user', 'version'
85 85 possible_values_options(obj).collect(&:last)
86 86 when 'bool'
87 87 ['1', '0']
88 88 else
89 89 values = super()
90 90 if values.is_a?(Array)
91 91 values.each do |value|
92 92 value.force_encoding('UTF-8') if value.respond_to?(:force_encoding)
93 93 end
94 94 end
95 95 values || []
96 96 end
97 97 end
98 98
99 99 # Makes possible_values accept a multiline string
100 100 def possible_values=(arg)
101 101 if arg.is_a?(Array)
102 102 super(arg.compact.collect(&:strip).select {|v| !v.blank?})
103 103 else
104 104 self.possible_values = arg.to_s.split(/[\n\r]+/)
105 105 end
106 106 end
107 107
108 108 def cast_value(value)
109 109 casted = nil
110 110 unless value.blank?
111 111 case field_format
112 112 when 'string', 'text', 'list'
113 113 casted = value
114 114 when 'date'
115 115 casted = begin; value.to_date; rescue; nil end
116 116 when 'bool'
117 117 casted = (value == '1' ? true : false)
118 118 when 'int'
119 119 casted = value.to_i
120 120 when 'float'
121 121 casted = value.to_f
122 122 when 'user', 'version'
123 123 casted = (value.blank? ? nil : field_format.classify.constantize.find_by_id(value.to_i))
124 124 end
125 125 end
126 126 casted
127 127 end
128 128
129 129 def value_from_keyword(keyword, customized)
130 130 possible_values_options = possible_values_options(customized)
131 131 if possible_values_options.present?
132 132 keyword = keyword.to_s.downcase
133 133 possible_values_options.detect {|text, id| text.downcase == keyword}.try(:last)
134 134 else
135 135 keyword
136 136 end
137 137 end
138 138
139 139 # Returns a ORDER BY clause that can used to sort customized
140 140 # objects by their value of the custom field.
141 141 # Returns nil if the custom field can not be used for sorting.
142 142 def order_statement
143 143 return nil if multiple?
144 144 case field_format
145 145 when 'string', 'text', 'list', 'date', 'bool'
146 146 # COALESCE is here to make sure that blank and NULL values are sorted equally
147 147 "COALESCE((SELECT cv_sort.value FROM #{CustomValue.table_name} cv_sort" +
148 148 " WHERE cv_sort.customized_type='#{self.class.customized_class.base_class.name}'" +
149 149 " AND cv_sort.customized_id=#{self.class.customized_class.table_name}.id" +
150 150 " AND cv_sort.custom_field_id=#{id} LIMIT 1), '')"
151 151 when 'int', 'float'
152 152 # Make the database cast values into numeric
153 153 # Postgresql will raise an error if a value can not be casted!
154 154 # CustomValue validations should ensure that it doesn't occur
155 155 "(SELECT CAST(cv_sort.value AS decimal(60,3)) FROM #{CustomValue.table_name} cv_sort" +
156 156 " WHERE cv_sort.customized_type='#{self.class.customized_class.base_class.name}'" +
157 157 " AND cv_sort.customized_id=#{self.class.customized_class.table_name}.id" +
158 158 " AND cv_sort.custom_field_id=#{id} AND cv_sort.value <> '' AND cv_sort.value IS NOT NULL LIMIT 1)"
159 159 when 'user', 'version'
160 160 value_class.fields_for_order_statement(value_join_alias)
161 161 else
162 162 nil
163 163 end
164 164 end
165 165
166 166 # Returns a GROUP BY clause that can used to group by custom value
167 167 # Returns nil if the custom field can not be used for grouping.
168 168 def group_statement
169 169 return nil if multiple?
170 170 case field_format
171 171 when 'list', 'date', 'bool', 'int'
172 172 order_statement
173 173 when 'user', 'version'
174 174 "COALESCE((SELECT cv_sort.value FROM #{CustomValue.table_name} cv_sort" +
175 175 " WHERE cv_sort.customized_type='#{self.class.customized_class.base_class.name}'" +
176 176 " AND cv_sort.customized_id=#{self.class.customized_class.table_name}.id" +
177 177 " AND cv_sort.custom_field_id=#{id} LIMIT 1), '')"
178 178 else
179 179 nil
180 180 end
181 181 end
182 182
183 183 def join_for_order_statement
184 184 case field_format
185 185 when 'user', 'version'
186 186 "LEFT OUTER JOIN #{CustomValue.table_name} #{join_alias}" +
187 187 " ON #{join_alias}.customized_type = '#{self.class.customized_class.base_class.name}'" +
188 188 " AND #{join_alias}.customized_id = #{self.class.customized_class.table_name}.id" +
189 189 " AND #{join_alias}.custom_field_id = #{id}" +
190 190 " AND #{join_alias}.value <> ''" +
191 191 " AND #{join_alias}.id = (SELECT max(#{join_alias}_2.id) FROM #{CustomValue.table_name} #{join_alias}_2" +
192 192 " WHERE #{join_alias}_2.customized_type = #{join_alias}.customized_type" +
193 193 " AND #{join_alias}_2.customized_id = #{join_alias}.customized_id" +
194 194 " AND #{join_alias}_2.custom_field_id = #{join_alias}.custom_field_id)" +
195 195 " LEFT OUTER JOIN #{value_class.table_name} #{value_join_alias}" +
196 196 " ON CAST(#{join_alias}.value as decimal(60,0)) = #{value_join_alias}.id"
197 197 else
198 198 nil
199 199 end
200 200 end
201 201
202 202 def join_alias
203 203 "cf_#{id}"
204 204 end
205 205
206 206 def value_join_alias
207 207 join_alias + "_" + field_format
208 208 end
209 209
210 210 def <=>(field)
211 211 position <=> field.position
212 212 end
213 213
214 214 # Returns the class that values represent
215 215 def value_class
216 216 case field_format
217 217 when 'user', 'version'
218 218 field_format.classify.constantize
219 219 else
220 220 nil
221 221 end
222 222 end
223 223
224 224 def self.customized_class
225 225 self.name =~ /^(.+)CustomField$/
226 226 begin; $1.constantize; rescue nil; end
227 227 end
228 228
229 229 # to move in project_custom_field
230 230 def self.for_all
231 231 find(:all, :conditions => ["is_for_all=?", true], :order => 'position')
232 232 end
233 233
234 234 def type_name
235 235 nil
236 236 end
237 237
238 238 # Returns the error messages for the given value
239 239 # or an empty array if value is a valid value for the custom field
240 240 def validate_field_value(value)
241 241 errs = []
242 242 if value.is_a?(Array)
243 243 if !multiple?
244 244 errs << ::I18n.t('activerecord.errors.messages.invalid')
245 245 end
246 246 if is_required? && value.detect(&:present?).nil?
247 247 errs << ::I18n.t('activerecord.errors.messages.blank')
248 248 end
249 249 value.each {|v| errs += validate_field_value_format(v)}
250 250 else
251 251 if is_required? && value.blank?
252 252 errs << ::I18n.t('activerecord.errors.messages.blank')
253 253 end
254 254 errs += validate_field_value_format(value)
255 255 end
256 256 errs
257 257 end
258 258
259 259 # Returns true if value is a valid value for the custom field
260 260 def valid_field_value?(value)
261 261 validate_field_value(value).empty?
262 262 end
263 263
264 def format_in?(*args)
265 args.include?(field_format)
266 end
267
264 268 protected
265 269
266 270 # Returns the error message for the given value regarding its format
267 271 def validate_field_value_format(value)
268 272 errs = []
269 273 if value.present?
270 274 errs << ::I18n.t('activerecord.errors.messages.invalid') unless regexp.blank? or value =~ Regexp.new(regexp)
271 275 errs << ::I18n.t('activerecord.errors.messages.too_short', :count => min_length) if min_length > 0 and value.length < min_length
272 276 errs << ::I18n.t('activerecord.errors.messages.too_long', :count => max_length) if max_length > 0 and value.length > max_length
273 277
274 278 # Format specific validations
275 279 case field_format
276 280 when 'int'
277 281 errs << ::I18n.t('activerecord.errors.messages.not_a_number') unless value =~ /^[+-]?\d+$/
278 282 when 'float'
279 283 begin; Kernel.Float(value); rescue; errs << ::I18n.t('activerecord.errors.messages.invalid') end
280 284 when 'date'
281 285 errs << ::I18n.t('activerecord.errors.messages.not_a_date') unless value =~ /^\d{4}-\d{2}-\d{2}$/ && begin; value.to_date; rescue; false end
282 286 when 'list'
283 287 errs << ::I18n.t('activerecord.errors.messages.inclusion') unless possible_values.include?(value)
284 288 end
285 289 end
286 290 errs
287 291 end
288 292 end
@@ -1,130 +1,72
1 1 <%= error_messages_for 'custom_field' %>
2 2
3 <script type="text/javascript">
4 //<![CDATA[
5 function toggle_custom_field_format() {
6 var format = $("#custom_field_field_format").val();
7 var p_length = $("#custom_field_min_length");
8 var p_regexp = $("#custom_field_regexp");
9 var p_values = $("#custom_field_possible_values");
10 var p_searchable = $("#custom_field_searchable");
11 var p_default = $("#custom_field_default_value");
12 var p_multiple = $("#custom_field_multiple");
13 // can't change type on JQuery objects
14 var p_default2 = document.getElementById("custom_field_default_value");
15
16 p_default2.type = 'text';
17 p_default.parent().show();
18
19 switch (format) {
20 case "list":
21 p_length.parent().hide();
22 p_regexp.parent().hide();
23 p_searchable.parent().show();
24 p_values.parent().show();
25 p_multiple.parent().show();
26 break;
27 case "bool":
28 p_default2.type = 'checkbox';
29 p_length.parent().hide();
30 p_regexp.parent().hide();
31 p_searchable.parent().hide();
32 p_values.parent().hide();
33 p_multiple.parent().hide();
34 break;
35 case "date":
36 p_length.parent().hide();
37 p_regexp.parent().hide();
38 p_searchable.parent().hide();
39 p_values.parent().hide();
40 p_multiple.parent().hide();
41 break;
42 case "float":
43 case "int":
44 p_length.parent().show();
45 p_regexp.parent().show();
46 p_searchable.parent().hide();
47 p_values.parent().hide();
48 p_multiple.parent().hide();
49 break;
50 case "user":
51 case "version":
52 p_length.parent().hide();
53 p_regexp.parent().hide();
54 p_searchable.parent().hide();
55 p_values.parent().hide();
56 p_multiple.parent().show();
57 p_default.parent().hide();
58 break;
59 default:
60 p_length.parent().show();
61 p_regexp.parent().show();
62 p_searchable.parent().show();
63 p_values.parent().hide();
64 p_multiple.parent().hide();
65 break;
66 }
67 }
68
69 //]]>
70 </script>
71
72 3 <div class="box tabular">
73 4 <p><%= f.text_field :name, :required => true %></p>
74 <p><%= f.select :field_format, custom_field_formats_for_select(@custom_field), {}, :onchange => "toggle_custom_field_format();",
75 :disabled => !@custom_field.new_record? %></p>
5 <p><%= f.select :field_format, custom_field_formats_for_select(@custom_field), {}, :disabled => !@custom_field.new_record? %></p>
6
7 <% if @custom_field.format_in? 'list', 'user', 'version' %>
76 8 <p><%= f.check_box :multiple, :disabled => @custom_field.multiple && !@custom_field.new_record? %></p>
9 <% end %>
10
11 <% unless @custom_field.format_in? 'list', 'bool', 'date', 'user', 'version' %>
77 12 <p><label for="custom_field_min_length"><%=l(:label_min_max_length)%></label>
78 13 <%= f.text_field :min_length, :size => 5, :no_label => true %> -
79 14 <%= f.text_field :max_length, :size => 5, :no_label => true %><br />(<%=l(:text_min_max_length_info)%>)</p>
80 15 <p><%= f.text_field :regexp, :size => 50 %><br />(<%=l(:text_regexp_info)%>)</p>
16 <% end %>
17
18 <% if @custom_field.format_in? 'list' %>
81 19 <p>
82 20 <%= f.text_area :possible_values, :value => @custom_field.possible_values.to_a.join("\n"), :rows => 15 %>
83 21 <em class="info"><%= l(:text_custom_field_possible_values_info) %></em>
84 22 </p>
23 <% end %>
24
25 <% unless @custom_field.format_in? 'user', 'version' %>
85 26 <p><%= @custom_field.field_format == 'bool' ? f.check_box(:default_value) : f.text_field(:default_value) %></p>
27 <% end %>
28
86 29 <%= call_hook(:view_custom_fields_form_upper_box, :custom_field => @custom_field, :form => f) %>
87 30 </div>
88 31
89 32 <div class="box tabular">
90 33 <% case @custom_field.class.name
91 34 when "IssueCustomField" %>
92 35
93 36 <fieldset><legend><%=l(:label_tracker_plural)%></legend>
94 37 <% Tracker.sorted.all.each do |tracker| %>
95 38 <%= check_box_tag "custom_field[tracker_ids][]",
96 39 tracker.id,
97 40 (@custom_field.trackers.include? tracker),
98 41 :id => "custom_field_tracker_ids_#{tracker.id}" %>
99 42 <label class="no-css" for="custom_field_tracker_ids_<%=tracker.id%>">
100 43 <%= h(tracker.name) %>
101 44 </label>
102 45 <% end %>
103 46 <%= hidden_field_tag "custom_field[tracker_ids][]", '' %>
104 47 </fieldset>
105 48 &nbsp;
106 49 <p><%= f.check_box :is_required %></p>
107 50 <p><%= f.check_box :is_for_all %></p>
108 51 <p><%= f.check_box :is_filter %></p>
109 52 <p><%= f.check_box :searchable %></p>
110 53
111 54 <% when "UserCustomField" %>
112 55 <p><%= f.check_box :is_required %></p>
113 56 <p><%= f.check_box :visible %></p>
114 57 <p><%= f.check_box :editable %></p>
115 58
116 59 <% when "ProjectCustomField" %>
117 60 <p><%= f.check_box :is_required %></p>
118 61 <p><%= f.check_box :visible %></p>
119 62 <p><%= f.check_box :searchable %></p>
120 63
121 64 <% when "TimeEntryCustomField" %>
122 65 <p><%= f.check_box :is_required %></p>
123 66
124 67 <% else %>
125 68 <p><%= f.check_box :is_required %></p>
126 69
127 70 <% end %>
128 71 <%= call_hook(:"view_custom_fields_form_#{@custom_field.type.to_s.underscore}", :custom_field => @custom_field, :form => f) %>
129 72 </div>
130 <%= javascript_tag "toggle_custom_field_format();" %>
@@ -1,8 +1,8
1 1 <h2><%= link_to l(:label_custom_field_plural), :controller => 'custom_fields', :action => 'index' %>
2 2 &#187; <%= link_to l(@custom_field.type_name), :controller => 'custom_fields', :action => 'index', :tab => @custom_field.class.name %>
3 3 &#187; <%=h @custom_field.name %></h2>
4 4
5 <%= labelled_form_for :custom_field, @custom_field, :url => custom_field_path(@custom_field), :html => {:method => :put} do |f| %>
5 <%= labelled_form_for :custom_field, @custom_field, :url => custom_field_path(@custom_field), :html => {:method => :put, :id => 'custom_field_form'} do |f| %>
6 6 <%= render :partial => 'form', :locals => { :f => f } %>
7 7 <%= submit_tag l(:button_save) %>
8 8 <% end %>
@@ -1,9 +1,19
1 1 <h2><%= link_to l(:label_custom_field_plural), :controller => 'custom_fields', :action => 'index' %>
2 2 &#187; <%= link_to l(@custom_field.type_name), :controller => 'custom_fields', :action => 'index', :tab => @custom_field.class.name %>
3 3 &#187; <%= l(:label_custom_field_new) %></h2>
4 4
5 <%= labelled_form_for :custom_field, @custom_field, :url => custom_fields_path do |f| %>
5 <%= labelled_form_for :custom_field, @custom_field, :url => custom_fields_path, :html => {:id => 'custom_field_form'} do |f| %>
6 6 <%= render :partial => 'form', :locals => { :f => f } %>
7 7 <%= hidden_field_tag 'type', @custom_field.type %>
8 8 <%= submit_tag l(:button_save) %>
9 9 <% end %>
10
11 <%= javascript_tag do %>
12 $('#custom_field_field_format').change(function(){
13 $.ajax({
14 url: '<%= new_custom_field_path(:format => 'js') %>',
15 type: 'get',
16 data: $('#custom_field_form').serialize()
17 });
18 });
19 <% end %>
@@ -1,155 +1,152
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2012 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.expand_path('../../test_helper', __FILE__)
19 require 'custom_fields_controller'
20
21 # Re-raise errors caught by the controller.
22 class CustomFieldsController; def rescue_action(e) raise e end; end
23 19
24 20 class CustomFieldsControllerTest < ActionController::TestCase
25 21 fixtures :custom_fields, :custom_values, :trackers, :users
26 22
27 23 def setup
28 @controller = CustomFieldsController.new
29 @request = ActionController::TestRequest.new
30 @response = ActionController::TestResponse.new
31 24 @request.session[:user_id] = 1
32 25 end
33 26
34 27 def test_index
35 28 get :index
36 29 assert_response :success
37 30 assert_template 'index'
38 31 end
39 32
40 33 def test_new
41 34 custom_field_classes.each do |klass|
42 35 get :new, :type => klass.name
43 36 assert_response :success
44 37 assert_template 'new'
45 38 assert_kind_of klass, assigns(:custom_field)
46 assert_tag :select, :attributes => {:name => 'custom_field[field_format]'}
39 assert_select 'form#custom_field_form' do
40 assert_select 'select#custom_field_field_format[name=?]', 'custom_field[field_format]'
41 assert_select 'input[type=hidden][name=type][value=?]', klass.name
42 end
47 43 end
48 44 end
49 45
50 46 def test_new_issue_custom_field
51 47 get :new, :type => 'IssueCustomField'
52 48 assert_response :success
53 49 assert_template 'new'
54 assert_tag :input, :attributes => {:name => 'custom_field[name]'}
55 assert_tag :select,
56 :attributes => {:name => 'custom_field[field_format]'},
57 :child => {
58 :tag => 'option',
59 :attributes => {:value => 'user'},
60 :content => 'User'
61 }
62 assert_tag :select,
63 :attributes => {:name => 'custom_field[field_format]'},
64 :child => {
65 :tag => 'option',
66 :attributes => {:value => 'version'},
67 :content => 'Version'
68 }
69 assert_tag :input, :attributes => {:name => 'type', :value => 'IssueCustomField'}
50 assert_select 'form#custom_field_form' do
51 assert_select 'select#custom_field_field_format[name=?]', 'custom_field[field_format]' do
52 assert_select 'option[value=user]', :text => 'User'
53 assert_select 'option[value=version]', :text => 'Version'
54 end
55 assert_select 'input[type=hidden][name=type][value=IssueCustomField]'
56 end
57 end
58
59 def test_new_js
60 get :new, :type => 'IssueCustomField', :custom_field => {:field_format => 'list'}, :format => 'js'
61 assert_response :success
62 assert_template 'new'
63 assert_equal 'text/javascript', response.content_type
64
65 field = assigns(:custom_field)
66 assert_equal 'list', field.field_format
70 67 end
71 68
72 69 def test_new_with_invalid_custom_field_class_should_render_404
73 70 get :new, :type => 'UnknownCustomField'
74 71 assert_response 404
75 72 end
76 73
77 74 def test_create_list_custom_field
78 75 assert_difference 'CustomField.count' do
79 76 post :create, :type => "IssueCustomField",
80 77 :custom_field => {:name => "test_post_new_list",
81 78 :default_value => "",
82 79 :min_length => "0",
83 80 :searchable => "0",
84 81 :regexp => "",
85 82 :is_for_all => "1",
86 83 :possible_values => "0.1\n0.2\n",
87 84 :max_length => "0",
88 85 :is_filter => "0",
89 86 :is_required =>"0",
90 87 :field_format => "list",
91 88 :tracker_ids => ["1", ""]}
92 89 end
93 90 assert_redirected_to '/custom_fields?tab=IssueCustomField'
94 91 field = IssueCustomField.find_by_name('test_post_new_list')
95 92 assert_not_nil field
96 93 assert_equal ["0.1", "0.2"], field.possible_values
97 94 assert_equal 1, field.trackers.size
98 95 end
99 96
100 97 def test_create_with_failure
101 98 assert_no_difference 'CustomField.count' do
102 99 post :create, :type => "IssueCustomField", :custom_field => {:name => ''}
103 100 end
104 101 assert_response :success
105 102 assert_template 'new'
106 103 end
107 104
108 105 def test_edit
109 106 get :edit, :id => 1
110 107 assert_response :success
111 108 assert_template 'edit'
112 109 assert_tag 'input', :attributes => {:name => 'custom_field[name]', :value => 'Database'}
113 110 end
114 111
115 112 def test_edit_invalid_custom_field_should_render_404
116 113 get :edit, :id => 99
117 114 assert_response 404
118 115 end
119 116
120 117 def test_update
121 118 put :update, :id => 1, :custom_field => {:name => 'New name'}
122 119 assert_redirected_to '/custom_fields?tab=IssueCustomField'
123 120
124 121 field = CustomField.find(1)
125 122 assert_equal 'New name', field.name
126 123 end
127 124
128 125 def test_update_with_failure
129 126 put :update, :id => 1, :custom_field => {:name => ''}
130 127 assert_response :success
131 128 assert_template 'edit'
132 129 end
133 130
134 131 def test_destroy
135 132 custom_values_count = CustomValue.count(:conditions => {:custom_field_id => 1})
136 133 assert custom_values_count > 0
137 134
138 135 assert_difference 'CustomField.count', -1 do
139 136 assert_difference 'CustomValue.count', - custom_values_count do
140 137 delete :destroy, :id => 1
141 138 end
142 139 end
143 140
144 141 assert_redirected_to '/custom_fields?tab=IssueCustomField'
145 142 assert_nil CustomField.find_by_id(1)
146 143 assert_nil CustomValue.find_by_custom_field_id(1)
147 144 end
148 145
149 146 def custom_field_classes
150 147 files = Dir.glob(File.join(Rails.root, 'app/models/*_custom_field.rb')).map {|f| File.basename(f).sub(/\.rb$/, '') }
151 148 classes = files.map(&:classify).map(&:constantize)
152 149 assert classes.size > 0
153 150 classes
154 151 end
155 152 end
General Comments 0
You need to be logged in to leave comments. Login now