b4um_generators 0.3.0 → 0.4.2
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/.rubocop.yml +2 -2
- data/CHANGELOG.md +72 -0
- data/README.de.md +338 -4
- data/README.md +330 -5
- data/lib/b4um_generators/version.rb +1 -1
- data/lib/generators/b4um/admin/admin_generator.rb +725 -0
- data/lib/generators/b4um/admin/templates/add_admin_fields_migration.rb.tt +10 -0
- data/lib/generators/b4um/admin/templates/admin_base_controller.rb.tt +5 -0
- data/lib/generators/b4um/admin/templates/admin_dashboard.html.erb.tt +19 -0
- data/lib/generators/b4um/admin/templates/admin_dashboard_controller.rb.tt +6 -0
- data/lib/generators/b4um/admin/templates/admin_users_controller.rb.tt +70 -0
- data/lib/generators/b4um/admin/templates/admin_users_index.html.erb.tt +110 -0
- data/lib/generators/b4um/admin/templates/b4um_admin.rake.tt +106 -0
- data/lib/generators/b4um/authentication/authentication_generator.rb +436 -23
- data/lib/generators/b4um/comments/comments_generator.rb +39 -9
- data/lib/generators/b4um/guest/guest_generator.rb +673 -0
- data/lib/generators/b4um/guest/templates/add_guest_fields_migration.rb.tt +12 -0
- data/lib/generators/b4um/guest/templates/b4um_guests.rake.tt +12 -0
- data/lib/generators/b4um/guest/templates/edit.html.erb.tt +156 -0
- data/lib/generators/b4um/guest/templates/guest_expiration_warning.html.erb.tt +12 -0
- data/lib/generators/b4um/guest/templates/guests_controller.rb.tt +88 -0
- data/lib/generators/b4um/guest/templates/new.html.erb.tt +136 -0
- data/lib/generators/b4um/help/help_generator.rb +162 -0
- data/lib/generators/b4um/in_place/in_place_generator.rb +132 -7
- data/lib/generators/b4um/readable/readable_generator.rb +8 -5
- data/lib/generators/b4um/scaffold/scaffold_generator.rb +213 -73
- data/lib/generators/b4um/scaffold/templates/_form.html.erb.tt +18 -14
- data/lib/generators/b4um/sortable/sortable_generator.rb +104 -36
- metadata +16 -1
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
<div class="page-header">
|
|
2
|
+
<h1>Create your account</h1>
|
|
3
|
+
</div>
|
|
4
|
+
|
|
5
|
+
<div class="b4um-grid">
|
|
6
|
+
<section class="b4um-card b4um-card--full">
|
|
7
|
+
<%%= form_with model: @<%= authentication_model_name %>,
|
|
8
|
+
url: convert_guest_path,
|
|
9
|
+
method: :patch,
|
|
10
|
+
class: "form" do |form| %>
|
|
11
|
+
<%% if @<%= authentication_model_name %>.errors.any? %>
|
|
12
|
+
<div class="error-messages">
|
|
13
|
+
<h2>
|
|
14
|
+
<%%= pluralize(@<%= authentication_model_name %>.errors.count, "error") %>
|
|
15
|
+
prohibited this account from being saved:
|
|
16
|
+
</h2>
|
|
17
|
+
|
|
18
|
+
<ul>
|
|
19
|
+
<%% @<%= authentication_model_name %>.errors.each do |error| %>
|
|
20
|
+
<li><%%= error.full_message %></li>
|
|
21
|
+
<%% end %>
|
|
22
|
+
</ul>
|
|
23
|
+
</div>
|
|
24
|
+
<%% end %>
|
|
25
|
+
|
|
26
|
+
<% guest_available_fields.each do |field| -%>
|
|
27
|
+
<% field_type = guest_field_type(field) -%>
|
|
28
|
+
<% required = account_required_fields.include?(field) -%>
|
|
29
|
+
<% label = field.humanize + (required ? " *" : "") -%>
|
|
30
|
+
<% if field.match?(/(?:^|_)email(?:_|$)/) -%>
|
|
31
|
+
<div class="form-field">
|
|
32
|
+
<%%= form.email_field :<%= field %>,
|
|
33
|
+
class: "form-input",
|
|
34
|
+
placeholder: " ",
|
|
35
|
+
required: <%= required %> %>
|
|
36
|
+
<%%= form.label :<%= field %>, "<%= label %>", class: "form-label" %>
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
<% elsif field.match?(/(?:^|_)(?:phone|telephone|mobile)(?:_|$)/) -%>
|
|
40
|
+
<div class="form-field">
|
|
41
|
+
<%%= form.telephone_field :<%= field %>,
|
|
42
|
+
class: "form-input",
|
|
43
|
+
placeholder: " ",
|
|
44
|
+
required: <%= required %> %>
|
|
45
|
+
<%%= form.label :<%= field %>, "<%= label %>", class: "form-label" %>
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
<% elsif field.match?(/(?:^|_)(?:url|website|homepage)(?:_|$)/) -%>
|
|
49
|
+
<div class="form-field">
|
|
50
|
+
<%%= form.url_field :<%= field %>,
|
|
51
|
+
class: "form-input",
|
|
52
|
+
placeholder: " ",
|
|
53
|
+
required: <%= required %> %>
|
|
54
|
+
<%%= form.label :<%= field %>, "<%= label %>", class: "form-label" %>
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<% elsif field_type == :boolean -%>
|
|
58
|
+
<div class="form-field form-field--checkbox">
|
|
59
|
+
<%%= form.check_box :<%= field %>,
|
|
60
|
+
class: "form-checkbox",
|
|
61
|
+
required: <%= required %> %>
|
|
62
|
+
<%%= form.label :<%= field %>, "<%= label %>",
|
|
63
|
+
class: "form-label form-label--checkbox" %>
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
<% elsif field_type == :text -%>
|
|
67
|
+
<div class="form-field form-field--textarea">
|
|
68
|
+
<%%= form.text_area :<%= field %>,
|
|
69
|
+
class: "form-textarea",
|
|
70
|
+
placeholder: " ",
|
|
71
|
+
required: <%= required %> %>
|
|
72
|
+
<%%= form.label :<%= field %>, "<%= label %>", class: "form-label" %>
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
<% elsif field_type == :integer -%>
|
|
76
|
+
<div class="form-field">
|
|
77
|
+
<%%= form.number_field :<%= field %>,
|
|
78
|
+
class: "form-input",
|
|
79
|
+
placeholder: " ",
|
|
80
|
+
step: 1,
|
|
81
|
+
required: <%= required %> %>
|
|
82
|
+
<%%= form.label :<%= field %>, "<%= label %>", class: "form-label" %>
|
|
83
|
+
</div>
|
|
84
|
+
|
|
85
|
+
<% elsif [:float, :decimal].include?(field_type) -%>
|
|
86
|
+
<div class="form-field">
|
|
87
|
+
<%%= form.number_field :<%= field %>,
|
|
88
|
+
class: "form-input",
|
|
89
|
+
placeholder: " ",
|
|
90
|
+
step: "any",
|
|
91
|
+
required: <%= required %> %>
|
|
92
|
+
<%%= form.label :<%= field %>, "<%= label %>", class: "form-label" %>
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
<% elsif field_type == :date -%>
|
|
96
|
+
<div class="form-field">
|
|
97
|
+
<%%= form.date_field :<%= field %>,
|
|
98
|
+
class: "form-input",
|
|
99
|
+
required: <%= required %> %>
|
|
100
|
+
<%%= form.label :<%= field %>, "<%= label %>", class: "form-label" %>
|
|
101
|
+
</div>
|
|
102
|
+
|
|
103
|
+
<% elsif [:datetime, :timestamp].include?(field_type) -%>
|
|
104
|
+
<div class="form-field">
|
|
105
|
+
<%%= form.datetime_local_field :<%= field %>,
|
|
106
|
+
class: "form-input",
|
|
107
|
+
required: <%= required %> %>
|
|
108
|
+
<%%= form.label :<%= field %>, "<%= label %>", class: "form-label" %>
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
<% elsif field_type == :time -%>
|
|
112
|
+
<div class="form-field">
|
|
113
|
+
<%%= form.time_field :<%= field %>,
|
|
114
|
+
class: "form-input",
|
|
115
|
+
required: <%= required %> %>
|
|
116
|
+
<%%= form.label :<%= field %>, "<%= label %>", class: "form-label" %>
|
|
117
|
+
</div>
|
|
118
|
+
|
|
119
|
+
<% else -%>
|
|
120
|
+
<div class="form-field">
|
|
121
|
+
<%%= form.text_field :<%= field %>,
|
|
122
|
+
class: "form-input",
|
|
123
|
+
placeholder: " ",
|
|
124
|
+
required: <%= required %> %>
|
|
125
|
+
<%%= form.label :<%= field %>, "<%= label %>", class: "form-label" %>
|
|
126
|
+
</div>
|
|
127
|
+
|
|
128
|
+
<% end -%>
|
|
129
|
+
<% end -%>
|
|
130
|
+
|
|
131
|
+
<div class="form-field">
|
|
132
|
+
<%%= form.password_field :password,
|
|
133
|
+
class: "form-input",
|
|
134
|
+
placeholder: " ",
|
|
135
|
+
required: true,
|
|
136
|
+
autocomplete: "new-password" %>
|
|
137
|
+
<%%= form.label :password, "Password *", class: "form-label" %>
|
|
138
|
+
</div>
|
|
139
|
+
|
|
140
|
+
<div class="form-field">
|
|
141
|
+
<%%= form.password_field :password_confirmation,
|
|
142
|
+
class: "form-input",
|
|
143
|
+
placeholder: " ",
|
|
144
|
+
required: true,
|
|
145
|
+
autocomplete: "new-password" %>
|
|
146
|
+
<%%= form.label :password_confirmation,
|
|
147
|
+
"Password confirmation *",
|
|
148
|
+
class: "form-label" %>
|
|
149
|
+
</div>
|
|
150
|
+
|
|
151
|
+
<div class="form-actions">
|
|
152
|
+
<%%= form.submit "Create account", class: "form-submit" %>
|
|
153
|
+
</div>
|
|
154
|
+
<%% end %>
|
|
155
|
+
</section>
|
|
156
|
+
</div>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<%% if guest_expiring_soon? %>
|
|
2
|
+
<div class="flash flash--alert">
|
|
3
|
+
<span>Your guest access expires soon.</span>
|
|
4
|
+
|
|
5
|
+
<%%= link_to "Create account", convert_guest_path %>
|
|
6
|
+
|
|
7
|
+
<%%= button_to "Delete guest account",
|
|
8
|
+
guest_path,
|
|
9
|
+
method: :delete,
|
|
10
|
+
data: { turbo_confirm: "Delete your guest account?" } %>
|
|
11
|
+
</div>
|
|
12
|
+
<%% end %>
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
require "securerandom"
|
|
2
|
+
|
|
3
|
+
class GuestsController < ApplicationController
|
|
4
|
+
before_action :require_guest, only: %i[edit update destroy]
|
|
5
|
+
before_action :require_logged_out, only: %i[new create]
|
|
6
|
+
|
|
7
|
+
def new
|
|
8
|
+
@<%= authentication_model_name %> = <%= authentication_class_name %>.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def create
|
|
12
|
+
@<%= authentication_model_name %> = <%= authentication_class_name %>.new(guest_params)
|
|
13
|
+
@<%= authentication_model_name %>.guest = true
|
|
14
|
+
@<%= authentication_model_name %>.guest_expires_at = <%= options[:expires_in].to_i %>.days.from_now
|
|
15
|
+
|
|
16
|
+
guest_password = SecureRandom.base64(32)
|
|
17
|
+
@<%= authentication_model_name %>.password = guest_password
|
|
18
|
+
@<%= authentication_model_name %>.password_confirmation = guest_password
|
|
19
|
+
|
|
20
|
+
if @<%= authentication_model_name %>.save
|
|
21
|
+
session[:<%= authentication_model_name %>_id] = @<%= authentication_model_name %>.id
|
|
22
|
+
redirect_to root_path
|
|
23
|
+
else
|
|
24
|
+
render :new, status: :unprocessable_content
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def edit
|
|
29
|
+
@<%= authentication_model_name %> = <%= current_authentication_method %>
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def update
|
|
33
|
+
@<%= authentication_model_name %> = <%= current_authentication_method %>
|
|
34
|
+
|
|
35
|
+
if conversion_params[:password].blank?
|
|
36
|
+
@<%= authentication_model_name %>.errors.add(:password, "can't be blank")
|
|
37
|
+
render :edit, status: :unprocessable_content
|
|
38
|
+
return
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
guest_expires_at = @<%= authentication_model_name %>.guest_expires_at
|
|
42
|
+
|
|
43
|
+
@<%= authentication_model_name %>.assign_attributes(conversion_params)
|
|
44
|
+
@<%= authentication_model_name %>.guest = false
|
|
45
|
+
@<%= authentication_model_name %>.guest_expires_at = nil
|
|
46
|
+
|
|
47
|
+
if @<%= authentication_model_name %>.save
|
|
48
|
+
redirect_to root_path
|
|
49
|
+
else
|
|
50
|
+
@<%= authentication_model_name %>.guest = true
|
|
51
|
+
@<%= authentication_model_name %>.guest_expires_at = guest_expires_at
|
|
52
|
+
render :edit, status: :unprocessable_content
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def destroy
|
|
57
|
+
@<%= authentication_model_name %> = <%= current_authentication_method %>
|
|
58
|
+
|
|
59
|
+
session.delete(:<%= authentication_model_name %>_id)
|
|
60
|
+
@<%= authentication_model_name %>.destroy!
|
|
61
|
+
|
|
62
|
+
redirect_to root_path
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def guest_params
|
|
68
|
+
params.require(:guest).permit(<%= guest_available_fields.map { |field| ":#{field}" }.join(", ") %>)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def conversion_params
|
|
72
|
+
params.require(:<%= authentication_model_name %>).permit(
|
|
73
|
+
<%= (guest_available_fields + %w[password password_confirmation]).map { |field| ":#{field}" }.join(", ") %>
|
|
74
|
+
)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def require_guest
|
|
78
|
+
return if <%= current_authentication_method %>&.guest?
|
|
79
|
+
|
|
80
|
+
redirect_to root_path, alert: "Guest access required."
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def require_logged_out
|
|
84
|
+
return unless <%= current_authentication_method %>
|
|
85
|
+
|
|
86
|
+
redirect_to root_path, alert: "You are already logged in."
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
<div class="page-header">
|
|
2
|
+
<h1>Guest access</h1>
|
|
3
|
+
</div>
|
|
4
|
+
|
|
5
|
+
<div class="b4um-grid">
|
|
6
|
+
<section class="b4um-card b4um-card--full">
|
|
7
|
+
<%%= form_with model: @<%= authentication_model_name %>,
|
|
8
|
+
url: guest_path,
|
|
9
|
+
scope: :guest,
|
|
10
|
+
class: "form" do |form| %>
|
|
11
|
+
<%% if @<%= authentication_model_name %>.errors.any? %>
|
|
12
|
+
<div class="error-messages">
|
|
13
|
+
<h2>
|
|
14
|
+
<%%= pluralize(@<%= authentication_model_name %>.errors.count, "error") %>
|
|
15
|
+
prohibited this guest from being saved:
|
|
16
|
+
</h2>
|
|
17
|
+
|
|
18
|
+
<ul>
|
|
19
|
+
<%% @<%= authentication_model_name %>.errors.each do |error| %>
|
|
20
|
+
<li><%%= error.full_message %></li>
|
|
21
|
+
<%% end %>
|
|
22
|
+
</ul>
|
|
23
|
+
</div>
|
|
24
|
+
<%% end %>
|
|
25
|
+
|
|
26
|
+
<% guest_available_fields.each do |field| -%>
|
|
27
|
+
<% field_type = guest_field_type(field) -%>
|
|
28
|
+
<% required = guest_required_fields.include?(field) -%>
|
|
29
|
+
<% label = field.humanize + (required ? " *" : "") -%>
|
|
30
|
+
<% if field.match?(/(?:^|_)email(?:_|$)/) -%>
|
|
31
|
+
<div class="form-field">
|
|
32
|
+
<%%= form.email_field :<%= field %>,
|
|
33
|
+
class: "form-input",
|
|
34
|
+
placeholder: " ",
|
|
35
|
+
required: <%= required %> %>
|
|
36
|
+
<%%= form.label :<%= field %>, "<%= label %>", class: "form-label" %>
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
<% elsif field.match?(/(?:^|_)(?:phone|telephone|mobile)(?:_|$)/) -%>
|
|
40
|
+
<div class="form-field">
|
|
41
|
+
<%%= form.telephone_field :<%= field %>,
|
|
42
|
+
class: "form-input",
|
|
43
|
+
placeholder: " ",
|
|
44
|
+
required: <%= required %> %>
|
|
45
|
+
<%%= form.label :<%= field %>, "<%= label %>", class: "form-label" %>
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
<% elsif field.match?(/(?:^|_)(?:url|website|homepage)(?:_|$)/) -%>
|
|
49
|
+
<div class="form-field">
|
|
50
|
+
<%%= form.url_field :<%= field %>,
|
|
51
|
+
class: "form-input",
|
|
52
|
+
placeholder: " ",
|
|
53
|
+
required: <%= required %> %>
|
|
54
|
+
<%%= form.label :<%= field %>, "<%= label %>", class: "form-label" %>
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<% elsif field_type == :boolean -%>
|
|
58
|
+
<div class="form-field form-field--checkbox">
|
|
59
|
+
<%%= form.check_box :<%= field %>,
|
|
60
|
+
class: "form-checkbox",
|
|
61
|
+
required: <%= required %> %>
|
|
62
|
+
<%%= form.label :<%= field %>, "<%= label %>",
|
|
63
|
+
class: "form-label form-label--checkbox" %>
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
<% elsif field_type == :text -%>
|
|
67
|
+
<div class="form-field form-field--textarea">
|
|
68
|
+
<%%= form.text_area :<%= field %>,
|
|
69
|
+
class: "form-textarea",
|
|
70
|
+
placeholder: " ",
|
|
71
|
+
required: <%= required %> %>
|
|
72
|
+
<%%= form.label :<%= field %>, "<%= label %>", class: "form-label" %>
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
<% elsif field_type == :integer -%>
|
|
76
|
+
<div class="form-field">
|
|
77
|
+
<%%= form.number_field :<%= field %>,
|
|
78
|
+
class: "form-input",
|
|
79
|
+
placeholder: " ",
|
|
80
|
+
step: 1,
|
|
81
|
+
required: <%= required %> %>
|
|
82
|
+
<%%= form.label :<%= field %>, "<%= label %>", class: "form-label" %>
|
|
83
|
+
</div>
|
|
84
|
+
|
|
85
|
+
<% elsif [:float, :decimal].include?(field_type) -%>
|
|
86
|
+
<div class="form-field">
|
|
87
|
+
<%%= form.number_field :<%= field %>,
|
|
88
|
+
class: "form-input",
|
|
89
|
+
placeholder: " ",
|
|
90
|
+
step: "any",
|
|
91
|
+
required: <%= required %> %>
|
|
92
|
+
<%%= form.label :<%= field %>, "<%= label %>", class: "form-label" %>
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
<% elsif field_type == :date -%>
|
|
96
|
+
<div class="form-field">
|
|
97
|
+
<%%= form.date_field :<%= field %>,
|
|
98
|
+
class: "form-input",
|
|
99
|
+
required: <%= required %> %>
|
|
100
|
+
<%%= form.label :<%= field %>, "<%= label %>", class: "form-label" %>
|
|
101
|
+
</div>
|
|
102
|
+
|
|
103
|
+
<% elsif [:datetime, :timestamp].include?(field_type) -%>
|
|
104
|
+
<div class="form-field">
|
|
105
|
+
<%%= form.datetime_local_field :<%= field %>,
|
|
106
|
+
class: "form-input",
|
|
107
|
+
required: <%= required %> %>
|
|
108
|
+
<%%= form.label :<%= field %>, "<%= label %>", class: "form-label" %>
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
<% elsif field_type == :time -%>
|
|
112
|
+
<div class="form-field">
|
|
113
|
+
<%%= form.time_field :<%= field %>,
|
|
114
|
+
class: "form-input",
|
|
115
|
+
required: <%= required %> %>
|
|
116
|
+
<%%= form.label :<%= field %>, "<%= label %>", class: "form-label" %>
|
|
117
|
+
</div>
|
|
118
|
+
|
|
119
|
+
<% else -%>
|
|
120
|
+
<div class="form-field">
|
|
121
|
+
<%%= form.text_field :<%= field %>,
|
|
122
|
+
class: "form-input",
|
|
123
|
+
placeholder: " ",
|
|
124
|
+
required: <%= required %> %>
|
|
125
|
+
<%%= form.label :<%= field %>, "<%= label %>", class: "form-label" %>
|
|
126
|
+
</div>
|
|
127
|
+
|
|
128
|
+
<% end -%>
|
|
129
|
+
<% end -%>
|
|
130
|
+
|
|
131
|
+
<div class="form-actions">
|
|
132
|
+
<%%= form.submit "Continue as guest", class: "form-submit" %>
|
|
133
|
+
</div>
|
|
134
|
+
<%% end %>
|
|
135
|
+
</section>
|
|
136
|
+
</div>
|
|
@@ -362,6 +362,7 @@ module B4um
|
|
|
362
362
|
- b4um index, show, new and edit views
|
|
363
363
|
- Bento index layout by default
|
|
364
364
|
- Optional table index layout
|
|
365
|
+
- Required fields with presence validation
|
|
365
366
|
- Select fields with custom labels
|
|
366
367
|
- Radio fields with custom labels
|
|
367
368
|
- Automatic navigation entry
|
|
@@ -371,6 +372,19 @@ module B4um
|
|
|
371
372
|
- Password field support
|
|
372
373
|
- Optional readable URL parameters
|
|
373
374
|
|
|
375
|
+
Required fields can be generated with:
|
|
376
|
+
|
|
377
|
+
--required=FIELD,FIELD
|
|
378
|
+
|
|
379
|
+
Example:
|
|
380
|
+
|
|
381
|
+
bin/rails generate b4um:scaffold Customer first_name:string last_name:string company:string email:string --required=first_name,last_name,email
|
|
382
|
+
|
|
383
|
+
This adds a presence validation for the selected fields
|
|
384
|
+
to the generated model.
|
|
385
|
+
|
|
386
|
+
Fields not listed in --required remain optional.
|
|
387
|
+
|
|
374
388
|
Select fields can be generated with:
|
|
375
389
|
|
|
376
390
|
--select='FIELD:VALUE=LABEL,VALUE=LABEL'
|
|
@@ -597,6 +611,154 @@ module B4um
|
|
|
597
611
|
helpers, routes or navigation controls.
|
|
598
612
|
|
|
599
613
|
|
|
614
|
+
ADMIN
|
|
615
|
+
|
|
616
|
+
bin/rails generate b4um:admin MODEL
|
|
617
|
+
|
|
618
|
+
Adds administrator user management to an existing
|
|
619
|
+
b4um authentication model.
|
|
620
|
+
|
|
621
|
+
Example:
|
|
622
|
+
|
|
623
|
+
bin/rails generate b4um:admin User
|
|
624
|
+
bin/rails db:migrate
|
|
625
|
+
|
|
626
|
+
The admin generator requires b4um authentication to be
|
|
627
|
+
installed for the selected model first.
|
|
628
|
+
|
|
629
|
+
Example setup:
|
|
630
|
+
|
|
631
|
+
bin/rails generate b4um:scaffold User name:string email:string password_digest:string
|
|
632
|
+
bin/rails generate b4um:authentication User
|
|
633
|
+
bin/rails generate b4um:admin User
|
|
634
|
+
bin/rails db:migrate
|
|
635
|
+
|
|
636
|
+
The generator adds two fields to the authentication model:
|
|
637
|
+
|
|
638
|
+
admin
|
|
639
|
+
blocked
|
|
640
|
+
|
|
641
|
+
Both fields are boolean values and default to false.
|
|
642
|
+
|
|
643
|
+
The generator also adds:
|
|
644
|
+
|
|
645
|
+
- Admin dashboard
|
|
646
|
+
- User management
|
|
647
|
+
- Admin-only controller protection
|
|
648
|
+
- Administrator routes
|
|
649
|
+
- Blocking and unblocking users
|
|
650
|
+
- Granting and revoking administrator rights
|
|
651
|
+
- Deleting users
|
|
652
|
+
- Protection against blocking your own account
|
|
653
|
+
- Protection against deleting your own account
|
|
654
|
+
- Protection against removing the last administrator
|
|
655
|
+
- Blocked session invalidation
|
|
656
|
+
- Blocked login prevention
|
|
657
|
+
|
|
658
|
+
The admin area is available at:
|
|
659
|
+
|
|
660
|
+
/admin
|
|
661
|
+
|
|
662
|
+
Only logged-in users with administrator rights can access
|
|
663
|
+
the admin area.
|
|
664
|
+
|
|
665
|
+
The first administrator is created from the command line.
|
|
666
|
+
This prevents public registration from granting administrator
|
|
667
|
+
rights.
|
|
668
|
+
|
|
669
|
+
Run:
|
|
670
|
+
|
|
671
|
+
bin/rails b4um:admin:create
|
|
672
|
+
|
|
673
|
+
Run bin/rails db:migrate before creating the first administrator.
|
|
674
|
+
|
|
675
|
+
The task asks for the authentication model fields automatically.
|
|
676
|
+
|
|
677
|
+
Additional authentication model fields are requested automatically.
|
|
678
|
+
Fields with an unconditional presence validation are marked with * and are required.
|
|
679
|
+
Optional fields can be left empty.
|
|
680
|
+
|
|
681
|
+
Email, password and password confirmation are always required.
|
|
682
|
+
|
|
683
|
+
The password is not displayed while it is entered.
|
|
684
|
+
|
|
685
|
+
Existing users cannot be converted to administrators with
|
|
686
|
+
this task. Administrator rights for existing users are
|
|
687
|
+
managed from the admin user management interface.
|
|
688
|
+
|
|
689
|
+
From the admin user management interface, administrators can:
|
|
690
|
+
|
|
691
|
+
- Block a user
|
|
692
|
+
- Unblock a user
|
|
693
|
+
- Grant administrator rights
|
|
694
|
+
- Revoke administrator rights
|
|
695
|
+
- Delete a user
|
|
696
|
+
|
|
697
|
+
A blocked user cannot log in. If a logged-in user becomes
|
|
698
|
+
blocked, the existing session is invalidated.
|
|
699
|
+
|
|
700
|
+
Administrators cannot block or delete their own account
|
|
701
|
+
through the generated user management interface.
|
|
702
|
+
|
|
703
|
+
The last administrator cannot lose administrator rights.
|
|
704
|
+
|
|
705
|
+
|
|
706
|
+
GUEST
|
|
707
|
+
|
|
708
|
+
bin/rails generate b4um:guest MODEL --required=FIELDS
|
|
709
|
+
|
|
710
|
+
Adds temporary guest access to an existing
|
|
711
|
+
b4um authentication model.
|
|
712
|
+
|
|
713
|
+
Example:
|
|
714
|
+
|
|
715
|
+
bin/rails generate b4um:guest User --required=first_name,email
|
|
716
|
+
bin/rails db:migrate
|
|
717
|
+
|
|
718
|
+
The guest generator requires b4um authentication to be
|
|
719
|
+
installed for the selected model first.
|
|
720
|
+
|
|
721
|
+
At least one field must be supplied with --required.
|
|
722
|
+
These fields are required when creating a guest account.
|
|
723
|
+
|
|
724
|
+
Additional suitable model fields are offered automatically
|
|
725
|
+
and remain optional unless included in --required.
|
|
726
|
+
|
|
727
|
+
The generator adds two fields to the authentication model:
|
|
728
|
+
|
|
729
|
+
guest
|
|
730
|
+
guest_expires_at
|
|
731
|
+
|
|
732
|
+
Guest accounts use the same authentication model as regular
|
|
733
|
+
accounts. No separate guest model is created.
|
|
734
|
+
|
|
735
|
+
Guest accounts receive an internal password automatically.
|
|
736
|
+
The guest does not need to choose or enter this password.
|
|
737
|
+
|
|
738
|
+
By default, guest access expires after 7 days.
|
|
739
|
+
|
|
740
|
+
A different lifetime can be configured with --expires-in:
|
|
741
|
+
|
|
742
|
+
bin/rails generate b4um:guest User --required=first_name,email --expires-in=14
|
|
743
|
+
|
|
744
|
+
Guest accounts can be converted into regular accounts.
|
|
745
|
+
The existing record is retained so existing account data
|
|
746
|
+
remains associated with the user.
|
|
747
|
+
|
|
748
|
+
During conversion, missing required account fields and a
|
|
749
|
+
password are requested.
|
|
750
|
+
|
|
751
|
+
Guest accounts approaching expiration receive a warning.
|
|
752
|
+
Expired guest accounts can be removed with:
|
|
753
|
+
|
|
754
|
+
bin/rails b4um:guests:cleanup
|
|
755
|
+
|
|
756
|
+
Run the cleanup task regularly in production to remove
|
|
757
|
+
expired guest accounts.
|
|
758
|
+
|
|
759
|
+
Run bin/rails db:migrate after installing guest access.
|
|
760
|
+
|
|
761
|
+
|
|
600
762
|
ACTIVE STORAGE / IMAGES
|
|
601
763
|
|
|
602
764
|
Image attachments require Active Storage.
|