nice_form 1.0.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 +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +13 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +9 -0
- data/README.md +179 -0
- data/Rakefile +12 -0
- data/lib/nice_form/acts_like.rb +37 -0
- data/lib/nice_form/base.rb +115 -0
- data/lib/nice_form/config.rb +27 -0
- data/lib/nice_form/instantiation.rb +70 -0
- data/lib/nice_form/primary_key.rb +38 -0
- data/lib/nice_form/version.rb +5 -0
- data/lib/nice_form.rb +9 -0
- metadata +100 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 72f4c95c9bf001b15641096f7319debd084001453ec44d2d2f542364fc2b49c2
|
4
|
+
data.tar.gz: f5a2b2e1c06c38ed2021e0c4a3291294aa25e985b4be7b7a2efff855ab33a0c0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 35428d57f07eca576a171a9fdc8ab2c819de10da76ac60f81f028ff88c0debb5b439319ad0cdd2cbebd3d9a90ef8f9508c2f3df9600403112a70a5683030fa1e
|
7
|
+
data.tar.gz: 36c61bcb52645737f4f1043dae8f9efdea5bbc8a9b5aa9e057ffc03fd9b03f015548a7262f6659f7fe78adabb4b5d02e1a98dbb5b25ee6832707ccffce3a3d79
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,179 @@
|
|
1
|
+
# NiceForm
|
2
|
+
|
3
|
+
A nice form object for Rails that makes sense.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Install the gem and add to the application's Gemfile by executing:
|
8
|
+
|
9
|
+
$ bundle add nice_form
|
10
|
+
|
11
|
+
You might want to create an application-wide form:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
class ApplicationForm < NiceForm::Base; end
|
15
|
+
```
|
16
|
+
|
17
|
+
Or configure the default primary key settings if you're using something other than `id`:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
NiceForm.configure do |config|
|
21
|
+
# name, type
|
22
|
+
config.primary_key = [:uuid, :string]
|
23
|
+
end
|
24
|
+
```
|
25
|
+
|
26
|
+
You can also set this on a form-by-form basis.
|
27
|
+
|
28
|
+
## Usage
|
29
|
+
|
30
|
+
It's just like Active Model, but with some nice-to-haves.
|
31
|
+
|
32
|
+
### Basic usage
|
33
|
+
|
34
|
+
Treat it like an Active Model object:
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
class PostForm < NiceForm::Base
|
38
|
+
self.acts_like = :post
|
39
|
+
|
40
|
+
attribute :subject
|
41
|
+
attribute :context, :text
|
42
|
+
attribute :published_at, :datetime
|
43
|
+
attribute :requires_review, :boolean
|
44
|
+
end
|
45
|
+
```
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
class PostsController < ApplicationController
|
49
|
+
def new
|
50
|
+
@form = PostForm.new
|
51
|
+
end
|
52
|
+
end
|
53
|
+
```
|
54
|
+
|
55
|
+
### From params
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
class PostsController < ApplicationController
|
59
|
+
def create
|
60
|
+
@form = PostForm.new(post_params)
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def post_params
|
66
|
+
params.require(:post).permit(:subject, :content, :published_at, :requires_review)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
```
|
70
|
+
|
71
|
+
### From a model
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
class PostsController < ApplicationController
|
75
|
+
def edit
|
76
|
+
post = Post.find(params[:id])
|
77
|
+
@form = PostForm.from_model(post) # { id: 1, subject: "hello" ... }
|
78
|
+
end
|
79
|
+
end
|
80
|
+
```
|
81
|
+
|
82
|
+
#### Map additional attributes to a form object
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
class PostsController < ApplicationController
|
86
|
+
def edit
|
87
|
+
post = Post.find(params[:id])
|
88
|
+
@form = PostForm.from_model(post)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
```
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
class PostForm < NiceForm::Base
|
95
|
+
self.acts_like = :post
|
96
|
+
|
97
|
+
attribute :subject
|
98
|
+
attribute :context, :text
|
99
|
+
attribute :published_at, :datetime
|
100
|
+
attribute :requires_review, :boolean
|
101
|
+
|
102
|
+
def map_model(model)
|
103
|
+
model.requires_review = model.reviews.last.status == 'review'
|
104
|
+
end
|
105
|
+
end
|
106
|
+
```
|
107
|
+
|
108
|
+
### Change the param key
|
109
|
+
|
110
|
+
```ruby
|
111
|
+
Rails.application.routes.draw do
|
112
|
+
resources :posts, param_name: :uuid
|
113
|
+
end
|
114
|
+
```
|
115
|
+
|
116
|
+
```ruby
|
117
|
+
class PostsController < ApplicationController
|
118
|
+
def edit
|
119
|
+
post = Post.find(params[:uuid])
|
120
|
+
@form = PostForm.from_model(post)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
```
|
124
|
+
|
125
|
+
```ruby
|
126
|
+
class PostForm < NiceForm::Base
|
127
|
+
self.acts_like = :post
|
128
|
+
|
129
|
+
self.primary_key :uuid, :string
|
130
|
+
|
131
|
+
# ...
|
132
|
+
end
|
133
|
+
```
|
134
|
+
|
135
|
+
## Validations
|
136
|
+
|
137
|
+
Again, just like an Active Model object:
|
138
|
+
|
139
|
+
```ruby
|
140
|
+
class PostForm < NiceForm::Base
|
141
|
+
self.acts_like = :post
|
142
|
+
|
143
|
+
attribute :subject
|
144
|
+
|
145
|
+
validates :subject, presence: true
|
146
|
+
end
|
147
|
+
```
|
148
|
+
|
149
|
+
## External context
|
150
|
+
|
151
|
+
```ruby
|
152
|
+
class PostsController < ApplicationController
|
153
|
+
def new
|
154
|
+
@form = PostForm.new.with_context(user: current_staff_user)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
```
|
158
|
+
|
159
|
+
```ruby
|
160
|
+
class PostForm < NiceForm::Base
|
161
|
+
self.acts_like = :post
|
162
|
+
|
163
|
+
attribute :category_id, :integer
|
164
|
+
attribute :subject
|
165
|
+
attribute :context, :text
|
166
|
+
attribute :published_at, :datetime
|
167
|
+
|
168
|
+
validates :category_id, with: :ensure_category_id!
|
169
|
+
|
170
|
+
private
|
171
|
+
|
172
|
+
def ensure_category_id!
|
173
|
+
unless CategoryUser.where(category_id: category_id, user: context[:user]).exists?
|
174
|
+
self.errors.add(:category_id, "is invalid")
|
175
|
+
throw(:abort)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module NiceForm
|
4
|
+
# Allows you to define the model name of the form
|
5
|
+
#
|
6
|
+
# class CatForm < NiceForm::Base
|
7
|
+
# self.acts_like = :cat
|
8
|
+
# end
|
9
|
+
#
|
10
|
+
# Automatically infers the name if not set.
|
11
|
+
module ActsLike
|
12
|
+
def self.included(klass)
|
13
|
+
klass.extend ClassMethods
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
def acts_like=(val)
|
18
|
+
@acts_like_model = val.to_s.underscore.to_sym
|
19
|
+
end
|
20
|
+
|
21
|
+
def acts_like_model_name
|
22
|
+
@acts_like_model || inferred_model_name
|
23
|
+
end
|
24
|
+
|
25
|
+
def inferred_model_name
|
26
|
+
class_name = name.demodulize
|
27
|
+
return :form if class_name == "Form"
|
28
|
+
|
29
|
+
class_name.delete_suffix("Form").underscore.to_sym
|
30
|
+
end
|
31
|
+
|
32
|
+
def model_name
|
33
|
+
ActiveModel::Name.new(self, nil, acts_like_model_name.to_s.camelize)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_model'
|
4
|
+
|
5
|
+
require_relative "instantiation"
|
6
|
+
require_relative "acts_like"
|
7
|
+
require_relative "primary_key"
|
8
|
+
|
9
|
+
module NiceForm
|
10
|
+
class Base
|
11
|
+
extend ActiveModel::Naming
|
12
|
+
extend ActiveModel::Translation
|
13
|
+
|
14
|
+
include ActiveModel::Attributes
|
15
|
+
include ActiveModel::AttributeAssignment
|
16
|
+
include ActiveModel::Callbacks
|
17
|
+
include ActiveModel::Conversion
|
18
|
+
include ActiveModel::Validations
|
19
|
+
|
20
|
+
include ActsLike
|
21
|
+
include Instantiation
|
22
|
+
include PrimaryKey
|
23
|
+
|
24
|
+
define_model_callbacks :validation, only: :before
|
25
|
+
|
26
|
+
attr_reader :context
|
27
|
+
|
28
|
+
def self.inherited(klass)
|
29
|
+
super
|
30
|
+
klass.primary_key(*NiceForm.config.primary_key)
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(attributes = {})
|
34
|
+
assign_attributes(attributes) if attributes
|
35
|
+
super()
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.inspect
|
39
|
+
attr_list = attribute_types.map { |name, type| "#{name}: #{type.type}" } * ", "
|
40
|
+
"#{self.name}(#{attr_list})"
|
41
|
+
end
|
42
|
+
|
43
|
+
def inspect
|
44
|
+
inspection = if defined?(@attributes) && @attributes
|
45
|
+
self.class.attribute_names.filter_map do |name|
|
46
|
+
"#{name}: #{attribute_for_inspect(name)}" if _has_attribute?(name)
|
47
|
+
end.join(", ")
|
48
|
+
else
|
49
|
+
"not initialized"
|
50
|
+
end
|
51
|
+
|
52
|
+
"#<#{self.class} #{inspection}>"
|
53
|
+
end
|
54
|
+
|
55
|
+
def attributes
|
56
|
+
attrs = [self.class.form_primary_key]
|
57
|
+
|
58
|
+
attrs << if ::NiceForm.config.primary_key.is_a?(Array)
|
59
|
+
::NiceForm.config.primary_key[0].to_s
|
60
|
+
else
|
61
|
+
::NiceForm::Config.primary_key.to_s
|
62
|
+
end
|
63
|
+
|
64
|
+
super.except(*attrs)
|
65
|
+
end
|
66
|
+
|
67
|
+
def to_model
|
68
|
+
self
|
69
|
+
end
|
70
|
+
|
71
|
+
def to_param
|
72
|
+
attribute(self.class.form_primary_key)
|
73
|
+
end
|
74
|
+
|
75
|
+
def to_key
|
76
|
+
key = attribute(self.class.form_primary_key)
|
77
|
+
return nil if key.nil?
|
78
|
+
|
79
|
+
[key]
|
80
|
+
end
|
81
|
+
|
82
|
+
def persisted?
|
83
|
+
to_param.present?
|
84
|
+
end
|
85
|
+
|
86
|
+
def with_context(attrs = {})
|
87
|
+
@context = attrs
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def format_for_inspect(value)
|
93
|
+
if value.nil?
|
94
|
+
value.inspect
|
95
|
+
elsif value.is_a?(String) && value.length > 50
|
96
|
+
"#{value[0, 50]}...".inspect
|
97
|
+
elsif value.is_a?(Date) || value.is_a?(Time)
|
98
|
+
%("#{value.to_fs(:inspect)}")
|
99
|
+
else
|
100
|
+
value.inspect
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def attribute_for_inspect(attr_name)
|
105
|
+
attr_name = attr_name.to_s
|
106
|
+
attr_name = self.class.attribute_aliases[attr_name] || attr_name
|
107
|
+
value = _read_attribute(attr_name)
|
108
|
+
format_for_inspect(value)
|
109
|
+
end
|
110
|
+
|
111
|
+
def _has_attribute?(attr_name)
|
112
|
+
@attributes.key?(attr_name)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module NiceForm
|
4
|
+
class Configuration
|
5
|
+
attr_accessor :primary_key
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@primary_key = %i[id integer]
|
9
|
+
end
|
10
|
+
|
11
|
+
def primary_key=(val)
|
12
|
+
@primary_key = if val.is_a?(Array)
|
13
|
+
val
|
14
|
+
else
|
15
|
+
[val, :integer]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.configure
|
21
|
+
yield config
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.config
|
25
|
+
@config ||= Configuration.new
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module NiceForm
|
4
|
+
module Instantiation
|
5
|
+
def self.included(klass)
|
6
|
+
klass.include FromParams
|
7
|
+
klass.include FromHash
|
8
|
+
klass.include FromModel
|
9
|
+
klass.include FromJson
|
10
|
+
end
|
11
|
+
|
12
|
+
module FromHash
|
13
|
+
def self.included(klass)
|
14
|
+
klass.extend ClassMethods
|
15
|
+
end
|
16
|
+
|
17
|
+
module ClassMethods
|
18
|
+
def from_hash(hash)
|
19
|
+
from_params(hash)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
module FromParams
|
25
|
+
def self.included(klass)
|
26
|
+
klass.extend ClassMethods
|
27
|
+
end
|
28
|
+
|
29
|
+
module ClassMethods
|
30
|
+
def from_params(params, additional_params = {})
|
31
|
+
instance = new
|
32
|
+
instance.assign_attributes(params.merge(additional_params))
|
33
|
+
instance
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module FromModel
|
39
|
+
def self.included(klass)
|
40
|
+
klass.extend ClassMethods
|
41
|
+
end
|
42
|
+
|
43
|
+
module ClassMethods
|
44
|
+
def from_model(model)
|
45
|
+
instance = new
|
46
|
+
instance.class.attribute_names.each do |attr|
|
47
|
+
instance.public_send("#{attr}=", model.public_send(attr)) if model.respond_to?(attr)
|
48
|
+
end
|
49
|
+
instance.map_model(model)
|
50
|
+
instance
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# assign attributes to self
|
55
|
+
def map_model(model); end
|
56
|
+
end
|
57
|
+
|
58
|
+
module FromJson
|
59
|
+
def self.included(klass)
|
60
|
+
klass.extend ClassMethods
|
61
|
+
end
|
62
|
+
|
63
|
+
module ClassMethods
|
64
|
+
def from_json(string)
|
65
|
+
from_params(JSON.parse(string))
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module NiceForm
|
4
|
+
module PrimaryKey
|
5
|
+
def self.included(klass)
|
6
|
+
klass.extend ClassMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def primary_key(name, type = :integer)
|
11
|
+
if name.is_a?(Array)
|
12
|
+
type = name[1]
|
13
|
+
name = name[0]
|
14
|
+
end
|
15
|
+
undefine_primary_key(form_primary_key)
|
16
|
+
define_primary_key(name, type)
|
17
|
+
end
|
18
|
+
|
19
|
+
def form_primary_key
|
20
|
+
@form_primary_key ||= define_primary_key(NiceForm.config.primary_key[0], NiceForm.config.primary_key[1])
|
21
|
+
end
|
22
|
+
|
23
|
+
def undefine_primary_key(name)
|
24
|
+
if attribute_names.include?(name.to_s)
|
25
|
+
undef_method(name.to_s) if respond_to?(name.to_s)
|
26
|
+
undef_method("#{name}=") if respond_to?("#{name}=")
|
27
|
+
attribute_types.delete(name.to_s)
|
28
|
+
_default_attributes.send(:attributes).delete(name.to_s)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def define_primary_key(name, type = :integer)
|
33
|
+
attribute name, type
|
34
|
+
@form_primary_key = name.to_s
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/nice_form.rb
ADDED
metadata
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: nice_form
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Partytray
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-05-23 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activemodel
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '5.1'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '5.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activesupport
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '5.1'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '5.1'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: pry
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: A form object.
|
56
|
+
email:
|
57
|
+
- 97254326+Partytray@users.noreply.github.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- ".rspec"
|
63
|
+
- ".rubocop.yml"
|
64
|
+
- CHANGELOG.md
|
65
|
+
- Gemfile
|
66
|
+
- README.md
|
67
|
+
- Rakefile
|
68
|
+
- lib/nice_form.rb
|
69
|
+
- lib/nice_form/acts_like.rb
|
70
|
+
- lib/nice_form/base.rb
|
71
|
+
- lib/nice_form/config.rb
|
72
|
+
- lib/nice_form/instantiation.rb
|
73
|
+
- lib/nice_form/primary_key.rb
|
74
|
+
- lib/nice_form/version.rb
|
75
|
+
homepage: https://github.com/partytray/nice_form
|
76
|
+
licenses: []
|
77
|
+
metadata:
|
78
|
+
homepage_uri: https://github.com/partytray/nice_form
|
79
|
+
source_code_uri: https://github.com/partytray/nice_form
|
80
|
+
changelog_uri: https://github.com/partytray/nice_form
|
81
|
+
post_install_message:
|
82
|
+
rdoc_options: []
|
83
|
+
require_paths:
|
84
|
+
- lib
|
85
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 2.4.2
|
90
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
requirements: []
|
96
|
+
rubygems_version: 3.3.11
|
97
|
+
signing_key:
|
98
|
+
specification_version: 4
|
99
|
+
summary: A form object.
|
100
|
+
test_files: []
|