api_maker 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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +476 -0
- data/Rakefile +27 -0
- data/app/channels/api_maker/subscriptions_channel.rb +80 -0
- data/app/controllers/api_maker/base_controller.rb +32 -0
- data/app/controllers/api_maker/commands_controller.rb +26 -0
- data/app/controllers/api_maker/devise_controller.rb +60 -0
- data/app/controllers/api_maker/session_statuses_controller.rb +33 -0
- data/app/services/api_maker/application_service.rb +7 -0
- data/app/services/api_maker/collection_command_service.rb +24 -0
- data/app/services/api_maker/command_response.rb +67 -0
- data/app/services/api_maker/command_service.rb +31 -0
- data/app/services/api_maker/create_command.rb +62 -0
- data/app/services/api_maker/create_command_service.rb +18 -0
- data/app/services/api_maker/destroy_command.rb +39 -0
- data/app/services/api_maker/destroy_command_service.rb +22 -0
- data/app/services/api_maker/generate_react_native_api_service.rb +61 -0
- data/app/services/api_maker/index_command.rb +96 -0
- data/app/services/api_maker/index_command_service.rb +22 -0
- data/app/services/api_maker/js_method_namer_service.rb +11 -0
- data/app/services/api_maker/member_command_service.rb +25 -0
- data/app/services/api_maker/model_content_generator_service.rb +108 -0
- data/app/services/api_maker/models_finder_service.rb +22 -0
- data/app/services/api_maker/models_generator_service.rb +104 -0
- data/app/services/api_maker/update_command.rb +43 -0
- data/app/services/api_maker/update_command_service.rb +21 -0
- data/app/services/api_maker/valid_command.rb +35 -0
- data/app/services/api_maker/valid_command_service.rb +21 -0
- data/app/views/api_maker/_data.html.erb +15 -0
- data/config/rails_best_practices.yml +55 -0
- data/config/routes.rb +7 -0
- data/lib/api_maker.rb +36 -0
- data/lib/api_maker/ability.rb +39 -0
- data/lib/api_maker/ability_loader.rb +21 -0
- data/lib/api_maker/action_controller_base_extensions.rb +5 -0
- data/lib/api_maker/base_command.rb +81 -0
- data/lib/api_maker/base_resource.rb +78 -0
- data/lib/api_maker/collection_serializer.rb +69 -0
- data/lib/api_maker/command_spec_helper.rb +57 -0
- data/lib/api_maker/configuration.rb +34 -0
- data/lib/api_maker/engine.rb +5 -0
- data/lib/api_maker/individual_command.rb +37 -0
- data/lib/api_maker/javascript/api.js +92 -0
- data/lib/api_maker/javascript/base-model.js +543 -0
- data/lib/api_maker/javascript/bootstrap/attribute-row.jsx +16 -0
- data/lib/api_maker/javascript/bootstrap/attribute-rows.jsx +47 -0
- data/lib/api_maker/javascript/bootstrap/card.jsx +79 -0
- data/lib/api_maker/javascript/bootstrap/checkbox.jsx +127 -0
- data/lib/api_maker/javascript/bootstrap/checkboxes.jsx +105 -0
- data/lib/api_maker/javascript/bootstrap/live-table.jsx +168 -0
- data/lib/api_maker/javascript/bootstrap/money-input.jsx +136 -0
- data/lib/api_maker/javascript/bootstrap/radio-buttons.jsx +80 -0
- data/lib/api_maker/javascript/bootstrap/select.jsx +168 -0
- data/lib/api_maker/javascript/bootstrap/string-input.jsx +203 -0
- data/lib/api_maker/javascript/cable-connection-pool.js +169 -0
- data/lib/api_maker/javascript/cable-subscription-pool.js +111 -0
- data/lib/api_maker/javascript/cable-subscription.js +33 -0
- data/lib/api_maker/javascript/collection.js +186 -0
- data/lib/api_maker/javascript/commands-pool.js +123 -0
- data/lib/api_maker/javascript/custom-error.js +14 -0
- data/lib/api_maker/javascript/deserializer.js +35 -0
- data/lib/api_maker/javascript/devise.js.erb +113 -0
- data/lib/api_maker/javascript/error-logger.js +119 -0
- data/lib/api_maker/javascript/event-connection.jsx +24 -0
- data/lib/api_maker/javascript/event-created.jsx +26 -0
- data/lib/api_maker/javascript/event-destroyed.jsx +26 -0
- data/lib/api_maker/javascript/event-emitter-listener.jsx +32 -0
- data/lib/api_maker/javascript/event-listener.jsx +41 -0
- data/lib/api_maker/javascript/event-updated.jsx +26 -0
- data/lib/api_maker/javascript/form-data-to-object.js +70 -0
- data/lib/api_maker/javascript/included.js +39 -0
- data/lib/api_maker/javascript/key-value-store.js +47 -0
- data/lib/api_maker/javascript/logger.js +23 -0
- data/lib/api_maker/javascript/model-name.js +21 -0
- data/lib/api_maker/javascript/model-template.js.erb +110 -0
- data/lib/api_maker/javascript/models-response-reader.js +43 -0
- data/lib/api_maker/javascript/paginate.jsx +128 -0
- data/lib/api_maker/javascript/params.js +68 -0
- data/lib/api_maker/javascript/resource-route.jsx +75 -0
- data/lib/api_maker/javascript/resource-routes.jsx +36 -0
- data/lib/api_maker/javascript/result.js +25 -0
- data/lib/api_maker/javascript/session-status-updater.js +113 -0
- data/lib/api_maker/javascript/sort-link.jsx +88 -0
- data/lib/api_maker/javascript/updated-attribute.jsx +60 -0
- data/lib/api_maker/loader.rb +14 -0
- data/lib/api_maker/memory_storage.rb +65 -0
- data/lib/api_maker/model_extensions.rb +96 -0
- data/lib/api_maker/permitted_params_argument.rb +12 -0
- data/lib/api_maker/preloader.rb +91 -0
- data/lib/api_maker/preloader_belongs_to.rb +58 -0
- data/lib/api_maker/preloader_has_many.rb +69 -0
- data/lib/api_maker/preloader_has_one.rb +70 -0
- data/lib/api_maker/preloader_through.rb +101 -0
- data/lib/api_maker/railtie.rb +14 -0
- data/lib/api_maker/relationship_includer.rb +42 -0
- data/lib/api_maker/resource_routing.rb +8 -0
- data/lib/api_maker/result_parser.rb +50 -0
- data/lib/api_maker/serializer.rb +86 -0
- data/lib/api_maker/spec_helper.rb +100 -0
- data/lib/api_maker/version.rb +3 -0
- data/lib/tasks/api_maker_tasks.rake +5 -0
- metadata +581 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 7d65964fbfeb5bd8a5d89702083930f77e3d9c46956695c4f0877039a43c3010
|
|
4
|
+
data.tar.gz: 2a9431af5f0bfebcfb9605d85fafc40b824448aeac9ccd5a0f595b8e9f6d642d
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: bf2858ef950edf1aa8cc9ce45938ebd1b5ea5f3dd1f11223fd42959bff910a5cceae21599abbfdce7dbabedcdcd481c54c832c77712417436d02f423285fb48d
|
|
7
|
+
data.tar.gz: 7f63b82811ef1a5207d2ecbdcc62072b4d4297263884de1c4b36704e7b114a2d027cbbb3dac324de69af6c19fc79f185f273b4bf070def5f7c9282e1b1caa404
|
data/MIT-LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright 2018 kjabtion
|
|
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,476 @@
|
|
|
1
|
+
# ApiMaker
|
|
2
|
+
|
|
3
|
+
Generates Rails API endpoints and JavaScript API files for Webpack and more by inspecting your models and serializers.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
Add this line to your application's Gemfile:
|
|
7
|
+
|
|
8
|
+
```ruby
|
|
9
|
+
gem "api_maker"
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
ApiMaker requires [Webpacker](https://github.com/rails/webpacker), so make sure you have that set up as well. It also uses an extension called [qs](https://www.npmjs.com/package/qs), that you should add to your packages, but that is probally already there by default.
|
|
13
|
+
|
|
14
|
+
ApiMaker makes use of [CanCanCan](https://github.com/CanCanCommunity/cancancan) to keep track of what models a given user should have access to. Each resource defines its own abilities under `app/api_maker/resources/user_resource` like this:
|
|
15
|
+
```ruby
|
|
16
|
+
class Resources::UserResource < Resources::ApplicationResource
|
|
17
|
+
def abilities
|
|
18
|
+
can :update, User if current_user&.admin?
|
|
19
|
+
can :update, User, id: current_user&.id if current_user.present?
|
|
20
|
+
can :read, User
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Add an `api_maker_args` method to your application controller. This controls what arguments will be passed to the CanCan ability and the serializers:
|
|
26
|
+
```ruby
|
|
27
|
+
class ApplicationController
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def api_maker_args
|
|
31
|
+
@api_maker_args ||= {current_user: current_user}
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Insert this mount into `config/routes.rb`:
|
|
37
|
+
```ruby
|
|
38
|
+
Rails.application.routes.draw do
|
|
39
|
+
mount ApiMaker::Engine => "/api_maker"
|
|
40
|
+
end
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
ApiMaker will only create models, endpoints and serializers for ActiveRecord models that are defined as resources. So be sure to add resources under `app/api_maker/resources` for your models first. You can add some helper methods if you want to use in your resources like `current_user` and `signed_in_as_admin?`.
|
|
44
|
+
```ruby
|
|
45
|
+
class Resources::ApplicationResource < ApiMaker::BaseResource
|
|
46
|
+
def current_user
|
|
47
|
+
args&.dig(:current_user)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def signed_in_as_admin?
|
|
51
|
+
current_user&.role == "admin"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
```ruby
|
|
57
|
+
class Resources::UserResources < Resources::ApplicationResource
|
|
58
|
+
attributes :id, :email, :custom_attribute
|
|
59
|
+
attributes :calculated_attribute, selected_by_default: false
|
|
60
|
+
attributes :secret_attribute, if: :signed_in_as_admin?
|
|
61
|
+
collection_commands :count_users
|
|
62
|
+
member_commands :calculate_age
|
|
63
|
+
relationships :account, :tasks
|
|
64
|
+
|
|
65
|
+
def custom_attribute
|
|
66
|
+
"Hello world! Current user is: #{args.fetch(:current_user).email}"
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
You should also create an application command here: `app/api_maker/commands/application_command` with content like this:
|
|
72
|
+
```ruby
|
|
73
|
+
class Commands::ApplicationCommand < ApiMaker::BaseCommand
|
|
74
|
+
end
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Add this to your application model:
|
|
78
|
+
```ruby
|
|
79
|
+
class ApplicationRecord < ActiveRecord::Base
|
|
80
|
+
include ApiMaker::ModelExtensions
|
|
81
|
+
end
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
ApiMaker uses that to keep track of what attributes, relationships and commands you want exposed through the API.
|
|
85
|
+
|
|
86
|
+
Its now time to generate everything like this:
|
|
87
|
+
```bash
|
|
88
|
+
rake api_maker:generate_models
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
If you want to be able to create and update models, then you should go into each resource and create a params method to define, which attributes can be written on each model like this:
|
|
92
|
+
```ruby
|
|
93
|
+
class Resources::TaskResource < ApiMaker::ModelController
|
|
94
|
+
def permitted_params(arg)
|
|
95
|
+
arg.params.require(:project).permit(:name)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### I18n
|
|
101
|
+
|
|
102
|
+
In order to use the built in text support, you need to add `i18n-js` to your project.
|
|
103
|
+
|
|
104
|
+
Start by adding to your Gemfile:
|
|
105
|
+
```ruby
|
|
106
|
+
gem "i18n-js"
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Then add `config/i18n-js.yml`:
|
|
110
|
+
```yml
|
|
111
|
+
translations:
|
|
112
|
+
- file: "app/assets/javascripts/i18n/translations.js"
|
|
113
|
+
only: ["*.activerecord.attributes.*", "*.activerecord.models.*", "*.date.*", "*.js.*", "*.number.currency.*", "*.time.*"]
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Then add this to `app/assets/javascript/application.js.erb`:
|
|
117
|
+
```js
|
|
118
|
+
//= require i18n
|
|
119
|
+
//= require i18n/translations
|
|
120
|
+
|
|
121
|
+
var locale = document.querySelector("html").getAttribute("lang")
|
|
122
|
+
I18n.locale = locale
|
|
123
|
+
|
|
124
|
+
<% if Rails.env.development? || Rails.env.test? %>
|
|
125
|
+
I18n.missingTranslation = function(key) {
|
|
126
|
+
console.error(`No translation for: ${key}`)
|
|
127
|
+
return `translation missing: ${key}`
|
|
128
|
+
}
|
|
129
|
+
<% end %>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Add this to the `<html>`-tag:
|
|
133
|
+
```html
|
|
134
|
+
<html lang="<%= I18n.locale %>">
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Add this to `config/application.rb` to ease development:
|
|
138
|
+
```ruby
|
|
139
|
+
config.middleware.use I18n::JS::Middleware
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### ActionCable
|
|
143
|
+
|
|
144
|
+
Your `connection.rb` should look something like this:
|
|
145
|
+
```rb
|
|
146
|
+
class ApplicationCable::Connection < ActionCable::Connection::Base
|
|
147
|
+
identified_by :current_user
|
|
148
|
+
|
|
149
|
+
def connect
|
|
150
|
+
self.current_user = find_verified_user
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
private
|
|
154
|
+
|
|
155
|
+
def find_verified_user
|
|
156
|
+
verified_user = User.find_by(id: cookies.signed["user.id"])
|
|
157
|
+
|
|
158
|
+
if verified_user && cookies.signed["user.expires_at"] > Time.zone.now
|
|
159
|
+
verified_user
|
|
160
|
+
else
|
|
161
|
+
reject_unauthorized_connection
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Your `channel.rb` should look something like this:
|
|
168
|
+
```rb
|
|
169
|
+
class ApplicationCable::Channel < ActionCable::Channel::Base
|
|
170
|
+
private # rubocop:disable Layout/IndentationWidth
|
|
171
|
+
|
|
172
|
+
def current_ability
|
|
173
|
+
@current_ability ||= ApiMakerAbility.for_user(current_user)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def current_user
|
|
177
|
+
@current_user ||= env["warden"].user
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Usage
|
|
183
|
+
|
|
184
|
+
### Creating a new model from JavaScript
|
|
185
|
+
|
|
186
|
+
```js
|
|
187
|
+
import Task from "api-maker/models/task"
|
|
188
|
+
|
|
189
|
+
var task = new Task()
|
|
190
|
+
task.assignAttributes({name: "New task"})
|
|
191
|
+
task.create().then(status => {
|
|
192
|
+
if (status.success) {
|
|
193
|
+
console.log(`Task was created with ID: ${task.id()}`)
|
|
194
|
+
} else {
|
|
195
|
+
console.log("Task wasnt created")
|
|
196
|
+
}
|
|
197
|
+
})
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Finding an existing model
|
|
201
|
+
|
|
202
|
+
```js
|
|
203
|
+
Task.find(5).then(task => {
|
|
204
|
+
console.log(`Task found: ${task.name()}`)
|
|
205
|
+
})
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Updating a model
|
|
209
|
+
|
|
210
|
+
```js
|
|
211
|
+
task.assignAttributes({name: "New name"})
|
|
212
|
+
task.save().then(status => {
|
|
213
|
+
if (status.success) {
|
|
214
|
+
console.log(`Task was updated and name is now: ${task.name()}`)
|
|
215
|
+
} else {
|
|
216
|
+
console.log("Task wasnt updated")
|
|
217
|
+
}
|
|
218
|
+
})
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
```js
|
|
222
|
+
task.update({name: "New name"}).then(status => {
|
|
223
|
+
if (status.success) {
|
|
224
|
+
console.log(`Task was updated and name is now: ${task.name()}`)
|
|
225
|
+
} else {
|
|
226
|
+
console.log("Task wasnt updated")
|
|
227
|
+
}
|
|
228
|
+
})
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Deleting a model
|
|
232
|
+
|
|
233
|
+
```js
|
|
234
|
+
task.destroy().then(status => {
|
|
235
|
+
if (status.success) {
|
|
236
|
+
console.log("Task was destroyed")
|
|
237
|
+
} else {
|
|
238
|
+
console.log("Task wasnt destroyed")
|
|
239
|
+
}
|
|
240
|
+
})
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### Preloading models
|
|
244
|
+
|
|
245
|
+
```js
|
|
246
|
+
Task.ransack().preload("project.customer").toArray().then(tasks => {
|
|
247
|
+
for(var task of tasks) {
|
|
248
|
+
console.log(`Project of task ${task.id()}: ${task.project().name()}`)
|
|
249
|
+
console.log(`Customer of task ${task.id()}: ${task.project().customer().name()}`)
|
|
250
|
+
}
|
|
251
|
+
})
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Query models
|
|
255
|
+
|
|
256
|
+
ApiModels uses [Ransack](https://github.com/activerecord-hackery/ransack) to expose a huge amount of options to query data.
|
|
257
|
+
|
|
258
|
+
```js
|
|
259
|
+
Task.ransack({name_cont: "something"}).toArray().then(tasks => {
|
|
260
|
+
console.log(`Found: ${tasks.length} tasks`)
|
|
261
|
+
})
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
Distinct:
|
|
265
|
+
```js
|
|
266
|
+
var tasks = await Task.ransack({relationships_something_eq: "something"}).distinct().toArray()
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Selecting only specific attributes
|
|
270
|
+
|
|
271
|
+
```js
|
|
272
|
+
Task.ransack().select({Task: ["id", "name"]}).toArray().then(tasks => this.setState({tasks}))
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Sorting models
|
|
276
|
+
|
|
277
|
+
```js
|
|
278
|
+
Task.ransack({s: "id desc"})
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Attributes
|
|
282
|
+
|
|
283
|
+
Each attribute is defined as a method on each model. So if you have an attribute called `name` on the `Task`-model, then it be read by doing this: `task.name()`.
|
|
284
|
+
|
|
285
|
+
### Relationships
|
|
286
|
+
|
|
287
|
+
#### Has many
|
|
288
|
+
|
|
289
|
+
A `has many` relationship will return a collection the queries the sub models.
|
|
290
|
+
|
|
291
|
+
```js
|
|
292
|
+
project.tasks().toArray().then(tasks => {
|
|
293
|
+
console.log(`Project ${project.id()} has ${tasks.length} tasks`)
|
|
294
|
+
|
|
295
|
+
for(var key in tasks) {
|
|
296
|
+
var task = tasks[key]
|
|
297
|
+
console.log(`Task ${task.id()} is named: ${task.name()}`)
|
|
298
|
+
}
|
|
299
|
+
})
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
#### Belongs to
|
|
303
|
+
|
|
304
|
+
A `belongs to` relationship will return a promise that will get that model:
|
|
305
|
+
|
|
306
|
+
```js
|
|
307
|
+
task.project().then(project => {
|
|
308
|
+
console.log(`Task ${task.id()} belongs to a project called: ${project.name()}`)
|
|
309
|
+
})
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
#### Has one
|
|
313
|
+
|
|
314
|
+
A `has one` relationship will also return a promise that will get that model like a `belongs to` relationship.
|
|
315
|
+
|
|
316
|
+
#### Getting the current user
|
|
317
|
+
|
|
318
|
+
First include this in your layout, so JS can know which user is signed in:
|
|
319
|
+
```erb
|
|
320
|
+
<body>
|
|
321
|
+
<%= render "/api_maker/data" %>
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
Then you can do like this in JS:
|
|
325
|
+
```js
|
|
326
|
+
import Devise from "api-maker/devise"
|
|
327
|
+
|
|
328
|
+
Devise.currentUser().then(user => {
|
|
329
|
+
console.log(`The current user has this email: ${user.email()}`)
|
|
330
|
+
})
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
## Events from the backend
|
|
334
|
+
|
|
335
|
+
### Custom events
|
|
336
|
+
|
|
337
|
+
Add the relevant access to your abilities:
|
|
338
|
+
|
|
339
|
+
```ruby
|
|
340
|
+
class ApiMakerAbility < ApplicationAbility
|
|
341
|
+
def initialize(args:)
|
|
342
|
+
can :event_new_message, User, id: 5
|
|
343
|
+
end
|
|
344
|
+
end
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
```ruby
|
|
348
|
+
user = User.find(5)
|
|
349
|
+
user.api_maker_event("new_message", message: "Hello world")
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
```js
|
|
353
|
+
User.find(5).then(user => {
|
|
354
|
+
user.connect("new_message", args => {
|
|
355
|
+
console.log(`New message: ${args.message}`)
|
|
356
|
+
})
|
|
357
|
+
})
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### Update models
|
|
361
|
+
|
|
362
|
+
Add this to your abilities:
|
|
363
|
+
```ruby
|
|
364
|
+
class ApiMakerAbility < ApplicationAbility
|
|
365
|
+
def initialize(args:)
|
|
366
|
+
can [:create_events, :destroy_events, :update_events], User, id: 5
|
|
367
|
+
end
|
|
368
|
+
end
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
Add this to the model you want to broadcast updates:
|
|
372
|
+
```ruby
|
|
373
|
+
class User < ApplicationRecord
|
|
374
|
+
api_maker_broadcast_creates
|
|
375
|
+
api_maker_broadcast_destroys
|
|
376
|
+
api_maker_broadcast_updates
|
|
377
|
+
end
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
```js
|
|
381
|
+
User.find(5).then(user => {
|
|
382
|
+
let subscription = user.connectUpdated(args => {
|
|
383
|
+
console.log(`Model was updated: ${args.model.id()}`)
|
|
384
|
+
})
|
|
385
|
+
})
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
Remember to unsubscrube again:
|
|
389
|
+
```js
|
|
390
|
+
subscription.unsubscribe()
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
You can also use a React component if you use React and dont want to keep track of when to unsubscribe:
|
|
394
|
+
```jsx
|
|
395
|
+
import EventUpdated from "api-maker/event-created"
|
|
396
|
+
import EventUpdated from "api-maker/event-destroyed"
|
|
397
|
+
import EventUpdated from "api-maker/event-updated"
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
```jsx
|
|
401
|
+
<EventCreated modelClass={User} onCreated={(args) => this.onUserCreated(args)} />
|
|
402
|
+
<EventDestroyed model={user} onDestroyed={(args) => this.onUserDestroyed(args)} />
|
|
403
|
+
<EventUpdated model={user} onUpdated={(args) => this.onUserUpdated(args)} />
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
```jsx
|
|
407
|
+
onUserCreated(args) {
|
|
408
|
+
this.setState({user: args.model})
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
onUserDestroyed(args) {
|
|
412
|
+
this.setState({user: args.model})
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
onUserUpdated(args) {
|
|
416
|
+
this.setState({user: args.model})
|
|
417
|
+
}
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
You can also use this React component to show a models attribute with automatic updates:
|
|
421
|
+
|
|
422
|
+
```jsx
|
|
423
|
+
import UpdatedAttribute from "api-maker/updated-attribute"
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
```jsx
|
|
427
|
+
<UpdatedAttribute model={user} attribute="email" />
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
You can also use the `EventConnection` React component so you don't need to keep track of your subscription and unsubscribe:
|
|
431
|
+
```jsx
|
|
432
|
+
import EventConnection from "api-maker/event-connection"
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
```jsx
|
|
436
|
+
<EventConnection model={this.state.user} event="eventName" onCall={(data) => this.onEvent(data)} />
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
## Serializing
|
|
440
|
+
|
|
441
|
+
### Conditional attributes
|
|
442
|
+
|
|
443
|
+
This will only include the email for users, if the current user signed in is an admin.
|
|
444
|
+
|
|
445
|
+
```ruby
|
|
446
|
+
class Resources::UserResource < Resources::ApplicationResource
|
|
447
|
+
attributes :id
|
|
448
|
+
attributes :email, if: :signed_in_as_admin?
|
|
449
|
+
|
|
450
|
+
private
|
|
451
|
+
|
|
452
|
+
def signed_in_as_admin?
|
|
453
|
+
args[:current_user]&.admin?
|
|
454
|
+
end
|
|
455
|
+
end
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
## Reporting errors
|
|
460
|
+
|
|
461
|
+
Add an intializer with something like this:
|
|
462
|
+
|
|
463
|
+
```ruby
|
|
464
|
+
ApiMaker::Configuration.configure do |config|
|
|
465
|
+
config.on_error do |controller:, error:|
|
|
466
|
+
ExceptionNotifier.notify_exception(error, env: controller&.request&.env)
|
|
467
|
+
end
|
|
468
|
+
end
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
## Contributing
|
|
473
|
+
Contribution directions go here.
|
|
474
|
+
|
|
475
|
+
## License
|
|
476
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|