service_crud 0.0.1
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.
- data/README.markdown +106 -0
- data/lib/service_crud/couchrest_model.rb +7 -0
- data/lib/service_crud/default_orm.rb +10 -0
- data/lib/service_crud/service_crud.rb +153 -0
- data/lib/service_crud.rb +3 -0
- metadata +85 -0
data/README.markdown
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Service Crud
|
|
2
|
+
|
|
3
|
+
The `service_crud` gem: A simple mixin for adding crud actions for a RESTful, ActiveResource style service (xml and json).
|
|
4
|
+
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
This gem works with Rails 3.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
$ cd /path/to/your/rails3/app
|
|
12
|
+
$ echo "gem service_crud" >> Gemfile
|
|
13
|
+
$ bundle install
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
Let's suppose we have a "Book" model, and we want to create XML and JSON RESTful services for it. Simple:
|
|
18
|
+
|
|
19
|
+
First, go to your routes.rb file and add the following route:
|
|
20
|
+
|
|
21
|
+
resources :books
|
|
22
|
+
|
|
23
|
+
Next, create the following controller in RAILS_ROOT/app/books_controller.rb:
|
|
24
|
+
|
|
25
|
+
class BooksController
|
|
26
|
+
include ServiceCrud
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
That's it. You can now GET, POST, PUT, and DELETE books through the standard RESTful urls.
|
|
30
|
+
|
|
31
|
+
## Callbacks
|
|
32
|
+
|
|
33
|
+
Sometimes you need to do a little extra work on your data before/after you create/update/destroy. And sometimes that can't be pushed down to the ORM layer.
|
|
34
|
+
For example, suppose we want to set the `:updated_by` property on our model to the `current_user`. We could simply:
|
|
35
|
+
|
|
36
|
+
class BooksController
|
|
37
|
+
include ServiceCrud
|
|
38
|
+
before_update :set_updated_by
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
def set_updated_by(model)
|
|
42
|
+
model.update_by = current_user
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
ServiceCrud supports the following callbacks: `before_create`, `after_create`, `before_update`, `after_update`, `before_destroy`, and `after_destroy`.
|
|
47
|
+
|
|
48
|
+
## Model Guessing
|
|
49
|
+
|
|
50
|
+
The `service_crud` library will look at the controller name and try to guess the model (e.g., "BooksController" -> "Book").
|
|
51
|
+
|
|
52
|
+
If your controller name doesn't match your model, call the `model` method:
|
|
53
|
+
|
|
54
|
+
class MyBooksController
|
|
55
|
+
include ServiceCrud
|
|
56
|
+
model Book
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
## PUT/POST parameter guessing
|
|
60
|
+
|
|
61
|
+
Similarly, on POST or PUT, `service_crud` assumes that the top-level node of the XML or JSON is the lowercased, underscored, singularized symbol of your model name.
|
|
62
|
+
|
|
63
|
+
If that's not the case for your service, call the `model_attribute_root` class method:
|
|
64
|
+
|
|
65
|
+
class BooksController
|
|
66
|
+
include ServiceCrud
|
|
67
|
+
model_attribute_root :my_book
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
## ORM
|
|
71
|
+
|
|
72
|
+
The `service_crud` library assumes an ActiveRecord ORM by default. It also, out of the box, supports the `couchrest_model` ORM for couchdb.
|
|
73
|
+
To use `couchrest_model`, simply:
|
|
74
|
+
|
|
75
|
+
class BooksController
|
|
76
|
+
include ServiceCrud
|
|
77
|
+
orm_methods! ServiceCrud::CouchRest::Model
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
The default ORM methods are:
|
|
81
|
+
|
|
82
|
+
module ServiceCrud
|
|
83
|
+
module DefaultOrm
|
|
84
|
+
def all; :all; end
|
|
85
|
+
def new; :new; end
|
|
86
|
+
def find; :find; end
|
|
87
|
+
def destroy; :destroy; end
|
|
88
|
+
def update_attributes; :update_attributes; end
|
|
89
|
+
def save; :save; end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
If you're using an ORM other than ActiveRecord or CouchRest::Model, and some or all of your ORM's method names differ from ActiveRecord's,
|
|
94
|
+
then simply create a module that redefines one or more DefaultOrm methods. For example, suppose we create our own ORM, `MoonOrm`, and our method for finding
|
|
95
|
+
records is `lookup` instead of `find`. Then we'd simply:
|
|
96
|
+
|
|
97
|
+
module MoonOrmMethods
|
|
98
|
+
def find; :lookup; end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
Then, in our controller:
|
|
102
|
+
|
|
103
|
+
class BooksController
|
|
104
|
+
include ServiceCrud
|
|
105
|
+
orm_methods! MoonOrmMethods
|
|
106
|
+
end
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
module ServiceCrud
|
|
2
|
+
|
|
3
|
+
def self.included(base)
|
|
4
|
+
base.extend ClassMethods
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
module ClassMethods
|
|
8
|
+
def model(klass=nil)
|
|
9
|
+
@model ||= klass
|
|
10
|
+
@model || self.to_s.gsub("Controller", "").singularize.constantize
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def model_attribute_root(root=nil)
|
|
14
|
+
@model_attribute_root ||= root
|
|
15
|
+
@model_attribute_root || self.model.to_s.underscore.to_sym
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def orm_methods!(orm_module)
|
|
19
|
+
self.orm_methods.extend orm_module
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def orm_methods
|
|
23
|
+
@orm_methods ||= ServiceCrud::DefaultOrm.new
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def before_create(method=nil, &block)
|
|
27
|
+
self.before_creates << method if method
|
|
28
|
+
self.before_creates << block if block
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def before_update(method=nil, &block)
|
|
32
|
+
self.before_updates << method if method
|
|
33
|
+
self.before_updates << block if block
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def before_destroy(method=nil, &block)
|
|
37
|
+
self.before_destroys << method if method
|
|
38
|
+
self.before_destroys << block if block
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def after_create(method=nil, &block)
|
|
42
|
+
self.after_creates << method if method
|
|
43
|
+
self.after_creates << block if block
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def after_update(method=nil, &block)
|
|
47
|
+
self.after_updates << method if method
|
|
48
|
+
self.after_updates << block if block
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def after_destroy(method=nil, &block)
|
|
52
|
+
self.after_destroys << method if method
|
|
53
|
+
self.after_destroys << block if block
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def before_creates; @before_creates ||= []; end
|
|
57
|
+
def before_updates; @before_updates ||= []; end
|
|
58
|
+
def before_destroys; @before_destroys ||= []; end
|
|
59
|
+
def after_creates; @after_creates ||= []; end
|
|
60
|
+
def after_updates; @after_updates ||= []; end
|
|
61
|
+
def after_destroys; @after_destroys ||= []; end
|
|
62
|
+
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# GET /your_model.xml
|
|
66
|
+
# GET /your_model.json
|
|
67
|
+
def index
|
|
68
|
+
@models = self.class.model.send self.class.orm_methods.all
|
|
69
|
+
|
|
70
|
+
respond_to do |format|
|
|
71
|
+
format.xml { render :xml => @models }
|
|
72
|
+
format.json { render :json => @models }
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# GET /your_model/1.xml
|
|
77
|
+
# GET /your_model/1.json
|
|
78
|
+
def show
|
|
79
|
+
@model = self.class.model.send self.class.orm_methods.find, params[:id]
|
|
80
|
+
|
|
81
|
+
respond_to do |format|
|
|
82
|
+
format.xml { render :xml => @model }
|
|
83
|
+
format.json { render :json => @model }
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# POST /your_model.xml
|
|
88
|
+
# POST /your_model.json
|
|
89
|
+
def create
|
|
90
|
+
@model = self.class.model.send self.class.orm_methods.new, params[self.class.model_attribute_root]
|
|
91
|
+
run_service_crud_before_callbacks @model
|
|
92
|
+
|
|
93
|
+
respond_to do |format|
|
|
94
|
+
if @model.send self.class.orm_methods.save
|
|
95
|
+
run_service_crud_after_callbacks @model
|
|
96
|
+
location = "/#{controller_name}/#{@model.id}"
|
|
97
|
+
format.xml { render :xml => @model, :status => :created, :location => location }
|
|
98
|
+
format.json { render :json => @model, :status => :created, :location => location }
|
|
99
|
+
else
|
|
100
|
+
format.xml { render :xml => @model.errors, :status => :unprocessable_entity }
|
|
101
|
+
format.json { render :json => {:errors => @model.errors.to_a}.to_json, :status => :unprocessable_entity }
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# PUT /your_model/1.xml
|
|
107
|
+
# PUT /your_model/1.json
|
|
108
|
+
def update
|
|
109
|
+
@model = self.class.model.send self.class.orm_methods.find, params[:id]
|
|
110
|
+
run_service_crud_before_callbacks @model
|
|
111
|
+
|
|
112
|
+
respond_to do |format|
|
|
113
|
+
if @model.send self.class.orm_methods.update_attributes, params[self.class.model_attribute_root]
|
|
114
|
+
run_service_crud_after_callbacks @model
|
|
115
|
+
format.xml { head :ok }
|
|
116
|
+
format.json { head :ok }
|
|
117
|
+
else
|
|
118
|
+
format.xml { render :xml => @model.errors, :status => :unprocessable_entity }
|
|
119
|
+
format.json { render :json => {:errors => @model.errors.to_a}.to_json, :status => :unprocessable_entity }
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# DELETE /your_model/1.xml
|
|
125
|
+
# DELETE /your_model/1.json
|
|
126
|
+
def destroy
|
|
127
|
+
@model = self.class.model.send self.class.orm_methods.find, params[:id]
|
|
128
|
+
run_service_crud_before_callbacks @model
|
|
129
|
+
@model.send self.class.orm_methods.destroy
|
|
130
|
+
run_service_crud_after_callbacks @model
|
|
131
|
+
|
|
132
|
+
respond_to do |format|
|
|
133
|
+
format.xml { head :ok }
|
|
134
|
+
format.json { head :ok }
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
private
|
|
139
|
+
def run_service_crud_before_callbacks(model)
|
|
140
|
+
run_service_crud_callbacks self.class.send("before_#{action_name}s".to_sym), model
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def run_service_crud_after_callbacks(model)
|
|
144
|
+
run_service_crud_callbacks self.class.send("after_#{action_name}s".to_sym), model
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def run_service_crud_callbacks(service_crud_callbacks, model)
|
|
148
|
+
service_crud_callbacks.each do |method|
|
|
149
|
+
method.call(model) if method.respond_to?(:call) # if it's a proc
|
|
150
|
+
self.send method, model if method.kind_of?(Symbol)
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
data/lib/service_crud.rb
ADDED
metadata
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: service_crud
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
hash: 29
|
|
5
|
+
prerelease: false
|
|
6
|
+
segments:
|
|
7
|
+
- 0
|
|
8
|
+
- 0
|
|
9
|
+
- 1
|
|
10
|
+
version: 0.0.1
|
|
11
|
+
platform: ruby
|
|
12
|
+
authors:
|
|
13
|
+
- Matt Parker
|
|
14
|
+
autorequire:
|
|
15
|
+
bindir: bin
|
|
16
|
+
cert_chain: []
|
|
17
|
+
|
|
18
|
+
date: 2010-11-07 00:00:00 -04:00
|
|
19
|
+
default_executable:
|
|
20
|
+
dependencies:
|
|
21
|
+
- !ruby/object:Gem::Dependency
|
|
22
|
+
name: rails
|
|
23
|
+
prerelease: false
|
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
|
25
|
+
none: false
|
|
26
|
+
requirements:
|
|
27
|
+
- - ">="
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
hash: 7
|
|
30
|
+
segments:
|
|
31
|
+
- 3
|
|
32
|
+
- 0
|
|
33
|
+
version: "3.0"
|
|
34
|
+
type: :runtime
|
|
35
|
+
version_requirements: *id001
|
|
36
|
+
description: A simple mixin for providing crud actions for a RESTful, ActiveResource style service (xml and json).
|
|
37
|
+
email: moonmaster9000@gmail.com
|
|
38
|
+
executables: []
|
|
39
|
+
|
|
40
|
+
extensions: []
|
|
41
|
+
|
|
42
|
+
extra_rdoc_files:
|
|
43
|
+
- README.markdown
|
|
44
|
+
files:
|
|
45
|
+
- README.markdown
|
|
46
|
+
- lib/service_crud.rb
|
|
47
|
+
- lib/service_crud/couchrest_model.rb
|
|
48
|
+
- lib/service_crud/default_orm.rb
|
|
49
|
+
- lib/service_crud/service_crud.rb
|
|
50
|
+
has_rdoc: true
|
|
51
|
+
homepage: http://github.com/moonmaster9000/service_crud
|
|
52
|
+
licenses: []
|
|
53
|
+
|
|
54
|
+
post_install_message:
|
|
55
|
+
rdoc_options:
|
|
56
|
+
- --charset=UTF-8
|
|
57
|
+
require_paths:
|
|
58
|
+
- lib
|
|
59
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
60
|
+
none: false
|
|
61
|
+
requirements:
|
|
62
|
+
- - ">="
|
|
63
|
+
- !ruby/object:Gem::Version
|
|
64
|
+
hash: 3
|
|
65
|
+
segments:
|
|
66
|
+
- 0
|
|
67
|
+
version: "0"
|
|
68
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
69
|
+
none: false
|
|
70
|
+
requirements:
|
|
71
|
+
- - ">="
|
|
72
|
+
- !ruby/object:Gem::Version
|
|
73
|
+
hash: 3
|
|
74
|
+
segments:
|
|
75
|
+
- 0
|
|
76
|
+
version: "0"
|
|
77
|
+
requirements: []
|
|
78
|
+
|
|
79
|
+
rubyforge_project:
|
|
80
|
+
rubygems_version: 1.3.7
|
|
81
|
+
signing_key:
|
|
82
|
+
specification_version: 3
|
|
83
|
+
summary: DRY service crud.
|
|
84
|
+
test_files: []
|
|
85
|
+
|