protos-protoform 0.0.1
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 +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +9 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +245 -0
- data/LICENSE.txt +21 -0
- data/README.md +61 -0
- data/Rakefile +8 -0
- data/lib/generators/protoform/install/USAGE +8 -0
- data/lib/generators/protoform/install/install_generator.rb +39 -0
- data/lib/generators/protoform/install/templates/application_form.rb +36 -0
- data/lib/protoform/dom.rb +60 -0
- data/lib/protoform/field.rb +38 -0
- data/lib/protoform/field_collection.rb +39 -0
- data/lib/protoform/namespace.rb +159 -0
- data/lib/protoform/namespace_collection.rb +77 -0
- data/lib/protoform/node.rb +14 -0
- data/lib/protoform/rails/components/button.rb +28 -0
- data/lib/protoform/rails/components/checkbox.rb +28 -0
- data/lib/protoform/rails/components/component.rb +15 -0
- data/lib/protoform/rails/components/field_component.rb +18 -0
- data/lib/protoform/rails/components/input.rb +42 -0
- data/lib/protoform/rails/components/label.rb +22 -0
- data/lib/protoform/rails/components/select.rb +72 -0
- data/lib/protoform/rails/components/textarea.rb +14 -0
- data/lib/protoform/rails/form/field.rb +62 -0
- data/lib/protoform/rails/form.rb +121 -0
- data/lib/protoform/rails/option_mapper.rb +40 -0
- data/lib/protoform/rails/strong_parameters.rb +19 -0
- data/lib/protoform/version.rb +5 -0
- data/lib/protoform.rb +22 -0
- data/protos-protoform.gemspec +49 -0
- metadata +122 -0
@@ -0,0 +1,159 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protoform
|
4
|
+
# A Namespace maps and object to values, but doesn't actually have a value
|
5
|
+
# itself. For example, a `User` object or ActiveRecord model could be passed
|
6
|
+
# into the `:user` namespace. To access the values on a Namespace, the `field`
|
7
|
+
# can be called for single values.
|
8
|
+
#
|
9
|
+
# Additionally, to access namespaces within a namespace, such as if a `User
|
10
|
+
# has_many :addresses` in ActiveRecord, the `namespace` method can be called
|
11
|
+
# which will return another Namespace object and set the current Namespace as
|
12
|
+
# the parent.
|
13
|
+
class Namespace < Node
|
14
|
+
include Enumerable
|
15
|
+
|
16
|
+
attr_reader :object
|
17
|
+
|
18
|
+
def initialize(key, parent:, object: nil, field_class: Field)
|
19
|
+
super(key, parent:)
|
20
|
+
@object = object
|
21
|
+
@field_class = field_class
|
22
|
+
@children = {}
|
23
|
+
yield self if block_given?
|
24
|
+
end
|
25
|
+
|
26
|
+
# Creates a `Namespace` child instance with the parent set to the current
|
27
|
+
# instance, adds to the `@children` Hash to ensure duplicate child
|
28
|
+
# namespaces aren't created, then calls the method on the `@object` to get
|
29
|
+
# the child object to pass into that namespace.
|
30
|
+
#
|
31
|
+
# For example, if a `User#permission` returns a `Permission` object, we
|
32
|
+
# could map that to a form like this:
|
33
|
+
#
|
34
|
+
# ```ruby
|
35
|
+
# Protoform :user, object: User.new do |form|
|
36
|
+
# form.namespace :permission do |permission|
|
37
|
+
# form.field :role
|
38
|
+
# end
|
39
|
+
# end
|
40
|
+
# ```
|
41
|
+
def namespace(key, &block)
|
42
|
+
create_child(
|
43
|
+
key:,
|
44
|
+
child_class: self.class,
|
45
|
+
field_class: @field_class,
|
46
|
+
object: object_for(key:),
|
47
|
+
&block
|
48
|
+
)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Maps the `Object#proprety` and `Object#property=` to a field in a web form
|
52
|
+
# that can be read and set by the form. For example, a User form might look
|
53
|
+
# like this:
|
54
|
+
#
|
55
|
+
# ```ruby
|
56
|
+
# Protoform :user, object: User.new do |form|
|
57
|
+
# form.field :email
|
58
|
+
# form.field :name
|
59
|
+
# end
|
60
|
+
# ```
|
61
|
+
def field(key)
|
62
|
+
create_child(
|
63
|
+
key:,
|
64
|
+
child_class: @field_class,
|
65
|
+
object:
|
66
|
+
).tap do |field|
|
67
|
+
yield field if block_given?
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Wraps an array of objects in Namespace classes. For example, if
|
72
|
+
# `User#addresses` returns an enumerable or array of `Address` classes:
|
73
|
+
#
|
74
|
+
# ```ruby
|
75
|
+
# Protoform :user, object: User.new do |form|
|
76
|
+
# form.field :email
|
77
|
+
# form.field :name
|
78
|
+
# form.collection :addresses do |address|
|
79
|
+
# address.field(:street)
|
80
|
+
# address.field(:state)
|
81
|
+
# address.field(:zip)
|
82
|
+
# end
|
83
|
+
# end
|
84
|
+
# ```
|
85
|
+
# The object within the block is a `Namespace` object that maps each object
|
86
|
+
# within the enumerable to another `Namespace` or `Field`.
|
87
|
+
def collection(key, &block)
|
88
|
+
create_child(
|
89
|
+
key:,
|
90
|
+
child_class: NamespaceCollection,
|
91
|
+
field_class: @field_class,
|
92
|
+
&block
|
93
|
+
)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Creates a Hash of Hashes and Arrays that represent the fields and
|
97
|
+
# collections of the Protoform. This can be used to safely update
|
98
|
+
# ActiveRecord objects without the need for Strong Parameters. You will want
|
99
|
+
# to make sure that all the fields displayed in the form are ones that
|
100
|
+
# you're OK updating from the generated hash.
|
101
|
+
def serialize
|
102
|
+
each_with_object({}) do |child, hash|
|
103
|
+
hash[child.key] = child.serialize
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Iterates through the children of the current namespace, which could be
|
108
|
+
# `Namespace` or `Field` objects.
|
109
|
+
def each(&block)
|
110
|
+
@children.values.each(&block)
|
111
|
+
end
|
112
|
+
|
113
|
+
# Assigns a hash to the current namespace and children namespace.
|
114
|
+
def assign(hash)
|
115
|
+
tap do
|
116
|
+
each do |child|
|
117
|
+
child.assign hash[child.key] if hash.key? child.key
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# Creates a root Namespace, which is essentially a form.
|
123
|
+
def self.root(*args, **kwargs, &block)
|
124
|
+
new(*args, parent: nil, **kwargs, &block)
|
125
|
+
end
|
126
|
+
|
127
|
+
protected
|
128
|
+
|
129
|
+
# Calls the corresponding method on the object for the `key` name, if it
|
130
|
+
# exists. For example if the `key` is `email` on `User`, this method would
|
131
|
+
# call `User#email` if the method is present.
|
132
|
+
#
|
133
|
+
# This method could be overwritten if the mapping between the `@object` and
|
134
|
+
# `key` name is not a method call. For example, a `Hash` would be accessed
|
135
|
+
# via `user[:email]` instead of `user.send(:email)`
|
136
|
+
def object_for(key:)
|
137
|
+
@object.send(key) if @object.respond_to? key
|
138
|
+
end
|
139
|
+
|
140
|
+
private
|
141
|
+
|
142
|
+
# Checks if the child exists. If it does then it returns that. If it
|
143
|
+
# doesn't, it will build the child.
|
144
|
+
def create_child(key:, child_class:, **kwargs, &block)
|
145
|
+
if (child = @children.fetch(key, nil))
|
146
|
+
# ensure that found children are also yielded
|
147
|
+
child.tap { yield child if block }
|
148
|
+
else
|
149
|
+
# new children added to hash and block passed to constructor
|
150
|
+
@children[key] = child_class.new(
|
151
|
+
key,
|
152
|
+
parent: self,
|
153
|
+
**kwargs,
|
154
|
+
&block
|
155
|
+
)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protoform
|
4
|
+
class NamespaceCollection < Node
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
def initialize(key, parent:, field_class:, &template)
|
8
|
+
super(key, parent:)
|
9
|
+
@template = template
|
10
|
+
@field_class = field_class
|
11
|
+
@namespaces = enumerate(parent_collection)
|
12
|
+
end
|
13
|
+
|
14
|
+
def serialize
|
15
|
+
map(&:serialize)
|
16
|
+
end
|
17
|
+
|
18
|
+
def assign(array)
|
19
|
+
# The problem with zip-ing the array is if I need to add new
|
20
|
+
# elements to it and wrap it in the namespace.
|
21
|
+
zip(array) do |namespace, hash|
|
22
|
+
namespace.assign hash
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def each(&block)
|
27
|
+
@namespaces.each(&block)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def enumerate(enumerator)
|
33
|
+
Enumerator.new do |y|
|
34
|
+
enumerator.each.with_index do |object, key|
|
35
|
+
y << build_namespace(key, object:)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def build_namespace(index, **kwargs)
|
41
|
+
parent.class.new(
|
42
|
+
index,
|
43
|
+
parent: self,
|
44
|
+
field_class: @field_class,
|
45
|
+
**kwargs,
|
46
|
+
&@template
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
def parent_collection
|
51
|
+
raise_missing_object unless @parent.respond_to? :object
|
52
|
+
@parent.object.send(@key).tap do |value|
|
53
|
+
raise_invalid_enumerator(value) unless value.respond_to? :each
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def raise_invalid_enumerator(value)
|
58
|
+
raise(
|
59
|
+
ArgumentError,
|
60
|
+
<<~ERROR
|
61
|
+
#{@parent.object.class} did not return something that responds to
|
62
|
+
:each for #{@key}. #{self.class} requires the model to return
|
63
|
+
something that can be enumerated for #{@key}.
|
64
|
+
Got #{value.class}: #{value.inspect} instead.
|
65
|
+
ERROR
|
66
|
+
)
|
67
|
+
end
|
68
|
+
|
69
|
+
def raise_missing_object
|
70
|
+
raise(
|
71
|
+
ArgumentError,
|
72
|
+
"Parent of a #{self.class} must respond to :object, " \
|
73
|
+
"#{@parent.class} does not"
|
74
|
+
)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protoform
|
4
|
+
# Superclass for Namespace and Field classes. Not much to it other than it has
|
5
|
+
# a `name` and `parent` node attribute. Think of it as a tree.
|
6
|
+
class Node
|
7
|
+
attr_reader :key, :parent
|
8
|
+
|
9
|
+
def initialize(key, parent:)
|
10
|
+
@key = key
|
11
|
+
@parent = parent
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protoform
|
4
|
+
module Rails
|
5
|
+
module Components
|
6
|
+
class Button < FieldComponent
|
7
|
+
def view_template(&content)
|
8
|
+
content ||= proc { button_text }
|
9
|
+
button(**attrs, &content)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def button_text
|
15
|
+
attrs.fetch(:value, dom.value).titleize
|
16
|
+
end
|
17
|
+
|
18
|
+
def default_attrs
|
19
|
+
{
|
20
|
+
id: dom.id,
|
21
|
+
name: dom.name,
|
22
|
+
value: dom.value
|
23
|
+
}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protoform
|
4
|
+
module Rails
|
5
|
+
module Components
|
6
|
+
class Checkbox < FieldComponent
|
7
|
+
def view_template
|
8
|
+
# Rails has a hidden and checkbox input to deal with sending back
|
9
|
+
# a value to the server regardless of if the input is checked or not.
|
10
|
+
input(name: dom.name, type: :hidden, value: "0")
|
11
|
+
# The hard coded keys need to be in here so the user can't overrite
|
12
|
+
# them.
|
13
|
+
input(type: :checkbox, value: "1", **attrs)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def default_attrs
|
19
|
+
{
|
20
|
+
id: dom.id,
|
21
|
+
name: dom.name,
|
22
|
+
checked: field.value
|
23
|
+
}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protoform
|
4
|
+
module Rails
|
5
|
+
module Components
|
6
|
+
class Input < FieldComponent
|
7
|
+
option :type, reader: false, default: -> { inferred_type }
|
8
|
+
|
9
|
+
def view_template
|
10
|
+
input(**attrs)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def default_attrs
|
16
|
+
{
|
17
|
+
id: dom.id,
|
18
|
+
name: dom.name,
|
19
|
+
type: @type
|
20
|
+
}.tap do |hash|
|
21
|
+
hash[:value] = field.value unless @type.to_sym == :file
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def inferred_type
|
26
|
+
case field.value
|
27
|
+
when URI
|
28
|
+
"url"
|
29
|
+
when Integer
|
30
|
+
"number"
|
31
|
+
when Date, DateTime
|
32
|
+
"date"
|
33
|
+
when Time
|
34
|
+
"time"
|
35
|
+
else
|
36
|
+
"text"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protoform
|
4
|
+
module Rails
|
5
|
+
module Components
|
6
|
+
class Label < Component
|
7
|
+
def view_template(&content)
|
8
|
+
content ||= proc { field.key.to_s.titleize }
|
9
|
+
label(**attrs, &content)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def default_attrs
|
15
|
+
{
|
16
|
+
for: dom.id
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protoform
|
4
|
+
module Rails
|
5
|
+
module Components
|
6
|
+
class Select < FieldComponent
|
7
|
+
option :collection, default: -> { [] }
|
8
|
+
option :include_blank, default: -> { true }
|
9
|
+
option :multiple, reader: false, default: -> { false }
|
10
|
+
|
11
|
+
def view_template(&options)
|
12
|
+
name = @multiple ? "#{attrs[:name]}[]" : attrs[:name]
|
13
|
+
|
14
|
+
if @multiple
|
15
|
+
input(
|
16
|
+
name:,
|
17
|
+
type: :hidden,
|
18
|
+
value: ""
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
if options
|
23
|
+
select(multiple: @multiple, **attrs, name:, &options)
|
24
|
+
else
|
25
|
+
select(multiple: @multiple, **attrs, name:) do
|
26
|
+
blank_option
|
27
|
+
options(*@collection)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def options(*collection)
|
33
|
+
map_options(collection).each do |key, value|
|
34
|
+
option(
|
35
|
+
selected: selected_value_for(key) ? "selected" : false,
|
36
|
+
value: key
|
37
|
+
) { value }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def blank_option(&block)
|
42
|
+
option(selected: field.value.nil?, &block)
|
43
|
+
end
|
44
|
+
|
45
|
+
def true_option(&block)
|
46
|
+
option(selected: field.value == true, value: true.to_s, &block)
|
47
|
+
end
|
48
|
+
|
49
|
+
def false_option(&block)
|
50
|
+
option(selected: field.value == false, value: false.to_s, &block)
|
51
|
+
end
|
52
|
+
|
53
|
+
protected
|
54
|
+
|
55
|
+
def selected_value_for(key)
|
56
|
+
case field.value
|
57
|
+
when String, Symbol
|
58
|
+
field.value.to_s == key.to_s
|
59
|
+
when Array
|
60
|
+
field.value.include?(key)
|
61
|
+
else
|
62
|
+
field.value == key
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def map_options(collection)
|
67
|
+
OptionMapper.new(collection)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protoform
|
4
|
+
module Rails
|
5
|
+
class Form
|
6
|
+
# The Field class is designed to be extended to create custom forms. To
|
7
|
+
# override, in your subclass you may have something like this:
|
8
|
+
#
|
9
|
+
# ```ruby
|
10
|
+
# class MyForm < Protoform::Rails::Form
|
11
|
+
# class MyLabel < Protoform::Rails::Components::LabelComponent
|
12
|
+
# def view_template(&content)
|
13
|
+
# label(form: @field.dom.name, class: "text-bold", &content)
|
14
|
+
# end
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# class Field < Field
|
18
|
+
# def label(**attributes)
|
19
|
+
# MyLabel.new(self, **attributes)
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
# ```
|
24
|
+
#
|
25
|
+
# Now all calls to `label` will have the `text-bold` class applied to it.
|
26
|
+
class Field < Protoform::Field
|
27
|
+
def button(...)
|
28
|
+
Components::Button.new(self, ...)
|
29
|
+
end
|
30
|
+
|
31
|
+
def input(...)
|
32
|
+
Components::Input.new(self, ...)
|
33
|
+
end
|
34
|
+
|
35
|
+
def checkbox(...)
|
36
|
+
Components::Checkbox.new(self, ...)
|
37
|
+
end
|
38
|
+
|
39
|
+
def label(...)
|
40
|
+
Components::Label.new(self, ...)
|
41
|
+
end
|
42
|
+
|
43
|
+
def textarea(...)
|
44
|
+
Components::Textarea.new(self, ...)
|
45
|
+
end
|
46
|
+
|
47
|
+
def select(*collection, **attributes, &block)
|
48
|
+
Components::Select.new(
|
49
|
+
self,
|
50
|
+
collection:,
|
51
|
+
**attributes,
|
52
|
+
&block
|
53
|
+
)
|
54
|
+
end
|
55
|
+
|
56
|
+
def title
|
57
|
+
key.to_s.titleize
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protoform
|
4
|
+
module Rails
|
5
|
+
Component = ::ApplicationComponent
|
6
|
+
# A Protos::Component class that accepts a model and sets
|
7
|
+
# a `Protoform::Namespace` with the `Object#model_name` as the key and maps
|
8
|
+
# the object to form fields and namespaces.
|
9
|
+
#
|
10
|
+
# The `Form::Field` is a class that's meant to be extended so you can
|
11
|
+
# customize the `Form` inputs to your applications needs. Defaults for the
|
12
|
+
# `input`, `button`, `label`, and `textarea` tags are provided.
|
13
|
+
#
|
14
|
+
# The `Form` component also handles Rails authenticity tokens via the
|
15
|
+
# `authenticity_toklen_field` method and the HTTP verb via the
|
16
|
+
# `_method_field`.
|
17
|
+
class Form < Component
|
18
|
+
param :model, reader: false
|
19
|
+
option :helpers, reader: false, default: -> {}
|
20
|
+
option :action, reader: false, default: -> {}
|
21
|
+
option :method, reader: false, default: -> {}
|
22
|
+
option :namespace, reader: false, default: -> do
|
23
|
+
Namespace.root(key, object: @model, field_class: self.class::Field)
|
24
|
+
end
|
25
|
+
|
26
|
+
def field(...)
|
27
|
+
@namespace.field(...)
|
28
|
+
end
|
29
|
+
|
30
|
+
def collection(...)
|
31
|
+
@namespace.collection(...)
|
32
|
+
end
|
33
|
+
|
34
|
+
def namespace(...)
|
35
|
+
@namespace.namespace(...)
|
36
|
+
end
|
37
|
+
|
38
|
+
def assign(...)
|
39
|
+
@namespace.assign(...)
|
40
|
+
end
|
41
|
+
|
42
|
+
def serialize(...)
|
43
|
+
@namespace.serialize(...)
|
44
|
+
end
|
45
|
+
|
46
|
+
def around_template(&block)
|
47
|
+
form_tag do
|
48
|
+
authenticity_token_field
|
49
|
+
_method_field
|
50
|
+
super
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def form_tag(&block)
|
55
|
+
form action:, method: form_method, **attrs, &block
|
56
|
+
end
|
57
|
+
|
58
|
+
def view_template(&block)
|
59
|
+
yield_content(&block)
|
60
|
+
end
|
61
|
+
|
62
|
+
def submit(value = submit_value, **attributes)
|
63
|
+
input(
|
64
|
+
**attributes.merge(
|
65
|
+
name: "commit",
|
66
|
+
type: "submit",
|
67
|
+
value:
|
68
|
+
)
|
69
|
+
)
|
70
|
+
end
|
71
|
+
|
72
|
+
def key
|
73
|
+
@model.model_name.param_key
|
74
|
+
end
|
75
|
+
|
76
|
+
protected
|
77
|
+
|
78
|
+
def authenticity_token_field
|
79
|
+
input(
|
80
|
+
name: "authenticity_token",
|
81
|
+
type: "hidden",
|
82
|
+
value: helpers.form_authenticity_token
|
83
|
+
)
|
84
|
+
end
|
85
|
+
|
86
|
+
def _method_field
|
87
|
+
input(
|
88
|
+
name: "_method",
|
89
|
+
type: "hidden",
|
90
|
+
value: _method_field_value
|
91
|
+
)
|
92
|
+
end
|
93
|
+
|
94
|
+
def _method_field_value
|
95
|
+
@method || (@model.persisted? ? "patch" : "post")
|
96
|
+
end
|
97
|
+
|
98
|
+
def submit_value
|
99
|
+
"#{resource_action.to_s.capitalize} #{@model.model_name}"
|
100
|
+
end
|
101
|
+
|
102
|
+
def resource_action
|
103
|
+
@model.persisted? ? :update : :create
|
104
|
+
end
|
105
|
+
|
106
|
+
def action
|
107
|
+
@action ||= helpers.url_for(action: resource_action)
|
108
|
+
end
|
109
|
+
|
110
|
+
def form_method
|
111
|
+
@method.to_s.downcase == "get" ? "get" : "post"
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
|
116
|
+
def helpers
|
117
|
+
@helpers ||= super
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|