tramway-api 1.1.0.1 → 1.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 15a37c45bc7e5c0628296885e619e8081402ec6c2e08dd4667dac931f725e31e
4
- data.tar.gz: c7b0d35d1f0e292936b776e9b1f500baf102a324e23a9d3b4d51587150e7c090
3
+ metadata.gz: 875752ec80bea3a12cdac3f2a3424f777fc0bcf4a94b6c28a5f1c4f98e5a6e34
4
+ data.tar.gz: ce5f8b2cb550ad0d1a5495ae622152119dc4253dd045fa348fa6921a88751691
5
5
  SHA512:
6
- metadata.gz: d507ebf4f4134352edd16a64e545ff2572c9a315c401e3ddb238e963d5fbd687c2ef10561de04395c90719264fce26d889229db40c09779a417c60672a830d56
7
- data.tar.gz: 7102cbd966ef91bc4a65de1645450af677648cfc5a0923f52a8f69e403d371d0532ab47bbc2cc10fb93a181a3c60ef7b1527e24e7e355782a2bae9d9d544862b
6
+ metadata.gz: 8b629b1c487b02b054885db26d4e49b97ed652cda40cb4d53e11d25cca170d8d0d876619b13df307cb0a19290d9f7447196dc4f24b5c7962edfad26092a194ff
7
+ data.tar.gz: 37241c50fc18e27b16fb2c4a2c7eb10ec611b163a046c92cca128a95ca9127950e0e739ddc5ff468890cc40da59bca2d569c04b1d7a8cfac7c24d3baba6fcc86
data/README.md CHANGED
@@ -1,26 +1,287 @@
1
1
  # Tramway::Api
