brut 0.0.24 → 0.0.26

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 66debd5e3492d152f6e1284b9d207c288b8ae4369a632a2d66c4a9c79cb32c35
4
- data.tar.gz: 9587bfb3d5baac04b9add2fac1d5da24db0230c985162fde5216f56212d7880c
3
+ metadata.gz: 327b83333a37823010e1d2763646d56bd503d505d6c965ddc5d0d8098ecd9299
4
+ data.tar.gz: d12d8d46f6e459d97f3489218302da647e073ac4d8e48cf57cd1d1fee998c6a1
5
5
  SHA512:
6
- metadata.gz: c977cb67e52844a531a0f865a82766fe651d3a310c8875d2e7c5206a1d07443152560323c46b2be42e93284e5d07dc05c44421cf223afd7143c6456f72f03999
7
- data.tar.gz: 86e156145eac29a767b934da1ca0d4f6020971c100ed122963492567788d7ccf82ec9534b570871784abc893d1e98bd5795cd296dd3a3a102eec5e3b6fe11ed2
6
+ metadata.gz: a55e3607d5d127e74f93864f6dc19fad6dc2a0631e56559cf92df4b5762771d82d5bc0c5a2d289d6948a0899568e0138e503fea98f91d42007cefb9b3e83482b
7
+ data.tar.gz: e901897e8d8eb2a2ef08bc4e5efacc0c3a13f6981f8523a2e0db3ade740f648923ecb29e9634ea133dd16efccedeecb0b9ec06f820c0b4d77b7f34068f96d540
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- brut (0.0.24)
4
+ brut (0.0.26)
5
5
  concurrent-ruby
6
6
  i18n
7
7
  irb
@@ -83,13 +83,25 @@ export default defineConfig({
83
83
  },
84
84
  {
85
85
  text: "Advanced Topics",
86
- collapsed: false,
86
+ collapsed: true,
87
87
  items: [
88
88
  { text: "Route Hooks", link: "/hooks" },
89
89
  { text: "Middleware", link: "/middleware" },
90
90
  { text: "Instrumentation", link: "/instrumentation" },
91
91
  { text: "Security", link: "/security" },
92
92
  ],
93
+ },
94
+ {
95
+ text: "Recipes",
96
+ collapsed: true,
97
+ items: [
98
+ { text: "Authentication", link: "/recipes/authentication" },
99
+ { text: "Form Validations", link: "/recipes/form-validations" },
100
+ { text: "Database Migrations", link: "/recipes/database-migrations" },
101
+ { text: "Ajax Form Submission", link: "/recipes/ajax-form" },
102
+ { text: "Custom Telemetry", link: "/recipes/telemetry" },
103
+ { text: "CLI App/Task", link: "/recipes/cli-app" },
104
+ ],
93
105
  }
94
106
  ],
95
107
 
@@ -0,0 +1,26 @@
1
+ # Authentication Example
2
+
3
+ It's impossible to account for all types of authentication you may want to use, but
4
+ this recipe will demonstrate all the moving parts:
5
+
6
+ * How to require authentication for some pages
7
+ * How to design pages that require authentication
8
+ * How to manage the signed-in user in code
9
+
10
+ ## Feature Description
11
+
12
+ * Visitors can sign up for an account with an email and password
13
+ * Visitors can log in with their email and password
14
+ * Visitors cannot access the home page without logging in
15
+ * Visitors can access the about page without logging in
16
+
17
+ ## Recipe
18
+
19
+ First, we'll make a database table called `accounts` that will have an email field
20
+ and a password hash field.
21
+
22
+ ```
23
+ bin/db new-migration accounts
24
+ ```
25
+
26
+ This will create a file in `app/src/back_end/data_models/migrations`
@@ -170,6 +170,9 @@ class Brut::CLI::Apps::DB < Brut::CLI::App
170
170
  if !migrations_dir.exist?
171
171
  err.puts "#{migrations_dir} doesn't exist"
172
172
  return
173
+ elsif Dir[migrations_dir / "*.rb"].empty?
174
+ out.puts "No migrations yet"
175
+ return
173
176
  end
174
177
  Brut.container.sequel_db_handle.extension :pg_array
175
178
 
@@ -4,16 +4,24 @@ class Brut::FrontEnd::Components::FormTag < Brut::FrontEnd::Component
4
4
  # If the form's action is GET, it will not.
