Commit 5e149b3d authored by Tiger's avatar Tiger

Create helper to set blank attributes to nil before validation

Uses a before_validation callback to set configured
attributes to nil if they have a truthy response to #blank?,
which helps prevent empty strings ending up in the database.
parent 5e778daa
# frozen_string_literal: true
# Helper that sets attributes to nil prior to validation if they
# are blank (are false, empty or contain only whitespace), to avoid
# unnecessarily persisting empty strings.
#
# Model usage:
#
# class User < ApplicationRecord
# include NullifyIfBlank
#
# nullify_if_blank :name, :email
# end
#
#
# Test usage:
#
# RSpec.describe User do
# it { is_expected.to nullify_if_blank(:name) }
# it { is_expected.to nullify_if_blank(:email) }
# end
#
module NullifyIfBlank
extend ActiveSupport::Concern
class_methods do
def nullify_if_blank(*attributes)
self.attributes_to_nullify += attributes
end
end
included do
class_attribute :attributes_to_nullify,
instance_accessor: false,
instance_predicate: false,
default: Set.new
before_validation :nullify_blank_attributes
end
private
def nullify_blank_attributes
self.class.attributes_to_nullify.each do |attribute|
assign_attributes(attribute => nil) if read_attribute(attribute).blank?
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe NullifyIfBlank do
let_it_be(:model) do
Class.new(ApplicationRecord) do
include NullifyIfBlank
nullify_if_blank :name
self.table_name = 'users'
end
end
context 'attribute exists' do
let(:instance) { model.new(name: name) }
subject { instance.name }
before do
instance.validate
end
context 'attribute is blank' do
let(:name) { '' }
it { is_expected.to be_nil }
end
context 'attribute is nil' do
let(:name) { nil }
it { is_expected.to be_nil}
end
context 'attribute is not blank' do
let(:name) { 'name' }
it { is_expected.to eq('name') }
end
end
context 'attribute does not exist' do
before do
model.table_name = 'issues'
end
it { expect { model.new.valid? }.to raise_error(ActiveModel::UnknownAttributeError) }
end
end
# frozen_string_literal: true
RSpec::Matchers.define :nullify_if_blank do |attribute|
match do |record|
expect(record.class.attributes_to_nullify).to include(attribute)
end
failure_message do |record|
"expected nullify_if_blank configuration on #{record.class} to include #{attribute}"
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment