Skip to content

Commit fe60085

Browse files
committed
Add form helpers
1 parent f2ff87b commit fe60085

4 files changed

Lines changed: 218 additions & 0 deletions

File tree

app/views/oxidizer/form.rb

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
module Oxidizer
2+
module Form
3+
extend ActiveSupport::Concern
4+
5+
def initialize(model:)
6+
@model = model
7+
end
8+
9+
def template
10+
form_tag do
11+
form_template
12+
end
13+
end
14+
15+
def fields
16+
form_model.fields.values
17+
end
18+
19+
def field(name)
20+
form_model.field(name)
21+
end
22+
23+
def form_tag(**attrs, &)
24+
form **form_model.attributes(method: "post", action: action, **attrs) do
25+
authenticity_token_field
26+
_method_field
27+
yield
28+
end
29+
end
30+
31+
def action
32+
helpers.url_for(action: form_model.resource_action)
33+
end
34+
35+
def authenticity_token_field
36+
input(type: :hidden, name: :authenticity_token, value: helpers.form_authenticity_token)
37+
end
38+
39+
def _method_field
40+
input(name: "_method", type: :hidden, value: form_model._method_field_value)
41+
end
42+
43+
def default_button_text
44+
form_model.button_text
45+
end
46+
47+
private
48+
49+
def form_model
50+
@form_model ||= Form::Model.new(@model)
51+
end
52+
end
53+
end

app/views/oxidizer/form/field.rb

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
module Oxidizer
2+
module Form
3+
# Generates Form attributes for an ActiveRecord model that can be passed into
4+
# Phlex tags for fun and for profit.
5+
# TODO: This should handle:
6+
# * Nested fields
7+
class Field
8+
include ActionView::Helpers::FormTagHelper
9+
10+
def initialize(method:, form: nil)
11+
@method = method
12+
@attribute = method.name
13+
@model = method.receiver
14+
@form = form
15+
end
16+
17+
def id
18+
"#{naming.param_key}_#{@attribute}_#{object_id}"
19+
end
20+
21+
def name
22+
field_name naming.param_key, @attribute
23+
end
24+
25+
def value
26+
@method.call
27+
end
28+
29+
def label
30+
@attribute.to_s.titleize
31+
end
32+
33+
def naming
34+
@model.model_name
35+
end
36+
37+
def form
38+
@form.id if @form
39+
end
40+
41+
def errors
42+
@model.errors[@attribute]
43+
end
44+
45+
def invalid?
46+
errors.any?
47+
end
48+
49+
def validators
50+
@model.class.validators_on @attribute
51+
end
52+
53+
def validation_attributes(**attrs)
54+
validations = validators.each_with_object Hash.new do |validator, attributes|
55+
case validator
56+
when ActiveRecord::Validations::PresenceValidator
57+
attributes[:required] = true
58+
end
59+
end
60+
attrs.merge(**validations)
61+
end
62+
63+
def input_attributes(**attrs)
64+
attrs.merge(id: id, name: name, value: value).merge(validation_attributes)
65+
end
66+
67+
def textarea_attributes(**attrs)
68+
attrs.merge(id: id, name: name).merge(validation_attributes)
69+
end
70+
71+
def label_attributes(**attrs)
72+
attrs.merge(for: id)
73+
end
74+
75+
def self.for(model, attribute, **kwargs)
76+
new **kwargs.merge(method: model.method(attribute))
77+
end
78+
end
79+
end
80+
end

app/views/oxidizer/form/model.rb

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
module Oxidizer
2+
module Form
3+
class Model
4+
attr_reader :fields, :model
5+
6+
def initialize(model)
7+
@model = model
8+
@fields ||= Hash.new do | hash, key |
9+
hash[key] = Field.for(model, key, form: self)
10+
end
11+
end
12+
13+
def field(key)
14+
@fields[key]
15+
end
16+
17+
def id
18+
"#{naming.param_key}_#{object_id}"
19+
end
20+
21+
def _method_field_value
22+
@model.persisted? ? "patch" : "post"
23+
end
24+
25+
def naming
26+
@model.model_name
27+
end
28+
29+
def attributes(**attrs)
30+
attrs.merge(id: id)
31+
end
32+
33+
def resource_action
34+
@model.persisted? ? :update : :create
35+
end
36+
37+
def button_text
38+
"#{@model.persisted? ? "Save" : "Create"} #{naming.human.downcase}"
39+
end
40+
alias :submit_value :button_text
41+
end
42+
end
43+
end
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
module Oxidizer
2+
module Form
3+
module StrongParams
4+
extend ActiveSupport::Concern
5+
6+
included do
7+
prepend Extensions
8+
end
9+
10+
module Extensions
11+
def field(name)
12+
if permitted_keys.include? name
13+
super(name)
14+
else
15+
fail "Unpermitted form field: #{name}"
16+
end
17+
end
18+
end
19+
20+
def permitted_keys
21+
self.class.permitted_keys
22+
end
23+
24+
module ClassMethods
25+
def permit(*keys)
26+
permitted_keys.append *keys
27+
end
28+
29+
def permitted_keys
30+
@permitted_keys ||= []
31+
end
32+
33+
def permitted_params(**kwargs)
34+
case kwargs.to_a
35+
in [[param_key, params]]
36+
params.require(param_key).permit(permitted_keys)
37+
end
38+
end
39+
end
40+
end
41+
end
42+
end

0 commit comments

Comments
 (0)