5
5
  #
6
6
  # @example Route without parameters
7
- # <%= form_tag(for: NewWidgetForm, class: "new-form") do %>
8
- # <input type="text" name="name">
9
- # <button>Create</button>
10
- # <% end %>
7
+ # # assumes you have included Brut::FrontEnd::Components
8
+ # def view_template
9
+ # FormTag(for: NewWidgetForm, class: "new-form") do
10
+ # input(type: "text", name: "name")
11
+ # button { "Create" }
12
+ # end
13
+ # end
11
14
  #
12
15
  # @example Route with parameters
13
- # <%= form_tag(for: SaveWidgetWithIdForm, route_params: { id: widget.external_id }, class: "new-form") do %>
14
- # <input type="text" name="name">
15
- # <button>Save</button>
16
- # <% end %>
16
+ # # assumes you have included Brut::FrontEnd::Components
17
+ # def view_template
18
+ # FormTag(for: SaveWidgetWithIdForm,
19
+ # route_params: { id: widget.external_id },
20
+ # class: "new-form") do
21
+ # input(type: "text", name: "name")
22
+ # button { "Save" }
23
+ # end
24
+ # end
17
25
  #
18
26
  # @param route_params [Hash] if the form requires route parameters, their values must be passed here so that the HTML `action`
19
27
  # attribute can be constructed properly.
@@ -1,5 +1,7 @@
1
- # Generates an HTML `<input>` field.
1
+ # Generates an HTML `<input>` field based on a form input.
2
2
  class Brut::FrontEnd::Components::Inputs::InputTag < Brut::FrontEnd::Components::Input
3
+ def invalid? = @attributes["data-invalid"] == true
4
+
3
5
  # Creates the appropriate input for the given {Brut::FrontEnd::Form} and input name.
4
6
  # Generally, you want to use this method over the initializer.
5
7
  #
@@ -7,7 +9,7 @@ class Brut::FrontEnd::Components::Inputs::InputTag < Brut::FrontEnd::Components:
7
9
  # @param [String] input_name the name of the input, which should be a member of `form`
8
10
  # @param [Integer] index if this input is part of an array, this is the index into that array. This is used to get the input's value.
9
11
  # @param [Hash] html_attributes any additional HTML attributes to include on the `<input>` element.
10
- def self.for_form_input(form:, input_name:, index: nil, **html_attributes)
12
+ def initialize(form:, input_name:, index: nil, **html_attributes)
11
13
  input = form.input(input_name, index:)
12
14
  default_html_attributes = {}
13
15
  html_attributes = html_attributes.map { |key,value| [ key.to_sym, value ] }.to_h
@@ -49,16 +51,7 @@ class Brut::FrontEnd::Components::Inputs::InputTag < Brut::FrontEnd::Components:
49
51
  default_html_attributes["data-#{constraint}"] = true
50
52
  end
51
53
  end
52
- Brut::FrontEnd::Components::Inputs::InputTag.new(default_html_attributes.merge(html_attributes))
53
- end
54
-
55
- def invalid? = @attributes["data-invalid"] == true
56
-
57
- # Create an instance
58
- #
59
- # @param [Hash] attributes HTML attributes to put on the element.
60
- def initialize(attributes)
61
- @attributes = attributes
54
+ @attributes = default_html_attributes.merge(html_attributes)
62
55
  end
63
56
 
64
57
  def view_template
@@ -12,14 +12,18 @@ class Brut::FrontEnd::Components::Inputs::RadioButton < Brut::FrontEnd::Componen
12
12
  # @param [String] value the value for this radio button. The {Brut::FrontEnd::Forms::RadioButtonGroupInput} value is compared
13
13
  # against this value to determine if this `<input>` will have the `checked` attribute.
14
14
  # @param [Hash] html_attributes any additional HTML attributes to include on the `<input>` element.
15
- def self.for_form_input(form:, input_name:, value:, html_attributes: {})
15
+ def initialize(form:, input_name:, value:, html_attributes: {})
16
+ input = form.input(input_name)
16
17
  default_html_attributes = {}
17
18
  html_attributes = html_attributes.map { |key,value| [ key.to_sym, value ] }.to_h
18
- input = form.input(input_name)
19
19
 
20
20
  default_html_attributes[:required] = input.required
21
21
  default_html_attributes[:type] = "radio"
