Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/sergeypedan/formtastic-tristate-radio
Have 3-state radiobuttons instead of a 2-state checkbox for your Boolean columns which can store NULLs
https://github.com/sergeypedan/formtastic-tristate-radio
activeadmin formtastic gem rails ruby
Last synced: about 1 month ago
JSON representation
Have 3-state radiobuttons instead of a 2-state checkbox for your Boolean columns which can store NULLs
- Host: GitHub
- URL: https://github.com/sergeypedan/formtastic-tristate-radio
- Owner: sergeypedan
- License: mit
- Created: 2021-10-30T19:36:37.000Z (about 3 years ago)
- Default Branch: master
- Last Pushed: 2023-03-09T01:23:58.000Z (almost 2 years ago)
- Last Synced: 2024-08-31T05:51:32.662Z (4 months ago)
- Topics: activeadmin, formtastic, gem, rails, ruby
- Language: Ruby
- Homepage: https://sergeypedan.ru/open_source_projects/formtastic-tristate-radio
- Size: 88.9 KB
- Stars: 0
- Watchers: 2
- Forks: 0
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: MIT-LICENSE
Awesome Lists containing this project
README
# Formtastic tri-state radio
[![Gem Version](https://badge.fury.io/rb/formtastic_tristate_radio.svg)](https://badge.fury.io/rb/formtastic_tristate_radio)
[![Maintainability](https://api.codeclimate.com/v1/badges/c2508d7f23238fb2b87f/maintainability)](https://codeclimate.com/github/sergeypedan/formtastic-tristate-radio/maintainability)
[![Test Coverage](https://api.codeclimate.com/v1/badges/c2508d7f23238fb2b87f/test_coverage)](https://codeclimate.com/github/sergeypedan/formtastic-tristate-radio/test_coverage)## What is “tri-state”?
— that which has 3 states.
By defenition Boolean values have 2 states: True & False.
However, if you store a Boolean value in a database column with no `NOT NULL` restriction, it aquires a 3d possible state: `null`.
Some may consider this practice questionable — 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.
## What the gem does
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).
1. Teaches Rails recognize `"null"` and `"nil"` param values as `nil`. See “[How it works](#how-it-works)” ☟ section for technical details on this.
1. Encourages you to add translations for ActiveAdmin “status tag” so that `nil` be correctly translated as “Unset” instead of “False”.## Usage
For a Boolean column with 3 possible states:
```ruby
f.input :am_i_awake, as: :tristate_radio
```You get (HTML is simplified, actually there are more classes etc.):
```html
Am i awake?
Yes
No
Unset```
## Installation
### Gem
```ruby
gem "formtastic_tristate_radio"
```### Translations
Add translation for the new “unset” option:
```yaml
ru:
formtastic:
# :yes: Да # <- these two fall back to translations
# :no: Нет # in Formtastic gem but have only English
null: Неизвестно # <- this you must provide youself
```You can override individual translations like so:
```ruby
f.input :attribute, as: :tristate_radio, null: "Your text"
```### ActiveAdmin translations
ActiveAdmin will automatically translate `nil` as “No”, so if you use ActiveAdmin, add translation like so:
```yaml
ru:
active_admin:
status_tag:
:yes: Да
:no: Нет
unset: Неизвестно
```Notice that the key ActiveAdmin uses is “unset”, not “null”.
## Configuration
It’s difficult to come up with a reasonable use case for that, but you can configure what will be used as inputs value:
```ruby
# config/initializers/formtastic.rb
FormtasticTristateRadio.configure do |config|
config.unset_key = "__unset" # default is :null
end
```which will result in:
```html
```
Mind that for your custom value to work, you also need to configure `ActiveModel` to recognize that value as `nil`. Currently that is done [like so](https://github.com/sergeypedan/formtastic-tristate-radio/blob/master/config/initializers/activemodel_type_boolean.rb#L9).
## Documentation
Low-level methods are properly documented in RubyDoc [here](https://www.rubydoc.info/gems/formtastic_tristate_radio/TristateRadioInput).
## Dependencies
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.
## How it works
In Ruby any String is cast to `true`:
```ruby
!!"" #=> true
!!"false" #=> true
!!"nil" #=> true
!!"no" #=> true
!!"null" #=> true
```Web form params are passed as plain text and are interpreted as String by Rack.
So how are Boolean values transfered as strings if a `"no"` or `"0"` and even `""` is truthy in Ruby?
Frameworks just have a list of string values to be recognized and mapped to Boolean values:
```ruby
ActiveModel::Type::Boolean::FALSE_VALUES
#=> [
0, "0", :"0",
"f", :f, "F", :F,
false, "false", :false, "FALSE", :FALSE,
"off", :off, "OFF", :OFF,
]
```so that
```ruby
ActiveModel::Type::Boolean.new.cast("0") #=> false
ActiveModel::Type::Boolean.new.cast("f") #=> false
ActiveModel::Type::Boolean.new.cast(:FALSE) #=> false
ActiveModel::Type::Boolean.new.cast("off") #=> false
# etc
```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`:
```ruby
module ActiveModel
module Type
class Boolean < ValueNULL_VALUES = [nil, "", "null", :null, "nil", :nil].to_set.freeze
private def cast_value(value)
NULL_VALUES.include?(value) ? nil : !FALSE_VALUES.include?(value)
endend
end
end
```And voila!
```ruby
ActiveModel::Type::Boolean.new.cast("") #=> nil
ActiveModel::Type::Boolean.new.cast("null") #=> nil
ActiveModel::Type::Boolean.new.cast(:null) #=> nil
ActiveModel::Type::Boolean.new.cast("nil") #=> nil
ActiveModel::Type::Boolean.new.cast(:nil) #=> nil
```**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).
## Roadmap
- [ ] Remove `require_relative "../app/models/active_record/base"` from main file
- [x] Make the gem configurable
- [x] Pull the key used for “unset” choice value into configuration
- [x] Add translations into most popular languages
- [ ] Load translations from gem
- [ ] Rgister `:tristate_radio` for Boolean columns with `null`
- [ ] Decouple `ActiveModel::Type::Boolean` thing from Formtastic things, maybe into a separate gem
- [ ] Decouple from Rails## License
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).