plutonium 0.50.0 → 0.51.0
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 +4 -4
- data/.claude/skills/plutonium/SKILL.md +85 -102
- data/.claude/skills/plutonium-app/SKILL.md +572 -0
- data/.claude/skills/plutonium-auth/SKILL.md +163 -300
- data/.claude/skills/plutonium-behavior/SKILL.md +838 -0
- data/.claude/skills/plutonium-resource/SKILL.md +1176 -0
- data/.claude/skills/plutonium-tenancy/SKILL.md +655 -0
- data/.claude/skills/plutonium-testing/SKILL.md +6 -5
- data/.claude/skills/plutonium-ui/SKILL.md +900 -0
- data/CHANGELOG.md +27 -2
- data/Rakefile +2 -1
- data/app/assets/plutonium.css +1 -11
- data/app/assets/plutonium.js +1009 -1214
- data/app/assets/plutonium.js.map +3 -3
- data/app/assets/plutonium.min.js +52 -51
- data/app/assets/plutonium.min.js.map +3 -3
- data/docs/.vitepress/config.ts +37 -27
- data/docs/getting-started/index.md +22 -29
- data/docs/getting-started/installation.md +37 -80
- data/docs/getting-started/tutorial/index.md +4 -5
- data/docs/guides/adding-resources.md +66 -377
- data/docs/guides/authentication.md +94 -463
- data/docs/guides/authorization.md +124 -370
- data/docs/guides/creating-packages.md +94 -296
- data/docs/guides/custom-actions.md +121 -441
- data/docs/guides/index.md +22 -42
- data/docs/guides/multi-tenancy.md +116 -187
- data/docs/guides/nested-resources.md +103 -431
- data/docs/guides/search-filtering.md +123 -240
- data/docs/guides/testing.md +5 -4
- data/docs/guides/theming.md +157 -407
- data/docs/guides/troubleshooting.md +5 -3
- data/docs/guides/user-invites.md +106 -425
- data/docs/guides/user-profile.md +76 -243
- data/docs/index.md +1 -1
- data/docs/reference/app/generators.md +517 -0
- data/docs/reference/app/index.md +158 -0
- data/docs/reference/app/packages.md +146 -0
- data/docs/reference/app/portals.md +377 -0
- data/docs/reference/auth/accounts.md +230 -0
- data/docs/reference/auth/index.md +88 -0
- data/docs/reference/auth/profile.md +185 -0
- data/docs/reference/behavior/controllers.md +395 -0
- data/docs/reference/behavior/index.md +22 -0
- data/docs/reference/behavior/interactions.md +341 -0
- data/docs/reference/behavior/policies.md +417 -0
- data/docs/reference/index.md +56 -49
- data/docs/reference/resource/actions.md +423 -0
- data/docs/reference/resource/definition.md +508 -0
- data/docs/reference/resource/index.md +50 -0
- data/docs/reference/resource/model.md +348 -0
- data/docs/reference/resource/query.md +305 -0
- data/docs/reference/tenancy/entity-scoping.md +361 -0
- data/docs/reference/tenancy/index.md +36 -0
- data/docs/reference/tenancy/invites.md +393 -0
- data/docs/reference/tenancy/nested-resources.md +267 -0
- data/docs/reference/testing/index.md +287 -0
- data/docs/reference/ui/assets.md +400 -0
- data/docs/reference/ui/components.md +165 -0
- data/docs/reference/ui/displays.md +104 -0
- data/docs/reference/ui/forms.md +284 -0
- data/docs/reference/ui/index.md +30 -0
- data/docs/reference/ui/layouts.md +106 -0
- data/docs/reference/ui/pages.md +189 -0
- data/docs/reference/ui/tables.md +117 -0
- data/docs/superpowers/specs/2026-05-09-typeahead-endpoint-design.md +203 -0
- data/docs/superpowers/specs/2026-05-12-skill-compaction-design.md +99 -0
- data/docs/superpowers/specs/2026-05-13-docs-restructure-design.md +186 -0
- data/gemfiles/rails_7.gemfile.lock +1 -1
- data/gemfiles/rails_8.0.gemfile.lock +1 -1
- data/gemfiles/rails_8.1.gemfile.lock +1 -1
- data/lib/generators/pu/core/update/update_generator.rb +0 -20
- data/lib/generators/pu/invites/install_generator.rb +1 -0
- data/lib/plutonium/definition/base.rb +1 -1
- data/lib/plutonium/definition/{views.rb → index_views.rb} +21 -20
- data/lib/plutonium/helpers/turbo_helper.rb +11 -0
- data/lib/plutonium/helpers/turbo_stream_actions_helper.rb +14 -0
- data/lib/plutonium/resource/controller.rb +1 -0
- data/lib/plutonium/resource/controllers/crud_actions.rb +19 -1
- data/lib/plutonium/resource/controllers/typeahead.rb +180 -0
- data/lib/plutonium/resource/policy.rb +7 -0
- data/lib/plutonium/routing/mapper_extensions.rb +15 -0
- data/lib/plutonium/ui/component/methods.rb +4 -0
- data/lib/plutonium/ui/form/base.rb +6 -2
- data/lib/plutonium/ui/form/components/json.rb +58 -0
- data/lib/plutonium/ui/form/components/resource_select.rb +62 -8
- data/lib/plutonium/ui/form/components/secure_association.rb +98 -22
- data/lib/plutonium/ui/form/concerns/typeahead_attributes.rb +83 -0
- data/lib/plutonium/ui/form/resource.rb +0 -4
- data/lib/plutonium/ui/grid/resource.rb +1 -1
- data/lib/plutonium/ui/layout/base.rb +1 -0
- data/lib/plutonium/ui/page/base.rb +0 -7
- data/lib/plutonium/ui/page/index.rb +4 -4
- data/lib/plutonium/ui/table/resource.rb +1 -1
- data/lib/plutonium/version.rb +1 -1
- data/lib/plutonium.rb +8 -0
- data/lib/tasks/release.rake +15 -1
- data/package.json +10 -10
- data/src/css/slim_select.css +4 -0
- data/src/js/controllers/slim_select_controller.js +61 -0
- data/src/js/turbo/turbo_actions.js +33 -0
- data/yarn.lock +553 -543
- metadata +44 -33
- data/.claude/skills/plutonium-assets/SKILL.md +0 -512
- data/.claude/skills/plutonium-controller/SKILL.md +0 -396
- data/.claude/skills/plutonium-create-resource/SKILL.md +0 -303
- data/.claude/skills/plutonium-definition/SKILL.md +0 -1223
- data/.claude/skills/plutonium-entity-scoping/SKILL.md +0 -317
- data/.claude/skills/plutonium-forms/SKILL.md +0 -465
- data/.claude/skills/plutonium-installation/SKILL.md +0 -331
- data/.claude/skills/plutonium-interaction/SKILL.md +0 -413
- data/.claude/skills/plutonium-invites/SKILL.md +0 -408
- data/.claude/skills/plutonium-model/SKILL.md +0 -440
- data/.claude/skills/plutonium-nested-resources/SKILL.md +0 -360
- data/.claude/skills/plutonium-package/SKILL.md +0 -198
- data/.claude/skills/plutonium-policy/SKILL.md +0 -456
- data/.claude/skills/plutonium-portal/SKILL.md +0 -410
- data/.claude/skills/plutonium-views/SKILL.md +0 -651
- data/docs/reference/assets/index.md +0 -496
- data/docs/reference/controller/index.md +0 -412
- data/docs/reference/definition/actions.md +0 -462
- data/docs/reference/definition/fields.md +0 -383
- data/docs/reference/definition/index.md +0 -326
- data/docs/reference/definition/query.md +0 -351
- data/docs/reference/generators/index.md +0 -648
- data/docs/reference/interaction/index.md +0 -449
- data/docs/reference/model/features.md +0 -248
- data/docs/reference/model/index.md +0 -218
- data/docs/reference/policy/index.md +0 -456
- data/docs/reference/portal/index.md +0 -379
- data/docs/reference/views/forms.md +0 -411
- data/docs/reference/views/index.md +0 -544
data/docs/guides/user-profile.md
CHANGED
|
@@ -1,322 +1,155 @@
|
|
|
1
1
|
# User Profile
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Add a profile / account-settings page where users edit personal fields and access Rodauth security features (change password, 2FA, etc.) in one place.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Goal
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- **Profile Resource**: A standard Plutonium resource linked to the User model
|
|
9
|
-
- **Security Section**: Automatic display of enabled Rodauth security features
|
|
10
|
-
- **Customizable Fields**: Add any fields you need (bio, avatar, preferences, etc.)
|
|
7
|
+
A `/profile` URL that shows the user's personal fields plus a "Security" section linking to Rodauth-managed features.
|
|
11
8
|
|
|
12
|
-
##
|
|
9
|
+
## 🚨 Critical
|
|
13
10
|
|
|
14
|
-
|
|
11
|
+
- **Profile association is always `:profile`** regardless of the model class — `current_user.profile`, `build_profile`, `params.require(:profile)` always work.
|
|
12
|
+
- **Profile needs `pu:profile:conn` to be visible** — without it, no `/profile` route, no `profile_url` helper.
|
|
13
|
+
- **Every user needs a profile row.** Add an `after_create :create_profile!` callback to the user model. Without it, `current_user.profile` is nil.
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
2. **Model Markers**: The User model with marker comments
|
|
18
|
-
|
|
19
|
-
The easiest way to set this up is with the SaaS generator:
|
|
15
|
+
## Quick path
|
|
20
16
|
|
|
21
17
|
```bash
|
|
22
|
-
rails g pu:
|
|
18
|
+
rails g pu:profile:setup date_of_birth:date bio:text \
|
|
19
|
+
--dest=competition \
|
|
20
|
+
--portal=competition_portal
|
|
23
21
|
```
|
|
24
22
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
### Step 1: Install the Profile Resource
|
|
23
|
+
`pu:profile:setup` is a meta-generator — runs `pu:profile:install` + `pu:profile:conn` in one shot.
|
|
28
24
|
|
|
29
|
-
|
|
30
|
-
rails generate pu:profile:install --dest=main_app
|
|
31
|
-
```
|
|
25
|
+
## Step-by-step
|
|
32
26
|
|
|
33
|
-
|
|
27
|
+
### 1. Install
|
|
34
28
|
|
|
35
29
|
```bash
|
|
36
|
-
rails
|
|
37
|
-
|
|
38
|
-
avatar:attachment \
|
|
39
|
-
'timezone:string?' \
|
|
40
|
-
notifications_enabled:boolean \
|
|
41
|
-
--dest=main_app
|
|
30
|
+
rails generate pu:profile:install bio:text avatar:attachment 'timezone:string?' \
|
|
31
|
+
--dest=customer
|
|
42
32
|
```
|
|
43
33
|
|
|
44
|
-
### Options
|
|
45
|
-
|
|
46
34
|
| Option | Default | Description |
|
|
47
|
-
|
|
48
|
-
| `--dest` | (prompts) | Target
|
|
49
|
-
| `--user-model` | User | Rodauth user model
|
|
35
|
+
|---|---|---|
|
|
36
|
+
| `--dest=DEST` | (prompts) | Target package or `main_app` |
|
|
37
|
+
| `--user-model=NAME` | `User` | Rodauth user model |
|
|
50
38
|
|
|
51
|
-
|
|
39
|
+
Custom resource name (first positional argument):
|
|
52
40
|
|
|
53
41
|
```bash
|
|
54
|
-
rails
|
|
42
|
+
rails g pu:profile:install AccountSettings bio:text --dest=main_app
|
|
55
43
|
```
|
|
56
44
|
|
|
57
|
-
|
|
45
|
+
By default the model is `{UserModel}Profile` (`UserProfile`, `StaffUserProfile`, etc.).
|
|
58
46
|
|
|
59
|
-
|
|
47
|
+
### 2. Migrate
|
|
60
48
|
|
|
61
49
|
```bash
|
|
62
|
-
rails
|
|
50
|
+
rails db:migrate
|
|
63
51
|
```
|
|
64
52
|
|
|
65
|
-
|
|
66
|
-
- Registers the Profile as a singular resource (`/profile` instead of `/profiles/:id`)
|
|
67
|
-
- Configures the `profile_url` helper to enable the "Profile" link in the user menu
|
|
68
|
-
|
|
69
|
-
## Generated Files
|
|
53
|
+
### 3. Connect to a portal
|
|
70
54
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
```
|
|
74
|
-
app/models/profile.rb
|
|
75
|
-
db/migrate/xxx_create_profiles.rb
|
|
76
|
-
app/controllers/profiles_controller.rb
|
|
77
|
-
app/policies/profile_policy.rb
|
|
78
|
-
app/definitions/profile_definition.rb
|
|
55
|
+
```bash
|
|
56
|
+
rails g pu:profile:conn --dest=customer_portal
|
|
79
57
|
```
|
|
80
58
|
|
|
81
|
-
|
|
82
|
-
- **User model**: Adds `has_one :profile, dependent: :destroy`
|
|
83
|
-
- **Definition**: Injects custom ShowPage with security links
|
|
84
|
-
|
|
85
|
-
## Security Section
|
|
86
|
-
|
|
87
|
-
The ShowPage automatically displays links to enabled Rodauth security features.
|
|
88
|
-
|
|
89
|
-
Available features (only shown if enabled in Rodauth):
|
|
90
|
-
|
|
91
|
-
| Feature | Link Label | Description |
|
|
92
|
-
|---------|------------|-------------|
|
|
93
|
-
| `change_password` | Change Password | Update account password |
|
|
94
|
-
| `change_login` | Change Email | Update email address |
|
|
95
|
-
| `otp` | Two-Factor Authentication | Set up TOTP authenticator |
|
|
96
|
-
| `recovery_codes` | Recovery Codes | View or regenerate backup codes |
|
|
97
|
-
| `webauthn` | Security Keys | Manage passkeys and hardware keys |
|
|
98
|
-
| `active_sessions` | Active Sessions | View and revoke sessions |
|
|
99
|
-
| `close_account` | Close Account | Permanently delete account |
|
|
100
|
-
|
|
101
|
-
## Creating Profiles for Users
|
|
59
|
+
This registers the profile as a **singular** resource — exposes `/profile` (no `:id`) and the `profile_url` helper.
|
|
102
60
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
### Option A: Automatic Creation on User Signup
|
|
61
|
+
### 4. Add the auto-create callback
|
|
106
62
|
|
|
107
63
|
```ruby
|
|
108
|
-
# app/models/user.rb
|
|
64
|
+
# app/models/user.rb (modified by pu:profile:install)
|
|
109
65
|
class User < ApplicationRecord
|
|
110
|
-
has_one :profile, dependent: :destroy
|
|
66
|
+
has_one :profile, class_name: "UserProfile", dependent: :destroy
|
|
111
67
|
|
|
112
68
|
after_create :create_profile!
|
|
113
69
|
|
|
114
70
|
private
|
|
115
|
-
|
|
116
|
-
def create_profile!
|
|
117
|
-
create_profile
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
# add has_one associations above.
|
|
71
|
+
def create_profile! = create_profile
|
|
121
72
|
end
|
|
122
73
|
```
|
|
123
74
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
In your portal's application controller:
|
|
75
|
+
For existing users at migration time:
|
|
127
76
|
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
before_action :ensure_profile
|
|
131
|
-
|
|
132
|
-
private
|
|
133
|
-
|
|
134
|
-
def ensure_profile
|
|
135
|
-
return unless current_user
|
|
136
|
-
current_user.profile || current_user.create_profile
|
|
137
|
-
end
|
|
138
|
-
end
|
|
77
|
+
```bash
|
|
78
|
+
rails runner "User.find_each(&:create_profile)"
|
|
139
79
|
```
|
|
140
80
|
|
|
141
|
-
|
|
81
|
+
## What you get
|
|
142
82
|
|
|
143
|
-
|
|
144
|
-
# app/controllers/profiles_controller.rb
|
|
145
|
-
class ProfilesController < ResourceController
|
|
146
|
-
private
|
|
83
|
+
The generated definition injects a custom `ShowPage` that renders `SecuritySection` — dynamically lists Rodauth security links based on which features are enabled:
|
|
147
84
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
85
|
+
| Feature enabled | Link rendered |
|
|
86
|
+
|---|---|
|
|
87
|
+
| `change_password` | Change Password |
|
|
88
|
+
| `change_login` | Change Email |
|
|
89
|
+
| `otp` | Two-Factor Authentication |
|
|
90
|
+
| `recovery_codes` | Recovery Codes |
|
|
91
|
+
| `webauthn` | Security Keys |
|
|
92
|
+
| `active_sessions` | Active Sessions |
|
|
93
|
+
| `close_account` | Close Account |
|
|
153
94
|
|
|
154
|
-
|
|
95
|
+
If a feature isn't enabled, its link doesn't render — no configuration needed.
|
|
155
96
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
Edit the generated definition to configure how fields appear:
|
|
97
|
+
## Linking to the profile
|
|
159
98
|
|
|
160
99
|
```ruby
|
|
161
|
-
|
|
162
|
-
class ProfileDefinition < Plutonium::Resource::Definition
|
|
163
|
-
form do |f|
|
|
164
|
-
f.field :bio, as: :text
|
|
165
|
-
f.field :avatar, as: :attachment
|
|
166
|
-
f.field :timezone, collection: ActiveSupport::TimeZone.all.map(&:name)
|
|
167
|
-
f.field :notifications_enabled
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
display do |d|
|
|
171
|
-
d.field :bio
|
|
172
|
-
d.field :avatar
|
|
173
|
-
d.field :timezone
|
|
174
|
-
d.field :notifications_enabled
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
class ShowPage < ShowPage
|
|
178
|
-
private
|
|
179
|
-
|
|
180
|
-
def render_after_content
|
|
181
|
-
render Plutonium::Profile::SecuritySection.new
|
|
182
|
-
end
|
|
183
|
-
end
|
|
184
|
-
end
|
|
100
|
+
link_to("Profile", profile_url) if respond_to?(:profile_url)
|
|
185
101
|
```
|
|
186
102
|
|
|
187
|
-
|
|
103
|
+
The `respond_to?` guard is defensive — only portals that ran `pu:profile:conn` have the helper.
|
|
104
|
+
|
|
105
|
+
## Customizing the definition
|
|
188
106
|
|
|
189
|
-
|
|
107
|
+
The generated profile is a normal Plutonium definition. Customize like any other:
|
|
190
108
|
|
|
191
109
|
```ruby
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
h2(class: "text-lg font-semibold") { "Account Security" }
|
|
197
|
-
|
|
198
|
-
if rodauth.features.include?(:change_password)
|
|
199
|
-
a(href: rodauth.change_password_path) { "Change Password" }
|
|
200
|
-
end
|
|
201
|
-
|
|
202
|
-
# Add your custom links
|
|
203
|
-
a(href: "/settings/notifications") { "Notification Preferences" }
|
|
204
|
-
end
|
|
205
|
-
end
|
|
206
|
-
end
|
|
207
|
-
```
|
|
110
|
+
class UserProfileDefinition < Plutonium::Resource::Definition
|
|
111
|
+
field :bio, as: :markdown
|
|
112
|
+
input :avatar, as: :uppy
|
|
113
|
+
field :timezone, as: :select, choices: ActiveSupport::TimeZone.all.map(&:name)
|
|
208
114
|
|
|
209
|
-
|
|
115
|
+
metadata :created_at, :updated_at
|
|
210
116
|
|
|
211
|
-
```ruby
|
|
212
|
-
class ProfileDefinition < Plutonium::Resource::Definition
|
|
213
117
|
class ShowPage < ShowPage
|
|
214
118
|
private
|
|
215
119
|
|
|
216
120
|
def render_after_content
|
|
217
|
-
render
|
|
121
|
+
render Plutonium::Profile::SecuritySection.new
|
|
218
122
|
end
|
|
219
123
|
end
|
|
220
124
|
end
|
|
221
125
|
```
|
|
222
126
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
Add custom actions to the profile:
|
|
226
|
-
|
|
227
|
-
```ruby
|
|
228
|
-
class ProfileDefinition < Plutonium::Resource::Definition
|
|
229
|
-
action :export_data,
|
|
230
|
-
interaction: Profile::ExportDataInteraction,
|
|
231
|
-
icon: Phlex::TablerIcons::Download
|
|
232
|
-
|
|
233
|
-
action :verify_email,
|
|
234
|
-
interaction: Profile::VerifyEmailInteraction,
|
|
235
|
-
category: :secondary
|
|
236
|
-
end
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
### Profile Link in Navigation
|
|
240
|
-
|
|
241
|
-
Add a profile link to your application layout or header:
|
|
242
|
-
|
|
243
|
-
```ruby
|
|
244
|
-
# In your header component
|
|
245
|
-
if current_user && respond_to?(:profile_path)
|
|
246
|
-
a(href: profile_path) { "My Profile" }
|
|
247
|
-
end
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
## Policy Configuration
|
|
251
|
-
|
|
252
|
-
The generated policy controls access:
|
|
253
|
-
|
|
254
|
-
```ruby
|
|
255
|
-
# app/policies/profile_policy.rb
|
|
256
|
-
class ProfilePolicy < Plutonium::Resource::Policy
|
|
257
|
-
# Users can only access their own profile
|
|
258
|
-
def read?
|
|
259
|
-
resource.user == user
|
|
260
|
-
end
|
|
261
|
-
|
|
262
|
-
def update?
|
|
263
|
-
resource.user == user
|
|
264
|
-
end
|
|
265
|
-
|
|
266
|
-
def destroy?
|
|
267
|
-
false # Disable deletion through the UI
|
|
268
|
-
end
|
|
269
|
-
|
|
270
|
-
# Only allow editing these attributes
|
|
271
|
-
def permitted_attributes_for_update
|
|
272
|
-
[:bio, :avatar, :timezone, :notifications_enabled]
|
|
273
|
-
end
|
|
274
|
-
end
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
## Troubleshooting
|
|
278
|
-
|
|
279
|
-
### "Profile not found" Error
|
|
127
|
+
See [Reference › Resource › Definition](/reference/resource/definition) for the full definition surface.
|
|
280
128
|
|
|
281
|
-
|
|
129
|
+
## Multiple account types
|
|
282
130
|
|
|
283
|
-
|
|
131
|
+
If your app has both `User` and `StaffUser` accounts, run `pu:profile:install` once per:
|
|
284
132
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
# app/rodauth/user_rodauth_plugin.rb
|
|
289
|
-
class UserRodauthPlugin < Plutonium::Auth::RodauthPlugin
|
|
290
|
-
configure do
|
|
291
|
-
enable :change_password, :change_login, :otp, :active_sessions
|
|
292
|
-
# Only these features will show in the security section
|
|
293
|
-
end
|
|
294
|
-
end
|
|
133
|
+
```bash
|
|
134
|
+
rails g pu:profile:install --user-model=User --dest=main_app
|
|
135
|
+
rails g pu:profile:install --user-model=StaffUser --dest=main_app
|
|
295
136
|
```
|
|
296
137
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
Ensure you use `--singular` when connecting:
|
|
138
|
+
Each gets its own `*Profile` model with `:profile` association on the respective user. Connect each to the appropriate portal:
|
|
300
139
|
|
|
301
140
|
```bash
|
|
302
|
-
rails g pu:
|
|
141
|
+
rails g pu:profile:conn UserProfile --dest=customer_portal
|
|
142
|
+
rails g pu:profile:conn StaffUserProfile --dest=admin_portal
|
|
303
143
|
```
|
|
304
144
|
|
|
305
|
-
|
|
145
|
+
## Common issues
|
|
306
146
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
```ruby
|
|
312
|
-
def permitted_attributes_for_update
|
|
313
|
-
[:bio, :avatar, :timezone, :notifications_enabled]
|
|
314
|
-
end
|
|
315
|
-
```
|
|
147
|
+
- **`current_user.profile` is nil** — every user needs a profile row. Add `after_create :create_profile!` to the user model.
|
|
148
|
+
- **`profile_url` is undefined** — the profile isn't connected to this portal. Run `pu:profile:conn --dest=<portal>`.
|
|
149
|
+
- **`SecuritySection` shows nothing** — none of the relevant Rodauth features are enabled. Enable `change_password`, `otp`, etc. on the Rodauth plugin.
|
|
316
150
|
|
|
317
|
-
##
|
|
151
|
+
## Related
|
|
318
152
|
|
|
319
|
-
- [
|
|
320
|
-
- [
|
|
321
|
-
- [
|
|
322
|
-
- [Authorization](/guides/authorization) - Configure profile policies
|
|
153
|
+
- [Reference › Auth › Profile](/reference/auth/profile) — full surface
|
|
154
|
+
- [Reference › Auth › Accounts](/reference/auth/accounts) — Rodauth feature flags that gate SecuritySection
|
|
155
|
+
- [Authentication](./authentication) — the underlying auth setup
|
data/docs/index.md
CHANGED
|
@@ -68,7 +68,7 @@ rails g pu:res:conn Post \
|
|
|
68
68
|
<div class="ai-feature">
|
|
69
69
|
<div class="ai-icon">🧠</div>
|
|
70
70
|
<h3>Claude Code Skills</h3>
|
|
71
|
-
<p>
|
|
71
|
+
<p>Built-in skills teach AI assistants your app's patterns. Resources, policies, definitions, interactions — Claude understands them all.</p>
|
|
72
72
|
</div>
|
|
73
73
|
<div class="ai-feature">
|
|
74
74
|
<div class="ai-icon">⚡</div>
|