tramway-api 1.1.0.1 → 1.4

Sign up to get free protection for your applications and to get access to all the features.
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