Skip to content

Commit

Permalink
Support nullable boolean field. Closes #3145
Browse files Browse the repository at this point in the history
  • Loading branch information
mshibuya committed Oct 17, 2021
1 parent e4ae669 commit 7583369
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 19 deletions.
9 changes: 9 additions & 0 deletions app/assets/stylesheets/rails_admin/ra.widgets.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ iframe.wysihtml5-sandbox, .wysihtml5-editor{
display: none;
}

.form-group.boolean_type {
.success.active {
@extend .btn-success
}
.danger.active {
@extend .btn-danger
}
}

.links .inline.list-inline .disabled span {
color: $gray-light;
}
13 changes: 10 additions & 3 deletions app/views/rails_admin/main/_form_boolean.html.haml
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
.checkbox
%label{ style: 'display: block;' }
= form.send field.view_helper, field.method_name, field.html_attributes.reverse_merge({ value: field.form_value, checked: field.form_value.in?([true, '1']), required: field.required})
- if field.nullable?
.btn-group{'data-toggle': 'buttons'}
- {'1': true, '0': false, '': nil}.each do |text, value|
%label.btn.btn-default{class: [field.css_classes[value], ("active" if field.form_value == value)]}
= form.radio_button field.method_name, text, field.html_attributes.reverse_merge({ checked: field.form_value == value, required: field.required})
= field.labels[value].html_safe
- else
.checkbox
%label{ style: 'display: block;' }
= form.send field.view_helper, field.method_name, field.html_attributes.reverse_merge({ value: field.form_value, checked: field.form_value.in?([true, '1']), required: field.required})
40 changes: 32 additions & 8 deletions lib/rails_admin/config/fields/types/boolean.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,32 @@ class Boolean < RailsAdmin::Config::Fields::Base
# Register field type for the type loader
RailsAdmin::Config::Fields::Types.register(self)

register_instance_option :labels do
{
true => %(<span class="icon icon-ok"></span>),
false => %(<span class="icon icon-remove"></span>),
nil => %(<span class="icon icon-minus"></span>),
}
end

register_instance_option :css_classes do
{
true => 'success',
false => 'danger',
nil => 'default',
}
end

register_instance_option :nullable? do
properties&.nullable?
end

register_instance_option :view_helper do
:check_box
end

register_instance_option :pretty_value do
case value
when false
%(<span class='label label-danger'>&#x2718;</span>)
when true
%(<span class='label label-success'>&#x2713;</span>)
else
%(<span class='label label-default'>&#x2012;</span>)
end.html_safe
%(<span class="label label-#{css_classes[form_value]}">#{labels[form_value]}</span>).html_safe
end

register_instance_option :export_value do
Expand All @@ -29,10 +42,21 @@ class Boolean < RailsAdmin::Config::Fields::Base
:form_boolean
end

def form_value
case value
when true, false
value
end
end

# Accessor for field's help text displayed below input field.
def generic_help
''
end

def parse_input(params)
params[name] = params[name].presence if params.key?(name)
end
end
end
end
Expand Down
4 changes: 3 additions & 1 deletion spec/integration/actions/edit_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -833,7 +833,9 @@ class HelpTest < Tableless
it 'is updatable without any error' do
RailsAdmin.config FieldTest do
edit do
field :open
field :open do
nullable false
end
end
end
record = FieldTest.create
Expand Down
4 changes: 2 additions & 2 deletions spec/integration/authorization/cancancan_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ def initialize(user)
it 'POST /admin/player/new with unauthorized attribute value should raise access denied' do
visit new_path(model_name: 'player')
fill_in 'player[name]', with: 'Jackie Robinson'
uncheck 'player[suspended]'
choose name: 'player[suspended]', option: '0'
expect { click_button 'Save' }.to raise_error(CanCan::AccessDenied)
end

Expand Down Expand Up @@ -173,7 +173,7 @@ def initialize(user)
it 'PUT /admin/player/new with unauthorized attribute value should raise access denied' do
@player = FactoryBot.create :player
visit edit_path(model_name: 'player', id: @player.id)
check 'player[retired]'
choose name: 'player[retired]', option: '1'
expect { click_button 'Save' }.to raise_error(CanCan::AccessDenied)
end

Expand Down
4 changes: 2 additions & 2 deletions spec/integration/authorization/pundit_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@
it 'POST /admin/player/new with unauthorized attribute value should raise access denied' do
visit new_path(model_name: 'player')
fill_in 'player[name]', with: 'Jackie Robinson'
uncheck 'player[suspended]'
choose name: 'player[suspended]', option: '0'
expect { click_button 'Save' }.to raise_error(Pundit::NotAuthorizedError)
end
end
Expand All @@ -118,7 +118,7 @@
it 'PUT /admin/player/new with unauthorized attribute value should raise access denied' do
@player = FactoryBot.create :player
visit edit_path(model_name: 'player', id: @player.id)
check 'player[retired]'
choose name: 'player[retired]', option: '1'
expect { click_button 'Save' }.to raise_error(Pundit::NotAuthorizedError)
end
end
Expand Down
59 changes: 59 additions & 0 deletions spec/integration/fields/boolean_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
require 'spec_helper'

RSpec.describe 'Boolean field', type: :request do
subject { page }
let(:field_test) { FactoryBot.create :field_test }

context 'if nullable' do
before do
RailsAdmin.config FieldTest do
field :boolean_field
end
end

it 'shows 3 radio buttons' do
visit new_path(model_name: 'field_test')
is_expected.to have_content 'New Field test'
expect(all('[name="field_test[boolean_field]"]').map { |e| e['value'] }).to eq ['1', '0', '']
end

it 'can be updated' do
visit edit_path(model_name: 'field_test', id: field_test.id)
find('.boolean_type .icon-ok').sibling('input').click
click_button 'Save and edit'
expect(field_test.reload.boolean_field).to be true
find('.boolean_type .icon-remove').sibling('input').click
click_button 'Save and edit'
expect(field_test.reload.boolean_field).to be false
find('.boolean_type .icon-minus').sibling('input').click
click_button 'Save and edit'
expect(field_test.reload.boolean_field).to be nil
end
end

context 'if not nullable' do
before do
RailsAdmin.config FieldTest do
field :boolean_field do
nullable false
end
end
end

it 'shows a checkbox' do
visit new_path(model_name: 'field_test')
is_expected.to have_content 'New Field test'
is_expected.to have_css '[type="checkbox"][name="field_test[boolean_field]"]'
end

it 'can be updated' do
visit edit_path(model_name: 'field_test', id: field_test.id)
find('.boolean_type input').check
click_button 'Save and edit'
expect(field_test.reload.boolean_field).to be true
find('.boolean_type input').uncheck
click_button 'Save and edit'
expect(field_test.reload.boolean_field).to be false
end
end
end
6 changes: 3 additions & 3 deletions spec/rails_admin/config/fields/types/boolean_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@

describe '#pretty_value' do
{
false => %(<span class='label label-danger'>&#x2718;</span>),
true => %(<span class='label label-success'>&#x2713;</span>),
nil => %(<span class='label label-default'>&#x2012;</span>),
false => %(<span class="label label-danger"><span class="icon icon-remove"></span></span>),
true => %(<span class="label label-success"><span class="icon icon-ok"></span></span>),
nil => %(<span class="label label-default"><span class="icon icon-minus"></span></span>),
}.each do |field_value, expected_result|
context "when field value is '#{field_value.inspect}'" do
let(:test_object) { FieldTest.new(boolean_field: field_value) }
Expand Down

0 comments on commit 7583369

Please sign in to comment.