22
- default_html_attributes[:name] = input.name
22
+ default_html_attributes[:name] = if input.array?
23
+ "#{input.name}[]"
24
+ else
25
+ input.name
26
+ end
23
27
  default_html_attributes[:value] = value
24
28
 
25
29
  selected_value = input.value
@@ -36,6 +40,6 @@ class Brut::FrontEnd::Components::Inputs::RadioButton < Brut::FrontEnd::Componen
36
40
  end
37
41
  end
38
42
  end
39
- Brut::FrontEnd::Components::Inputs::RadioButton.new(default_html_attributes.merge(html_attributes))
43
+ @attributes = default_html_attributes.merge(html_attributes)
40
44
  end
41
45
  end
@@ -1,5 +1,6 @@
1
- # Generates an HTML `<textarea>` field.
1
+ # Generates an HTML `<textarea>` field based on a form input.
2
2
  class Brut::FrontEnd::Components::Inputs::TextareaTag < Brut::FrontEnd::Components::Input
3
+
3
4
  # Creates the appropriate textarea for the given {Brut::FrontEnd::Form} and input name.
4
5
  # Generally, you want to use this method over the initializer.
5
6
  #
@@ -7,7 +8,7 @@ class Brut::FrontEnd::Components::Inputs::TextareaTag < Brut::FrontEnd::Componen
7
8
  # @param [String] input_name the name of the input, which should be a member of `form`
8
9
  # @param [Integer] index if this input is part of an array, this is the index into that array. This is used to get the input's value.
9
10
  # @param [Hash] html_attributes any additional HTML attributes to include on the `<textarea>` element.
10
- def self.for_form_input(form:, input_name:, index: nil, html_attributes: {})
11
+ def initialize(form:, input_name:, index: nil, **html_attributes)
11
12
  html_attributes = html_attributes.map { |key,value| [ key.to_sym, value ] }.to_h
12
13
  default_html_attributes = {}
13
14
 
@@ -34,16 +35,8 @@ class Brut::FrontEnd::Components::Inputs::TextareaTag < Brut::FrontEnd::Componen
34
35
  end
35
36
  end
36
37
  end
37
- value = input.value
38
- Brut::FrontEnd::Components::Inputs::TextareaTag.new(default_html_attributes.merge(html_attributes), value)
39
- end
40
- # Create an instance
41
- #
42
- # @param [Hash] attributes HTML attributes to put on the element.
43
- # @param [String] value the value to place inside the text area
44
- def initialize(attributes, value)
45
- @attributes = attributes
46
- @value = value
38
+ @value = input.value
39
+ @attributes = default_html_attributes.merge(html_attributes)
47
40
  end
48
41
 
49
42
  def invalid? = @attributes["data-invalid"] == true
@@ -167,6 +167,7 @@ private
167
167
 
168
168
  def args_for_method(method:, request_params:, form:,route:)
169
169
  args = {}
170
+ rack_request = Rack::Request.new(self[:env])
170
171
  method.parameters.each do |(type,name)|
171
172
 
172
173
  if name.to_s == "**" || name.to_s == "*"
@@ -185,6 +186,14 @@ private
185
186
  elsif type == :keyreq
186
187
  args[name] = nil
187
188
  end
189
+ elsif name.to_s =~ /^rack_request_[^_]+/ &&
190
+ rack_request.respond_to?(name.to_s.sub(/^rack_request_/,""))
191
+ value = rack_request.send(name.to_s.sub(/^rack_request_/,""))
192
+ if value
193
+ args[name] = value
194
+ elsif type == :keyreq
195
+ args[name] = nil
196
+ end
188
197
  elsif !form.nil? && name == :form
189
198
  args[name] = form
190
199
  elsif !route.nil? && name == :route
data/lib/brut/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Brut
2
2
  # @!visibility private
3
- VERSION = "0.0.24"
3
+ VERSION = "0.0.26"
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brut
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.24
4
+ version: 0.0.26
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Bryant Copeland
@@ -623,6 +623,7 @@ files:
623
623
  - brutrb.com/pages.md
624
624
  - brutrb.com/public/images/logo-300.png
625
625
  - brutrb.com/public/images/logo.png
626
+ - brutrb.com/recipes/authentication.md
626
627
  - brutrb.com/routes.md
627
628
  - brutrb.com/security.md
628
629
  - brutrb.com/seed-data.md