formtastic_tristate_radio 0.1.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/README.md +151 -0
- data/Rakefile +12 -0
- data/app/inputs/tristate_radio_input.rb +170 -0
- data/app/models/active_record/base.rb +10 -0
- data/config/initializers/activemodel_type_boolean.rb +15 -0
- data/config/locales/active_admin.en.yml +5 -0
- data/config/locales/active_admin.ru.yml +7 -0
- data/config/locales/formtastic.en.yml +4 -0
- data/config/locales/formtastic.ru.yml +6 -0
- data/config/routes.rb +2 -0
- data/lib/formtastic_tristate_radio/engine.rb +4 -0
- data/lib/formtastic_tristate_radio/version.rb +3 -0
- data/lib/formtastic_tristate_radio.rb +8 -0
- data/lib/tasks/formtastic_tristate_radio_tasks.rake +4 -0
- metadata +166 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3c29b06aadeb4938a06be81d4b33c23c904d7033011aec8346d43b765f54d262
|
4
|
+
data.tar.gz: 471d66686e0aa7db2526642214602aa49ede7ab6183100877e9bda5954bab37d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7292702606d47a360a308d89c322bb3dda27adc62866c4bc0fa45e6939ebb841a30760684b8b299b7312838b83ebc800d1d5b83624a6d73b37d2f21f2ea33cc5
|
7
|
+
data.tar.gz: 97251242621b60cc2d1c9f381f29a58f408eddd44c202ba9f57ddf6c7075c54212733c70c9b7ef83c317e8fde8991b7aaaa9f79439e7d060f8f111fc6d0f6c11
|
data/README.md
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
# Formtastic tri-state radio
|
2
|
+
|
3
|
+
## What is “tri-state”?
|
4
|
+
|
5
|
+
— that which has 3 states.
|
6
|
+
|
7
|
+
By defenition Boolean values have 2 states: True | False.
|
8
|
+
|
9
|
+
However, if you store a Boolean value in a database column with no `NOT FULL` restriction, it aquires a 3d possible state: `null`.
|
10
|
+
|
11
|
+
Some may say this is a questionable practice — I don’t think so. In real life you always have a case when the answer to your question may be only “yes” or “no”, but you don’t know the answer yet. Using a string type column, storing there `"yes"`, `"no"` and `"unset"` + using a state machine + validations — feels overkill to me.
|
12
|
+
|
13
|
+
|
14
|
+
## What the gem does
|
15
|
+
|
16
|
+
1. Provides a custom Formtastic input type `:tristate_radio` which renders 3 radios (“Yes”, “No”, “Unset”) instead of a checkbox (only where you put it).
|
17
|
+
1. Teaches Rails recognize `"null"` and `"nil"` param values as `nil`. See “[How it works](#how-it-works)” ☟ section for technical details on this.
|
18
|
+
1. Encourages you to add translations for ActiveAdmin “status tag” so that `nil` be correctly translated as “Unset” instead of “False”.
|
19
|
+
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
For a Boolean column with 3 possible states:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
f.input :column_name, as: :tristate_radio
|
27
|
+
```
|
28
|
+
|
29
|
+
You get (HTML is simplified):
|
30
|
+
|
31
|
+
```html
|
32
|
+
<fieldset>
|
33
|
+
<input name="column_name" type="radio" value="true"> <label>Yes</label>
|
34
|
+
<input name="column_name" type="radio" value="false"> <label>No</label>
|
35
|
+
<input name="column_name" type="radio" value="null"> <label>Unset</label>
|
36
|
+
</fieldset>
|
37
|
+
```
|
38
|
+
|
39
|
+
In the future `:tristate_radio` will be registered for Boolean columns with `null` by default. Until then you have to assign it manually.
|
40
|
+
|
41
|
+
|
42
|
+
## Installation
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
gem "formtastic_tristate_radio"
|
46
|
+
```
|
47
|
+
|
48
|
+
Add translation for the new “unset” option:
|
49
|
+
|
50
|
+
```yaml
|
51
|
+
ru:
|
52
|
+
formtastic:
|
53
|
+
# :yes: Да # <- these two fall back to translations
|
54
|
+
# :no: Нет # in Formtastic gem but have only English
|
55
|
+
null: Неизвестно # <- this you must provide youself
|
56
|
+
```
|
57
|
+
|
58
|
+
ActiveAdmin will automatically translate `nil` as “No”, so if you use ActiveAdmin, add translation like so:
|
59
|
+
|
60
|
+
```yaml
|
61
|
+
ru:
|
62
|
+
active_admin:
|
63
|
+
status_tag:
|
64
|
+
:yes: Да
|
65
|
+
:no: Нет
|
66
|
+
null: Неизвестно
|
67
|
+
```
|
68
|
+
|
69
|
+
|
70
|
+
## Configuration
|
71
|
+
|
72
|
+
Nothing is configurable yet. I think of making configurable which values are regognized as `nil`.
|
73
|
+
|
74
|
+
|
75
|
+
## Dependencies
|
76
|
+
|
77
|
+
Now the gem depends on [Formtastic](https://github.com/formtastic/formtastic) (naturally) and Rails. Frankly I am not sure whether I will have time to make it work with other frameworks.
|
78
|
+
|
79
|
+
|
80
|
+
## How it works
|
81
|
+
|
82
|
+
In Ruby any String is cast to `true`:
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
!!"" #=> true
|
86
|
+
!!"false" #=> true
|
87
|
+
!!"nil" #=> true
|
88
|
+
!!"no" #=> true
|
89
|
+
!!"null" #=> true
|
90
|
+
```
|
91
|
+
|
92
|
+
Web form params are passed as plain text and are interpreted as String by Rack.
|
93
|
+
|
94
|
+
So how Boolean values are transfered as strings if a `"no"` or `"0"` and even `""` is truthy in Ruby?
|
95
|
+
|
96
|
+
Frameworks just have a list of string values to be recognized and mapped to Boolean values:
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
ActiveModel::Type::Boolean::FALSE_VALUES
|
100
|
+
#=> [
|
101
|
+
0, "0", :"0",
|
102
|
+
"f", :f, "F", :F,
|
103
|
+
false, "false", :false, "FALSE", :FALSE,
|
104
|
+
"off", :off, "OFF", :OFF,
|
105
|
+
]
|
106
|
+
```
|
107
|
+
|
108
|
+
so that
|
109
|
+
|
110
|
+
```ruby
|
111
|
+
ActiveModel::Type::Boolean.new.cast("0") #=> false
|
112
|
+
ActiveModel::Type::Boolean.new.cast("f") #=> false
|
113
|
+
ActiveModel::Type::Boolean.new.cast(:FALSE) #=> false
|
114
|
+
ActiveModel::Type::Boolean.new.cast("off") #=> false
|
115
|
+
# etc
|
116
|
+
```
|
117
|
+
|
118
|
+
So what [I do in this gem](https://github.com/sergeypedan/formtastic_tristate_radio/blob/master/config/initializers/activemodel_type_boolean.rb) is extend `ActiveModel::Type::Boolean` in a consistent way to teach it recognize null-ish values as `nil`:
|
119
|
+
|
120
|
+
```ruby
|
121
|
+
module ActiveModel
|
122
|
+
module Type
|
123
|
+
class Boolean < Value
|
124
|
+
|
125
|
+
NULL_VALUES = [nil, "", "null", :null, "nil", :nil].to_set.freeze
|
126
|
+
|
127
|
+
private def cast_value(value)
|
128
|
+
NULL_VALUES.include?(value) ? nil : !FALSE_VALUES.include?(value)
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
```
|
135
|
+
|
136
|
+
And voila!
|
137
|
+
|
138
|
+
```ruby
|
139
|
+
ActiveModel::Type::Boolean.new.cast("") #=> nil
|
140
|
+
ActiveModel::Type::Boolean.new.cast("null") #=> nil
|
141
|
+
ActiveModel::Type::Boolean.new.cast(:null) #=> nil
|
142
|
+
ActiveModel::Type::Boolean.new.cast("nil") #=> nil
|
143
|
+
ActiveModel::Type::Boolean.new.cast(:nil) #=> nil
|
144
|
+
```
|
145
|
+
|
146
|
+
**Warning**: as you might have noticed, default Rails behavior is changed. If you rely on Rails’ automatic conversion of strings with value `"null"` into `true`, this gem might not be for you (and you are definitely doing something weird).
|
147
|
+
|
148
|
+
|
149
|
+
## License
|
150
|
+
|
151
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
|
5
|
+
# APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
|
6
|
+
load "rails/tasks/engine.rake"
|
7
|
+
load "rails/tasks/statistics.rake"
|
8
|
+
|
9
|
+
require "bundler/gem_tasks"
|
10
|
+
require "rspec/core/rake_task"
|
11
|
+
RSpec::Core::RakeTask.new(:spec)
|
12
|
+
task default: :spec
|
@@ -0,0 +1,170 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "formtastic"
|
4
|
+
|
5
|
+
# It may also be appropriate to put this file in `app/inputs`
|
6
|
+
class TristateRadioInput
|
7
|
+
|
8
|
+
include Formtastic::Inputs::Base
|
9
|
+
include Formtastic::Inputs::Base::Collections
|
10
|
+
include Formtastic::Inputs::Base::Choices
|
11
|
+
|
12
|
+
|
13
|
+
# UNSET_KEY = :null
|
14
|
+
UNSET_KEY = ActiveModel::Type::Boolean::NULL_VALUES.reject(&:blank?).first
|
15
|
+
#
|
16
|
+
# Mind ActiveAdmin status resolving logic:
|
17
|
+
# https://github.com/activeadmin/activeadmin/blob/master/lib/active_admin/views/components/status_tag.rb#L51
|
18
|
+
# In status tag builder the value is lowercased before casting into boolean, and the keyword for nil is "unset", so
|
19
|
+
# if we have lowercase "unset", translations from `ru.formtastic.unset` will be overriden by `ru.active_admin.status_tag.unset`.
|
20
|
+
|
21
|
+
MISSING_TRANSLATION_ERROR_MSG = <<~HEREDOC
|
22
|
+
|
23
|
+
|
24
|
+
For ActiveAdmin status tags in index & view tables:
|
25
|
+
ru:
|
26
|
+
active_admin:
|
27
|
+
status_tag:
|
28
|
+
:yes: Да
|
29
|
+
:no: Нет
|
30
|
+
:#{UNSET_KEY}: Неизвестно
|
31
|
+
|
32
|
+
For radiobutton labels in forms:
|
33
|
+
ru:
|
34
|
+
formtastic:
|
35
|
+
:yes: Да
|
36
|
+
:no: Нет
|
37
|
+
:#{UNSET_KEY}: Неизвестно
|
38
|
+
|
39
|
+
Note: “yes”, “no”, “null” and some other words are reserved, converted into Boolean values in YAML, so you need to quote or symbolize them.
|
40
|
+
HEREDOC
|
41
|
+
|
42
|
+
|
43
|
+
# template => an instance of ActionView::Base
|
44
|
+
#
|
45
|
+
# @param choice [Array], ["Completed", "completed"]
|
46
|
+
#
|
47
|
+
def choice_html(choice)
|
48
|
+
template.content_tag(:label, tag_content(choice), tag_options(choice))
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
# collection => [["Completed", "completed"], ["In progress", "in_progress"], ["Unknown", "unset"]]
|
53
|
+
#
|
54
|
+
# @return [Array]
|
55
|
+
#
|
56
|
+
def collection_with_unset
|
57
|
+
collection + [[unset_label_translation, UNSET_KEY]]
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
# Override to remove the for attribute since this isn't associated with any element, as it's nested inside the legend
|
62
|
+
# @return [Hash]
|
63
|
+
#
|
64
|
+
# @example
|
65
|
+
# { for: nil, class: ["label"] }
|
66
|
+
#
|
67
|
+
def label_html_options
|
68
|
+
super.merge({ for: nil })
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
# choice_value(choice) => true | false | UNSET_KEY <- in our version
|
73
|
+
# choice_value(choice) => true | false | ? <- in regular radio-buttons version
|
74
|
+
# method => :status
|
75
|
+
# object => ActiveRecord::Base model subclass, `User`
|
76
|
+
#
|
77
|
+
# @param choice [Array], ["Completed", "completed"]
|
78
|
+
#
|
79
|
+
# For this to work, ActiveModel::Type::Boolean must be patched to resolve `UNSET_KEY` as nil
|
80
|
+
#
|
81
|
+
def selected?(choice)
|
82
|
+
ActiveModel::Type::Boolean.new.cast(choice_value(choice)) == object.public_send(method)
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
# @returns [String]
|
87
|
+
# "<input ...> Text..."
|
88
|
+
#
|
89
|
+
# @param choice [Array], ["Completed", "completed"]
|
90
|
+
#
|
91
|
+
# input_html_options => { id: "task_status", required: false, autofocus: false, readonly: false}
|
92
|
+
#
|
93
|
+
# input_html_options.merge(choice_html_options(choice)).merge({ required: false })
|
94
|
+
# => { id: "task_status_completed", required: false, autofocus: false, readonly: false }
|
95
|
+
#
|
96
|
+
# builder => an instance of ActiveAdmin::FormBuilder
|
97
|
+
# choice_label(choice) => "Completed"
|
98
|
+
# choice_html_options(choice) => { id: "task_status_completed" }
|
99
|
+
# choice_value(choice) => "completed"
|
100
|
+
# input_name => :status
|
101
|
+
#
|
102
|
+
def tag_content(choice)
|
103
|
+
builder.radio_button(
|
104
|
+
input_name,
|
105
|
+
choice_value(choice),
|
106
|
+
input_html_options.merge(choice_html_options(choice)).merge({ required: false, checked: selected?(choice) })
|
107
|
+
) << choice_label(choice)
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
# choice_input_dom_id(choice) => "task_status_completed"
|
112
|
+
# label_html_options => { for: nil, class: ["label"] }
|
113
|
+
#
|
114
|
+
# @param choice [Array], ["Completed", "completed"]
|
115
|
+
#
|
116
|
+
def tag_options(choice)
|
117
|
+
label_html_options.merge({ for: choice_input_dom_id(choice), class: nil })
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
# choice_wrapping_html_options(choice) #=> { class: "choice" }
|
122
|
+
#
|
123
|
+
# legend_html => "<legend class="label">
|
124
|
+
# <label>Status</label>
|
125
|
+
# </legend>"
|
126
|
+
#
|
127
|
+
# choice_html(choice) => "<label for="task_status_completed">
|
128
|
+
# <input type="radio" value="completed" name="task[status]" /> Completed
|
129
|
+
# </label>"
|
130
|
+
#
|
131
|
+
# collection.map do |choice|
|
132
|
+
# choice_wrapping({ class: "choice" }) do
|
133
|
+
# choice_html(choice)
|
134
|
+
# end
|
135
|
+
# end
|
136
|
+
# => ["<li class="choice">
|
137
|
+
# <label for="task_status_completed">
|
138
|
+
# <input type="radio" value="completed" name="task[status]" /> Completed
|
139
|
+
# </label>
|
140
|
+
# </li>",
|
141
|
+
# "<li class="choice">
|
142
|
+
# ...
|
143
|
+
# ]
|
144
|
+
#
|
145
|
+
# This method relies on ActiveAdmin
|
146
|
+
#
|
147
|
+
def to_html
|
148
|
+
choices = collection_with_unset #=> [["Completed", "completed"], ["In progress", "in_progress"], ["Unknown", "unset"]]
|
149
|
+
|
150
|
+
input_wrapping do
|
151
|
+
choices_wrapping do
|
152
|
+
legend_html << choices_group_wrapping do
|
153
|
+
choices.map { |choice|
|
154
|
+
choice_wrapping(choice_wrapping_html_options(choice)) do
|
155
|
+
choice_html(choice)
|
156
|
+
end
|
157
|
+
}.join("\n").html_safe
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
|
164
|
+
# @return [String] Label of the radio that stands for the unknown choice
|
165
|
+
#
|
166
|
+
def unset_label_translation
|
167
|
+
Formtastic::I18n.t(UNSET_KEY).presence or fail StandardError.new(MISSING_TRANSLATION_ERROR_MSG)
|
168
|
+
end
|
169
|
+
|
170
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveModel
|
4
|
+
module Type
|
5
|
+
class Boolean < Value
|
6
|
+
|
7
|
+
NULL_VALUES = [nil, "", "null", :null, "nil", :nil].to_set.freeze
|
8
|
+
|
9
|
+
private def cast_value(value)
|
10
|
+
NULL_VALUES.include?(value) ? nil : !FALSE_VALUES.include?(value)
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/config/routes.rb
ADDED
metadata
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: formtastic_tristate_radio
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sergey Pedan
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-11-03 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: formtastic
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3'
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '5'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '3'
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '5'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: rails
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '4'
|
40
|
+
- - "<"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '7'
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '4'
|
50
|
+
- - "<"
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '7'
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: coveralls
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - "~>"
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0.2'
|
60
|
+
type: :development
|
61
|
+
prerelease: false
|
62
|
+
version_requirements: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - "~>"
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0.2'
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: pry
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - "~>"
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0.14'
|
74
|
+
type: :development
|
75
|
+
prerelease: false
|
76
|
+
version_requirements: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - "~>"
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0.14'
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: rake
|
83
|
+
requirement: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - "~>"
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '13'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - "~>"
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '13'
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: yard
|
97
|
+
requirement: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - "~>"
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0.9'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - "~>"
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0.9'
|
109
|
+
description: 'Have 3-state radiobuttons instead of a 2-state checkbox for your Boolean
|
110
|
+
columns which can store NULL. Does not change controls, you need to turn it on via
|
111
|
+
`as: :tristate_radio` option.'
|
112
|
+
email:
|
113
|
+
- sergey.pedan@gmail.com
|
114
|
+
executables: []
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files:
|
117
|
+
- README.md
|
118
|
+
files:
|
119
|
+
- README.md
|
120
|
+
- Rakefile
|
121
|
+
- app/inputs/tristate_radio_input.rb
|
122
|
+
- app/models/active_record/base.rb
|
123
|
+
- config/initializers/activemodel_type_boolean.rb
|
124
|
+
- config/locales/active_admin.en.yml
|
125
|
+
- config/locales/active_admin.ru.yml
|
126
|
+
- config/locales/formtastic.en.yml
|
127
|
+
- config/locales/formtastic.ru.yml
|
128
|
+
- config/routes.rb
|
129
|
+
- lib/formtastic_tristate_radio.rb
|
130
|
+
- lib/formtastic_tristate_radio/engine.rb
|
131
|
+
- lib/formtastic_tristate_radio/version.rb
|
132
|
+
- lib/tasks/formtastic_tristate_radio_tasks.rake
|
133
|
+
homepage: https://github.com/sergeypedan/formtastic-tristate-radio
|
134
|
+
licenses:
|
135
|
+
- MIT
|
136
|
+
metadata:
|
137
|
+
changelog_uri: https://github.com/sergeypedan/formtastic-tristate-radio/blob/master/Changelog.md
|
138
|
+
documentation_uri: https://github.com/sergeypedan/formtastic-tristate-radio#usage
|
139
|
+
homepage_uri: https://github.com/sergeypedan/formtastic-tristate-radio
|
140
|
+
source_code_uri: https://github.com/sergeypedan/formtastic-tristate-radio
|
141
|
+
post_install_message:
|
142
|
+
rdoc_options:
|
143
|
+
- "--charset=UTF-8"
|
144
|
+
require_paths:
|
145
|
+
- lib
|
146
|
+
- app/inputs
|
147
|
+
- app/models/active_record
|
148
|
+
- config/initializers
|
149
|
+
- config/locales
|
150
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
151
|
+
requirements:
|
152
|
+
- - ">="
|
153
|
+
- !ruby/object:Gem::Version
|
154
|
+
version: 2.4.0
|
155
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
requirements: []
|
161
|
+
rubygems_version: 3.2.15
|
162
|
+
signing_key:
|
163
|
+
specification_version: 4
|
164
|
+
summary: Have 3-state radiobuttons instead of a 2-state checkbox for your Boolean
|
165
|
+
columns which can store NULL
|
166
|
+
test_files: []
|