Changesets can be listed by changeset number.
The Git repository is here.
- Revision:
- 373
- Log:
Initial import of Radiant 0.9.1, which is now packaged as a gem. This is an
import of the tagged 0.9.1 source checked out from GitHub, which isn't quite
the same as the gem distribution - but it doesn't seem to be available in an
archived form and the installed gem already has modifications, so this is
the closest I can get.
- Author:
- rool
- Date:
- Mon Mar 21 13:40:05 +0000 2011
- Size:
- 10178 Bytes
1 | module ActiveResource |
2 | class ResourceInvalid < ClientError #:nodoc: |
3 | end |
4 | |
5 | # Active Resource validation is reported to and from this object, which is used by Base#save |
6 | # to determine whether the object in a valid state to be saved. See usage example in Validations. |
7 | class Errors |
8 | include Enumerable |
9 | attr_reader :errors |
10 | |
11 | delegate :empty?, :to => :errors |
12 | |
13 | def initialize(base) # :nodoc: |
14 | @base, @errors = base, {} |
15 | end |
16 | |
17 | # Add an error to the base Active Resource object rather than an attribute. |
18 | # |
19 | # ==== Examples |
20 | # my_folder = Folder.find(1) |
21 | # my_folder.errors.add_to_base("You can't edit an existing folder") |
22 | # my_folder.errors.on_base |
23 | # # => "You can't edit an existing folder" |
24 | # |
25 | # my_folder.errors.add_to_base("This folder has been tagged as frozen") |
26 | # my_folder.valid? |
27 | # # => false |
28 | # my_folder.errors.on_base |
29 | # # => ["You can't edit an existing folder", "This folder has been tagged as frozen"] |
30 | # |
31 | def add_to_base(msg) |
32 | add(:base, msg) |
33 | end |
34 | |
35 | # Adds an error to an Active Resource object's attribute (named for the +attribute+ parameter) |
36 | # with the error message in +msg+. |
37 | # |
38 | # ==== Examples |
39 | # my_resource = Node.find(1) |
40 | # my_resource.errors.add('name', 'can not be "base"') if my_resource.name == 'base' |
41 | # my_resource.errors.on('name') |
42 | # # => 'can not be "base"!' |
43 | # |
44 | # my_resource.errors.add('desc', 'can not be blank') if my_resource.desc == '' |
45 | # my_resource.valid? |
46 | # # => false |
47 | # my_resource.errors.on('desc') |
48 | # # => 'can not be blank!' |
49 | # |
50 | def add(attribute, msg) |
51 | @errors[attribute.to_s] = [] if @errors[attribute.to_s].nil? |
52 | @errors[attribute.to_s] << msg |
53 | end |
54 | |
55 | # Returns true if the specified +attribute+ has errors associated with it. |
56 | # |
57 | # ==== Examples |
58 | # my_resource = Disk.find(1) |
59 | # my_resource.errors.add('location', 'must be Main') unless my_resource.location == 'Main' |
60 | # my_resource.errors.on('location') |
61 | # # => 'must be Main!' |
62 | # |
63 | # my_resource.errors.invalid?('location') |
64 | # # => true |
65 | # my_resource.errors.invalid?('name') |
66 | # # => false |
67 | def invalid?(attribute) |
68 | !@errors[attribute.to_s].nil? |
69 | end |
70 | |
71 | # A method to return the errors associated with +attribute+, which returns nil, if no errors are |
72 | # associated with the specified +attribute+, the error message if one error is associated with the specified +attribute+, |
73 | # or an array of error messages if more than one error is associated with the specified +attribute+. |
74 | # |
75 | # ==== Examples |
76 | # my_person = Person.new(params[:person]) |
77 | # my_person.errors.on('login') |
78 | # # => nil |
79 | # |
80 | # my_person.errors.add('login', 'can not be empty') if my_person.login == '' |
81 | # my_person.errors.on('login') |
82 | # # => 'can not be empty' |
83 | # |
84 | # my_person.errors.add('login', 'can not be longer than 10 characters') if my_person.login.length > 10 |
85 | # my_person.errors.on('login') |
86 | # # => ['can not be empty', 'can not be longer than 10 characters'] |
87 | def on(attribute) |
88 | errors = @errors[attribute.to_s] |
89 | return nil if errors.nil? |
90 | errors.size == 1 ? errors.first : errors |
91 | end |
92 | |
93 | alias :[] :on |
94 | |
95 | # A method to return errors assigned to +base+ object through add_to_base, which returns nil, if no errors are |
96 | # associated with the specified +attribute+, the error message if one error is associated with the specified +attribute+, |
97 | # or an array of error messages if more than one error is associated with the specified +attribute+. |
98 | # |
99 | # ==== Examples |
100 | # my_account = Account.find(1) |
101 | # my_account.errors.on_base |
102 | # # => nil |
103 | # |
104 | # my_account.errors.add_to_base("This account is frozen") |
105 | # my_account.errors.on_base |
106 | # # => "This account is frozen" |
107 | # |
108 | # my_account.errors.add_to_base("This account has been closed") |
109 | # my_account.errors.on_base |
110 | # # => ["This account is frozen", "This account has been closed"] |
111 | # |
112 | def on_base |
113 | on(:base) |
114 | end |
115 | |
116 | # Yields each attribute and associated message per error added. |
117 | # |
118 | # ==== Examples |
119 | # my_person = Person.new(params[:person]) |
120 | # |
121 | # my_person.errors.add('login', 'can not be empty') if my_person.login == '' |
122 | # my_person.errors.add('password', 'can not be empty') if my_person.password == '' |
123 | # messages = '' |
124 | # my_person.errors.each {|attr, msg| messages += attr.humanize + " " + msg + "<br />"} |
125 | # messages |
126 | # # => "Login can not be empty<br />Password can not be empty<br />" |
127 | # |
128 | def each |
129 | @errors.each_key { |attr| @errors[attr].each { |msg| yield attr, msg } } |
130 | end |
131 | |
132 | # Yields each full error message added. So Person.errors.add("first_name", "can't be empty") will be returned |
133 | # through iteration as "First name can't be empty". |
134 | # |
135 | # ==== Examples |
136 | # my_person = Person.new(params[:person]) |
137 | # |
138 | # my_person.errors.add('login', 'can not be empty') if my_person.login == '' |
139 | # my_person.errors.add('password', 'can not be empty') if my_person.password == '' |
140 | # messages = '' |
141 | # my_person.errors.each_full {|msg| messages += msg + "<br/>"} |
142 | # messages |
143 | # # => "Login can not be empty<br />Password can not be empty<br />" |
144 | # |
145 | def each_full |
146 | full_messages.each { |msg| yield msg } |
147 | end |
148 | |
149 | # Returns all the full error messages in an array. |
150 | # |
151 | # ==== Examples |
152 | # my_person = Person.new(params[:person]) |
153 | # |
154 | # my_person.errors.add('login', 'can not be empty') if my_person.login == '' |
155 | # my_person.errors.add('password', 'can not be empty') if my_person.password == '' |
156 | # messages = '' |
157 | # my_person.errors.full_messages.each {|msg| messages += msg + "<br/>"} |
158 | # messages |
159 | # # => "Login can not be empty<br />Password can not be empty<br />" |
160 | # |
161 | def full_messages |
162 | full_messages = [] |
163 | |
164 | @errors.each_key do |attr| |
165 | @errors[attr].each do |msg| |
166 | next if msg.nil? |
167 | |
168 | if attr == "base" |
169 | full_messages << msg |
170 | else |
171 | full_messages << [attr.humanize, msg].join(' ') |
172 | end |
173 | end |
174 | end |
175 | full_messages |
176 | end |
177 | |
178 | def clear |
179 | @errors = {} |
180 | end |
181 | |
182 | # Returns the total number of errors added. Two errors added to the same attribute will be counted as such |
183 | # with this as well. |
184 | # |
185 | # ==== Examples |
186 | # my_person = Person.new(params[:person]) |
187 | # my_person.errors.size |
188 | # # => 0 |
189 | # |
190 | # my_person.errors.add('login', 'can not be empty') if my_person.login == '' |
191 | # my_person.errors.add('password', 'can not be empty') if my_person.password == '' |
192 | # my_person.error.size |
193 | # # => 2 |
194 | # |
195 | def size |
196 | @errors.values.inject(0) { |error_count, attribute| error_count + attribute.size } |
197 | end |
198 | |
199 | alias_method :count, :size |
200 | alias_method :length, :size |
201 | |
202 | # Grabs errors from an array of messages (like ActiveRecord::Validations) |
203 | def from_array(messages) |
204 | clear |
205 | humanized_attributes = @base.attributes.keys.inject({}) { |h, attr_name| h.update(attr_name.humanize => attr_name) } |
206 | messages.each do |message| |
207 | attr_message = humanized_attributes.keys.detect do |attr_name| |
208 | if message[0, attr_name.size + 1] == "#{attr_name} " |
209 | add humanized_attributes[attr_name], message[(attr_name.size + 1)..-1] |
210 | end |
211 | end |
212 | |
213 | add_to_base message if attr_message.nil? |
214 | end |
215 | end |
216 | |
217 | # Grabs errors from the json response. |
218 | def from_json(json) |
219 | array = ActiveSupport::JSON.decode(json)['errors'] rescue [] |
220 | from_array array |
221 | end |
222 | |
223 | # Grabs errors from the XML response. |
224 | def from_xml(xml) |
225 | array = Array.wrap(Hash.from_xml(xml)['errors']['error']) rescue [] |
226 | from_array array |
227 | end |
228 | end |
229 | |
230 | # Module to support validation and errors with Active Resource objects. The module overrides |
231 | # Base#save to rescue ActiveResource::ResourceInvalid exceptions and parse the errors returned |
232 | # in the web service response. The module also adds an +errors+ collection that mimics the interface |
233 | # of the errors provided by ActiveRecord::Errors. |
234 | # |
235 | # ==== Example |
236 | # |
237 | # Consider a Person resource on the server requiring both a +first_name+ and a +last_name+ with a |
238 | # <tt>validates_presence_of :first_name, :last_name</tt> declaration in the model: |
239 | # |
240 | # person = Person.new(:first_name => "Jim", :last_name => "") |
241 | # person.save # => false (server returns an HTTP 422 status code and errors) |
242 | # person.valid? # => false |
243 | # person.errors.empty? # => false |
244 | # person.errors.count # => 1 |
245 | # person.errors.full_messages # => ["Last name can't be empty"] |
246 | # person.errors.on(:last_name) # => "can't be empty" |
247 | # person.last_name = "Halpert" |
248 | # person.save # => true (and person is now saved to the remote service) |
249 | # |
250 | module Validations |
251 | def self.included(base) # :nodoc: |
252 | base.class_eval do |
253 | alias_method_chain :save, :validation |
254 | end |
255 | end |
256 | |
257 | # Validate a resource and save (POST) it to the remote web service. |
258 | def save_with_validation |
259 | save_without_validation |
260 | true |
261 | rescue ResourceInvalid => error |
262 | case self.class.format |
263 | when ActiveResource::Formats[:xml] |
264 | errors.from_xml(error.response.body) |
265 | when ActiveResource::Formats[:json] |
266 | errors.from_json(error.response.body) |
267 | end |
268 | false |
269 | end |
270 | |
271 | # Checks for errors on an object (i.e., is resource.errors empty?). |
272 | # |
273 | # ==== Examples |
274 | # my_person = Person.create(params[:person]) |
275 | # my_person.valid? |
276 | # # => true |
277 | # |
278 | # my_person.errors.add('login', 'can not be empty') if my_person.login == '' |
279 | # my_person.valid? |
280 | # # => false |
281 | def valid? |
282 | errors.empty? |
283 | end |
284 | |
285 | # Returns the Errors object that holds all information about attribute error messages. |
286 | def errors |
287 | @errors ||= Errors.new(self) |
288 | end |
289 | end |
290 | end |