effective_resources 0.1.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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +74 -0
- data/app/controllers/concerns/effective/crud_controller.rb +158 -0
- data/app/helpers/effective_resources_helper.rb +13 -0
- data/app/models/effective/access_denied.rb +17 -0
- data/config/effective_resources.rb +22 -0
- data/lib/effective_resources.rb +20 -0
- data/lib/effective_resources/engine.rb +13 -0
- data/lib/effective_resources/version.rb +3 -0
- data/lib/generators/effective_resources/install_generator.rb +14 -0
- metadata +68 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c009d7e3ecdcedf8d6237f147268f258cb1def21
|
4
|
+
data.tar.gz: e626bb392c315716a7f8805a0ec43fee41aa2543
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 22d8d71e5e635de0dac748d98a99cabbcefb1a741c0705489de856274a5ce0903e355ffb0d10de19751e6e8132988dc785a1ba8ef077f47c319d232a95888b48
|
7
|
+
data.tar.gz: f37f7fec56ae18b3dd8e86f0cc6ff43127fd0a7150231cd2be2e43a7e42456ca8ba5d0db6089de3fcd31e7aff698ba9b28973e48c884b70d1e108447edbfbf67
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2017 Code and Effect Inc.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# Effective Resources
|
2
|
+
|
3
|
+
Make your controller an effective resource controller.
|
4
|
+
|
5
|
+
Implements the 7 RESTful actions as a one-liner on any controller.
|
6
|
+
|
7
|
+
## Getting Started
|
8
|
+
|
9
|
+
Add to your Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'effective_resources'
|
13
|
+
```
|
14
|
+
|
15
|
+
Run the bundle command to install it:
|
16
|
+
|
17
|
+
```console
|
18
|
+
bundle install
|
19
|
+
```
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
Add to your contoller:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
class PostsController < ApplicationController
|
27
|
+
include Effective::CrudController
|
28
|
+
|
29
|
+
def post_params
|
30
|
+
params.require(:post).permit(:id, :title, :body)
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
```
|
35
|
+
|
36
|
+
## What it does
|
37
|
+
|
38
|
+
Implements the 7 RESTful actions: `index`, `new`, `create`, `show`, `edit`, `update`, `destroy`.
|
39
|
+
|
40
|
+
# Loads an appropriate `@post` type instance
|
41
|
+
# Sets a `@page_title` (effective_pages).
|
42
|
+
# Calls authorize as per the configured `EffectiveResources.authorization_method` (flow through to CanCan or Pundit)
|
43
|
+
# Does the create/update save
|
44
|
+
# Sets a `flash[:success]` and redirects on success, or sets a `flash.now[:danger]` and renders on error.
|
45
|
+
|
46
|
+
## Helpers
|
47
|
+
|
48
|
+
### simple_form_submit
|
49
|
+
|
50
|
+
Call `simple_form_submit(f)` like follows:
|
51
|
+
|
52
|
+
```haml
|
53
|
+
= simple_form_for(post) do |f|
|
54
|
+
= f.input :title
|
55
|
+
= f.input :body
|
56
|
+
|
57
|
+
= simple_form_submit(f)
|
58
|
+
```
|
59
|
+
|
60
|
+
to render 3 submit buttons: `Save`, `Save and Continue`, and `Save and Add New`.
|
61
|
+
|
62
|
+
## License
|
63
|
+
|
64
|
+
MIT License. Copyright [Code and Effect Inc.](http://www.codeandeffect.com/)
|
65
|
+
|
66
|
+
## Contributing
|
67
|
+
|
68
|
+
1. Fork it
|
69
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
70
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
71
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
72
|
+
5. Bonus points for test coverage
|
73
|
+
6. Create new Pull Request
|
74
|
+
|
@@ -0,0 +1,158 @@
|
|
1
|
+
module Effective
|
2
|
+
module CrudController
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
end
|
10
|
+
|
11
|
+
def index
|
12
|
+
@page_title ||= resource_name.pluralize.titleize
|
13
|
+
EffectiveResources.authorized?(self, :index, resource_class)
|
14
|
+
|
15
|
+
self.resources ||= resource_class.all
|
16
|
+
@datatable ||= resource_datatable_class.new(params[:scopes])
|
17
|
+
end
|
18
|
+
|
19
|
+
def new
|
20
|
+
self.resource ||= resource_class.new
|
21
|
+
|
22
|
+
@page_title ||= "New #{resource_name.titleize}"
|
23
|
+
EffectiveResources.authorized?(self, :new, resource)
|
24
|
+
end
|
25
|
+
|
26
|
+
def create
|
27
|
+
self.resource ||= resource_class.new(send(resource_params_method_name))
|
28
|
+
|
29
|
+
@page_title ||= "New #{resource_name.titleize}"
|
30
|
+
EffectiveResources.authorized?(self, :create, resource)
|
31
|
+
|
32
|
+
if resource.save
|
33
|
+
flash[:success] = "Successfully created #{resource_name}"
|
34
|
+
redirect_to(resource_redirect_path)
|
35
|
+
else
|
36
|
+
flash.now[:danger] = "Unable to create #{resource_name}: #{resource.errors.full_messages.to_sentence}"
|
37
|
+
render :new
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def show
|
42
|
+
self.resource ||= resource_class.find(params[:id])
|
43
|
+
|
44
|
+
@page_title ||= resource.to_s
|
45
|
+
EffectiveResources.authorized?(self, :show, resource)
|
46
|
+
end
|
47
|
+
|
48
|
+
def edit
|
49
|
+
self.resource ||= resource_class.find(params[:id])
|
50
|
+
|
51
|
+
@page_title ||= "Edit #{resource}"
|
52
|
+
EffectiveResources.authorized?(self, :edit, resource)
|
53
|
+
end
|
54
|
+
|
55
|
+
def update
|
56
|
+
self.resource ||= resource_class.find(params[:id])
|
57
|
+
|
58
|
+
@page_title = "Edit #{resource}"
|
59
|
+
EffectiveResources.authorized?(self, :update, resource)
|
60
|
+
|
61
|
+
if resource.update_attributes(send(resource_params_method_name))
|
62
|
+
flash[:success] = "Successfully updated #{resource_name}"
|
63
|
+
redirect_to(resource_redirect_path)
|
64
|
+
else
|
65
|
+
flash.now[:danger] = "Unable to update #{resource_name}: #{resource.errors.full_messages.to_sentence}"
|
66
|
+
render :edit
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def destroy
|
71
|
+
self.resource = resource_class.find(params[:id])
|
72
|
+
|
73
|
+
@page_title = "Destroy #{resource}"
|
74
|
+
EffectiveResources.authorized?(self, :destroy, resource)
|
75
|
+
|
76
|
+
if resource.destroy
|
77
|
+
flash[:success] = "Successfully deleted #{resource_name}"
|
78
|
+
else
|
79
|
+
flash[:danger] = "Unable to delete #{resource_name}: #{resource.errors.full_messages.to_sentence}"
|
80
|
+
end
|
81
|
+
|
82
|
+
request.referer.present? ? redirect_to(request.referer) : redirect_to(resources_path)
|
83
|
+
end
|
84
|
+
|
85
|
+
protected
|
86
|
+
|
87
|
+
def resource # @thing
|
88
|
+
instance_variable_get("@#{resource_name}")
|
89
|
+
end
|
90
|
+
|
91
|
+
def resource=(instance)
|
92
|
+
instance_variable_set("@#{resource_name}", instance)
|
93
|
+
end
|
94
|
+
|
95
|
+
def resources # @things
|
96
|
+
send(:instance_variable_get, "@#{resource_name.pluralize}")
|
97
|
+
end
|
98
|
+
|
99
|
+
def resources=(instance)
|
100
|
+
send(:instance_variable_set, "@#{resource_name.pluralize}", instance)
|
101
|
+
end
|
102
|
+
|
103
|
+
def resource_class # Thing
|
104
|
+
resource_namespaced_name.classify.safe_constantize || resource_name.classify.constantize
|
105
|
+
end
|
106
|
+
|
107
|
+
def resource_name # 'thing'
|
108
|
+
controller_path.split('/').last.singularize
|
109
|
+
end
|
110
|
+
|
111
|
+
def resource_namespace # ['admin']
|
112
|
+
controller_path.split('/')[0..-2].presence
|
113
|
+
end
|
114
|
+
|
115
|
+
def resource_namespaced_name # 'Admin::Thing'
|
116
|
+
([resource_namespace, resource_name].compact * '/').singularize.camelize
|
117
|
+
end
|
118
|
+
|
119
|
+
def resource_datatable_class
|
120
|
+
if defined?(EffectiveDatatables)
|
121
|
+
"#{resource_namespaced_name.pluralize}Datatable".safe_constantize ||
|
122
|
+
"#{resource_name.pluralize.camelize}Datatable".safe_constantize ||
|
123
|
+
"Effective::Datatables::#{resource_namespaced_name.pluralize}".safe_constantize ||
|
124
|
+
"Effective::Datatables::#{resource_name.pluralize.camelize}".safe_constantize
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def resource_params_method_name
|
129
|
+
["#{resource_name}_params", "#{resource_name.pluralize}_params", 'permitted_params'].find { |name| respond_to?(name, true) } || 'params'
|
130
|
+
end
|
131
|
+
|
132
|
+
def resources_path # /admin/things
|
133
|
+
send([resource_namespace, resource_name.pluralize, 'path'].compact.join('_'))
|
134
|
+
end
|
135
|
+
|
136
|
+
def new_resource_path # /admin/things/new
|
137
|
+
send(['new', resource_namespace, resource_name, 'path'].compact.join('_'))
|
138
|
+
end
|
139
|
+
|
140
|
+
def edit_resource_path # /admin/things/1/edit
|
141
|
+
send(['edit', resource_namespace, resource_name, 'path'].compact.join('_'), resource)
|
142
|
+
end
|
143
|
+
|
144
|
+
def resource_path # /admin/things/1
|
145
|
+
send([resource_namespace, resource_name, 'path'].compact.join('_'), resource)
|
146
|
+
end
|
147
|
+
|
148
|
+
def resource_redirect_path
|
149
|
+
case params[:commit].to_s
|
150
|
+
when 'Save' ; edit_resource_path
|
151
|
+
when 'Save and Continue' ; resources_path
|
152
|
+
when 'Save and Add New' ; new_resource_path
|
153
|
+
else resource_path
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module EffectiveResourcesHelper
|
2
|
+
|
3
|
+
def simple_form_submit(form)
|
4
|
+
content_tag(:p, class: 'text-right') do
|
5
|
+
[
|
6
|
+
form.button(:submit, 'Save', data: { disable_with: 'Saving...' }),
|
7
|
+
form.button(:submit, 'Save and Continue', data: { disable_with: 'Saving...' }),
|
8
|
+
form.button(:submit, 'Save and Add New', data: { disable_with: 'Saving...' })
|
9
|
+
].join(' ').html_safe
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
unless defined?(Effective::AccessDenied)
|
2
|
+
module Effective
|
3
|
+
class AccessDenied < StandardError
|
4
|
+
attr_reader :action, :subject
|
5
|
+
|
6
|
+
def initialize(message = nil, action = nil, subject = nil)
|
7
|
+
@message = message
|
8
|
+
@action = action
|
9
|
+
@subject = subject
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
@message || I18n.t(:'unauthorized.default', :default => 'Access Denied')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
EffectiveResources.setup do |config|
|
2
|
+
# Authorization Method
|
3
|
+
#
|
4
|
+
# This method is called by all controller actions with the appropriate action and resource
|
5
|
+
# If the method returns false, an Effective::AccessDenied Error will be raised (see README.md for complete info)
|
6
|
+
#
|
7
|
+
# Use via Proc (and with CanCan):
|
8
|
+
# config.authorization_method = Proc.new { |controller, action, resource| can?(action, resource) }
|
9
|
+
#
|
10
|
+
# Use via custom method:
|
11
|
+
# config.authorization_method = :my_authorization_method
|
12
|
+
#
|
13
|
+
# And then in your application_controller.rb:
|
14
|
+
#
|
15
|
+
# def my_authorization_method(action, resource)
|
16
|
+
# current_user.is?(:admin)
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# Or disable the check completely:
|
20
|
+
# config.authorization_method = false
|
21
|
+
config.authorization_method = Proc.new { |controller, action, resource| authorize!(action, resource) } # CanCanCan
|
22
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'effective_resources/engine'
|
2
|
+
require 'effective_resources/version'
|
3
|
+
|
4
|
+
module EffectiveResources
|
5
|
+
|
6
|
+
# The following are all valid config keys
|
7
|
+
mattr_accessor :authorization_method
|
8
|
+
|
9
|
+
def self.setup
|
10
|
+
yield self
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.authorized?(controller, action, resource)
|
14
|
+
if authorization_method.respond_to?(:call) || authorization_method.kind_of?(Symbol)
|
15
|
+
raise Effective::AccessDenied.new() unless (controller || self).instance_exec(controller, action, resource, &authorization_method)
|
16
|
+
end
|
17
|
+
true
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module EffectiveResources
|
2
|
+
class Engine < ::Rails::Engine
|
3
|
+
engine_name 'effective_resources'
|
4
|
+
|
5
|
+
config.autoload_paths += Dir["#{config.root}/lib/"]
|
6
|
+
|
7
|
+
# Set up our default configuration options.
|
8
|
+
initializer 'effective_resources.defaults', before: :load_config_initializers do |app|
|
9
|
+
eval File.read("#{config.root}/config/effective_resources.rb")
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module EffectiveResources
|
2
|
+
module Generators
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
desc 'Creates an EffectiveResources initializer in your application.'
|
5
|
+
|
6
|
+
source_root File.expand_path('../../templates', __FILE__)
|
7
|
+
|
8
|
+
def copy_initializer
|
9
|
+
template ('../' * 3) + 'config/effective_resources.rb', 'config/initializers/effective_resources.rb'
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: effective_resources
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Code and Effect
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-01-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 3.2.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 3.2.0
|
27
|
+
description: Make any controller an effective resource controller.
|
28
|
+
email:
|
29
|
+
- info@codeandeffect.com
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- MIT-LICENSE
|
35
|
+
- README.md
|
36
|
+
- app/controllers/concerns/effective/crud_controller.rb
|
37
|
+
- app/helpers/effective_resources_helper.rb
|
38
|
+
- app/models/effective/access_denied.rb
|
39
|
+
- config/effective_resources.rb
|
40
|
+
- lib/effective_resources.rb
|
41
|
+
- lib/effective_resources/engine.rb
|
42
|
+
- lib/effective_resources/version.rb
|
43
|
+
- lib/generators/effective_resources/install_generator.rb
|
44
|
+
homepage: https://github.com/code-and-effect/effective_resources
|
45
|
+
licenses:
|
46
|
+
- MIT
|
47
|
+
metadata: {}
|
48
|
+
post_install_message:
|
49
|
+
rdoc_options: []
|
50
|
+
require_paths:
|
51
|
+
- lib
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
requirements: []
|
63
|
+
rubyforge_project:
|
64
|
+
rubygems_version: 2.4.5.1
|
65
|
+
signing_key:
|
66
|
+
specification_version: 4
|
67
|
+
summary: Make any controller an effective resource controller.
|
68
|
+
test_files: []
|