rodauth-model 0.1.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -3
- data/README.md +12 -16
- data/lib/rodauth/model/active_record.rb +1 -5
- data/lib/rodauth/model/sequel.rb +93 -0
- data/lib/rodauth/model.rb +3 -2
- data/rodauth-model.gemspec +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 59bbf27ffd624fa72ce609fcb9968118bf358e3e3f10893db7d0d73abf356d12
|
4
|
+
data.tar.gz: 2c286827b98cef9f1d593f740375ae2f74c759dee7dd2d7c954380a03659ecd4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a8ef44bd93fc5cdb4fabaf58544bcf3ddc7ab8084a6a38b73777cb26163fe0ad8ded45978975cf4423b8f44b97e1c49dc9d3d01f6ca7aac71f06d120a7bebf5b
|
7
|
+
data.tar.gz: 9d8067365baec855fed3ad8f2db189d8842e3244b2867ca6b67413715ddd15465aa7f5db1d416f80e4925df2b226f7edda80e68cd40a83a0697e7a1cfe669644
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
|
-
##
|
1
|
+
## 0.2.1 (2022-10-26)
|
2
2
|
|
3
|
-
|
3
|
+
* Fix `elsif` warning in sequel code (@janko)
|
4
4
|
|
5
|
-
|
5
|
+
## 0.2.0 (2022-05-11)
|
6
|
+
|
7
|
+
* Add support for Sequel models (@janko)
|
8
|
+
|
9
|
+
* Delete associated authentication audit logs after destroying account (@janko)
|
10
|
+
|
11
|
+
## 0.1.0 (2022-05-07)
|
12
|
+
|
13
|
+
* Initial release (@janko)
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# rodauth-model
|
2
2
|
|
3
|
-
Extension for [Rodauth] providing a mixin for the account model that defines password attribute and associations based on enabled authentication features.
|
3
|
+
Extension for [Rodauth] providing a mixin for the account model that defines password attribute and associations based on enabled authentication features. Supports both Active Record and Sequel models.
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -10,7 +10,7 @@ $ bundle add rodauth-model
|
|
10
10
|
|
11
11
|
## Usage
|
12
12
|
|
13
|
-
|
13
|
+
The model mixin is built by calling `Rodauth::Model(...)` with the Rodauth auth class, and included into the account model:
|
14
14
|
|
15
15
|
```rb
|
16
16
|
require "rodauth/model" # require before enabling any authentication features
|
@@ -22,7 +22,7 @@ class RodauthApp < Roda
|
|
22
22
|
end
|
23
23
|
```
|
24
24
|
```rb
|
25
|
-
class Account < ActiveRecord::Base
|
25
|
+
class Account < ActiveRecord::Base # Sequel::Model
|
26
26
|
include Rodauth::Model(RodauthApp.rodauth)
|
27
27
|
end
|
28
28
|
```
|
@@ -30,7 +30,7 @@ end
|
|
30
30
|
If you have multiple Rodauth configurations, pass the one for which you want associations to be defined.
|
31
31
|
|
32
32
|
```rb
|
33
|
-
class Account < ActiveRecord::Base
|
33
|
+
class Account < ActiveRecord::Base # Sequel::Model
|
34
34
|
include Rodauth::Model(RodauthApp.rodauth(:admin))
|
35
35
|
end
|
36
36
|
```
|
@@ -40,7 +40,7 @@ end
|
|
40
40
|
Regardless of whether you're storing the password hash in a column in the accounts table, or in a separate table, the `#password` attribute can be used to set or clear the password hash.
|
41
41
|
|
42
42
|
```rb
|
43
|
-
account = Account.create
|
43
|
+
account = Account.create(email: "user@example.com", password: "secret")
|
44
44
|
|
45
45
|
# when password hash is stored in a column on the accounts table
|
46
46
|
account.password_hash #=> "$2a$12$k/Ub1I2iomi84RacqY89Hu4.M0vK7klRnRtzorDyvOkVI.hKhkNw."
|
@@ -71,23 +71,23 @@ You can also reference the associated models directly:
|
|
71
71
|
Account::AuthenticationAuditLog.where(message: "login").group(:account_id)
|
72
72
|
```
|
73
73
|
|
74
|
-
The associated models define the inverse `
|
74
|
+
The associated models define the inverse `account` association:
|
75
75
|
|
76
76
|
```rb
|
77
|
-
Account::ActiveSessionKey.
|
77
|
+
Account::ActiveSessionKey.eager(:account).map(&:account)
|
78
78
|
```
|
79
79
|
|
80
80
|
### Association options
|
81
81
|
|
82
|
-
By default, all associations
|
82
|
+
By default, all associations are configured to be deleted when the associated account record is deleted. When using Active Record, you can use `:association_options` to modify global or per-association options:
|
83
83
|
|
84
84
|
```rb
|
85
|
-
# don't auto-delete associations when account model is deleted
|
85
|
+
# don't auto-delete associations when account model is deleted (Active Record)
|
86
86
|
Rodauth::Model(RodauthApp.rodauth, association_options: { dependent: nil })
|
87
87
|
|
88
|
-
# require authentication audit logs to be eager loaded before retrieval
|
88
|
+
# require authentication audit logs to be eager loaded before retrieval (Sequel)
|
89
89
|
Rodauth::Model(RodauthApp.rodauth, association_options: -> (name) {
|
90
|
-
{
|
90
|
+
{ forbid_lazy_load: true } if name == :authentication_audit_logs
|
91
91
|
})
|
92
92
|
```
|
93
93
|
|
@@ -117,7 +117,7 @@ Below is a list of all associations defined depending on the features loaded:
|
|
117
117
|
| webauthn | `:webauthn_keys` | `has_many` | `WebauthnKey` | `account_webauthn_keys` |
|
118
118
|
| webauthn | `:webauthn_user_id` | `has_one` | `WebauthnUserId` | `account_webauthn_user_ids` |
|
119
119
|
|
120
|
-
Note that some Rodauth tables use composite primary keys, which Active Record doesn't support out of the box. For associations to work properly, you might need to add the [composite_primary_keys] gem to your Gemfile.
|
120
|
+
Note that some Rodauth tables use composite primary keys, which Active Record doesn't support out of the box. For associations to work properly in Active Record, you might need to add the [composite_primary_keys] gem to your Gemfile. On Sequel, associations will work without any changes, because Sequel supports composite primary keys.
|
121
121
|
|
122
122
|
## Extending associations
|
123
123
|
|
@@ -178,10 +178,6 @@ end
|
|
178
178
|
|
179
179
|
## Future plans
|
180
180
|
|
181
|
-
### Sequel support
|
182
|
-
|
183
|
-
Currently on Active Record models are supported, but I would like support Sequel models in the near future as well.
|
184
|
-
|
185
181
|
### Joined associations
|
186
182
|
|
187
183
|
It's possible to have multiple Rodauth configurations that operate on the same tables, but it's currently possible to define associations just for a single configuration. I would like to support grabbing associations from multiple associations.
|
@@ -68,14 +68,10 @@ module Rodauth
|
|
68
68
|
|
69
69
|
model.const_set(name.to_s.singularize.camelize, associated_model)
|
70
70
|
|
71
|
-
unless name == :authentication_audit_logs
|
72
|
-
dependent = type == :has_many ? :delete_all : :delete
|
73
|
-
end
|
74
|
-
|
75
71
|
model.public_send type, name, scope,
|
76
72
|
class_name: associated_model.name,
|
77
73
|
foreign_key: foreign_key,
|
78
|
-
dependent:
|
74
|
+
dependent: type == :has_many ? :delete_all : :delete,
|
79
75
|
inverse_of: :account,
|
80
76
|
**options,
|
81
77
|
**association_options(name)
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "sequel"
|
4
|
+
|
5
|
+
module Rodauth
|
6
|
+
class Model
|
7
|
+
module Sequel
|
8
|
+
include ::Sequel::Inflections
|
9
|
+
|
10
|
+
ASSOCIATION_TYPES = { one: :one_to_one, many: :one_to_many }
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def define_methods(model)
|
15
|
+
rodauth = @auth_class.allocate.freeze
|
16
|
+
|
17
|
+
unless rodauth.account_password_hash_column
|
18
|
+
model.plugin :nested_attributes
|
19
|
+
model.nested_attributes :password_hash, destroy: true
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_reader :password
|
23
|
+
|
24
|
+
define_method(:password=) do |password|
|
25
|
+
@password = password
|
26
|
+
password_hash = rodauth.send(:password_hash, password) if password
|
27
|
+
set_password_hash(password_hash)
|
28
|
+
end
|
29
|
+
|
30
|
+
define_method(:set_password_hash) do |password_hash|
|
31
|
+
if rodauth.account_password_hash_column
|
32
|
+
public_send(:"#{rodauth.account_password_hash_column}=", password_hash)
|
33
|
+
else
|
34
|
+
return if password_hash.nil? && self.password_hash.nil?
|
35
|
+
|
36
|
+
attributes = { rodauth.password_hash_id_column => self.password_hash&.pk }.compact
|
37
|
+
if password_hash
|
38
|
+
attributes[rodauth.password_hash_column] = password_hash
|
39
|
+
else
|
40
|
+
attributes[:_delete] = true
|
41
|
+
end
|
42
|
+
self.password_hash_attributes = attributes
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def define_associations(model)
|
48
|
+
model.plugin :association_dependencies
|
49
|
+
|
50
|
+
define_password_hash_association(model) unless rodauth.account_password_hash_column
|
51
|
+
|
52
|
+
feature_associations.each do |association|
|
53
|
+
association[:type] = ASSOCIATION_TYPES.fetch(association[:type])
|
54
|
+
|
55
|
+
define_association(model, **association)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def define_password_hash_association(model)
|
60
|
+
select = [rodauth.password_hash_id_column] if rodauth.send(:use_database_authentication_functions?)
|
61
|
+
|
62
|
+
define_association model,
|
63
|
+
type: :one_to_one,
|
64
|
+
name: :password_hash,
|
65
|
+
table: rodauth.password_hash_table,
|
66
|
+
key: rodauth.password_hash_id_column,
|
67
|
+
select: select
|
68
|
+
end
|
69
|
+
|
70
|
+
def define_association(model, type:, name:, table:, key:, **options)
|
71
|
+
associated_model = Class.new(::Sequel::Model)
|
72
|
+
associated_model.set_dataset(model.db[table])
|
73
|
+
associated_model.many_to_one :account, class: model.name, key: key
|
74
|
+
|
75
|
+
model.const_set(camelize(singularize(name.to_s)), associated_model)
|
76
|
+
|
77
|
+
model.public_send type, name,
|
78
|
+
class: associated_model.name,
|
79
|
+
key: key,
|
80
|
+
**options,
|
81
|
+
**association_options(name)
|
82
|
+
|
83
|
+
model.add_association_dependencies name => :delete
|
84
|
+
end
|
85
|
+
|
86
|
+
def association_options(name)
|
87
|
+
options = @association_options
|
88
|
+
options = options.call(name) if options.respond_to?(:call)
|
89
|
+
options || {}
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
data/lib/rodauth/model.rb
CHANGED
@@ -9,6 +9,7 @@ module Rodauth
|
|
9
9
|
Error = Class.new(StandardError)
|
10
10
|
|
11
11
|
autoload :ActiveRecord, "rodauth/model/active_record"
|
12
|
+
autoload :Sequel, "rodauth/model/sequel"
|
12
13
|
|
13
14
|
def self.associations
|
14
15
|
@associations ||= {}
|
@@ -28,9 +29,9 @@ module Rodauth
|
|
28
29
|
if defined?(::ActiveRecord::Base) && model < ::ActiveRecord::Base
|
29
30
|
extend Rodauth::Model::ActiveRecord
|
30
31
|
elsif defined?(::Sequel::Model) && model < ::Sequel::Model
|
31
|
-
|
32
|
+
extend Rodauth::Model::Sequel
|
32
33
|
else
|
33
|
-
raise Error, "must be an Active Record model"
|
34
|
+
raise Error, "must be an Active Record or Sequel model"
|
34
35
|
end
|
35
36
|
|
36
37
|
define_associations(model)
|
data/rodauth-model.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rodauth-model
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Janko Marohnić
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-10-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rodauth
|
@@ -137,6 +137,7 @@ files:
|
|
137
137
|
- lib/rodauth/model.rb
|
138
138
|
- lib/rodauth/model/active_record.rb
|
139
139
|
- lib/rodauth/model/associations.rb
|
140
|
+
- lib/rodauth/model/sequel.rb
|
140
141
|
- rodauth-model.gemspec
|
141
142
|
homepage: https://github.com/janko/rodauth-model
|
142
143
|
licenses:
|