action_policy 0.3.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +3 -1
- data/docs/README.md +8 -1
- data/docs/assets/docsify-search.js +364 -0
- data/docs/assets/styles.css +32 -2
- data/docs/custom_policy.md +1 -0
- data/docs/decorators.md +1 -1
- data/docs/index.html +5 -1
- data/lib/action_policy.rb +4 -1
- data/lib/action_policy/policy/scoping.rb +13 -13
- data/lib/action_policy/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 998666ad64277112c6ddc44e6db9e0aa81b6bbf32994fb675797bcd8e1f9ca70
|
4
|
+
data.tar.gz: 5a35c722589841c6b41d6efd1735abe63833db03b9a7aec23e798648a97c5470
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 03a5594069a5947566708f3b3ad419d79be8931d38c25195f754d1474fa9b2f3bcf5e0f9e520a828d56c1fcfac762929ae4fdcf852c657f4b6bec973c0559e0b
|
7
|
+
data.tar.gz: e41e88d916fdf0832e7b03cdadcf7f6c1a4814c45e6ca76e12094bbcb03a6ea54146a0e676d079a0813caff31f54c3dfe90d0e917ade8c4261e17ec4d55a4221
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
## master
|
2
2
|
|
3
|
+
## 0.3.2 (2019-05-26) 👶
|
4
|
+
|
5
|
+
- Fixed thread-safety issues with scoping configs. ([@palkan][])
|
6
|
+
|
7
|
+
Fixes [#75](https://github.com/palkan/action_policy/issues/75).
|
8
|
+
|
3
9
|
## 0.3.1 (2019-05-30)
|
4
10
|
|
5
11
|
- Fixed bug with missing implicit target and hash like scoping data. ([@palkan][])
|
data/README.md
CHANGED
@@ -4,7 +4,9 @@
|
|
4
4
|
|
5
5
|
# ActionPolicy
|
6
6
|
|
7
|
-
|
7
|
+
Authorization framework for Ruby and Rails applications.
|
8
|
+
|
9
|
+
Composable. Extensible. Performant.
|
8
10
|
|
9
11
|
📑 [Documentation](https://actionpolicy.evilmartians.io)
|
10
12
|
|
data/docs/README.md
CHANGED
@@ -3,7 +3,8 @@
|
|
3
3
|
|
4
4
|
## Action Policy
|
5
5
|
|
6
|
-
>
|
6
|
+
> Authorization framework for Ruby and Rails.
|
7
|
+
<br>Composable. Extensible. Performant.
|
7
8
|
|
8
9
|
**NOTE:** this documentation is for the version "0.3.0+".
|
9
10
|
|
@@ -20,6 +21,12 @@ Action Policy provides flexible tools to build an _authorization layer_ for your
|
|
20
21
|
|
21
22
|
**NOTE:** Action Policy does not force you to use a specific authorization model (i.e., roles, permissions, etc.) and does not provide one. It only answers a single question: **How to verify access?**
|
22
23
|
|
24
|
+
## Where to go from here?
|
25
|
+
- [Quick start](./quick_start.md)
|
26
|
+
- [Using with Rails](./rails.md)
|
27
|
+
- [Using with other Ruby frameworks](./non_rails.md)
|
28
|
+
- [Using with GraphQL Ruby](./graphql.md)
|
29
|
+
|
23
30
|
## Project State
|
24
31
|
|
25
32
|
The project is being used in production since mid 2018. Major features have been implemented, API has been stabilized. Check out our [development board](https://github.com/palkan/action_policy/projects/1) to see what's coming next.
|
@@ -0,0 +1,364 @@
|
|
1
|
+
(function () {
|
2
|
+
var INDEXS = {};
|
3
|
+
|
4
|
+
var LOCAL_STORAGE = {
|
5
|
+
EXPIRE_KEY: 'docsify.search.expires',
|
6
|
+
INDEX_KEY: 'docsify.search.index'
|
7
|
+
};
|
8
|
+
|
9
|
+
function resolveExpireKey(namespace) {
|
10
|
+
return namespace ? ((LOCAL_STORAGE.EXPIRE_KEY) + "/" + namespace) : LOCAL_STORAGE.EXPIRE_KEY
|
11
|
+
}
|
12
|
+
function resolveIndexKey(namespace) {
|
13
|
+
return namespace ? ((LOCAL_STORAGE.INDEX_KEY) + "/" + namespace) : LOCAL_STORAGE.INDEX_KEY
|
14
|
+
}
|
15
|
+
|
16
|
+
function escapeHtml(string) {
|
17
|
+
var entityMap = {
|
18
|
+
'&': '&',
|
19
|
+
'<': '<',
|
20
|
+
'>': '>',
|
21
|
+
'"': '"',
|
22
|
+
'\'': ''',
|
23
|
+
'/': '/'
|
24
|
+
};
|
25
|
+
|
26
|
+
return String(string).replace(/[&<>"'/]/g, function (s) { return entityMap[s]; })
|
27
|
+
}
|
28
|
+
|
29
|
+
function getAllPaths(router) {
|
30
|
+
var paths = [];
|
31
|
+
|
32
|
+
Docsify.dom.findAll('.sidebar-nav a:not(.section-link):not([data-nosearch])').forEach(function (node) {
|
33
|
+
var href = node.href;
|
34
|
+
var originHref = node.getAttribute('href');
|
35
|
+
var path = router.parse(href).path;
|
36
|
+
|
37
|
+
if (
|
38
|
+
path &&
|
39
|
+
paths.indexOf(path) === -1 &&
|
40
|
+
!Docsify.util.isAbsolutePath(originHref)
|
41
|
+
) {
|
42
|
+
paths.push(path);
|
43
|
+
}
|
44
|
+
});
|
45
|
+
|
46
|
+
return paths
|
47
|
+
}
|
48
|
+
|
49
|
+
function saveData(maxAge, expireKey, indexKey) {
|
50
|
+
localStorage.setItem(expireKey, Date.now() + maxAge);
|
51
|
+
localStorage.setItem(indexKey, JSON.stringify(INDEXS));
|
52
|
+
}
|
53
|
+
|
54
|
+
function genIndex(path, content, router, depth) {
|
55
|
+
if ( content === void 0 ) content = '';
|
56
|
+
|
57
|
+
var tokens = window.marked.lexer(content);
|
58
|
+
var slugify = window.Docsify.slugify;
|
59
|
+
var index = {};
|
60
|
+
var slug;
|
61
|
+
|
62
|
+
tokens.forEach(function (token) {
|
63
|
+
if (token.type === 'heading' && token.depth <= depth) {
|
64
|
+
slug = router.toURL(path, {id: slugify(token.text)});
|
65
|
+
index[slug] = {slug: slug, title: token.text, body: ''};
|
66
|
+
} else {
|
67
|
+
if (!slug) {
|
68
|
+
return
|
69
|
+
}
|
70
|
+
if (!index[slug]) {
|
71
|
+
index[slug] = {slug: slug, title: '', body: ''};
|
72
|
+
} else if (index[slug].body) {
|
73
|
+
index[slug].body += '\n' + (token.text || '');
|
74
|
+
} else {
|
75
|
+
index[slug].body = token.text;
|
76
|
+
}
|
77
|
+
}
|
78
|
+
});
|
79
|
+
slugify.clear();
|
80
|
+
return index
|
81
|
+
}
|
82
|
+
|
83
|
+
/**
|
84
|
+
* @param {String} query
|
85
|
+
* @returns {Array}
|
86
|
+
*/
|
87
|
+
function search(query) {
|
88
|
+
var matchingResults = [];
|
89
|
+
var data = [];
|
90
|
+
Object.keys(INDEXS).forEach(function (key) {
|
91
|
+
data = data.concat(Object.keys(INDEXS[key]).map(function (page) { return INDEXS[key][page]; }));
|
92
|
+
});
|
93
|
+
|
94
|
+
query = query.trim();
|
95
|
+
var keywords = query.split(/[\s\-,\\/]+/);
|
96
|
+
if (keywords.length !== 1) {
|
97
|
+
keywords = [].concat(query, keywords);
|
98
|
+
}
|
99
|
+
|
100
|
+
var loop = function ( i ) {
|
101
|
+
var post = data[i];
|
102
|
+
var matchesScore = 0;
|
103
|
+
var resultStr = '';
|
104
|
+
var postTitle = post.title && post.title.trim();
|
105
|
+
var postContent = post.body && post.body.trim();
|
106
|
+
var postUrl = post.slug || '';
|
107
|
+
|
108
|
+
if (postTitle) {
|
109
|
+
keywords.forEach( function (keyword) {
|
110
|
+
// From https://github.com/sindresorhus/escape-string-regexp
|
111
|
+
var regEx = new RegExp(
|
112
|
+
keyword.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&'),
|
113
|
+
'gi'
|
114
|
+
);
|
115
|
+
var indexTitle = -1;
|
116
|
+
var indexContent = -1;
|
117
|
+
|
118
|
+
indexTitle = postTitle ? postTitle.search(regEx) : -1;
|
119
|
+
indexContent = postContent ? postContent.search(regEx) : -1;
|
120
|
+
|
121
|
+
if (indexTitle >= 0 || indexContent >= 0) {
|
122
|
+
matchesScore += indexTitle >= 0 ? 3 : indexContent >= 0 ? 2 : 0;
|
123
|
+
if (indexContent < 0) {
|
124
|
+
indexContent = 0;
|
125
|
+
}
|
126
|
+
|
127
|
+
var start = 0;
|
128
|
+
var end = 0;
|
129
|
+
|
130
|
+
start = indexContent < 11 ? 0 : indexContent - 10;
|
131
|
+
end = start === 0 ? 70 : indexContent + keyword.length + 60;
|
132
|
+
|
133
|
+
if (end > postContent.length) {
|
134
|
+
end = postContent.length;
|
135
|
+
}
|
136
|
+
|
137
|
+
var matchContent =
|
138
|
+
'...' +
|
139
|
+
escapeHtml(postContent)
|
140
|
+
.substring(start, end)
|
141
|
+
.replace(regEx, ("<em class=\"search-keyword\">" + keyword + "</em>")) +
|
142
|
+
'...';
|
143
|
+
|
144
|
+
resultStr += matchContent;
|
145
|
+
}
|
146
|
+
});
|
147
|
+
|
148
|
+
if (matchesScore > 0) {
|
149
|
+
var matchingPost = {
|
150
|
+
title: escapeHtml(postTitle),
|
151
|
+
content: postContent ? resultStr : '',
|
152
|
+
url: postUrl,
|
153
|
+
score: matchesScore
|
154
|
+
};
|
155
|
+
|
156
|
+
matchingResults.push(matchingPost);
|
157
|
+
}
|
158
|
+
}
|
159
|
+
};
|
160
|
+
|
161
|
+
for (var i = 0; i < data.length; i++) loop( i );
|
162
|
+
|
163
|
+
return matchingResults.sort(function (r1, r2) { return r2.score - r1.score; });
|
164
|
+
}
|
165
|
+
|
166
|
+
function init$1(config, vm) {
|
167
|
+
var isAuto = config.paths === 'auto';
|
168
|
+
|
169
|
+
var expireKey = resolveExpireKey(config.namespace);
|
170
|
+
var indexKey = resolveIndexKey(config.namespace);
|
171
|
+
|
172
|
+
var isExpired = localStorage.getItem(expireKey) < Date.now();
|
173
|
+
|
174
|
+
INDEXS = JSON.parse(localStorage.getItem(indexKey));
|
175
|
+
|
176
|
+
if (isExpired) {
|
177
|
+
INDEXS = {};
|
178
|
+
} else if (!isAuto) {
|
179
|
+
return
|
180
|
+
}
|
181
|
+
|
182
|
+
var paths = isAuto ? getAllPaths(vm.router) : config.paths;
|
183
|
+
var len = paths.length;
|
184
|
+
var count = 0;
|
185
|
+
|
186
|
+
paths.forEach(function (path) {
|
187
|
+
if (INDEXS[path]) {
|
188
|
+
return count++
|
189
|
+
}
|
190
|
+
|
191
|
+
Docsify
|
192
|
+
.get(vm.router.getFile(path), false, vm.config.requestHeaders)
|
193
|
+
.then(function (result) {
|
194
|
+
INDEXS[path] = genIndex(path, result, vm.router, config.depth);
|
195
|
+
len === ++count && saveData(config.maxAge, expireKey, indexKey);
|
196
|
+
});
|
197
|
+
});
|
198
|
+
}
|
199
|
+
|
200
|
+
var NO_DATA_TEXT = '';
|
201
|
+
var options;
|
202
|
+
|
203
|
+
function style() {
|
204
|
+
var code = "\n.sidebar {\n padding-top: 0;\n}\n\n.search {\n margin-bottom: 20px;\n padding: 6px;\n border-bottom: 1px solid #eee;\n}\n\n.search .input-wrap {\n display: flex;\n align-items: center;\n}\n\n.search .results-panel {\n display: none;\n}\n\n.search .results-panel.show {\n display: block;\n}\n\n.search input {\n outline: none;\n border: none;\n width: 100%;\n padding: 0 7px;\n line-height: 36px;\n font-size: 14px;\n}\n\n.search input::-webkit-search-decoration,\n.search input::-webkit-search-cancel-button,\n.search input {\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n}\n.search .clear-button {\n width: 36px;\n text-align: right;\n display: none;\n}\n\n.search .clear-button.show {\n display: block;\n}\n\n.search .clear-button svg {\n transform: scale(.5);\n}\n\n.search h2 {\n font-size: 17px;\n margin: 10px 0;\n}\n\n.search a {\n text-decoration: none;\n color: inherit;\n}\n\n.search .matching-post {\n border-bottom: 1px solid #eee;\n}\n\n.search .matching-post:last-child {\n border-bottom: 0;\n}\n\n.search p {\n font-size: 14px;\n overflow: hidden;\n text-overflow: ellipsis;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n}\n\n.search p.empty {\n text-align: center;\n}\n\n.app-name.hide, .sidebar-nav.hide {\n display: none;\n}";
|
205
|
+
|
206
|
+
Docsify.dom.style(code);
|
207
|
+
}
|
208
|
+
|
209
|
+
function tpl(defaultValue) {
|
210
|
+
if ( defaultValue === void 0 ) defaultValue = '';
|
211
|
+
|
212
|
+
var html =
|
213
|
+
"<div class=\"input-wrap\">\n <input type=\"search\" value=\"" + defaultValue + "\" />\n <div class=\"clear-button\">\n <svg width=\"26\" height=\"24\">\n <circle cx=\"12\" cy=\"12\" r=\"11\" fill=\"#ccc\" />\n <path stroke=\"white\" stroke-width=\"2\" d=\"M8.25,8.25,15.75,15.75\" />\n <path stroke=\"white\" stroke-width=\"2\"d=\"M8.25,15.75,15.75,8.25\" />\n </svg>\n </div>\n </div>\n <div class=\"results-panel\"></div>\n </div>";
|
214
|
+
var el = Docsify.dom.create('div', html);
|
215
|
+
var aside = Docsify.dom.find('aside');
|
216
|
+
|
217
|
+
Docsify.dom.toggleClass(el, 'search');
|
218
|
+
Docsify.dom.before(aside, el);
|
219
|
+
}
|
220
|
+
|
221
|
+
function doSearch(value) {
|
222
|
+
var $search = Docsify.dom.find('div.search');
|
223
|
+
var $panel = Docsify.dom.find($search, '.results-panel');
|
224
|
+
var $clearBtn = Docsify.dom.find($search, '.clear-button');
|
225
|
+
var $sidebarNav = Docsify.dom.find('.sidebar-nav');
|
226
|
+
var $appName = Docsify.dom.find('.app-name');
|
227
|
+
|
228
|
+
if (!value) {
|
229
|
+
$panel.classList.remove('show');
|
230
|
+
$clearBtn.classList.remove('show');
|
231
|
+
$panel.innerHTML = '';
|
232
|
+
|
233
|
+
if (options.hideOtherSidebarContent) {
|
234
|
+
$sidebarNav.classList.remove('hide');
|
235
|
+
$appName.classList.remove('hide');
|
236
|
+
}
|
237
|
+
return
|
238
|
+
}
|
239
|
+
var matchs = search(value);
|
240
|
+
|
241
|
+
var html = '';
|
242
|
+
matchs.forEach(function (post) {
|
243
|
+
html += "<div class=\"matching-post\">\n<a href=\"" + (post.url) + "\">\n<h2>" + (post.title) + "</h2>\n<p>" + (post.content) + "</p>\n</a>\n</div>";
|
244
|
+
});
|
245
|
+
|
246
|
+
$panel.classList.add('show');
|
247
|
+
$clearBtn.classList.add('show');
|
248
|
+
$panel.innerHTML = html || ("<p class=\"empty\">" + NO_DATA_TEXT + "</p>");
|
249
|
+
if (options.hideOtherSidebarContent) {
|
250
|
+
$sidebarNav.classList.add('hide');
|
251
|
+
$appName.classList.add('hide');
|
252
|
+
}
|
253
|
+
}
|
254
|
+
|
255
|
+
function bindEvents() {
|
256
|
+
var $search = Docsify.dom.find('div.search');
|
257
|
+
var $input = Docsify.dom.find($search, 'input');
|
258
|
+
var $inputWrap = Docsify.dom.find($search, '.input-wrap');
|
259
|
+
|
260
|
+
var timeId;
|
261
|
+
// Prevent to Fold sidebar
|
262
|
+
Docsify.dom.on(
|
263
|
+
$search,
|
264
|
+
'click',
|
265
|
+
function (e) { return e.target.tagName !== 'A' && e.stopPropagation(); }
|
266
|
+
);
|
267
|
+
Docsify.dom.on($input, 'input', function (e) {
|
268
|
+
clearTimeout(timeId);
|
269
|
+
timeId = setTimeout(function (_) { return doSearch(e.target.value.trim()); }, 100);
|
270
|
+
});
|
271
|
+
Docsify.dom.on($inputWrap, 'click', function (e) {
|
272
|
+
// Click input outside
|
273
|
+
if (e.target.tagName !== 'INPUT') {
|
274
|
+
$input.value = '';
|
275
|
+
doSearch();
|
276
|
+
}
|
277
|
+
});
|
278
|
+
}
|
279
|
+
|
280
|
+
function updatePlaceholder(text, path) {
|
281
|
+
var $input = Docsify.dom.getNode('.search input[type="search"]');
|
282
|
+
|
283
|
+
if (!$input) {
|
284
|
+
return
|
285
|
+
}
|
286
|
+
if (typeof text === 'string') {
|
287
|
+
$input.placeholder = text;
|
288
|
+
} else {
|
289
|
+
var match = Object.keys(text).filter(function (key) { return path.indexOf(key) > -1; })[0];
|
290
|
+
$input.placeholder = text[match];
|
291
|
+
}
|
292
|
+
}
|
293
|
+
|
294
|
+
function updateNoData(text, path) {
|
295
|
+
if (typeof text === 'string') {
|
296
|
+
NO_DATA_TEXT = text;
|
297
|
+
} else {
|
298
|
+
var match = Object.keys(text).filter(function (key) { return path.indexOf(key) > -1; })[0];
|
299
|
+
NO_DATA_TEXT = text[match];
|
300
|
+
}
|
301
|
+
}
|
302
|
+
|
303
|
+
function updateOptions(opts) {
|
304
|
+
options = opts;
|
305
|
+
}
|
306
|
+
|
307
|
+
function init(opts, vm) {
|
308
|
+
var keywords = vm.router.parse().query.s;
|
309
|
+
|
310
|
+
updateOptions(opts);
|
311
|
+
style();
|
312
|
+
tpl(keywords);
|
313
|
+
bindEvents();
|
314
|
+
keywords && setTimeout(function (_) { return doSearch(keywords); }, 500);
|
315
|
+
}
|
316
|
+
|
317
|
+
function update(opts, vm) {
|
318
|
+
updateOptions(opts);
|
319
|
+
updatePlaceholder(opts.placeholder, vm.route.path);
|
320
|
+
updateNoData(opts.noData, vm.route.path);
|
321
|
+
}
|
322
|
+
|
323
|
+
var CONFIG = {
|
324
|
+
placeholder: 'Type to search',
|
325
|
+
noData: 'No Results!',
|
326
|
+
paths: 'auto',
|
327
|
+
depth: 2,
|
328
|
+
maxAge: 86400000, // 1 day
|
329
|
+
hideOtherSidebarContent: false,
|
330
|
+
namespace: undefined
|
331
|
+
};
|
332
|
+
|
333
|
+
var install = function (hook, vm) {
|
334
|
+
var util = Docsify.util;
|
335
|
+
var opts = vm.config.search || CONFIG;
|
336
|
+
|
337
|
+
if (Array.isArray(opts)) {
|
338
|
+
CONFIG.paths = opts;
|
339
|
+
} else if (typeof opts === 'object') {
|
340
|
+
CONFIG.paths = Array.isArray(opts.paths) ? opts.paths : 'auto';
|
341
|
+
CONFIG.maxAge = util.isPrimitive(opts.maxAge) ? opts.maxAge : CONFIG.maxAge;
|
342
|
+
CONFIG.placeholder = opts.placeholder || CONFIG.placeholder;
|
343
|
+
CONFIG.noData = opts.noData || CONFIG.noData;
|
344
|
+
CONFIG.depth = opts.depth || CONFIG.depth;
|
345
|
+
CONFIG.hideOtherSidebarContent = opts.hideOtherSidebarContent || CONFIG.hideOtherSidebarContent;
|
346
|
+
CONFIG.namespace = opts.namespace || CONFIG.namespace;
|
347
|
+
}
|
348
|
+
|
349
|
+
var isAuto = CONFIG.paths === 'auto';
|
350
|
+
|
351
|
+
hook.mounted(function (_) {
|
352
|
+
init(CONFIG, vm);
|
353
|
+
!isAuto && init$1(CONFIG, vm);
|
354
|
+
});
|
355
|
+
hook.doneEach(function (_) {
|
356
|
+
update(CONFIG, vm);
|
357
|
+
isAuto && init$1(CONFIG, vm);
|
358
|
+
});
|
359
|
+
};
|
360
|
+
|
361
|
+
$docsify.plugins = [].concat(install, $docsify.plugins);
|
362
|
+
|
363
|
+
}());
|
364
|
+
|
data/docs/assets/styles.css
CHANGED
@@ -56,18 +56,23 @@ a {
|
|
56
56
|
text-align: center;
|
57
57
|
}
|
58
58
|
|
59
|
-
|
60
|
-
aside.sidebar {
|
59
|
+
.sidebar {
|
61
60
|
border: none;
|
62
61
|
background-color: var(--theme-color-secondary);
|
63
62
|
color: #fff;
|
64
63
|
width: 20%;
|
64
|
+
display: flex;
|
65
|
+
flex-direction: column;
|
65
66
|
}
|
66
67
|
|
67
68
|
body.close .sidebar {
|
68
69
|
transform: translateX(-100%);
|
69
70
|
}
|
70
71
|
|
72
|
+
.sidebar .sidebar-nav {
|
73
|
+
order: 3;
|
74
|
+
}
|
75
|
+
|
71
76
|
.sidebar ul li a {
|
72
77
|
color: rgba(255,255,255,0.8);
|
73
78
|
color: var(--theme-color-light);
|
@@ -89,7 +94,32 @@ body.close .sidebar {
|
|
89
94
|
}
|
90
95
|
|
91
96
|
.sidebar > h1 {
|
97
|
+
order: 1;
|
92
98
|
font-size: 2rem;
|
99
|
+
margin-top: 1.5rem;
|
100
|
+
}
|
101
|
+
|
102
|
+
/* search plugin related */
|
103
|
+
|
104
|
+
.sidebar .search {
|
105
|
+
order: 2;
|
106
|
+
margin: 1.5rem 0 0 0;
|
107
|
+
border: none;
|
108
|
+
margin-top: 20px;
|
109
|
+
margin-bottom: 20px;
|
110
|
+
padding: 6px;
|
111
|
+
}
|
112
|
+
|
113
|
+
.sidebar .search .input-wrap {
|
114
|
+
border: none;
|
115
|
+
position: relative;
|
116
|
+
}
|
117
|
+
|
118
|
+
.sidebar .search .clear-button.show {
|
119
|
+
display: block;
|
120
|
+
position: absolute;
|
121
|
+
right: 4px;
|
122
|
+
top: 8px;
|
93
123
|
}
|
94
124
|
|
95
125
|
body .sidebar-toggle {
|
data/docs/custom_policy.md
CHANGED
@@ -12,6 +12,7 @@ class ActionPolicy::Base
|
|
12
12
|
include ActionPolicy::Policy::PreCheck
|
13
13
|
include ActionPolicy::Policy::Reasons
|
14
14
|
include ActionPolicy::Policy::Aliases
|
15
|
+
include ActionPolicy::Policy::Scoping
|
15
16
|
include ActionPolicy::Policy::Cache
|
16
17
|
include ActionPolicy::Policy::CachedApply
|
17
18
|
include ActionPolicy::Policy::Defaults
|
data/docs/decorators.md
CHANGED
@@ -15,7 +15,7 @@ module ActionPolicy
|
|
15
15
|
module Draper
|
16
16
|
def policy_for(record:, **opts)
|
17
17
|
# From https://github.com/GoodMeasuresLLC/draper-cancancan/blob/master/lib/draper/cancancan.rb
|
18
|
-
record = record.model while record.is_a?(Draper::Decorator)
|
18
|
+
record = record.model while record.is_a?(::Draper::Decorator)
|
19
19
|
super(record: record, **opts)
|
20
20
|
end
|
21
21
|
end
|
data/docs/index.html
CHANGED
@@ -30,10 +30,14 @@
|
|
30
30
|
loadSidebar: true,
|
31
31
|
subMaxLevel: 3,
|
32
32
|
ga: 'UA-104346673-3',
|
33
|
-
auto2top:true
|
33
|
+
auto2top: true,
|
34
|
+
search: {
|
35
|
+
namespace: 'action-policy'
|
36
|
+
}
|
34
37
|
}
|
35
38
|
</script>
|
36
39
|
<script src="assets/docsify.min.js"></script>
|
40
|
+
<script src="assets/docsify-search.js"></script>
|
37
41
|
<script src="assets/prism-ruby.min.js"></script>
|
38
42
|
</body>
|
39
43
|
</html>
|
data/lib/action_policy.rb
CHANGED
@@ -13,7 +13,10 @@ module ActionPolicy
|
|
13
13
|
|
14
14
|
def initialize(target, message = nil)
|
15
15
|
@target = target
|
16
|
-
@message =
|
16
|
+
@message =
|
17
|
+
message ||
|
18
|
+
"Couldn't find policy class for #{target.inspect}" \
|
19
|
+
"#{target.is_a?(Module) ? "" : " (#{target.class})"}"
|
17
20
|
end
|
18
21
|
end
|
19
22
|
|
@@ -124,15 +124,14 @@ module ActionPolicy
|
|
124
124
|
def scoping_handlers
|
125
125
|
return @scoping_handlers if instance_variable_defined?(:@scoping_handlers)
|
126
126
|
|
127
|
-
@scoping_handlers =
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
127
|
+
@scoping_handlers =
|
128
|
+
Hash.new { |h, k| h[k] = {} }.tap do |handlers|
|
129
|
+
if superclass.respond_to?(:scoping_handlers)
|
130
|
+
superclass.scoping_handlers.each do |k, v|
|
131
|
+
handlers[k] = v.dup
|
132
|
+
end
|
133
|
+
end
|
132
134
|
end
|
133
|
-
end
|
134
|
-
|
135
|
-
@scoping_handlers
|
136
135
|
end
|
137
136
|
|
138
137
|
# Define scope type matcher.
|
@@ -149,11 +148,12 @@ module ActionPolicy
|
|
149
148
|
def scope_matchers
|
150
149
|
return @scope_matchers if instance_variable_defined?(:@scope_matchers)
|
151
150
|
|
152
|
-
@scope_matchers =
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
151
|
+
@scope_matchers =
|
152
|
+
if superclass.respond_to?(:scope_matchers)
|
153
|
+
superclass.scope_matchers.dup
|
154
|
+
else
|
155
|
+
[]
|
156
|
+
end
|
157
157
|
end
|
158
158
|
end
|
159
159
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: action_policy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vladimir Dementyev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-06-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -165,6 +165,7 @@ files:
|
|
165
165
|
- docs/README.md
|
166
166
|
- docs/_sidebar.md
|
167
167
|
- docs/aliases.md
|
168
|
+
- docs/assets/docsify-search.js
|
168
169
|
- docs/assets/docsify.min.js
|
169
170
|
- docs/assets/fonts/FiraCode-Medium.woff
|
170
171
|
- docs/assets/fonts/FiraCode-Regular.woff
|