##// END OF EJS Templates
Fixed: error when serializing back objects with custom fields using ActiveResource (#6403)....
Jean-Philippe Lang -
r4366:0e19aa4362a0
parent child
Show More
@@ -1,107 +1,118
1 1 # redMine - project management software
2 2 # Copyright (C) 2006 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 module CustomFieldsHelper
19 19
20 20 def custom_fields_tabs
21 21 tabs = [{:name => 'IssueCustomField', :partial => 'custom_fields/index', :label => :label_issue_plural},
22 22 {:name => 'TimeEntryCustomField', :partial => 'custom_fields/index', :label => :label_spent_time},
23 23 {:name => 'ProjectCustomField', :partial => 'custom_fields/index', :label => :label_project_plural},
24 24 {:name => 'VersionCustomField', :partial => 'custom_fields/index', :label => :label_version_plural},
25 25 {:name => 'UserCustomField', :partial => 'custom_fields/index', :label => :label_user_plural},
26 26 {:name => 'GroupCustomField', :partial => 'custom_fields/index', :label => :label_group_plural},
27 27 {:name => 'TimeEntryActivityCustomField', :partial => 'custom_fields/index', :label => TimeEntryActivity::OptionName},
28 28 {:name => 'IssuePriorityCustomField', :partial => 'custom_fields/index', :label => IssuePriority::OptionName},
29 29 {:name => 'DocumentCategoryCustomField', :partial => 'custom_fields/index', :label => DocumentCategory::OptionName}
30 30 ]
31 31 end
32 32
33 33 # Return custom field html tag corresponding to its format
34 34 def custom_field_tag(name, custom_value)
35 35 custom_field = custom_value.custom_field
36 36 field_name = "#{name}[custom_field_values][#{custom_field.id}]"
37 37 field_id = "#{name}_custom_field_values_#{custom_field.id}"
38 38
39 39 field_format = Redmine::CustomFieldFormat.find_by_name(custom_field.field_format)
40 40 case field_format.edit_as
41 41 when "date"
42 42 text_field_tag(field_name, custom_value.value, :id => field_id, :size => 10) +
43 43 calendar_for(field_id)
44 44 when "text"
45 45 text_area_tag(field_name, custom_value.value, :id => field_id, :rows => 3, :style => 'width:90%')
46 46 when "bool"
47 47 hidden_field_tag(field_name, '0') + check_box_tag(field_name, '1', custom_value.true?, :id => field_id)
48 48 when "list"
49 49 blank_option = custom_field.is_required? ?
50 50 (custom_field.default_value.blank? ? "<option value=\"\">--- #{l(:actionview_instancetag_blank_option)} ---</option>" : '') :
51 51 '<option></option>'
52 52 select_tag(field_name, blank_option + options_for_select(custom_field.possible_values, custom_value.value), :id => field_id)
53 53 else
54 54 text_field_tag(field_name, custom_value.value, :id => field_id)
55 55 end
56 56 end
57 57
58 58 # Return custom field label tag
59 59 def custom_field_label_tag(name, custom_value)
60 60 content_tag "label", custom_value.custom_field.name +
61 61 (custom_value.custom_field.is_required? ? " <span class=\"required\">*</span>" : ""),
62 62 :for => "#{name}_custom_field_values_#{custom_value.custom_field.id}",
63 63 :class => (custom_value.errors.empty? ? nil : "error" )
64 64 end
65 65
66 66 # Return custom field tag with its label tag
67 67 def custom_field_tag_with_label(name, custom_value)
68 68 custom_field_label_tag(name, custom_value) + custom_field_tag(name, custom_value)
69 69 end
70 70
71 71 def custom_field_tag_for_bulk_edit(name, custom_field)
72 72 field_name = "#{name}[custom_field_values][#{custom_field.id}]"
73 73 field_id = "#{name}_custom_field_values_#{custom_field.id}"
74 74 field_format = Redmine::CustomFieldFormat.find_by_name(custom_field.field_format)
75 75 case field_format.edit_as
76 76 when "date"
77 77 text_field_tag(field_name, '', :id => field_id, :size => 10) +
78 78 calendar_for(field_id)
79 79 when "text"
80 80 text_area_tag(field_name, '', :id => field_id, :rows => 3, :style => 'width:90%')
81 81 when "bool"
82 82 select_tag(field_name, options_for_select([[l(:label_no_change_option), ''],
83 83 [l(:general_text_yes), '1'],
84 84 [l(:general_text_no), '0']]), :id => field_id)
85 85 when "list"
86 86 select_tag(field_name, options_for_select([[l(:label_no_change_option), '']] + custom_field.possible_values), :id => field_id)
87 87 else
88 88 text_field_tag(field_name, '', :id => field_id)
89 89 end
90 90 end
91 91
92 92 # Return a string used to display a custom value
93 93 def show_value(custom_value)
94 94 return "" unless custom_value
95 95 format_value(custom_value.value, custom_value.custom_field.field_format)
96 96 end
97 97
98 98 # Return a string used to display a custom value
99 99 def format_value(value, field_format)
100 100 Redmine::CustomFieldFormat.format_value(value, field_format) # Proxy
101 101 end
102 102
103 103 # Return an array of custom field formats which can be used in select_tag
104 104 def custom_field_formats_for_select
105 105 Redmine::CustomFieldFormat.as_select
106 106 end
107
108 # Renders the custom_values in api views
109 def render_api_custom_values(custom_values, api)
110 api.array :custom_fields do
111 custom_values.each do |custom_value|
112 api.custom_field :id => custom_value.custom_field_id, :name => custom_value.custom_field.name do
113 api.value custom_value.value
114 end
115 end
116 end unless custom_values.empty?
117 end
107 118 end
@@ -1,32 +1,28
1 1 api.array :issues do
2 2 @issues.each do |issue|
3 3 api.issue do
4 4 api.id issue.id
5 5 api.project(:id => issue.project_id, :name => issue.project.name) unless issue.project.nil?
6 6 api.tracker(:id => issue.tracker_id, :name => issue.tracker.name) unless issue.tracker.nil?
7 7 api.status(:id => issue.status_id, :name => issue.status.name) unless issue.status.nil?
8 8 api.priority(:id => issue.priority_id, :name => issue.priority.name) unless issue.priority.nil?
9 9 api.author(:id => issue.author_id, :name => issue.author.name) unless issue.author.nil?
10 10 api.assigned_to(:id => issue.assigned_to_id, :name => issue.assigned_to.name) unless issue.assigned_to.nil?
11 11 api.category(:id => issue.category_id, :name => issue.category.name) unless issue.category.nil?
12 12 api.fixed_version(:id => issue.fixed_version_id, :name => issue.fixed_version.name) unless issue.fixed_version.nil?
13 13 api.parent(:id => issue.parent_id) unless issue.parent.nil?
14 14
15 15 api.subject issue.subject
16 16 api.description issue.description
17 17 api.start_date issue.start_date
18 18 api.due_date issue.due_date
19 19 api.done_ratio issue.done_ratio
20 20 api.estimated_hours issue.estimated_hours
21 21
22 api.array :custom_fields do
23 issue.custom_field_values.each do |custom_value|
24 api.custom_field custom_value.value, :id => custom_value.custom_field_id, :name => custom_value.custom_field.name
25 end
26 end
22 render_api_custom_values issue.custom_field_values, api
27 23
28 24 api.created_on issue.created_on
29 25 api.updated_on issue.updated_on
30 26 end
31 27 end
32 28 end
@@ -1,63 +1,59
1 1 api.issue do
2 2 api.id @issue.id
3 3 api.project(:id => @issue.project_id, :name => @issue.project.name) unless @issue.project.nil?
4 4 api.tracker(:id => @issue.tracker_id, :name => @issue.tracker.name) unless @issue.tracker.nil?
5 5 api.status(:id => @issue.status_id, :name => @issue.status.name) unless @issue.status.nil?
6 6 api.priority(:id => @issue.priority_id, :name => @issue.priority.name) unless @issue.priority.nil?
7 7 api.author(:id => @issue.author_id, :name => @issue.author.name) unless @issue.author.nil?
8 8 api.assigned_to(:id => @issue.assigned_to_id, :name => @issue.assigned_to.name) unless @issue.assigned_to.nil?
9 9 api.category(:id => @issue.category_id, :name => @issue.category.name) unless @issue.category.nil?
10 10 api.fixed_version(:id => @issue.fixed_version_id, :name => @issue.fixed_version.name) unless @issue.fixed_version.nil?
11 11 api.parent(:id => @issue.parent_id) unless @issue.parent.nil?
12 12
13 13 api.subject @issue.subject
14 14 api.description @issue.description
15 15 api.start_date @issue.start_date
16 16 api.due_date @issue.due_date
17 17 api.done_ratio @issue.done_ratio
18 18 api.estimated_hours @issue.estimated_hours
19 19 if User.current.allowed_to?(:view_time_entries, @project)
20 20 api.spent_hours @issue.spent_hours
21 21 end
22 22
23 api.array :custom_fields do
24 @issue.custom_field_values.each do |custom_value|
25 api.custom_field custom_value.value, :id => custom_value.custom_field_id, :name => custom_value.custom_field.name
26 end
27 end unless @issue.custom_field_values.empty?
23 render_api_custom_values @issue.custom_field_values, api
28 24
29 25 api.created_on @issue.created_on
30 26 api.updated_on @issue.updated_on
31 27
32 28 render_api_issue_children(@issue, api)
33 29
34 30 api.array :relations do
35 31 @issue.relations.select {|r| r.other_issue(@issue).visible? }.each do |relation|
36 32 api.relation(:id => relation.id, :issue_id => relation.other_issue(@issue).id, :relation_type => relation.relation_type_for(@issue), :delay => relation.delay)
37 33 end
38 34 end
39 35
40 36 api.array :changesets do
41 37 @issue.changesets.each do |changeset|
42 38 api.changeset :revision => changeset.revision do
43 39 api.user(:id => changeset.user_id, :name => changeset.user.name) unless changeset.user.nil?
44 40 api.comments changeset.comments
45 41 api.committed_on changeset.committed_on
46 42 end
47 43 end
48 44 end if User.current.allowed_to?(:view_changesets, @project) && @issue.changesets.any?
49 45
50 46 api.array :journals do
51 47 @issue.journals.each do |journal|
52 48 api.journal :id => journal.id do
53 49 api.user(:id => journal.user_id, :name => journal.user.name) unless journal.user.nil?
54 50 api.notes journal.notes
55 51 api.array :details do
56 52 journal.details.each do |detail|
57 53 api.detail :property => detail.property, :name => detail.prop_key, :old => detail.old_value, :new => detail.value
58 54 end
59 55 end
60 56 end
61 57 end
62 58 end unless @issue.journals.empty?
63 59 end
@@ -1,18 +1,16
1 1 api.array :projects do
2 2 @projects.each do |project|
3 3 api.project do
4 4 api.id project.id
5 5 api.name project.name
6 6 api.identifier project.identifier
7 7 api.description project.description
8 8 api.parent(:id => project.parent_id, :name => project.parent.name) unless project.parent.nil?
9 api.array :custom_fields do
10 project.visible_custom_field_values.each do |custom_value|
11 api.custom_field custom_value.value, :id => custom_value.custom_field_id, :name => custom_value.custom_field.name
12 end
13 end unless project.custom_field_values.empty?
9
10 render_api_custom_values project.visible_custom_field_values, api
11
14 12 api.created_on project.created_on
15 13 api.updated_on project.updated_on
16 14 end
17 15 end
18 16 end
@@ -1,22 +1,18
1 1 api.project do
2 2 api.id @project.id
3 3 api.name @project.name
4 4 api.identifier @project.identifier
5 5 api.description @project.description
6 6 api.homepage @project.homepage
7 7
8 api.array :custom_fields do
9 @project.visible_custom_field_values.each do |custom_value|
10 api.custom_field custom_value.value, :id => custom_value.custom_field_id, :name => custom_value.custom_field.name
11 end
12 end unless @project.custom_field_values.empty?
8 render_api_custom_values @project.visible_custom_field_values, api
13 9
14 10 api.created_on @project.created_on
15 11 api.updated_on @project.updated_on
16 12
17 13 api.array :trackers do
18 14 @project.trackers.each do |tracker|
19 15 api.tracker(:id => tracker.id, :name => tracker.name)
20 16 end
21 17 end
22 18 end
@@ -1,19 +1,15
1 1 api.array :users do
2 2 @users.each do |user|
3 3 api.user do
4 4 api.id user.id
5 5 api.login user.login
6 6 api.firstname user.firstname
7 7 api.lastname user.lastname
8 8 api.mail user.mail
9 9 api.created_on user.created_on
10 10 api.last_login_on user.last_login_on
11 11
12 api.array :custom_fields do
13 user.visible_custom_field_values.each do |custom_value|
14 api.custom_field custom_value.value, :id => custom_value.custom_field_id, :name => custom_value.custom_field.name
15 end
16 end unless user.visible_custom_field_values.empty?
12 render_api_custom_values user.visible_custom_field_values, api
17 13 end
18 14 end
19 15 end
@@ -1,28 +1,24
1 1 api.user do
2 2 api.id @user.id
3 3 api.login @user.login if User.current.admin?
4 4 api.firstname @user.firstname
5 5 api.lastname @user.lastname
6 6 api.mail @user.mail if User.current.admin? || !@user.pref.hide_mail
7 7 api.created_on @user.created_on
8 8 api.last_login_on @user.last_login_on
9 9
10 api.array :custom_fields do
11 @user.visible_custom_field_values.each do |custom_value|
12 api.custom_field custom_value.value, :id => custom_value.custom_field_id, :name => custom_value.custom_field.name
13 end
14 end unless @user.visible_custom_field_values.empty?
10 render_api_custom_values @user.visible_custom_field_values, api
15 11
16 12 api.array :memberships do
17 13 @memberships.each do |membership|
18 14 api.membership do
19 15 api.project :id => membership.project.id, :name => membership.project.name
20 16 api.array :roles do
21 17 membership.roles.each do |role|
22 18 api.role :id => role.id, :name => role.name
23 19 end
24 20 end
25 21 end if membership.project
26 22 end
27 23 end if @memberships.present?
28 24 end
@@ -1,394 +1,420
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2010 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.dirname(__FILE__)}/../../test_helper"
19 19
20 20 class ApiTest::IssuesTest < ActionController::IntegrationTest
21 21 fixtures :projects,
22 22 :users,
23 23 :roles,
24 24 :members,
25 25 :member_roles,
26 26 :issues,
27 27 :issue_statuses,
28 28 :versions,
29 29 :trackers,
30 30 :projects_trackers,
31 31 :issue_categories,
32 32 :enabled_modules,
33 33 :enumerations,
34 34 :attachments,
35 35 :workflows,
36 36 :custom_fields,
37 37 :custom_values,
38 38 :custom_fields_projects,
39 39 :custom_fields_trackers,
40 40 :time_entries,
41 41 :journals,
42 42 :journal_details,
43 43 :queries
44 44
45 45 def setup
46 46 Setting.rest_api_enabled = '1'
47 47 end
48 48
49 49 # Use a private project to make sure auth is really working and not just
50 50 # only showing public issues.
51 51 context "/index.xml" do
52 52 should_allow_api_authentication(:get, "/projects/private-child/issues.xml")
53 53 end
54 54
55 55 context "/index.json" do
56 56 should_allow_api_authentication(:get, "/projects/private-child/issues.json")
57 57 end
58 58
59 59 context "/index.xml with filter" do
60 60 should_allow_api_authentication(:get, "/projects/private-child/issues.xml?status_id=5")
61 61
62 62 should "show only issues with the status_id" do
63 63 get '/issues.xml?status_id=5'
64 64 assert_tag :tag => 'issues',
65 65 :children => { :count => Issue.visible.count(:conditions => {:status_id => 5}),
66 66 :only => { :tag => 'issue' } }
67 67 end
68 68 end
69 69
70 70 context "/index.json with filter" do
71 71 should_allow_api_authentication(:get, "/projects/private-child/issues.json?status_id=5")
72 72
73 73 should "show only issues with the status_id" do
74 74 get '/issues.json?status_id=5'
75 75
76 76 json = ActiveSupport::JSON.decode(response.body)
77 77 status_ids_used = json['issues'].collect {|j| j['status']['id'] }
78 78 assert_equal 3, status_ids_used.length
79 79 assert status_ids_used.all? {|id| id == 5 }
80 80 end
81 81
82 82 end
83 83
84 84 # Issue 6 is on a private project
85 85 context "/issues/6.xml" do
86 86 should_allow_api_authentication(:get, "/issues/6.xml")
87 87 end
88 88
89 89 context "/issues/6.json" do
90 90 should_allow_api_authentication(:get, "/issues/6.json")
91 91 end
92 92
93 93 context "GET /issues/:id" do
94 context "with custom fields" do
95 context ".xml" do
96 should "display custom fields" do
97 get '/issues/3.xml'
98
99 assert_tag :tag => 'issue',
100 :child => {
101 :tag => 'custom_fields',
102 :attributes => { :type => 'array' },
103 :child => {
104 :tag => 'custom_field',
105 :attributes => { :id => '1'},
106 :child => {
107 :tag => 'value',
108 :content => 'MySQL'
109 }
110 }
111 }
112
113 assert_nothing_raised do
114 Hash.from_xml(response.body).to_xml
115 end
116 end
117 end
118 end
119
94 120 context "with subtasks" do
95 121 setup do
96 122 @c1 = Issue.generate!(:status_id => 1, :subject => "child c1", :tracker_id => 1, :project_id => 1, :parent_issue_id => 1)
97 123 @c2 = Issue.generate!(:status_id => 1, :subject => "child c2", :tracker_id => 1, :project_id => 1, :parent_issue_id => 1)
98 124 @c3 = Issue.generate!(:status_id => 1, :subject => "child c3", :tracker_id => 1, :project_id => 1, :parent_issue_id => @c1.id)
99 125 end
100 126
101 127 context ".xml" do
102 128 should "display children" do
103 129 get '/issues/1.xml'
104 130
105 131 assert_tag :tag => 'issue',
106 132 :child => {
107 133 :tag => 'children',
108 134 :children => {:count => 2},
109 135 :child => {
110 136 :tag => 'issue',
111 137 :attributes => {:id => @c1.id.to_s},
112 138 :child => {
113 139 :tag => 'subject',
114 140 :content => 'child c1',
115 141 :sibling => {
116 142 :tag => 'children',
117 143 :children => {:count => 1},
118 144 :child => {
119 145 :tag => 'issue',
120 146 :attributes => {:id => @c3.id.to_s}
121 147 }
122 148 }
123 149 }
124 150 }
125 151 }
126 152 end
127 153
128 154 context ".json" do
129 155 should "display children" do
130 156 get '/issues/1.json'
131 157
132 158 json = ActiveSupport::JSON.decode(response.body)
133 159 assert_equal([
134 160 {
135 161 'id' => @c1.id, 'subject' => 'child c1', 'tracker' => {'id' => 1, 'name' => 'Bug'},
136 162 'children' => [{ 'id' => @c3.id, 'subject' => 'child c3', 'tracker' => {'id' => 1, 'name' => 'Bug'} }]
137 163 },
138 164 { 'id' => @c2.id, 'subject' => 'child c2', 'tracker' => {'id' => 1, 'name' => 'Bug'} }
139 165 ],
140 166 json['issue']['children'])
141 167 end
142 168 end
143 169 end
144 170 end
145 171 end
146 172
147 173 context "POST /issues.xml" do
148 174 should_allow_api_authentication(:post,
149 175 '/issues.xml',
150 176 {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}},
151 177 {:success_code => :created})
152 178
153 179 should "create an issue with the attributes" do
154 180 assert_difference('Issue.count') do
155 181 post '/issues.xml', {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}}, :authorization => credentials('jsmith')
156 182 end
157 183
158 184 issue = Issue.first(:order => 'id DESC')
159 185 assert_equal 1, issue.project_id
160 186 assert_equal 2, issue.tracker_id
161 187 assert_equal 3, issue.status_id
162 188 assert_equal 'API test', issue.subject
163 189
164 190 assert_response :created
165 191 assert_equal 'application/xml', @response.content_type
166 192 assert_tag 'issue', :child => {:tag => 'id', :content => issue.id.to_s}
167 193 end
168 194 end
169 195
170 196 context "POST /issues.xml with failure" do
171 197 should_allow_api_authentication(:post,
172 198 '/issues.xml',
173 199 {:issue => {:project_id => 1}},
174 200 {:success_code => :unprocessable_entity})
175 201
176 202 should "have an errors tag" do
177 203 assert_no_difference('Issue.count') do
178 204 post '/issues.xml', {:issue => {:project_id => 1}}, :authorization => credentials('jsmith')
179 205 end
180 206
181 207 assert_tag :errors, :child => {:tag => 'error', :content => "Subject can't be blank"}
182 208 end
183 209 end
184 210
185 211 context "POST /issues.json" do
186 212 should_allow_api_authentication(:post,
187 213 '/issues.json',
188 214 {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}},
189 215 {:success_code => :created})
190 216
191 217 should "create an issue with the attributes" do
192 218 assert_difference('Issue.count') do
193 219 post '/issues.json', {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}}, :authorization => credentials('jsmith')
194 220 end
195 221
196 222 issue = Issue.first(:order => 'id DESC')
197 223 assert_equal 1, issue.project_id
198 224 assert_equal 2, issue.tracker_id
199 225 assert_equal 3, issue.status_id
200 226 assert_equal 'API test', issue.subject
201 227 end
202 228
203 229 end
204 230
205 231 context "POST /issues.json with failure" do
206 232 should_allow_api_authentication(:post,
207 233 '/issues.json',
208 234 {:issue => {:project_id => 1}},
209 235 {:success_code => :unprocessable_entity})
210 236
211 237 should "have an errors element" do
212 238 assert_no_difference('Issue.count') do
213 239 post '/issues.json', {:issue => {:project_id => 1}}, :authorization => credentials('jsmith')
214 240 end
215 241
216 242 json = ActiveSupport::JSON.decode(response.body)
217 243 assert json['errors'].include?(['subject', "can't be blank"])
218 244 end
219 245 end
220 246
221 247 # Issue 6 is on a private project
222 248 context "PUT /issues/6.xml" do
223 249 setup do
224 250 @parameters = {:issue => {:subject => 'API update', :notes => 'A new note'}}
225 251 @headers = { :authorization => credentials('jsmith') }
226 252 end
227 253
228 254 should_allow_api_authentication(:put,
229 255 '/issues/6.xml',
230 256 {:issue => {:subject => 'API update', :notes => 'A new note'}},
231 257 {:success_code => :ok})
232 258
233 259 should "not create a new issue" do
234 260 assert_no_difference('Issue.count') do
235 261 put '/issues/6.xml', @parameters, @headers
236 262 end
237 263 end
238 264
239 265 should "create a new journal" do
240 266 assert_difference('Journal.count') do
241 267 put '/issues/6.xml', @parameters, @headers
242 268 end
243 269 end
244 270
245 271 should "add the note to the journal" do
246 272 put '/issues/6.xml', @parameters, @headers
247 273
248 274 journal = Journal.last
249 275 assert_equal "A new note", journal.notes
250 276 end
251 277
252 278 should "update the issue" do
253 279 put '/issues/6.xml', @parameters, @headers
254 280
255 281 issue = Issue.find(6)
256 282 assert_equal "API update", issue.subject
257 283 end
258 284
259 285 end
260 286
261 287 context "PUT /issues/6.xml with failed update" do
262 288 setup do
263 289 @parameters = {:issue => {:subject => ''}}
264 290 @headers = { :authorization => credentials('jsmith') }
265 291 end
266 292
267 293 should_allow_api_authentication(:put,
268 294 '/issues/6.xml',
269 295 {:issue => {:subject => ''}}, # Missing subject should fail
270 296 {:success_code => :unprocessable_entity})
271 297
272 298 should "not create a new issue" do
273 299 assert_no_difference('Issue.count') do
274 300 put '/issues/6.xml', @parameters, @headers
275 301 end
276 302 end
277 303
278 304 should "not create a new journal" do
279 305 assert_no_difference('Journal.count') do
280 306 put '/issues/6.xml', @parameters, @headers
281 307 end
282 308 end
283 309
284 310 should "have an errors tag" do
285 311 put '/issues/6.xml', @parameters, @headers
286 312
287 313 assert_tag :errors, :child => {:tag => 'error', :content => "Subject can't be blank"}
288 314 end
289 315 end
290 316
291 317 context "PUT /issues/6.json" do
292 318 setup do
293 319 @parameters = {:issue => {:subject => 'API update', :notes => 'A new note'}}
294 320 @headers = { :authorization => credentials('jsmith') }
295 321 end
296 322
297 323 should_allow_api_authentication(:put,
298 324 '/issues/6.json',
299 325 {:issue => {:subject => 'API update', :notes => 'A new note'}},
300 326 {:success_code => :ok})
301 327
302 328 should "not create a new issue" do
303 329 assert_no_difference('Issue.count') do
304 330 put '/issues/6.json', @parameters, @headers
305 331 end
306 332 end
307 333
308 334 should "create a new journal" do
309 335 assert_difference('Journal.count') do
310 336 put '/issues/6.json', @parameters, @headers
311 337 end
312 338 end
313 339
314 340 should "add the note to the journal" do
315 341 put '/issues/6.json', @parameters, @headers
316 342
317 343 journal = Journal.last
318 344 assert_equal "A new note", journal.notes
319 345 end
320 346
321 347 should "update the issue" do
322 348 put '/issues/6.json', @parameters, @headers
323 349
324 350 issue = Issue.find(6)
325 351 assert_equal "API update", issue.subject
326 352 end
327 353
328 354 end
329 355
330 356 context "PUT /issues/6.json with failed update" do
331 357 setup do
332 358 @parameters = {:issue => {:subject => ''}}
333 359 @headers = { :authorization => credentials('jsmith') }
334 360 end
335 361
336 362 should_allow_api_authentication(:put,
337 363 '/issues/6.json',
338 364 {:issue => {:subject => ''}}, # Missing subject should fail
339 365 {:success_code => :unprocessable_entity})
340 366
341 367 should "not create a new issue" do
342 368 assert_no_difference('Issue.count') do
343 369 put '/issues/6.json', @parameters, @headers
344 370 end
345 371 end
346 372
347 373 should "not create a new journal" do
348 374 assert_no_difference('Journal.count') do
349 375 put '/issues/6.json', @parameters, @headers
350 376 end
351 377 end
352 378
353 379 should "have an errors attribute" do
354 380 put '/issues/6.json', @parameters, @headers
355 381
356 382 json = ActiveSupport::JSON.decode(response.body)
357 383 assert json['errors'].include?(['subject', "can't be blank"])
358 384 end
359 385 end
360 386
361 387 context "DELETE /issues/1.xml" do
362 388 should_allow_api_authentication(:delete,
363 389 '/issues/6.xml',
364 390 {},
365 391 {:success_code => :ok})
366 392
367 393 should "delete the issue" do
368 394 assert_difference('Issue.count',-1) do
369 395 delete '/issues/6.xml', {}, :authorization => credentials('jsmith')
370 396 end
371 397
372 398 assert_nil Issue.find_by_id(6)
373 399 end
374 400 end
375 401
376 402 context "DELETE /issues/1.json" do
377 403 should_allow_api_authentication(:delete,
378 404 '/issues/6.json',
379 405 {},
380 406 {:success_code => :ok})
381 407
382 408 should "delete the issue" do
383 409 assert_difference('Issue.count',-1) do
384 410 delete '/issues/6.json', {}, :authorization => credentials('jsmith')
385 411 end
386 412
387 413 assert_nil Issue.find_by_id(6)
388 414 end
389 415 end
390 416
391 417 def credentials(user, password=nil)
392 418 ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user)
393 419 end
394 420 end
General Comments 0
You need to be logged in to leave comments. Login now