smart_adapters 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +215 -8
- data/lib/smart_adapters/version.rb +1 -1
- metadata +2 -30
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6bc9acf4e7970034d8d7686621dd8e3d796db5e2f6a0be6b95019fc4907fd0a1
|
4
|
+
data.tar.gz: e072efc3832e85caed186bf930361f742e06635d23018fdd3c8243b80c7d2c75
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8a9c3baba90c72167965bf87cf4b277e2c56b64d81b61e1f60ce5fcecb4bfe6c033f7cda52528cfcd343c0730610f4fbcdd568ff6172dc394a0ca976f6c75902
|
7
|
+
data.tar.gz: 93101103f2e19c2c72161d7af7042f5748675f8e9f326d9e30792992d3b98f6543d3a14d5920cb74e0fc95d5eb4127759223e986c0d787f5a30be6e82d2acd25
|
data/README.md
CHANGED
@@ -1,10 +1,52 @@
|
|
1
|
-
# WIP
|
2
|
-
|
3
1
|
# SmartAdapters
|
4
|
-
Short description and motivation.
|
5
2
|
|
6
|
-
|
7
|
-
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/smart_adapters.svg)](https://badge.fury.io/rb/smart_adapters) [![Build Status](https://travis-ci.org/andrearampin/smart_adapters.svg?branch=master)](https://travis-ci.org/andrearampin/smart_adapters) [![Maintainability](https://api.codeclimate.com/v1/badges/9d55d1d054401ab93a6e/maintainability)](https://codeclimate.com/github/andrearampin/smart_adapters/maintainability)
|
4
|
+
|
5
|
+
Smart Adapters were born from the need to fully decouple the controller logic from the rendering of the response.
|
6
|
+
In the [Ruby on Rails documentation](https://apidock.com/rails/ActionController/MimeResponds/InstanceMethods/respond_to), the controller has to decide the format of the answer based on the (Content-Type) request:
|
7
|
+
|
8
|
+
```ruby
|
9
|
+
# app/controllers/people_controller.rb
|
10
|
+
def index
|
11
|
+
@people = Person.all
|
12
|
+
respond_to do |format|
|
13
|
+
format.html
|
14
|
+
format.xml { render :xml => @people.to_xml }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
```
|
18
|
+
|
19
|
+
Although, this method looks simple it's already highlighting how two distinct formats might have a slightly different implementation. The problem here is that over time this controller might inherit unnecessary complexity by simply introducting new properties or formats.
|
20
|
+
|
21
|
+
The Smart Adapters solve this problem by delegating the task of properly render the response based on the request format to well-defined classes, one per format. The following implementation makes use of the Smart Adapters:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
# app/controllers/people_controller.rb
|
25
|
+
def index
|
26
|
+
current_adapter.success Person.all
|
27
|
+
end
|
28
|
+
|
29
|
+
# app/models/smart_adapters/people/index/html_adapter.rb
|
30
|
+
def success(people)
|
31
|
+
render 'people/show', locals: { people: people }
|
32
|
+
end
|
33
|
+
|
34
|
+
# app/models/smart_adapters/people/index/xml_adapter.rb
|
35
|
+
def success(people)
|
36
|
+
render xml: people, status: :ok
|
37
|
+
end
|
38
|
+
```
|
39
|
+
|
40
|
+
Now that the application has a class per format, it is easy to keep the controller dry while implementing format specific features. For instance, in case of an XML request, the adapter could add more details to the `people` collection or track some metrics without bloating the controller.
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
# app/models/smart_adapters/people/index/xml_adapter.rb
|
44
|
+
def success(people)
|
45
|
+
metric_tracker.push('New XML request')
|
46
|
+
people.filter_private_details!
|
47
|
+
render xml: people, status: :ok
|
48
|
+
end
|
49
|
+
```
|
8
50
|
|
9
51
|
## Installation
|
10
52
|
Add this line to your application's Gemfile:
|
@@ -18,7 +60,172 @@ And then execute:
|
|
18
60
|
$ bundle
|
19
61
|
```
|
20
62
|
|
21
|
-
|
22
|
-
```
|
23
|
-
|
63
|
+
Update the `ApplicationController` by adding the `SmartAdapters` concern:
|
64
|
+
```ruby
|
65
|
+
class ApplicationController < ActionController::Base
|
66
|
+
include SmartAdapters
|
67
|
+
end
|
68
|
+
```
|
69
|
+
|
70
|
+
Add the adapters for your **controller/action/format**.
|
71
|
+
|
72
|
+
### Example
|
73
|
+
|
74
|
+
`app/controlles/users_controller.rb`
|
75
|
+
```ruby
|
76
|
+
class UsersController < ApplicationController
|
77
|
+
# GET /users
|
78
|
+
def index
|
79
|
+
current_adapter.success User.all
|
80
|
+
end
|
81
|
+
|
82
|
+
# GET /users/1
|
83
|
+
def show
|
84
|
+
if user
|
85
|
+
current_adapter.success(user)
|
86
|
+
else
|
87
|
+
current_adapter.failure(user)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# PATCH/PUT /users/1
|
92
|
+
def update
|
93
|
+
if user.update_attributes(update_params)
|
94
|
+
current_adapter.success(user)
|
95
|
+
else
|
96
|
+
current_adapter.failure(user)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
def update_params
|
103
|
+
params.require(:user).permit(:first_name, :last_name)
|
104
|
+
end
|
105
|
+
|
106
|
+
def user
|
107
|
+
@user ||= User.find_by(id: params[:id])
|
108
|
+
end
|
109
|
+
end
|
110
|
+
```
|
111
|
+
`app/models/smart_adapters/users/index/html_adapter.rb`
|
112
|
+
```ruby
|
113
|
+
module SmartAdapters
|
114
|
+
module Users
|
115
|
+
module Index
|
116
|
+
class HtmlAdapter < SimpleDelegator
|
117
|
+
include SmartAdapters::Util::Adapters::Html::Default
|
118
|
+
|
119
|
+
def success(resource)
|
120
|
+
render 'users/show', locals: { resource: resource }
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
```
|
127
|
+
`app/models/smart_adapters/users/index/json_adapter.rb`
|
128
|
+
```ruby
|
129
|
+
module SmartAdapters
|
130
|
+
module Users
|
131
|
+
module Index
|
132
|
+
class JsonAdapter < SimpleDelegator
|
133
|
+
include SmartAdapters::Util::Adapters::Json::Default
|
134
|
+
|
135
|
+
def success(resource)
|
136
|
+
render json: resource, status: :ok
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
```
|
144
|
+
`app/models/smart_adapters/users/show/html_adapter.rb`
|
145
|
+
```ruby
|
146
|
+
module SmartAdapters
|
147
|
+
module Users
|
148
|
+
module Show
|
149
|
+
class HtmlAdapter < SimpleDelegator
|
150
|
+
include SmartAdapters::Util::Adapters::Html::Default
|
151
|
+
|
152
|
+
def success(resource)
|
153
|
+
render 'objects/show', locals: { resource: resource }
|
154
|
+
end
|
155
|
+
|
156
|
+
def failure(resource)
|
157
|
+
redirect_back fallback_location: root_path, flash: { error: 'Resource not found' }
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
24
163
|
```
|
164
|
+
`app/models/smart_adapters/users/show/json_adapter.rb`
|
165
|
+
```ruby
|
166
|
+
module SmartAdapters
|
167
|
+
module Users
|
168
|
+
module Show
|
169
|
+
class JsonAdapter < SimpleDelegator
|
170
|
+
include SmartAdapters::Util::Adapters::Json::Default
|
171
|
+
|
172
|
+
def success(resource)
|
173
|
+
render json: resource, status: :ok
|
174
|
+
end
|
175
|
+
|
176
|
+
def failure(resource)
|
177
|
+
render json: {}, status: :not_found
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
```
|
184
|
+
`app/models/smart_adapters/users/update/html_adapter.rb`
|
185
|
+
```ruby
|
186
|
+
module SmartAdapters
|
187
|
+
module Users
|
188
|
+
module Update
|
189
|
+
class HtmlAdapter < SimpleDelegator
|
190
|
+
include SmartAdapters::Util::Adapters::Html::Default
|
191
|
+
|
192
|
+
def success(resource)
|
193
|
+
render 'objects/show', locals: { resource: resource }
|
194
|
+
end
|
195
|
+
|
196
|
+
def failure(resource)
|
197
|
+
unless resource.present?
|
198
|
+
return redirect_back fallback_location: root_path, flash: { error: 'Resource not found' }
|
199
|
+
end
|
200
|
+
return redirect_back fallback_location: root_path, flash: { error: resource.errors }
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
```
|
207
|
+
`app/models/smart_adapters/users/update/json_adapter.rb`
|
208
|
+
```ruby
|
209
|
+
module SmartAdapters
|
210
|
+
module Users
|
211
|
+
module Update
|
212
|
+
class JsonAdapter < SimpleDelegator
|
213
|
+
include SmartAdapters::Util::Adapters::Json::Default
|
214
|
+
|
215
|
+
def success(resource)
|
216
|
+
render json: resource, status: :ok
|
217
|
+
end
|
218
|
+
|
219
|
+
def failure(resource)
|
220
|
+
return render json: {}, status: :not_found unless resource.present?
|
221
|
+
render json: { errors: resource.errors }, status: :bad_request
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
```
|
228
|
+
|
229
|
+
## TODO
|
230
|
+
- Add remaining formats: `:text`, `:ics`, `:csv`, `:yaml`, `:rss`, `:atom`
|
231
|
+
- Add generator
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smart_adapters
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrea Rampin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-08-
|
11
|
+
date: 2018-08-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -38,34 +38,6 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: sqlite3
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: byebug
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
69
41
|
- !ruby/object:Gem::Dependency
|
70
42
|
name: rspec-rails
|
71
43
|
requirement: !ruby/object:Gem::Requirement
|