iry 0.2.0 → 0.4.0

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: e650372034f89b6bd6d8187f83f7e54ec43a9fa9cf69f4c1ec07ee091b07063c
4
- data.tar.gz: 0dad363e7219745a1f92a0af6fe2348a98029f3740cd6031d46535a39c742dd2
3
+ metadata.gz: 4e4fc1d3dfa1e63a0ac7c38443301f2635ac7d60866d5799a1a6a78b5cdb9326
4
+ data.tar.gz: 7b4a3e8b2118dfb0788f15579e61ca35b1e32277cd571fb53e83c2905e23cc49
5
5
  SHA512:
6
- metadata.gz: 460f2ebab05bbe7271634f5a7d5cb0ae6644d5f53982e3bec6ac0f8c9f6745ca5c8e3aea3f931649112a2b1641d411c788f9fc3aba643ae03c9e4f50b85784b7
7
- data.tar.gz: 17a3e4033f3a731e110706db24b6b71f95b3059b7b113299cf6c651001e7f309b2402b867b7a974f9532ba89a7f499cb7533a2eebc8217bb693513923e8713af
6
+ metadata.gz: 27cc273db8893f605a6d3480305a0e575f214a4c88562a701b0ba1b00b4a98b004735f7f776428b246722c0a26706ba2681405028f0454658085cf562e94fd7b
7
+ data.tar.gz: 01b82838cf8c8e02432fe038086fa3a96db7ff83a128e5e3ac1aacc5524e2e9a76c908f0af72e85eac19bbed6ccc0972718ba9f49e69ab5d81775fc508a946e6
data/CHANGELOG.md CHANGED
@@ -1,16 +1,15 @@
1
- ## [0.1.1](https://github.com/Fire-Dragon-DoL/iry/compare/v0.1.0...v0.1.1) (2023-07-07)
2
-
3
-
4
-
5
- # [0.1.0](https://github.com/Fire-Dragon-DoL/iry/compare/8a133c2c19b99881619a9e1c7c11076030755f66...v0.1.0) (2023-07-07)
1
+ # [0.2.0](https://github.com/Fire-Dragon-DoL/iry/compare/8a133c2c19b99881619a9e1c7c11076030755f66...v0.2.0) (2023-07-08)
6
2
 
7
3
 
8
4
  ### Features
9
5
 
