Skip to content

Commit f33b2c0

Browse files
neilshwekyp-mongo
andauthored
MONGOID-5264 add :present option to localized fields (#5408)
* MONGOID-5264 add :present option to localize * MONGOID-5264 change present? to localize_present? * MONGOID-5264 add tests and fix present * MONGOID-5264 add docs and release notes * MONGOID-5264 potentially fix tests * MONGOID-5264 fix docs * MONGOID-5264 update the docstring * MONGOID-5264 reset fallbacks after setting * Update docs/reference/fields.txt Co-authored-by: Oleg Pudeyev <[email protected]> * MONGOID-5264 answer comments * Update lib/mongoid/attributes.rb Co-authored-by: Oleg Pudeyev <[email protected]> Co-authored-by: Oleg Pudeyev <[email protected]>
1 parent 12e3e86 commit f33b2c0

File tree

9 files changed

+294
-21
lines changed

9 files changed

+294
-21
lines changed

docs/reference/fields.txt

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1396,6 +1396,42 @@ You can get and set all the translations at once by using the corresponding ``_t
13961396
{ "en" => "Marvelous!", "de" => "Wunderbar!" }
13971397

13981398

1399+
.. _present-fields:
1400+
1401+
Localize ``:present`` Field Option
1402+
----------------------------------
1403+
1404+
Mongoid supports the ``:present`` option when creating a localized field:
1405+
1406+
.. code-block:: ruby
1407+
1408+
class Product
1409+
include Mongoid::Document
1410+
field :description, localize: :present
1411+
end
1412+
1413+
This option automatically removes ``blank`` values (i.e. those that return true
1414+
for the ``blank?`` method) from the ``_translations`` hash:
1415+
1416+
.. code-block:: ruby
1417+
1418+
I18n.default_locale = :en
1419+
product = Product.new
1420+
product.description = "Marvelous!"
1421+
I18n.locale = :de
1422+
product.description = "Fantastisch!"
1423+
1424+
product.description_translations
1425+
# { "en" => "Marvelous!", "de" => "Fantastisch!" }
1426+
1427+
product.description = ""
1428+
product.description_translations
1429+
# { "en" => "Marvelous!" }
1430+
1431+
When the empty string is written for the ``:de`` locale, the ``"de"`` key is
1432+
removed from the ``_translations`` hash instead of writing the empty string.
1433+
1434+
13991435
Fallbacks
14001436
---------
14011437

docs/release-notes/mongoid-8.1.txt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,20 @@ specific version:
9999
This is helpful for upgrading between versions. See the section on
100100
:ref:`Version Based Default Configuration <load-defaults>` for more details on
101101
how to use this feature to make upgrading between Mongoid versions easier.
102+
103+
104+
Added ``:present`` option to localized fields
105+
---------------------------------------------
106+
107+
The ``:present`` option was added to localized fields for removing blank values
108+
from the ``_translations`` hash:
109+
110+
.. code-block:: ruby
111+
112+
class Product
113+
include Mongoid::Document
114+
field :description, localize: :present
115+
end
116+
117+
See the section on :ref:`Localize :present Field Option <present-fields>` for
118+
more details on how these are used.

lib/mongoid/attributes.rb

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,14 @@ def write_attribute(name, value)
177177
attribute_will_change!(field_name)
178178
end
179179
if localized
180-
attributes[field_name] ||= {}
181-
attributes[field_name].merge!(typed_value)
180+
present = fields[field_name].try(:localize_present?)
181+
loc_key, loc_val = typed_value.first
182+
if present && loc_val.blank?
183+
attributes[field_name]&.delete(loc_key)
184+
else
185+
attributes[field_name] ||= {}
186+
attributes[field_name].merge!(typed_value)
187+
end
182188
else
183189
attributes[field_name] = typed_value
184190
end

lib/mongoid/fields.rb

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -802,18 +802,18 @@ def field_for(name, options)
802802
Fields::Standard.new(name, opts)
803803
end
804804

805-
# Get the class for the given type.
806-
#
807-
# @param [ Symbol ] name The name of the field.
808-
# @param [ Symbol | Class ] type The type of the field.
809-
#
810-
# @return [ Class ] The type of the field.
811-
#
812-
# @raises [ Mongoid::Errors::InvalidFieldType ] if given an invalid field
813-
# type.
814-
#
815-
# @api private
816-
def retrieve_and_validate_type(name, type)
805+
# Get the class for the given type.
806+
#
807+
# @param [ Symbol ] name The name of the field.
808+
# @param [ Symbol | Class ] type The type of the field.
809+
#
810+
# @return [ Class ] The type of the field.
811+
#
812+
# @raises [ Mongoid::Errors::InvalidFieldType ] if given an invalid field
813+
# type.
814+
#
815+
# @api private
816+
def retrieve_and_validate_type(name, type)
817817
type_mapping = TYPE_MAPPINGS[type]
818818
result = type_mapping || unmapped_type(type)
819819
if !result.is_a?(Class)

lib/mongoid/fields/localized.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,16 @@ def localized?
2929
true
3030
end
3131

32+
# Is the localized field enforcing values to be present?
33+
#
34+
# @example Is the localized field enforcing values to be present?
35+
# field.localize_present?
36+
#
37+
# @return [ true | false ] If the field enforces present.
38+
def localize_present?
39+
options[:localize] == :present
40+
end
41+
3242
# Convert the provided string into a hash for the locale.
3343
#
3444
# @example Serialize the value.

lib/mongoid/fields/standard.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,16 @@ def localized?
9797
false
9898
end
9999

100+
# Is the localized field enforcing values to be present?
101+
#
102+
# @example Is the localized field enforcing values to be present?
103+
# field.localize_present?
104+
#
105+
# @return [ true | false ] If the field enforces present.
106+
def localize_present?
107+
false
108+
end
109+
100110
# Get the metadata for the field if its a foreign key.
101111
#
102112
# @example Get the metadata.

spec/mongoid/fields/localized_spec.rb

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,11 @@
124124

125125
context "when fallbacks are defined" do
126126

127-
before do
127+
around do |example|
128+
prev_fallbacks = I18n.fallbacks.dup
128129
::I18n.fallbacks[:de] = [ :de, :en, :es ]
130+
example.run
131+
I18n.fallbacks = prev_fallbacks
129132
end
130133

131134
context "when the first fallback translation exists" do
@@ -164,8 +167,11 @@
164167

165168
context "when no fallbacks are defined" do
166169

167-
before do
170+
around do |example|
171+
prev_fallbacks = I18n.fallbacks.dup
168172
::I18n.fallbacks[:de] = [ :de ]
173+
example.run
174+
I18n.fallbacks = prev_fallbacks
169175
end
170176

171177
let(:value) do
@@ -179,8 +185,11 @@
179185

180186
context 'when fallbacks are empty' do
181187

182-
before do
188+
around do |example|
189+
prev_fallbacks = I18n.fallbacks.dup
183190
::I18n.fallbacks[:de] = [ ]
191+
example.run
192+
I18n.fallbacks = prev_fallbacks
184193
end
185194

186195
let(:value) do
@@ -282,8 +291,11 @@
282291

283292
context "when fallbacks are defined" do
284293

285-
before do
294+
around do |example|
295+
prev_fallbacks = I18n.fallbacks.dup
286296
::I18n.fallbacks[:de] = [ :de, :en, :es ]
297+
example.run
298+
I18n.fallbacks = prev_fallbacks
287299
end
288300

289301
context 'when fallbacks are enabled' do
@@ -340,8 +352,11 @@
340352

341353
context "when no fallbacks are defined" do
342354

343-
before do
355+
around do |example|
356+
prev_fallbacks = I18n.fallbacks.dup
344357
::I18n.fallbacks[:de] = [ :de ]
358+
example.run
359+
I18n.fallbacks = prev_fallbacks
345360
end
346361

347362
let(:value) do
@@ -485,8 +500,11 @@
485500

486501
context "when the value is false" do
487502

488-
before do
503+
around do |example|
504+
prev_fallbacks = I18n.fallbacks.dup
489505
::I18n.fallbacks[:de] = [:en, :es]
506+
example.run
507+
I18n.fallbacks = prev_fallbacks
490508
end
491509

492510
let(:field) do
@@ -504,8 +522,11 @@
504522

505523
context "when the value is true" do
506524

507-
before do
525+
around do |example|
526+
prev_fallbacks = I18n.fallbacks.dup
508527
::I18n.fallbacks[:de] = [:en, :es]
528+
example.run
529+
I18n.fallbacks = prev_fallbacks
509530
end
510531

511532
let(:field) do
@@ -525,4 +546,37 @@
525546
end
526547
end
527548
end
549+
550+
describe "localize: :present" do
551+
552+
let(:field) do
553+
described_class.new(:description, localize: :present, type: String)
554+
end
555+
556+
context "when setting the localize to present" do
557+
558+
it "is localized?" do
559+
expect(field.localized?).to be true
560+
end
561+
562+
it "is localize_present?" do
563+
expect(field.localize_present?).to be true
564+
end
565+
end
566+
567+
context "when localize is not localize_present" do
568+
569+
let(:field) do
570+
described_class.new(:description, localize: true, type: String)
571+
end
572+
573+
it "is localized?" do
574+
expect(field.localized?).to be true
575+
end
576+
577+
it "is not localize_present?" do
578+
expect(field.localize_present?).to be false
579+
end
580+
end
581+
end
528582
end

0 commit comments

Comments
 (0)