err_supply-orac 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- data/.gitignore +4 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +281 -0
- data/Rakefile +2 -0
- data/err_supply.gemspec +24 -0
- data/lib/assets/javascripts/err_supply-bootstrap.js +94 -0
- data/lib/assets/stylesheets/err_supply-bootstrap.scss +21 -0
- data/lib/err_supply.rb +26 -0
- data/lib/err_supply/controller_helpers.rb +90 -0
- data/lib/err_supply/version.rb +3 -0
- data/lib/err_supply/view_helpers.rb +22 -0
- metadata +89 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MzRkYzJlZWZkMWY3YTc5YmIzODE2YWYwMDZhODBlMDczMmZhNzY4YQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
NWQzMTU2ZDhlZmM4ODdkNjM1MjVlMDUyMzdkZWVkZjZhN2UwNTBjMA==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ZjUwYWQ2MzU5NjUxZjY0ZjYyMzA2MzY2ZmIyYTM3NTI0MzRiOGQ4MDNiYTg2
|
10
|
+
YWVjYTQxM2NlNmI1MzE2ZmY3ZTBmZTJhNzAzODMwNmJkODU5ZWJmMTg5NTJm
|
11
|
+
ZGE0ZmRmYTc1ZmFjYTQ3OWE1Zjg5ZWZhOTcwZjg1ZTkxY2U3NmU=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZmM1YjY1YTY5YTg2Mjg0MmQzYzdkNmJmNjY1NmQ0YmM5ZGZlODY1YTY1Y2Y2
|
14
|
+
ZjJiNzUxMzBlMDE4NGNhZjczN2QxODI3ZGU4MjBhZWNlNTRlNWYwOTgyNmNi
|
15
|
+
NWU4MDUzODcwNDdjYzEwOTYyYWUyYjZhOWIzZjk0MzIyYTQ4ODg=
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2011 Coroutine, LLC
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,281 @@
|
|
1
|
+
# err_supply
|
2
|
+
|
3
|
+
Err Supply is a Rails view helper that produces simple, beautiful error messages.
|
4
|
+
|
5
|
+
The helper unpacks and rekeys the standard Rails error hash to make applying error messages to your views dead simple. Even better, because the extension cures Rails' brain-damaged way of recording errors from nested resources/attributes, it works with both simple and complex forms.
|
6
|
+
|
7
|
+
|
8
|
+
## What Is This?
|
9
|
+
|
10
|
+
Err Supply is designed to make the default Rails error reporting structure more useful for complex
|
11
|
+
interfaces.
|
12
|
+
|
13
|
+
### HTML vs AJAX form submissions
|
14
|
+
|
15
|
+
We started thinking about Err Supply when we worked on a project that required an AJAX form submission.
|
16
|
+
|
17
|
+
For normal HTML submissions, we coded up a custom error handler in Rails to display the messages below the
|
18
|
+
form input. To replicate this for the AJAX submission, we realized we would have to convert the error hash
|
19
|
+
to JSON and then wire up a jQuery event handler to perform the same DOM manipulations Rails was performing
|
20
|
+
internally. Obviously, we weren't super excited about having code in two places and in two languages to
|
21
|
+
provide the same business value.
|
22
|
+
|
23
|
+
|
24
|
+
### Ambiguous error messages for nested attributes
|
25
|
+
|
26
|
+
The problem was compounded a few months later when we worked on a different project that required an AJAX
|
27
|
+
form submission for a nested form.
|
28
|
+
|
29
|
+
Here, even the workaround is problematic. Because Rails reports errors on nested attributes ambiguously,
|
30
|
+
there really wasn't any way to use a javascript workaround without first reconstituting the error hash
|
31
|
+
itself.
|
32
|
+
|
33
|
+
If you don't know what I mean by saying the error messages are ambiguous, here's an example. Say you have
|
34
|
+
these models defined:
|
35
|
+
|
36
|
+
class Father < ActiveRecord::Base
|
37
|
+
attr_accessible :name
|
38
|
+
attr_accessible :age
|
39
|
+
|
40
|
+
has_many :sons
|
41
|
+
|
42
|
+
accepts_nested_attributes_for :sons, :allow_destroy => true
|
43
|
+
|
44
|
+
validates_presence_of :name, :age
|
45
|
+
end
|
46
|
+
|
47
|
+
class Son < ActiveRecord::Base
|
48
|
+
attr_accessible :name
|
49
|
+
attr_accessible :age
|
50
|
+
|
51
|
+
belongs_to :father
|
52
|
+
|
53
|
+
validates_presence_of :name, :age
|
54
|
+
end
|
55
|
+
|
56
|
+
If you pull up the nested edit form for a father with two sons and delete one son's name and the other
|
57
|
+
son's age, Rails will return the following error hash:
|
58
|
+
|
59
|
+
{
|
60
|
+
"sons.name": ["can't be blank"],
|
61
|
+
"sons.age": ["can't be blank"]
|
62
|
+
}
|
63
|
+
|
64
|
+
Umm, thanks, but which son is missing a name and which one is missing an age? Or is it the same son missing
|
65
|
+
both values? Or, do they both have problems?
|
66
|
+
|
67
|
+
|
68
|
+
|
69
|
+
## Our Solution
|
70
|
+
|
71
|
+
Err Supply converts the Rails error hash from a slightly ambiguous object graph to a flat, unambiguous
|
72
|
+
hash of DOM element ids. It does this by traversing the object graph for you and determining exactly which
|
73
|
+
child resources have errors. It then adds those errors to a new hash object where the key is the DOM id
|
74
|
+
of the corresponding form input.
|
75
|
+
|
76
|
+
Err Supply publishes this newly constituted error hash via a custom jQuery event, allowing the view
|
77
|
+
to handle errors through a single javascript interface. This strategy allows errors from HTML and AJAX
|
78
|
+
form submissions to be run through a single piece of code.
|
79
|
+
|
80
|
+
|
81
|
+
|
82
|
+
## Installation
|
83
|
+
|
84
|
+
Install me from RubyGems.org by adding a gem dependency to your Gemfile. Bundler does
|
85
|
+
the rest.
|
86
|
+
|
87
|
+
gem 'err_supply'
|
88
|
+
|
89
|
+
Add the appropriate javascript file to the asset pipeline. Err Supply comes with an adapter for
|
90
|
+
Twitter Bootstrap enabled sites. Those using other frameworks will need to write a separate adapter
|
91
|
+
based on their framework's interface.
|
92
|
+
|
93
|
+
#= require err_supply-bootstrap
|
94
|
+
|
95
|
+
|
96
|
+
Add the appropriate stylesheet file to the asset pipeline. Err Supply comes with style classes for
|
97
|
+
Twitter Bootstrap enabled sites. Those using other frameworks will need to write a separate set of
|
98
|
+
style classes based on their framework's interface.
|
99
|
+
|
100
|
+
@import 'err_supply-bootstrap';
|
101
|
+
|
102
|
+
|
103
|
+
|
104
|
+
## Basic Usage
|
105
|
+
|
106
|
+
The main `err_supply` helper returns an escaped javascript invocation that triggers a custom
|
107
|
+
event named `err_supply:loaded` and supplies the edited error hash as data.
|
108
|
+
|
109
|
+
<script type="text/javascript">
|
110
|
+
<%= err_supply @father %>
|
111
|
+
</script>
|
112
|
+
|
113
|
+
This will evaluate @father.errors and apply an errors to the form. It assumes all form inputs
|
114
|
+
are named in the standard rails way and that all error attribute keys match the form input
|
115
|
+
keys exactly.
|
116
|
+
|
117
|
+
|
118
|
+
### 1. Whitelists/Blacklists
|
119
|
+
|
120
|
+
Attributes can be whitelisted or blacklisted using the standard `:only` and `:except` notation.
|
121
|
+
|
122
|
+
Because `err_supply` will ignore any unmatched attributes, such declarations are not strictly
|
123
|
+
required. They typically only make sense for minor actions against models with many,
|
124
|
+
many attributes.
|
125
|
+
|
126
|
+
|
127
|
+
### 2. Changing Labels
|
128
|
+
|
129
|
+
Say a User class has an attribute `:born_on` to store the user's date of birth. In your form
|
130
|
+
builder you declare the textbox normally like so:
|
131
|
+
|
132
|
+
<%= f.text_field :born_on %>
|
133
|
+
|
134
|
+
A presence\_of error will be formatted as:
|
135
|
+
|
136
|
+
Born on can't be blank.
|
137
|
+
|
138
|
+
To make this nicer, we can change the label for the attribute like this:
|
139
|
+
|
140
|
+
<script type="text/javascript">
|
141
|
+
<%= err_supply @user, :born_on => { :label => "Date of birth" } %>
|
142
|
+
</script>
|
143
|
+
|
144
|
+
This will attach the following presence of error to the :born_on field:
|
145
|
+
|
146
|
+
Date of birth can't be blank.
|
147
|
+
|
148
|
+
|
149
|
+
### 3. Changing Keys
|
150
|
+
|
151
|
+
Say a User class belongs to an Organization class. In your form, you declare a selector
|
152
|
+
for assigning the organization. The selector is named `:ogranization_id`.
|
153
|
+
|
154
|
+
Depending on how your validations are written, you might very well get an error message for
|
155
|
+
this form keyed to `:organization`. Because your selector is keyed to `:organization_id`,
|
156
|
+
the default javascript handler will consider this an unmatched attribute.
|
157
|
+
|
158
|
+
You can solve this problem by changing the key for the attribute like so:
|
159
|
+
|
160
|
+
<script type="text/javascript">
|
161
|
+
<%= err_supply @user, :organization => { :key => :organization_id } %>
|
162
|
+
</script>
|
163
|
+
|
164
|
+
|
165
|
+
### 4. Nested Attributes
|
166
|
+
|
167
|
+
You can apply the same principles to nested attributes by nesting the instructions. To return
|
168
|
+
to our father/son example, you can change the name labels for both entities using the following
|
169
|
+
notation:
|
170
|
+
|
171
|
+
<script type="text/javascript">
|
172
|
+
<%= err_supply @father,
|
173
|
+
:name => { :label => "Father's name" },
|
174
|
+
:sons => {
|
175
|
+
:name => { :label => "Son's name" }
|
176
|
+
}
|
177
|
+
%>
|
178
|
+
</script>
|
179
|
+
|
180
|
+
|
181
|
+
### 5. Combining Instructions (aka Go Crazy)
|
182
|
+
|
183
|
+
Attribute instructions are provided as hashes so that both `key` and `label` changes can be
|
184
|
+
declared on the same attribute.
|
185
|
+
|
186
|
+
Honestly, such instructions are rare in the real world, but error handling can get weird fast,
|
187
|
+
so the library supports it.
|
188
|
+
|
189
|
+
|
190
|
+
|
191
|
+
|
192
|
+
## Advanced Usage
|
193
|
+
|
194
|
+
There are a handful of scenarios that fall outside the area of basic usage worth discussing.
|
195
|
+
|
196
|
+
### 1. AJAX Submissions and Nested Forms
|
197
|
+
|
198
|
+
When Rails submits a nested form via a full page refresh, Rails automatically re-indexes any
|
199
|
+
DOM elements in a nested collection starting at 0.
|
200
|
+
|
201
|
+
If you're submitting a form remotely, it's on you to do this by re-rendering the nested fields
|
202
|
+
with the current collection.
|
203
|
+
|
204
|
+
As long as you do this before the `err_supply` call is made, everything will work normally.
|
205
|
+
|
206
|
+
|
207
|
+
### 2. Other Javascript Libraries
|
208
|
+
|
209
|
+
If you don't use jQuery, you may want to override the `err_supply` helper to format the
|
210
|
+
javascript invocation differently.
|
211
|
+
|
212
|
+
The library is constructed so the main public method named `err_supply` is pretty dumb. Most
|
213
|
+
of the real hash-altering magic occurs in a protected method called `err_supply_hash`. You can
|
214
|
+
override the much simpler method without worrying about damaging the core hash interpretation
|
215
|
+
functionality.
|
216
|
+
|
217
|
+
See the `lib` directory for details.
|
218
|
+
|
219
|
+
|
220
|
+
### 3. Handling Unmatched Errors
|
221
|
+
|
222
|
+
The default javascript handler bundles up unmatched error keys into a new hash and publishes them
|
223
|
+
using the custom jQuery event `err_supply:unmatched`.
|
224
|
+
|
225
|
+
|
226
|
+
|
227
|
+
|
228
|
+
## Prerequisites
|
229
|
+
|
230
|
+
* <b>Ruby on Rails:</b> <http://rubyonrails.org>
|
231
|
+
* <b>jQuery:</b> <http://jquery.com>
|
232
|
+
|
233
|
+
|
234
|
+
|
235
|
+
|
236
|
+
## Helpful Links
|
237
|
+
|
238
|
+
* <b>Repository:</b> <http://github.com/coroutine/err_supply>
|
239
|
+
* <b>Gem:</b> <http://rubygems.org/gems/err_supply>
|
240
|
+
* <b>Authors:</b> <http://coroutine.com>
|
241
|
+
|
242
|
+
|
243
|
+
|
244
|
+
|
245
|
+
## Gemroll
|
246
|
+
|
247
|
+
Other gems by Coroutine include:
|
248
|
+
|
249
|
+
* [acts\_as\_current](http://github.com/coroutine/acts_as_current)
|
250
|
+
* [acts\_as\_label](http://github.com/coroutine/acts_as_label)
|
251
|
+
* [acts\_as\_list\_with\_sti\_support](http://github.com/coroutine/acts_as_list_with_sti_support)
|
252
|
+
* [delayed\_form\_observer](http://github.com/coroutine/delayed_form_observer)
|
253
|
+
* [kenny\_dialoggins](http://github.com/coroutine/kenny_dialoggins)
|
254
|
+
* [michael\_hintbuble](http://github.com/coroutine/michael_hintbuble)
|
255
|
+
* [tiny\_navigation](http://github.com/coroutine/tiny_navigation)
|
256
|
+
|
257
|
+
|
258
|
+
|
259
|
+
|
260
|
+
## License
|
261
|
+
|
262
|
+
Copyright (c) 2011 [Coroutine LLC](http://coroutine.com).
|
263
|
+
|
264
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
265
|
+
a copy of this software and associated documentation files (the
|
266
|
+
"Software"), to deal in the Software without restriction, including
|
267
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
268
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
269
|
+
permit persons to whom the Software is furnished to do so, subject to
|
270
|
+
the following conditions:
|
271
|
+
|
272
|
+
The above copyright notice and this permission notice shall be
|
273
|
+
included in all copies or substantial portions of the Software.
|
274
|
+
|
275
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
276
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
277
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
278
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
279
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
280
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
281
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
data/err_supply.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'err_supply/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'err_supply-orac'
|
8
|
+
spec.version = ErrSupply::VERSION
|
9
|
+
spec.authors = ['Coroutine', 'John Dugan']
|
10
|
+
spec.email = ['gems@coroutine.com']
|
11
|
+
spec.summary = %q{Simple, beautiful error messages for Rails.}
|
12
|
+
spec.description = %q{Simple, beautiful error messages for Rails. Err_supply unpacks and rekeys the standard Rails error hash to make applying error messages to your views dead simple. Even better, because the library cures Rails' brain-damaged way of recording errors from nested resources/attributes, err_supply works with both simple and complex forms.}
|
13
|
+
spec.homepage = 'http://github.com/coroutine/err_supply'
|
14
|
+
spec.licenses = ['MIT']
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_dependency 'rails', '>= 3.0.0'
|
22
|
+
|
23
|
+
spec.add_development_dependency 'rspec', '>= 2.0.0'
|
24
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
/*
|
2
|
+
ErrSupply Twitter Bootstrap3 Adapter
|
3
|
+
Copyright (c) 2014 Coroutine LLC
|
4
|
+
Licensed under the MIT license
|
5
|
+
*/
|
6
|
+
(function() {
|
7
|
+
var errSupplyPlugin = function(event, errors) {
|
8
|
+
|
9
|
+
// define how errors are applied to dom elements
|
10
|
+
var applyFn = function(error_hash) {
|
11
|
+
var unmatched = {};
|
12
|
+
var errors = error_hash || {};
|
13
|
+
var error;
|
14
|
+
var content;
|
15
|
+
var $field;
|
16
|
+
var position;
|
17
|
+
|
18
|
+
for (var id in errors) {
|
19
|
+
error = errors[id];
|
20
|
+
if (error && error.messages && error.messages.length) {
|
21
|
+
|
22
|
+
content = '<ul class="err_supply">';
|
23
|
+
for (var i = 0, n = error.messages.length; i < n; i++) {
|
24
|
+
content += '<li>' + error.label + " " + error.messages[i] + '</li>';
|
25
|
+
};
|
26
|
+
content += '</ul>';
|
27
|
+
|
28
|
+
$field = $('#' + id);
|
29
|
+
options = {}
|
30
|
+
if ($field.offset()) {
|
31
|
+
|
32
|
+
// determine position
|
33
|
+
if (($field.offset().left + $field.outerWidth() + 300) < $(window).width()) {
|
34
|
+
position = 'right';
|
35
|
+
}
|
36
|
+
else {
|
37
|
+
position = 'left';
|
38
|
+
};
|
39
|
+
|
40
|
+
// add class
|
41
|
+
$field.addClass('error').closest('.input-group').addClass('has-error');
|
42
|
+
|
43
|
+
// add popover
|
44
|
+
$field.popover({
|
45
|
+
html: true,
|
46
|
+
placement: position,
|
47
|
+
trigger: 'focus',
|
48
|
+
content: content
|
49
|
+
});
|
50
|
+
}
|
51
|
+
else {
|
52
|
+
unmatched[id] = error;
|
53
|
+
};
|
54
|
+
};
|
55
|
+
};
|
56
|
+
|
57
|
+
return unmatched;
|
58
|
+
};
|
59
|
+
|
60
|
+
// get reference to form firing event
|
61
|
+
var $form = $(this);
|
62
|
+
|
63
|
+
// find all contained elements with a style of error and remove the class.
|
64
|
+
// this is typically more important for ajax submissions. html submissions
|
65
|
+
// tend not to have this problem.
|
66
|
+
$form.find('.error').removeClass('error').closest('.input-group').removeClass('has-error');
|
67
|
+
|
68
|
+
// hide all fields that have been explicitly destroyed. when an html submission
|
69
|
+
// has errors, the _destroy value renders as true rather than 1, which may or may not
|
70
|
+
// causes destroyed sets to be visible after the reload. here, we scan for both
|
71
|
+
// values and hide any containing div.fields elements.
|
72
|
+
$form.find('input:hidden[id$=_destroy]').filter('[value=true], [value=1]').closest('.fields').hide();
|
73
|
+
|
74
|
+
// apply errors to dom elements
|
75
|
+
var unmatched_errors = applyFn(errors) || {};
|
76
|
+
|
77
|
+
// publish unmatched errors, in case view cares about that
|
78
|
+
$form.trigger('err_supply:unmatched', unmatched_errors);
|
79
|
+
|
80
|
+
// move focus to first field with error (or first field)
|
81
|
+
var $focus_field = ($form.find('.error').size() > 0) ?
|
82
|
+
$form.find('.error').filter(':first') :
|
83
|
+
$form.find(':not(.filter) :input:visible:enabled:first');
|
84
|
+
$focus_field.focus()
|
85
|
+
};
|
86
|
+
|
87
|
+
$.fn.err_supply = function() {
|
88
|
+
$(this).on("err_supply:loaded", errSupplyPlugin.bind(this));
|
89
|
+
}
|
90
|
+
})()
|
91
|
+
|
92
|
+
jQuery(function($) {
|
93
|
+
$("form").err_supply();
|
94
|
+
});
|
@@ -0,0 +1,21 @@
|
|
1
|
+
/*---------------------------------------------
|
2
|
+
err_supply styles
|
3
|
+
-----------------------------------------------*/
|
4
|
+
|
5
|
+
ul.err_supply {
|
6
|
+
margin: 0;
|
7
|
+
padding: 0;
|
8
|
+
list-style: none;
|
9
|
+
}
|
10
|
+
|
11
|
+
.form-group .popover {
|
12
|
+
width: 325px;
|
13
|
+
background: $brand-danger;
|
14
|
+
color: #fff;
|
15
|
+
}
|
16
|
+
.form-group .popover.right .arrow:after {
|
17
|
+
border-right-color: $brand-danger;
|
18
|
+
}
|
19
|
+
.form-group .popover.left .arrow:after {
|
20
|
+
border-left-color: $brand-danger;
|
21
|
+
}
|
data/lib/err_supply.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'err_supply/version'
|
2
|
+
require 'err_supply/controller_helpers'
|
3
|
+
require 'err_supply/view_helpers'
|
4
|
+
|
5
|
+
module ErrSupply
|
6
|
+
class Engine < ::Rails::Engine
|
7
|
+
|
8
|
+
#-------------------------------------------------------
|
9
|
+
# Initialization
|
10
|
+
#-------------------------------------------------------
|
11
|
+
initializer "err_supply.start" do |app|
|
12
|
+
|
13
|
+
# extend views
|
14
|
+
ActiveSupport.on_load :action_view do
|
15
|
+
include ErrSupply::ViewHelpers
|
16
|
+
end
|
17
|
+
|
18
|
+
# extend controllers
|
19
|
+
ActiveSupport.on_load :action_controller do
|
20
|
+
include ErrSupply::ControllerHelpers
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module ErrSupply
|
2
|
+
module ControllerHelpers
|
3
|
+
|
4
|
+
# Declare our method as a helper method so it is accessible to views.
|
5
|
+
ActionController::Base.helper_method :err_supply_hash
|
6
|
+
|
7
|
+
# This method can be called recursively to unpack a rails object's error hash
|
8
|
+
# into something more manageable for the view. Basically, it uses the keys in the
|
9
|
+
# object's error hash to traverse the object graph and expand the errors into a
|
10
|
+
# flattened hash, keyed using the dom ids rails will generate for the
|
11
|
+
# associated objects.
|
12
|
+
#
|
13
|
+
# Because the method is called recursively, it only pays attention to errors for
|
14
|
+
# the given object and its immediate child collections. More remote descendents
|
15
|
+
# will be processed in subsequent passes.
|
16
|
+
#
|
17
|
+
def err_supply_hash(obj, options={})
|
18
|
+
|
19
|
+
#---------------------------------------------
|
20
|
+
# set up main variables
|
21
|
+
#---------------------------------------------
|
22
|
+
|
23
|
+
prefix = options[:prefix]
|
24
|
+
errors = obj.errors
|
25
|
+
h = {}
|
26
|
+
|
27
|
+
|
28
|
+
#---------------------------------------------
|
29
|
+
# apply options to local attrs
|
30
|
+
#---------------------------------------------
|
31
|
+
|
32
|
+
# get keys
|
33
|
+
attrs = errors.keys.select { |k| k.to_s.split(".").size == 1 }
|
34
|
+
|
35
|
+
# whitelist/blacklist keys
|
36
|
+
if options.has_key?(:only)
|
37
|
+
attrs = attrs.select { |k| Array(options[:only]).flatten.include?(k) }
|
38
|
+
end
|
39
|
+
if options.has_key?(:except)
|
40
|
+
attrs = attrs.reject { |k| Array(options[:except]).flatten.include?(k) }
|
41
|
+
end
|
42
|
+
|
43
|
+
# apply errors that match our list (slightly inefficient, but a touch easier to read)
|
44
|
+
attrs.each do |attr|
|
45
|
+
o = options[attr.to_sym] || {}
|
46
|
+
id = [prefix, "#{(o[:key] || attr).to_s}"].reject(&:blank?).join('_')
|
47
|
+
|
48
|
+
unless h.has_key?(id)
|
49
|
+
h[id] = {
|
50
|
+
"label" => obj.class.human_attribute_name(attr),
|
51
|
+
"messages" => []
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
h[id]["label"] = o[:label].to_s.underscore.humanize unless o[:label].nil?
|
56
|
+
h[id]["messages"] = (h[id]["messages"] + errors[attr].map { |msg| "#{msg}.".gsub("..", ".") }).flatten
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
#---------------------------------------------
|
61
|
+
# apply options to children
|
62
|
+
#---------------------------------------------
|
63
|
+
|
64
|
+
# get keys
|
65
|
+
assoc_names = errors.keys.map { |k| k.to_s.split(".") }.select { |a| a.many? }.map { |a| a[0] }.compact.uniq
|
66
|
+
|
67
|
+
# if child has errors or is invalid (i.e., we prefer explicitly declared errrors),
|
68
|
+
# call function recursively and merge results
|
69
|
+
assoc_names.each do |assoc_name|
|
70
|
+
c_options = options[assoc_name.to_sym] || {}
|
71
|
+
obj.send("#{assoc_name}").each_with_index do |child, index|
|
72
|
+
if !child.errors.empty? or child.invalid?
|
73
|
+
c_prefix = [prefix, "#{assoc_name}_attributes_#{index}"].reject(&:blank?).join('_')
|
74
|
+
c_hash = err_supply_hash(child, c_options.merge({ :prefix => c_prefix }))
|
75
|
+
|
76
|
+
h.merge!(c_hash)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
#---------------------------------------------
|
83
|
+
# return the hash
|
84
|
+
#---------------------------------------------
|
85
|
+
h
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module ErrSupply
|
2
|
+
module ViewHelpers
|
3
|
+
|
4
|
+
# Converts the given object's error hash into our JSON structure and
|
5
|
+
# triggers a custom event on the associated form element.
|
6
|
+
#
|
7
|
+
def err_supply(obj, options={})
|
8
|
+
form_css_selector = options[:form_css_selector]
|
9
|
+
|
10
|
+
if form_css_selector.blank?
|
11
|
+
id = obj.new_record? ? dom_id(obj) : dom_id(obj, :edit)
|
12
|
+
form_css_selector = "##{id}"
|
13
|
+
end
|
14
|
+
|
15
|
+
prefix = obj.class.name.underscore.split('/').last
|
16
|
+
payload = err_supply_hash(obj, options.merge({ :prefix => prefix }))
|
17
|
+
|
18
|
+
"$('#{ form_css_selector }').trigger('err_supply:loaded', #{ payload.to_json });".html_safe
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: err_supply-orac
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Coroutine
|
8
|
+
- John Dugan
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2017-02-14 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rails
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ! '>='
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: 3.0.0
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ! '>='
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 3.0.0
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: rspec
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ! '>='
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 2.0.0
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ! '>='
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 2.0.0
|
42
|
+
description: Simple, beautiful error messages for Rails. Err_supply unpacks and rekeys
|
43
|
+
the standard Rails error hash to make applying error messages to your views dead
|
44
|
+
simple. Even better, because the library cures Rails' brain-damaged way of recording
|
45
|
+
errors from nested resources/attributes, err_supply works with both simple and complex
|
46
|
+
forms.
|
47
|
+
email:
|
48
|
+
- gems@coroutine.com
|
49
|
+
executables: []
|
50
|
+
extensions: []
|
51
|
+
extra_rdoc_files: []
|
52
|
+
files:
|
53
|
+
- .gitignore
|
54
|
+
- Gemfile
|
55
|
+
- LICENSE.txt
|
56
|
+
- README.md
|
57
|
+
- Rakefile
|
58
|
+
- err_supply.gemspec
|
59
|
+
- lib/assets/javascripts/err_supply-bootstrap.js
|
60
|
+
- lib/assets/stylesheets/err_supply-bootstrap.scss
|
61
|
+
- lib/err_supply.rb
|
62
|
+
- lib/err_supply/controller_helpers.rb
|
63
|
+
- lib/err_supply/version.rb
|
64
|
+
- lib/err_supply/view_helpers.rb
|
65
|
+
homepage: http://github.com/coroutine/err_supply
|
66
|
+
licenses:
|
67
|
+
- MIT
|
68
|
+
metadata: {}
|
69
|
+
post_install_message:
|
70
|
+
rdoc_options: []
|
71
|
+
require_paths:
|
72
|
+
- lib
|
73
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ! '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
requirements: []
|
84
|
+
rubyforge_project:
|
85
|
+
rubygems_version: 2.5.1
|
86
|
+
signing_key:
|
87
|
+
specification_version: 4
|
88
|
+
summary: Simple, beautiful error messages for Rails.
|
89
|
+
test_files: []
|