10
- * **constraints:** check constraint is present ([2723ad7](https://github.com/Fire-Dragon-DoL/iry/commit/2723ad70d7dbb4cea4b4c6e92ce59627fae64c27))
11
- * **constraints:** exclusion constraint is present ([bdb904a](https://github.com/Fire-Dragon-DoL/iry/commit/bdb904a80dd1f6b1960f2b8378490cc192deb83e))
12
- * **constraints:** foreign key constraint is present ([efed498](https://github.com/Fire-Dragon-DoL/iry/commit/efed4986a10b40c77dcd063d8801eb77d605d807))
13
- * **deps:** dependency surface is reduced ([ff4af7e](https://github.com/Fire-Dragon-DoL/iry/commit/ff4af7e365537e30a0d95bfdee84e681f54c155a))
6
+ * **constraints:** check constraint is present ([d0cc380](https://github.com/Fire-Dragon-DoL/iry/commit/d0cc3803fdcda45df964f6431890f8831d3641e5))
7
+ * **constraints:** exclusion constraint is present ([1894e85](https://github.com/Fire-Dragon-DoL/iry/commit/1894e85bfa11e272be9b5f0f8efc170f7ce57a48))
8
+ * **constraints:** foreign key constraint is present ([e637b06](https://github.com/Fire-Dragon-DoL/iry/commit/e637b0603bb6fd34e2732426544fc31904bb5409))
9
+ * **deps:** dependency surface is reduced ([2dfc595](https://github.com/Fire-Dragon-DoL/iry/commit/2dfc595ebd221aedb072398e1ace8460208d06ac))
14
10
  * **project:** setup ([8a133c2](https://github.com/Fire-Dragon-DoL/iry/commit/8a133c2c19b99881619a9e1c7c11076030755f66))
15
- * **ruby:** version is forced to >= 2.7 ([f386ce6](https://github.com/Fire-Dragon-DoL/iry/commit/f386ce6db3aab7399b71a15bfed8228884a82f16))
11
+ * **ruby:** version is forced to >= 2.7 ([9b20ed8](https://github.com/Fire-Dragon-DoL/iry/commit/9b20ed8ec0ae2a9906bdefe28cf674d4700f4d67))
16
12
  * **unique-constraint:** test is implemented ([c4266b9](https://github.com/Fire-Dragon-DoL/iry/commit/c4266b910757b6adef18db41dfa5dfd9353c1037))
13
+
14
+
15
+
data/README.md CHANGED
@@ -6,7 +6,7 @@ Convert constraint errors into Rails model validation errors.
6
6
 
7
7
  ## Documentation
8
8
 
9
- https://rubydoc.info/gems/iry/frames
9
+ https://rubydoc.info/gems/iry
10
10
 
11
11
  ## Usage
12
12
 
@@ -14,7 +14,6 @@ Given the following database schema:
14
14
 
15
15
  ```sql
16
16
  create extension if not exists "pgcrypto";
17
- create extension if not exists "btree_gist";
18
17
 
19
18
  create table if not exists users (
20
19
  id uuid primary key default gen_random_uuid(),
@@ -24,7 +23,7 @@ create table if not exists users (
24
23
  );
25
24
  ```
26
25
 
27
- The following constraint can be used on the `User` class:
26
+ Set the following constraint on the `User` class:
28
27
 
29
28
  ```ruby
30
29
  class User < ActiveRecord::Base
@@ -36,14 +35,21 @@ class User < ActiveRecord::Base
36
35
  end
37
36
  ```
38
37
 
38
+ Now one of the saving mechanisms can be used:
39
+ - [`handle_constraints`](#handle_constraints)
40
+ - [`save`](#save)
41
+ - [`save!`](#save!)
42
+
39
43
  When saving a new `User` record or updating it, in case constraint exceptions are raised, these will be rescued and
40
44
  validation errors will be applied to the record, like in the following example:
41
45
 
42
46
  ```ruby
43
47
  user = User.create!(unique_text: "some unique text")
48
+ fail_user = User.new(unique_text: "some unique text")
44
49
 
45
- fail_user = User.create(unique_text: "some unique text")
50
+ success = Iry.save(fail_user)
46
51
 
52
+ success #=> false
47
53
  fail_user.errors.details.fetch(:unique_text) #=> [{error: :taken}]
48
54
  ```
49
55
 
@@ -62,7 +68,7 @@ The class method `.constraints` is also available, that returns all the constrai
62
68
 
63
69
  ### [`check_constraint`](https://rubydoc.info/gems/iry/Iry%2FMacros:check_constraint)
64
70
 
65
- ```rbs
71
+ ```ruby
66
72
  check_constraint(key, name: nil, message: :invalid) ⇒ void
67
73
  ```
68
74
 
@@ -74,7 +80,7 @@ Catches a specific check constraint violation.
74
80
 
75
81
  ### [`exclusion_constraint`](https://rubydoc.info/gems/iry/Iry%2FMacros:exclusion_constraint)
76
82
 
77
- ```rbs
83
+ ```ruby
78
84
  exclusion_constraint(key, name: nil, message: :taken) ⇒ void
79
85
  ```
80
86
 
@@ -86,7 +92,7 @@ Catches a specific exclusion constraint violation.
86
92
 
87
93
  ### [`foreign_key_constraint`](https://rubydoc.info/gems/iry/Iry%2FMacros:foreign_key_constraint)
88
94
 
89
- ```rbs
95
+ ```ruby
90
96
  foreign_key_constraint(key_or_keys, name: nil, message: :required, error_key: nil) ⇒ void
91
97
  ```
92
98
 
@@ -99,7 +105,7 @@ Catches a specific foreign key constraint violation.
99
105
 
100
106
  ### [`unique_constraint`](https://rubydoc.info/gems/iry/Iry%2FMacros:unique_constraint)
101
107
 
102
- ```rbs
108
+ ```ruby
103
109
  unique_constraint(key_or_keys, name: nil, message: :taken, error_key: nil) ⇒ void
104
110
  ```
105
111
 
@@ -110,12 +116,36 @@ Catches a specific foreign key constraint violation.
110
116
  - **message** (optional `String` or `Symbol`) error message, defaults to `:taken`
111
117
  - **error_key** (optional `Symbol`) which key will have validation errors added to
112
118
 
119
+ ## Advanced Usage
120
+
121
+ ### [`handle_constraints!`](https://rubydoc.info/gems/iry/Iry.handle_constraints)
122
+
123
+ ```ruby
124
+ .handle_constraints(model) { ... } ⇒ nil, Handlers::Model
125
+ ```
126
+
127
+ Serving as base for `save` and `save!`, it will detects constraint violations, halt the execution of the block, convert
128
+ violations to validation errors and return `nil` when violations are detected, otherwise the model object provided as
129
+ argument.
130
+
131
+ ### [`save`](https://rubydoc.info/gems/iry/Iry.save)
132
+
133
+ Acts the same as `ActiveRecord::Base#save`, accepting the same arguments and returning the same values.
134
+ In addition, it will return `false` if a constraint violation of the tracked constraints is detected and validation
135
+ errors will be added to `errors`.
136
+
137
+ ### [`save!`](https://rubydoc.info/gems/iry/Iry.save!)
138
+
139
+ Acts the same as `ActiveRecord::Base#save!`, accepting the same arguments and returning the same values.
140
+ In addition, it will raise `Iry::ConstraintViolation` when constraint violations are detected.
141
+
113
142
  ## Limitations
114
143
 
115
144
  - `valid?` will not check for constraints. If calling `valid?` right after a `save` operation, keep in mind `errors`
116
145
  are cleared
117
- - `create!` and `update!` will raise `ActiveRecord::RecordNotSaved` for constraints that are caught by `iry`, instead
118
- of `ActiveModel::ValidationError`
146
+ - It is recommended to avoid transactions when using `Iry`, because if a violation is detected, anything after
147
+ `Iry.save/save!/handle_constraints` will result in `ActiveRecord::StatementInvalid`, since the transaction is
148
+ aborted
119
149
  - Currently only PostgreSQL is supported with the `pg` gem, but it should be simple to add support for other databases.
120
150
 
121
151
  ## Installation
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.4.0
data/db/schema.pgsql CHANGED
@@ -7,6 +7,7 @@ create table if not exists users (
7
7
  exclude_text text not null default gen_random_uuid()::text,
8
8
  user_id uuid references users (id),
9
9
  untracked_text text unique not null default gen_random_uuid()::text,
10
+ free_text text not null default '',
10
11
  friend_user_id uuid references users (id),
11
12
  created_at timestamp(6) not null,
12
13
  updated_at timestamp(6) not null,
data/lib/iry/callbacks.rb CHANGED
@@ -19,7 +19,11 @@ module Iry
19
19
 
20
20
  is_handled = handler.handle(err, model)
21
21
 
22
- if !is_handled
22
+ if is_handled
23
+ # Rolling back allows to keep using SQL in other callbacks, which
24
+ # otherwise would raise PG::InFailedSqlTransaction
25
+ raise ActiveRecord::Rollback
26
+ else
23
27
  raise
24
28
  end
25
29
  end
data/lib/iry/macros.rb CHANGED
@@ -1,11 +1,9 @@
1
1
  module Iry
2
2
  # Class-level methods available to classes executing `include Iry`
3
3
  module Macros
4
- # Constraints by name
5
- # @return [{String => Constraint}]
6
- def constraints
7
- @constraints ||= {}
8
- end
4
+ # @!method constraints
5
+ # Constraints by name
6
+ # @return [{String => Constraint}]
9
7
 
10
8
  # Tracks check constraint for the given key and convert constraint errors into validation errors
11
9
  # @param key [Symbol] key to apply validation errors to
data/lib/iry.rb CHANGED
@@ -29,18 +29,116 @@ require_relative "iry/constraint/unique"
29
29
  # end
30
30
  #
31
31
  # user = User.create!(email: "user@example.com")
32
- # fail_user = User.create(email: "user@example.com")
32
+ # fail_user = User.new(email: "user@example.com")
33
+ # Iry.save(fail_user)
33
34
  # fail_user.errors.details.fetch(:email) #=> [{error: :taken}]
34
35
  module Iry
36
+ # Included in all exceptions triggered by Iry, this allows to rescue any
37
+ # gem-related exception by rescuing {Iry::Error}
38
+ module Error
39
+ end
40
+
41
+ # Raised when constraints have been violated and have been converted to
42
+ # model errors
43
+ class ConstraintViolation < ActiveRecord::RecordInvalid
44
+ include Error
45
+
46
+ # @!method record
47
+ # Inherited from {ActiveRecord::RecordInvalid}, returns the model for
48
+ # which the constraint violations have been detected
49
+ # @return [Handlers::Model]
50
+ end
51
+
35
52
  # @param klass [Module]
36
53
  # @return [void]
37
54
  # @private
38
55
  def self.included(klass)
39
56
  klass.class_eval do
57
+ # From activesupport
58
+ class_attribute(:constraints)
59
+ self.constraints = {}
40
60
  extend(Iry::Macros)
41
- # Prepend ensures around save happens before all around_save callbacks
42
- # adding the errors as soon as possible
43
- around_save(Iry::Callbacks, prepend: true)
44
61
  end
45
62
  end
63
+
64
+ # Executes block and in case of constraints violations on `model`, block is
65
+ # halted and errors are appended to `model`
66
+ # @param model [Handlers::Model] model object for which constraints should be
67
+ # monitored and for which errors should be added to
68
+ # @yield block must perform the save operation, usually with `save`
69
+ # @return [nil, Handlers::Model] the `model` or `nil` if a a constraint is
70
+ # violated
71
+ # @example Handle constraints for unique user
72
+ # # The database schema has a unique constraint on email field
73
+ # class User < ActiveRecord::Base
74
+ # include Iry
75
+ #
76
+ # unique_constraint :email
77
+ # end
78
+ #
79
+ # user = User.create!(email: "user@example.com")
80
+ # fail_user = User.new(email: "user@example.com")
81
+ # result = Iry.handle_constraints(fail_user) { fail_user.save }
82
+ # result #=> nil
83
+ # fail_user.errors.details.fetch(:email) #=> [{error: :taken}]
84
+ def self.handle_constraints(model, &block)
85
+ raise ArgumentError, "Block required" if block.nil?
86
+
87
+ block.()
88
+
89
+ return model
90
+ rescue ActiveRecord::StatementInvalid => err
91
+ handler = Handlers::Null
92
+ case
93
+ when Handlers::PG.handle?(err)
94
+ handler = Handlers::PG
95
+ end
96
+
97
+ is_handled = handler.handle(err, model)
98
+
99
+ # This constraint is not handled by Iry and should raise normally
100
+ if !is_handled
101
+ raise
102
+ end
103
+
104
+ return nil
105
+ end
106
+
107
+ # Similar to {ActiveRecord::Base#save} but in case of constraint violations,
108
+ # `false` is returned and `errors` are populated.
109
+ # Aside from `model`, it takes the same arguments as
110
+ # {ActiveRecord::Base#save}
111
+ # @param model [Handlers::Model] model to save
112
+ # @return [Boolean] `true` if successful
113
+ def self.save(model, ...)
114
+ success = nil
115
+ constraint_model = handle_constraints(model) { success = model.save(...) }
116
+
117
+ if constraint_model
118
+ return success
119
+ end
120
+
121
+ return false
122
+ end
123
+
124
+ # Similar to {ActiveRecord::Base#save!} but in case of constraint violations,
125
+ # it raises {ConstraintViolation} and `errors` are populated.
126
+ # Aside from `model`, it takes the same arguments as
127
+ # {ActiveRecord::Base#save!}
128
+ # @param model [Handlers::Model] model to save
129
+ # @return [true]
130
+ # @raise [ConstraintViolation] {ConstraintViolation} inherits from
131
+ # {ActiveRecord::RecordInvalid} but it's triggered only when a constraint
132
+ # violation happens
133
+ # @raise [ActiveRecord::RecordInvalid] triggered when a validation error is
134
+ # raised, but not a constraint violation
135
+ def self.save!(model, ...)
136
+ constraint_model = handle_constraints(model) { model.save!(...) }
137
+
138
+ if constraint_model
139
+ return true
140
+ end
141
+
142
+ raise ConstraintViolation.new(model)
143
+ end
46
144
  end
data/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "iry",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "iry",
9
- "version": "0.2.0",
9
+ "version": "0.4.0",
10
10
  "license": "MIT",
11
11
  "devDependencies": {
12
12
  "conventional-changelog-cli": ">= 3.0.0",
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iry",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Transform database constraint errors into activerecord validation errors",
5
5
  "private": true,
6
6
  "main": "index.js",
@@ -10,7 +10,8 @@
10
10
  "test": "test"
11
11
  },
12
12
  "scripts": {
13
- "test": "echo \"Error: no test specified\" && exit 1"
13
+ "test": "echo \"Error: no test specified\" && exit 1",
14
+ "version-get": "echo \"$npm_package_version\""
14
15
  },
15
16
  "repository": {
16
17
  "type": "git",
data/rbi/iry.rbi CHANGED
@@ -16,15 +16,78 @@
16
16
  # end
17
17
  #
18
18
  # user = User.create!(email: "user@example.com")
19
- # fail_user = User.create(email: "user@example.com")
19
+ # fail_user = User.new(email: "user@example.com")
20
+ # Iry.save(fail_user)
20
21
  # fail_user.errors.details.fetch(:email) #=> [{error: :taken}]
21
22
  module Iry
22
23
  VERSION = T.let(File.read(File.expand_path("../../VERSION", __dir__)).strip.freeze, T.untyped)
23
24
 
25
+ # Inherited from {ActiveRecord::RecordInvalid}, returns the model for
26
+ # which the constraint violations have been detected
27
+ sig { returns(Handlers::Model) }
28
+ def record; end
29
+
24
30
  # _@param_ `klass`
25
31
  sig { params(klass: Module).void }
26
32
  def self.included(klass); end
27
33
 
34
+ # Executes block and in case of constraints violations on `model`, block is
35
+ # halted and errors are appended to `model`
36
+ #
37
+ # _@param_ `model` — model object for which constraints should be monitored and for which errors should be added to
38
+ #
39
+ # _@return_ — the `model` or `nil` if a a constraint is
40
+ # violated
41
+ #
42
+ # Handle constraints for unique user
43
+ # ```ruby
44
+ # # The database schema has a unique constraint on email field
45
+ # class User < ActiveRecord::Base
46
+ # include Iry
47
+ #
48
+ # unique_constraint :email
49
+ # end
50
+ #
51
+ # user = User.create!(email: "user@example.com")
52
+ # fail_user = User.new(email: "user@example.com")
53
+ # result = Iry.handle_constraints(fail_user) { fail_user.save }
54
+ # result #=> nil
55
+ # fail_user.errors.details.fetch(:email) #=> [{error: :taken}]
56
+ # ```
57
+ sig { params(model: Handlers::Model, block: T.untyped).void }
58
+ def self.handle_constraints(model, &block); end
59
+
60
+ # Similar to {ActiveRecord::Base#save} but in case of constraint violations,
61
+ # `false` is returned and `errors` are populated.
62
+ # Aside from `model`, it takes the same arguments as
63
+ # {ActiveRecord::Base#save}
64
+ #
65
+ # _@param_ `model` — model to save
66
+ #
67
+ # _@return_ — `true` if successful
68
+ sig { params(model: Handlers::Model).returns(T::Boolean) }
69
+ def self.save(model); end
70
+
71
+ # Similar to {ActiveRecord::Base#save!} but in case of constraint violations,
72
+ # it raises {ConstraintViolation} and `errors` are populated.
73
+ # Aside from `model`, it takes the same arguments as
74
+ # {ActiveRecord::Base#save!}
75
+ #
76
+ # _@param_ `model` — model to save
77
+ sig { params(model: Handlers::Model).returns(T::Boolean) }
78
+ def self.save!(model); end
79
+
80
+ # Included in all exceptions triggered by Iry, this allows to rescue any
81
+ # gem-related exception by rescuing {Iry::Error}
82
+ module Error
83
+ end
84
+
85
+ # Raised when constraints have been violated and have been converted to
86
+ # model errors
87
+ class ConstraintViolation < ActiveRecord::RecordInvalid
88
+ include Iry::Error
89
+ end
90
+
28
91
  # Class-level methods available to classes executing `include Iry`
29
92
  module Macros
30
93
  # Constraints by name
data/sig/iry.rbs CHANGED
@@ -15,14 +15,73 @@
15
15
  # end
16
16
  #
17
17
  # user = User.create!(email: "user@example.com")
18
- # fail_user = User.create(email: "user@example.com")
18
+ # fail_user = User.new(email: "user@example.com")
19
+ # Iry.save(fail_user)
19
20
  # fail_user.errors.details.fetch(:email) #=> [{error: :taken}]
20
21
  module Iry
21
22
  VERSION: String
22
23
 
24
+ # Inherited from {ActiveRecord::RecordInvalid}, returns the model for
25
+ # which the constraint violations have been detected
26
+ def record: () -> Handlers::Model
27
+
23
28
  # _@param_ `klass`
24
29
  def self.included: (Module klass) -> void
25
30
 
31
+ # Executes block and in case of constraints violations on `model`, block is
32
+ # halted and errors are appended to `model`
33
+ #
34
+ # _@param_ `model` — model object for which constraints should be monitored and for which errors should be added to
35
+ #
36
+ # _@return_ — the `model` or `nil` if a a constraint is
37
+ # violated
38
+ #
39
+ # Handle constraints for unique user
40
+ # ```ruby
41
+ # # The database schema has a unique constraint on email field
42
+ # class User < ActiveRecord::Base
43
+ # include Iry
44
+ #
45
+ # unique_constraint :email
46
+ # end
47
+ #
48
+ # user = User.create!(email: "user@example.com")
49
+ # fail_user = User.new(email: "user@example.com")
50
+ # result = Iry.handle_constraints(fail_user) { fail_user.save }
51
+ # result #=> nil
52
+ # fail_user.errors.details.fetch(:email) #=> [{error: :taken}]
53
+ # ```
54
+ def self.handle_constraints: (Handlers::Model model) -> void
55
+
56
+ # Similar to {ActiveRecord::Base#save} but in case of constraint violations,
57
+ # `false` is returned and `errors` are populated.
58
+ # Aside from `model`, it takes the same arguments as
59
+ # {ActiveRecord::Base#save}
60
+ #
61
+ # _@param_ `model` — model to save
62
+ #
63
+ # _@return_ — `true` if successful
64
+ def self.save: (Handlers::Model model) -> bool
65
+
66
+ # Similar to {ActiveRecord::Base#save!} but in case of constraint violations,
67
+ # it raises {ConstraintViolation} and `errors` are populated.
68
+ # Aside from `model`, it takes the same arguments as
69
+ # {ActiveRecord::Base#save!}
70
+ #
71
+ # _@param_ `model` — model to save
72
+ def self.save!: (Handlers::Model model) -> bool
73
+
74
+ # Included in all exceptions triggered by Iry, this allows to rescue any
75
+ # gem-related exception by rescuing {Iry::Error}
76
+ module Error
77
+ end
78
+
79
+ # Raised when constraints have been violated and have been converted to
80
+ # model errors
81
+ class ConstraintViolation < ActiveRecord::RecordInvalid
82
+ include Iry::Error
83
+ end
84
+
26
85
  # Class-level methods available to classes executing `include Iry`
27
86
  module Macros
28
87
  # Constraints by name
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: iry
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Francesco Belladonna
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-07-08 00:00:00.000000000 Z
11
+ date: 2023-07-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord