restful_controller 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +151 -0
- data/Rakefile +44 -0
- data/lib/restful/actions.rb +168 -0
- data/lib/restful/base.rb +321 -0
- data/lib/restful/dummy_responder.rb +11 -0
- data/lib/restful/version.rb +7 -0
- data/lib/restful.rb +7 -0
- data/lib/tasks/resourceful_tasks.rake +4 -0
- data/test/actions_definition_test.rb +104 -0
- data/test/alternates_controller_test.rb +8 -0
- data/test/base_controller_test.rb +8 -0
- data/test/blocks_controller_test.rb +28 -0
- data/test/custom_notices_controller_test.rb +22 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +13 -0
- data/test/dummy/app/controllers/alternates_controller.rb +49 -0
- data/test/dummy/app/controllers/application_controller.rb +5 -0
- data/test/dummy/app/controllers/base_controller.rb +5 -0
- data/test/dummy/app/controllers/blocks_controller.rb +19 -0
- data/test/dummy/app/controllers/custom_notices_controller.rb +14 -0
- data/test/dummy/app/controllers/documents_controller.rb +11 -0
- data/test/dummy/app/controllers/home_controller.rb +5 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/models/document.rb +3 -0
- data/test/dummy/app/views/base/edit.html.erb +3 -0
- data/test/dummy/app/views/base/index.html.erb +3 -0
- data/test/dummy/app/views/base/new.html.erb +3 -0
- data/test/dummy/app/views/base/show.html.erb +1 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/config/application.rb +29 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +29 -0
- data/test/dummy/config/environments/production.rb +80 -0
- data/test/dummy/config/environments/test.rb +36 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/generators.rb +6 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +12 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +62 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/migrate/20130703024719_create_documents.rb +9 -0
- data/test/dummy/db/schema.rb +22 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/development.log +11 -0
- data/test/dummy/log/test.log +75091 -0
- data/test/dummy/public/404.html +58 -0
- data/test/dummy/public/422.html +58 -0
- data/test/dummy/public/500.html +57 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/test/fixtures/documents.yml +7 -0
- data/test/dummy/test/models/document_test.rb +7 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
- data/test/resourceful_test.rb +8 -0
- data/test/support/base_actions.rb +130 -0
- data/test/test_helper.rb +39 -0
- metadata +268 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 15e4f8de8ab53f6ca410c248e9b84d4ba7afe2c4
|
4
|
+
data.tar.gz: 21f2de7e065969b0f56fda318a94bca1aacdb428
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fcb5302fa9589c455bb6c4e0ee34e5e7320e041d08746c2abbb377beb8d4fd7f1a03068046feb3758cfb653b22892a9f5a6681cc55301ab9b4dae3cb8ec222a9
|
7
|
+
data.tar.gz: ccd5c3dafaab3fb91b0df5da70da7a74aa3b43849b2fddfe28ea65983b86ba86fbff0eeec3af493aae03ced53dc134cfd854e10597b137e5b98b670412653edd
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2013 YOURNAME
|
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.rdoc
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
{<img src="https://travis-ci.org/mariochavez/restful.png?branch=master" alt="Build Status" />}[https://travis-ci.org/mariochavez/restful]
|
2
|
+
= Restful
|
3
|
+
Restful helps to keep Controllers DRY, removing repetitive code from basic REST actions.
|
4
|
+
|
5
|
+
Very basic controllers repeat over and over the same code for REST actions, but if you do TDD - and should be doing it -, the code to test these controllers is also repetitive and boring.
|
6
|
+
|
7
|
+
Restful helps you to get rid of that repetitive and boring code with a very simple defaults for RESTful controllers.
|
8
|
+
|
9
|
+
But wait, this is not a new idea, there is already Inherited Resources (https://github.com/josevalim/inherited_resources) gem that allows you to do the same and maybe even more; so why write another library?
|
10
|
+
|
11
|
+
It's simple, I had the time and I wanted to try it. This library does not cover all the cases that Inherited Resources cover, but it's good enough for so many controllers. Also all the source code is documented and quite simple to follow in case that you want to learn how is it implemented.
|
12
|
+
|
13
|
+
== Installation
|
14
|
+
Resful requires Ruby on Rails 4.0 and Ruby 2.0.
|
15
|
+
|
16
|
+
To install it, just add the Restful gem to your Gemfile:
|
17
|
+
|
18
|
+
gem 'restful'
|
19
|
+
|
20
|
+
Run bundler command and you are all set.
|
21
|
+
|
22
|
+
== Usage
|
23
|
+
Restful module must be included on each controller that you want to become Restful. Also it's need for these controllers to include the respond_to macro, which will especify the format to which our controllers will respond to.
|
24
|
+
|
25
|
+
Finally the resful macro is need it to setup our controller.
|
26
|
+
This macro accepts 3 params:
|
27
|
+
|
28
|
+
=== Params
|
29
|
+
* model: A requires parameter which is a symbol of the model name.
|
30
|
+
* strong_params: A symbol, a string or a proc for the method that should apply the strong parameters to allow Active Model mass assignments.
|
31
|
+
* actions: An array of actions that a controller should implement, if none is passed then all seven REST actions are defined.
|
32
|
+
|
33
|
+
=== Examples
|
34
|
+
|
35
|
+
Simple:
|
36
|
+
|
37
|
+
class DocumentsController < ApplicationController
|
38
|
+
include restful
|
39
|
+
respond_to :html
|
40
|
+
|
41
|
+
restful model: :document, strong_params: :document_params
|
42
|
+
end
|
43
|
+
|
44
|
+
This definition will create the seven REST actions for Document model,
|
45
|
+
this setup a single object instance variable @document and a collection
|
46
|
+
variable @documents.
|
47
|
+
|
48
|
+
It's expected that this controller will provide a method
|
49
|
+
document_params which will be used to allow mass assignments.
|
50
|
+
|
51
|
+
Strong params variation:
|
52
|
+
|
53
|
+
class DocumentsController < ApplicationController
|
54
|
+
include restful
|
55
|
+
respond_to :html
|
56
|
+
|
57
|
+
restful model: :document,
|
58
|
+
strong_params: ->(params){ params.require(:document).permit :name }
|
59
|
+
end
|
60
|
+
|
61
|
+
In this example instead of providing a strong params method by string
|
62
|
+
or symbol, a proc is passed to do the same job.
|
63
|
+
|
64
|
+
Listed actions variation:
|
65
|
+
|
66
|
+
The last parameter *actions* allows you to list in an array the actions
|
67
|
+
that you want your controller to have:
|
68
|
+
|
69
|
+
class DocumentsController < ApplicationController
|
70
|
+
include restful
|
71
|
+
respond_to :html
|
72
|
+
|
73
|
+
restful model: :document, strong_params: :document_params,
|
74
|
+
actions: [:index, :show]
|
75
|
+
end
|
76
|
+
|
77
|
+
In this case our controller will only respond to those 2 actions. We
|
78
|
+
can do it the other way, indicate list of actions that shouldn't be
|
79
|
+
defined:
|
80
|
+
|
81
|
+
class DocumentsController < ApplicationController
|
82
|
+
include restful
|
83
|
+
respond_to :html
|
84
|
+
|
85
|
+
restful model: :document, strong_params: :document_params,
|
86
|
+
actions: [:all, except: [:destroy, :show]]
|
87
|
+
end
|
88
|
+
|
89
|
+
For this last example all seven REST actions will be defined but :destroy and :show
|
90
|
+
|
91
|
+
== Actions
|
92
|
+
|
93
|
+
Used as a template for all Restful controller actions
|
94
|
+
|
95
|
+
By default an action is created with an alias method with a bang(!).
|
96
|
+
If you need to override an action, just redefine it in you controller,
|
97
|
+
to call this base action, just call the bang version:
|
98
|
+
|
99
|
+
def index
|
100
|
+
@documents = Document.all
|
101
|
+
index!
|
102
|
+
end
|
103
|
+
|
104
|
+
This will allow you to let Restful to continue with the action flow.
|
105
|
+
|
106
|
+
When overriding an action, just be sure to have inside de action variables
|
107
|
+
with the name of the defined model, doing this will allow you to call the
|
108
|
+
bang action version:
|
109
|
+
|
110
|
+
def new
|
111
|
+
@document = Document.new name: 'Default name'
|
112
|
+
new!
|
113
|
+
end
|
114
|
+
|
115
|
+
For actions like :create and :update a notice or alert can be passed as
|
116
|
+
option to be set in flash object:
|
117
|
+
|
118
|
+
def create
|
119
|
+
@document = Document.new secure_params
|
120
|
+
create!(notice: 'Hey a new document was created!')
|
121
|
+
end
|
122
|
+
|
123
|
+
Also a block can be passed for the happy path to tell the application to
|
124
|
+
where redirect:
|
125
|
+
|
126
|
+
def update
|
127
|
+
@document = Document.find params[:id]
|
128
|
+
@document.update_attributes secure_params
|
129
|
+
|
130
|
+
update!(notice: 'Document has been updated'){ root_path }
|
131
|
+
end
|
132
|
+
|
133
|
+
It's also possible to supply a block for the non-happy path, this means
|
134
|
+
proving a dual block for success and failure results from our action:
|
135
|
+
|
136
|
+
def update
|
137
|
+
@document = Document.find params[:id]
|
138
|
+
@document = update_attributes secure_params
|
139
|
+
|
140
|
+
update! do |success, failure|
|
141
|
+
success.html { redirect_to root_path }
|
142
|
+
failure.html { render :custom }
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
== Bugs and feedback
|
147
|
+
Use issues at Github to report bugs or give feedback.
|
148
|
+
|
149
|
+
For detailed documentation look at http://rdoc.info/github/mariochavez/restful/master/frames
|
150
|
+
|
151
|
+
Copyright © 2013 Mario Alberto Chavez. This project uses MIT-LICENSE.
|
data/Rakefile
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'Restful'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.rdoc')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
Bundler::GemHelper.install_tasks
|
18
|
+
|
19
|
+
require 'rake/testtask'
|
20
|
+
|
21
|
+
desc 'Run rubocop checks'
|
22
|
+
task :rubocop do
|
23
|
+
sh 'rubocop lib test'
|
24
|
+
end
|
25
|
+
|
26
|
+
desc 'Run flay checks'
|
27
|
+
task :flay do
|
28
|
+
sh 'find lib -name \*.rb | xargs flog'
|
29
|
+
end
|
30
|
+
|
31
|
+
desc 'Run flog checks'
|
32
|
+
task :flog do
|
33
|
+
sh 'flay lib/*.rb'
|
34
|
+
end
|
35
|
+
|
36
|
+
Rake::TestTask.new(:test) do |t|
|
37
|
+
t.libs << 'lib'
|
38
|
+
t.libs << 'test'
|
39
|
+
t.pattern = 'test/**/*_test.rb'
|
40
|
+
t.verbose = false
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
task default: :test
|
@@ -0,0 +1,168 @@
|
|
1
|
+
module Restful
|
2
|
+
##
|
3
|
+
# = Actions
|
4
|
+
#
|
5
|
+
# Used as a template for all Restful controller actions
|
6
|
+
#
|
7
|
+
# By default an action is created with an alias method with a bang(!).
|
8
|
+
# If you need to override an action, just redefine it in you controller,
|
9
|
+
# to call this base action, just call the bang version:
|
10
|
+
#
|
11
|
+
# def index
|
12
|
+
# @documents = Document.all
|
13
|
+
# index!
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# This will allow you to let Restful to continue with the action flow.
|
17
|
+
#
|
18
|
+
# When overriding an action, just be sure to have inside de action variables
|
19
|
+
# with the name of the defined model, doing this will allow you to call the
|
20
|
+
# bang action version:
|
21
|
+
#
|
22
|
+
# def new
|
23
|
+
# @document = Document.new name: 'Default name'
|
24
|
+
# new!
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# For actions like :create and :update a notice or alert can be passed as
|
28
|
+
# option to be set in flash object:
|
29
|
+
#
|
30
|
+
# def create
|
31
|
+
# @document = Document.new secure_params
|
32
|
+
# create!(notice: 'Hey a new document was created!')
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# Also a block can be passed for the happy path to tell the application to
|
36
|
+
# where redirect:
|
37
|
+
#
|
38
|
+
# def update
|
39
|
+
# @document = Document.find params[:id]
|
40
|
+
# @document.update_attributes secure_params
|
41
|
+
#
|
42
|
+
# update!(notice: 'Document has been updated'){ root_path }
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# It's also possible to supply a block for the non-happy path, this means
|
46
|
+
# proving a dual block for success and failure results from our action:
|
47
|
+
#
|
48
|
+
# def update
|
49
|
+
# @document = Document.find params[:id]
|
50
|
+
# @document = update_attributes secure_params
|
51
|
+
#
|
52
|
+
# update! do |success, failure|
|
53
|
+
# success.html { redirect_to root_path }
|
54
|
+
# failure.html { render :custom }
|
55
|
+
# end
|
56
|
+
# end
|
57
|
+
#
|
58
|
+
# Be aware that Restful require that your controllers define to what they
|
59
|
+
# respond, it could be :html, :json or anything else, just remember to add
|
60
|
+
# the respond_to macro to the top of your controller's definition:
|
61
|
+
#
|
62
|
+
# class DocumentsController < ApplicationController
|
63
|
+
# respond_to :html
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
module Actions
|
67
|
+
##
|
68
|
+
# index action, this set a collection of objects to an instance variable
|
69
|
+
# which can be accessed from the view using the collection helper method.
|
70
|
+
# The instance variable name is a pluralization of the model name defined
|
71
|
+
# in the restful macro.
|
72
|
+
def index(options = {}, &block)
|
73
|
+
respond_with(collection, options, &block)
|
74
|
+
end
|
75
|
+
alias_method :index!, :index
|
76
|
+
|
77
|
+
##
|
78
|
+
# new action, creates a new object and sets an instance variable which can
|
79
|
+
# be accessed from the view using the resource helper method. The instance
|
80
|
+
# variable is named after the model name defined in the restful macro.
|
81
|
+
def new(options = {}, &block)
|
82
|
+
respond_with(build_resource, options, &block)
|
83
|
+
end
|
84
|
+
alias_method :new!, :new
|
85
|
+
|
86
|
+
##
|
87
|
+
# create action, creates a new object off the received params and sets an
|
88
|
+
# instance variable if record is saved then a redirect to index action is
|
89
|
+
# made.
|
90
|
+
#
|
91
|
+
# If record fail to be saved, the new form is renderd and the instance
|
92
|
+
# variable can be accessed from the view using the resource
|
93
|
+
# helper method. The instance variable is named after the model name
|
94
|
+
# defined in the restful macro.
|
95
|
+
def create(options = {}, &block)
|
96
|
+
object = get_resource_ivar || create_resource
|
97
|
+
|
98
|
+
options[:location] = collection_path if object.errors.empty?
|
99
|
+
|
100
|
+
respond_with_dual(object, options, &block)
|
101
|
+
end
|
102
|
+
alias_method :create!, :create
|
103
|
+
|
104
|
+
##
|
105
|
+
# edit action, finds an object based on the passed id, if no object is
|
106
|
+
# found an ActiveRecord::RecordNotFound is raised.
|
107
|
+
#
|
108
|
+
# If the record is found then an instance variable, based on the model
|
109
|
+
# name set in the restful macro.
|
110
|
+
#
|
111
|
+
# This variable can be accessed in teh form using the resource helper
|
112
|
+
# method.
|
113
|
+
def edit(options = {}, &block)
|
114
|
+
object = get_resource_ivar || find_resource
|
115
|
+
|
116
|
+
respond_with(object, options, &block)
|
117
|
+
end
|
118
|
+
alias_method :edit!, :edit
|
119
|
+
|
120
|
+
##
|
121
|
+
# update action, finds an object based on the passed id, if no object is
|
122
|
+
# found an ActiveRecord::RecordNotFound is raised. If the record is found
|
123
|
+
# then it's updated from params using ActiveRecord update_attributes method
|
124
|
+
# and an instance variable is set with the object, variable name is based
|
125
|
+
# on the model name set in the restful macro.
|
126
|
+
#
|
127
|
+
# If update_attributes fail, then edit form is displayed, and the instance
|
128
|
+
# variable can be accessed in teh form using the resource helper method.
|
129
|
+
#
|
130
|
+
# If update_attributes success, a redirect to the index action is made.
|
131
|
+
def update(options = {}, &block)
|
132
|
+
object = get_resource_ivar || find_and_update_resource
|
133
|
+
|
134
|
+
options[:location] = collection_path if object.errors.empty?
|
135
|
+
|
136
|
+
respond_with_dual(object, options, &block)
|
137
|
+
end
|
138
|
+
alias_method :update!, :update
|
139
|
+
|
140
|
+
##
|
141
|
+
# show action, finds an object based on the passed id, if no object is
|
142
|
+
# found an ActiveRecord::RecordNotFound is raised. If the record is found
|
143
|
+
# then an instance variable is set with the object, variable name is based
|
144
|
+
# on the model name set in the restful macro.
|
145
|
+
def show(options = {}, &block)
|
146
|
+
object = get_resource_ivar || find_resource
|
147
|
+
|
148
|
+
respond_with(object, options, &block)
|
149
|
+
end
|
150
|
+
alias_method :show!, :show
|
151
|
+
|
152
|
+
##
|
153
|
+
# destroy action, finds an object based on the passed id, if no object is
|
154
|
+
# found an ActiveRecord::RecordNotFound is raised. If the record is found
|
155
|
+
# then it's destroyed and a redirect to the index action is made.
|
156
|
+
def destroy(options = {}, &block)
|
157
|
+
object = get_resource_ivar || find_resource
|
158
|
+
|
159
|
+
object.destroy
|
160
|
+
options[:location] = collection_path
|
161
|
+
|
162
|
+
respond_with(object, options, &block)
|
163
|
+
end
|
164
|
+
alias_method :destroy!, :destroy
|
165
|
+
|
166
|
+
protected :index!, :new!, :create!, :edit!, :update!, :show!, :destroy!
|
167
|
+
end
|
168
|
+
end
|