2
- Short description and motivation.
2
+
3
+ ## English Readme
4
+
5
+ coming soon...
6
+
7
+ ## Russian Readme
8
+
9
+ Простой в использовании, легко устанавливаемый и плохо кастомизируемый Rails-engine с готовым CRUD через API.
10
+
11
+ Принцип работы. В приложении заранее указывается для каких моделей создаётся API CRUD. Идея проекта - возможность быстрой выкатки API, с возможностью в последствии избавиться от Tramway API, когда ваш проект становится сложнее.
12
+
13
+ Гем НЕ манкипатчит стандартные классы и поведение Rails! Именно по этой причине было решено реализовать как Rails-engine, который в последствии можно просто и легко удалить из проекта.
14
+
15
+ Фичи:
16
+
17
+ * готовый CRUD для определённых разработчиком моделей
18
+ * сохранение истории изменений записей (используется гем `audited`)
19
+ * поддержка загрузки файлов (используется `carrierwave`)
20
+ * аутентификация пользователя через JWT (используется `knock`)
21
+ * поддержка по умолчанию JSON API спецификации (через гем `active_model_serializers`)
22
+ * мягкое удаление записей по умолчанию
23
+ * поддержка коммуникации по уникальному uid объектов, чтобы не публиковать ID в базе
24
+
25
+ Ограничения:
26
+
27
+ * только с ActiveRecord
28
+ * только с версией Rails 5.1.* (поддержка 5.2 вскоре будет реализована автором гема, поддержка автором Rails 6 начнётся с версии 6.1. По религиозным автор не использует Rails версий *.0.*
29
+ * Ruby >= 2.3
30
+ * все модели, которые будут использованы гемом должны наследоваться от `Tramway::Core::ApplicationRecord`
31
+ * все модели, которые будут использованы гемом должны иметь атрибут `state`, типа `string` или `text`. Этот атрибут нужен для реализации мягкого удаления. Полное удаление записей из базы не поддерживается
32
+ * все модели, которые будут использованы гемом должны иметь атрибут
33
+
34
+ Недостатки, которые будут вскоре ликвидированы:
35
+
36
+ * ядро `tramway-core` подгружает в себя ненужных для API гемов (недостаток не имеет смысла в случае использования вместе с этим решением гема `tramway-admin`):
37
+ * bootstrap
38
+ * font_awesome5_rails
39
+ * haml
40
+ * требуется ручное добавление требуемых для работы гемов
41
+ ```ruby
42
+ gem 'active_model_serializers', '0.10.5'
43
+ gem 'tramway-core'
44
+ gem 'state_machine', github: 'seuros/state_machine'
45
+ gem 'knock'
46
+ ```
3
47
 
4
48
  ## Usage
5
- How to use my plugin.
6
49
 
7
- ## Installation
8
- Add this line to your application's Gemfile:
50
+ ```
51
+ rails new tramway_api_sample
52
+ ```
53
+
54
+ *Gemfile*
55
+
56
+ ```ruby
57
+ gem 'tramway-api', '>= 1.1.0.1'
58
+ gem 'active_model_serializers', '0.10.5'
59
+ gem 'tramway-core'
60
+ gem 'state_machine', github: 'seuros/state_machine'
61
+ gem 'knock'
62
+ ```
63
+
64
+ Run `bundle install`
65
+
66
+ Then generate User (you use another name, it's just an example) model
67
+
68
+ ```
69
+ rails g model user email:text password_digest:text username:text state:text uid:text
70
+ ```
71
+
72
+ Add generating uid by default
73
+
74
+ *db/migrate/create_users_*.rb
75
+
76
+ ```ruby
77
+ t.uuid :uid, default: 'uuid_generate_v4()'
78
+ ```
79
+
80
+ *app/models/user.rb*
81
+
82
+ ```ruby
83
+ class User < Tramway::Core::ApplicationRecord
84
+ has_secure_password
85
+ end
86
+ ```
87
+
88
+ Create file `config/initializers/tramway.rb`
89
+
90
+ ```ruby
91
+ ::Tramway::Api.auth_config = { user_model: User, auth_attributes: %i[email username] }
92
+ ::Tramway::Api.set_available_models user: %i[create update]
93
+ ```
94
+
95
+ Run `rails g tramway:core:install`
96
+
97
+ Run `rails db:create db:migrate`
98
+
99
+ *config/routes.rb*
100
+
101
+ ```ruby
102
+ Rails.application.routes.draw do
103
+ mount Tramway::Api::Engine, at: '/api'
104
+ end
105
+ ```
106
+
107
+ Create file *app/forms/user_sign_up_form.rb*
108
+
109
+ ```ruby
110
+ class UserSignUpForm < Tramway::Core::ApplicationForm
111
+ properties :username, :email, :password
112
+ end
113
+ ```
114
+
115
+ **DONE!**
116
+
117
+ ## Testing
118
+
119
+ # Preparation (optional)
120
+
121
+ Let's write RSpec test to check what we have:
122
+
123
+ *Gemfile*
9
124
 
10
125
  ```ruby
11
- gem 'tramway-api'
126
+ group :test do
127
+ gem 'rspec-rails', '~> 3.5'
128
+ gem 'rspec-json_expectations', '2.2.0'
129
+ gem 'factory_bot_rails', '~> 4.0'
130
+ gem 'json_matchers'
131
+ gem 'json_api_test_helpers', '1.1.1'
132
+ end
12
133
  ```
13
134
 
14
- And then execute:
15
- ```bash
16
- $ bundle
135
+ Run `bundle install`
136
+
137
+ Run `RAILS_ENV=test rails db:create db:migrate`
138
+
139
+ Run `mkdir spec`
140
+
141
+ Create file `spec/spec_helper.rb` with:
142
+
143
+ ```ruby
144
+ ENV['RAILS_ENV'] ||= 'test'
145
+ require File.expand_path('../config/environment', __dir__)
146
+ require 'rspec/rails'
147
+ require 'rspec/autorun'
148
+ require 'rspec/expectations'
149
+ require 'rspec/json_expectations'
150
+
151
+ RSpec.configure do |config|
152
+ config.expect_with :rspec do |expectations|
153
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
154
+ end
155
+ config.mock_with :rspec do |mocks|
156
+ mocks.verify_partial_doubles = true
157
+ end
158
+ end
17
159
  ```
18
160
 
19
- Or install it yourself as:
20
- ```bash
21
- $ gem install tramway-api
161
+ Create file `spec/rails_helper.rb` with:
162
+
163
+ ```ruby
164
+ require 'spec_helper'
165
+ require 'factory_bot'
166
+ require 'rspec/rails'
167
+ require 'rspec/json_expectations'
168
+ require 'json_matchers/rspec'
169
+ require 'json_api_test_helpers'
170
+ require 'rake'
171
+
172
+ RSpec.configure do |config|
173
+ config.include FactoryBot::Syntax::Methods
174
+ config.include RSpec::Rails::RequestExampleGroup, type: :feature
175
+ config.include JsonApiTestHelpers
176
+ end
22
177
  ```
23
178
 
179
+ # SignUp user
180
+
181
+ Create file `spec/tramway_api_spec.rb` with:
182
+
183
+ ```ruby
184
+ require 'rails_helper'
185
+
186
+ RSpec.describe 'Post creating user', type: :feature do
187
+ describe 'POST /api/v1/user with model User' do
188
+ let(:attributes) { attributes_for :user }
189
+
190
+ it 'returns created status' do
191
+ post '/api/v1/user', params: { user: attributes }
192
+ expect(response.status).to eq 201
193
+ end
194
+
195
+ it 'returns no errors' do
196
+ post '/api/v1/user', params: { user: attributes }
197
+
198
+ expect(json_response[:response]). to be_nil
199
+ end
200
+ end
201
+ end
202
+ ```
203
+
204
+ # SignIn User
205
+
206
+ ```ruby
207
+ require 'rails_helper'
208
+
209
+ RSpec.describe 'Post generate token', type: :feature do
210
+ describe 'POST /api/v1/user_token' do
211
+ let(:user) { create :user, password: '123456789' }
212
+
213
+ it 'returns created status' do
214
+ post '/api/v1/user_token', params: { auth: { login: user.email, password: '123456789' } }
215
+
216
+ expect(response.status).to eq 201
217
+ end
218
+
219
+ it 'returns token' do
220
+ post '/api/v1/user_token', params: { auth: { login: user.email, password: '123456789' } }
221
+
222
+ expect(json_response[:auth_token].present?).to be_truthy
223
+ expect(json_response[:user]).to include_json({ email: user.email, uid: user.uid })
224
+ end
225
+
226
+ end
227
+ end
228
+
229
+ ```
230
+
231
+ Run `rspec` to test
232
+
233
+ We have route `user`, which create new authenticable user.
234
+
235
+ For other models we have route `records`.
236
+
237
+ ```
238
+ ~: rails routes
239
+ Prefix Verb URI Pattern Controller#Action
240
+ tramway_api /api Tramway::Api::Engine
241
+
242
+ Routes for Tramway::Api::Engine:
243
+ v1_user_token POST /v1/user_token(.:format) tramway/api/v1/user_tokens#create
244
+ v1_user GET /v1/user(.:format) tramway/api/v1/users#show
245
+ POST /v1/user(.:format) tramway/api/v1/users#create
246
+ v1_records GET /v1/records(.:format) tramway/api/v1/records#index
247
+ POST /v1/records(.:format) tramway/api/v1/records#create
248
+ new_v1_record GET /v1/records/new(.:format) tramway/api/v1/records#new
249
+ edit_v1_record GET /v1/records/:id/edit(.:format) tramway/api/v1/records#edit
250
+ v1_record GET /v1/records/:id(.:format) tramway/api/v1/records#show
251
+ PATCH /v1/records/:id(.:format) tramway/api/v1/records#update
252
+ PUT /v1/records/:id(.:format) tramway/api/v1/records#update
253
+ DELETE /v1/records/:id(.:format) tramway/api/v1/records#destroy
254
+
255
+ ```
256
+
257
+ ## Methods
258
+
259
+ ### Initializer methods
260
+
261
+ #### auth_config
262
+
263
+ Sets default ActiveRecord model, which used as main user to be authenticated with JWT.
264
+
265
+ `user_model` - model name
266
+ `auth_attributes` - array of available attributes used as login.
267
+
268
+ this model must have field `password_digest`, because we use `bcrypt` gem for authentication (providing other name of password attribute instead of `password` is coming soon)
269
+
270
+ ### set_available_models
271
+
272
+ Sets ActiveRecord models which will be used in API
273
+
274
+ Argument is a hash. Keys are underscored models names, values are arrays of available methods for every model.
275
+
276
+ Enabled methods:
277
+
278
+ * create
279
+ * update
280
+ * show
281
+ * index
282
+ * destroy
283
+
284
+
24
285
  ## Contributing
25
286
  Contribution directions go here.
26
287
 
@@ -2,6 +2,7 @@ module Tramway::Api::V1
2
2
  class RecordsController < ::Tramway::Api::V1::ApplicationController
3
3
  before_action :check_available_model_class
4
4
  before_action :check_available_model_action
5
+ before_action :authenticate_user_if_needed
5
6
 
6
7
  def index
7
8
  records = model_class.active.order(id: :desc).send params[:scope] || :all
@@ -22,7 +23,7 @@ module Tramway::Api::V1
22
23
  end
23
24
 
24
25
  def update
25
- record_form = form_class.new model_class.find params[:id]
26
+ record_form = form_class.new model_class.active.find params[:id]
26
27
  if record_form.submit params[:data][:attributes]
27
28
  render json: record_form.model,
28
29
  serializer: serializer_class,
@@ -32,6 +33,21 @@ module Tramway::Api::V1
32
33
  end
33
34
  end
34
35
 
36
+ def show
37
+ record = model_class.active.find params[:id]
38
+ render json: record,
39
+ serializer: serializer_class,
40
+ status: :ok
41
+ end
42
+
43
+ def destroy
44
+ record = model_class.active.find params[:id]
45
+ record.remove
46
+ render json: record,
47
+ serializer: serializer_class,
48
+ status: :no_content
49
+ end
50
+
35
51
  private
36
52
 
37
53
  def check_available_model_class
@@ -39,7 +55,14 @@ module Tramway::Api::V1
39
55
  end
40
56
 
41
57
  def check_available_model_action
42
- head :unprocessable_entity and return unless action_name.in? Tramway::Api.available_models[model_class.to_s].map(&:to_s)
58
+ actions = Tramway::Api.available_models[model_class.to_s][:open]&.map(&:to_s) || [] + Tramway::Api.available_models[model_class.to_s][:closed]&.map(&:to_s) || []
59
+ head :unprocessable_entity and return unless action_name.in? actions
60
+ end
61
+
62
+ def authenticate_user_if_needed
63
+ if action_name.in? Tramway::Api::available_models[model_class.to_s][:closed]&.map(&:to_s) || []
64
+ authenticate_user
65
+ end
43
66
  end
44
67
 
45
68
  def model_class
@@ -6,6 +6,7 @@ class Tramway::Api::V1::UsersController < ::Tramway::Api::V1::ApplicationControl
6
6
 
7
7
  def create
8
8
  user_form = sign_up_form_class_name(Tramway::Api.user_based_model).new Tramway::Api.user_based_model.new
9
+ # Implement JSON API spec here
9
10
  if user_form.submit params[Tramway::Api.user_based_model.name.underscore]
10
11
  token = ::Knock::AuthToken.new(payload: { sub: user_form.model.id }).token
11
12
  # FIXME refactor this bullshit
@@ -1,5 +1,5 @@
1
1
  module Tramway
2
2
  module Api
3
- VERSION = '1.1.0.1'
3
+ VERSION = '1.4'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tramway-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0.1
4
+ version: '1.4'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pavel Kalashnikov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-08-05 00:00:00.000000000 Z
11
+ date: 2019-09-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: knock
@@ -99,8 +99,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
99
99
  - !ruby/object:Gem::Version
100
100
  version: '0'
101
101
  requirements: []
102
- rubyforge_project:
103
- rubygems_version: 2.7.6
102
+ rubygems_version: 3.0.3
104
103
  signing_key:
105
104
  specification_version: 4
106
105
  summary: Engine for api