@@ -545,103 +545,14 @@ This is useful for storing different values in ``id`` and ``_id`` fields:
545
545
# => #<Band _id: 5fc1c3f42c97a6590684046c, id: "42">
546
546
547
547
548
- Custom Fields
549
- -------------
550
-
551
- You can define custom types in Mongoid and determine how they are serialized and deserialized.
552
- You simply need to provide three methods on it for Mongoid to call to convert your object to
553
- and from MongoDB friendly values.
554
-
555
- .. code-block:: ruby
556
-
557
- class Profile
558
- include Mongoid::Document
559
- field :location, type: Point
560
- end
561
-
562
- class Point
563
-
564
- attr_reader :x, :y
565
-
566
- def initialize(x, y)
567
- @x, @y = x, y
568
- end
569
-
570
- # Converts an object of this instance into a database friendly value.
571
- def mongoize
572
- [ x, y ]
573
- end
574
-
575
- class << self
576
-
577
- # Get the object as it was stored in the database, and instantiate
578
- # this custom class from it.
579
- def demongoize(object)
580
- Point.new(object[0], object[1])
581
- end
582
-
583
- # Takes any possible object and converts it to how it would be
584
- # stored in the database.
585
- def mongoize(object)
586
- case object
587
- when Point then object.mongoize
588
- when Hash then Point.new(object[:x], object[:y]).mongoize
589
- else object
590
- end
591
- end
592
-
593
- # Converts the object that was supplied to a criteria and converts it
594
- # into a database friendly form.
595
- def evolve(object)
596
- case object
597
- when Point then object.mongoize
598
- else object
599
- end
600
- end
601
- end
602
- end
603
-
604
- The instance method ``mongoize`` takes an instance of your object, and converts it
605
- into how it will be stored in the database. In our example above, we want to store our
606
- point object as an array in the form ``[ x, y ]``.
607
-
608
- The class method ``demongoize`` takes an object as how it was stored in the database,
609
- and is responsible for instantiating an object of your custom type. In this case, we
610
- take an array and instantiate a ``Point`` from it.
611
-
612
- The class method ``mongoize`` takes an object that you would use to set on your model
613
- from your application code, and create the object as it would be stored in the database.
614
- This is for cases where you are not passing your model instances of your custom type in the setter:
615
-
616
- .. code-block:: ruby
617
-
618
- point = Point.new(12, 24)
619
- venue = Venue.new(location: point) # This uses the mongoize instance method.
620
- venue = Venue.new(location: [ 12, 24 ]) # This uses the mongoize class method.
621
-
622
- The class method ``evolve`` takes an object, and determines how it is to be transformed
623
- for use in criteria. For example we may want to write a query like so:
624
-
625
- .. code-block:: ruby
626
-
627
- point = Point.new(12, 24)
628
- Venue.where(location: point)
629
-
630
- Note that when accessing custom fields from the document, you will get a new instance
631
- of that object with each call to the getter. This is because Mongoid is generating a new
632
- object from the raw attributes on each access.
633
-
634
- We need the point object in the criteria to be transformed to a Mongo friendly value when
635
- it is not as well, ``evolve`` is the method that takes care of this. We check if the passed
636
- in object is a ``Point`` first, in case we also want to be able to pass in ordinary arrays instead.
637
-
638
548
Reserved Names
639
549
--------------
640
550
641
551
Attempting to define a field on a document that conflicts with a reserved
642
552
method name in Mongoid will raise an error. The list of reserved names can
643
553
be obtained by invoking the ``Mongoid.destructive_fields`` method.
644
554
555
+
645
556
Field Redefinition
646
557
------------------
647
558
@@ -729,6 +640,167 @@ alias can :ref:`be removed <unalias-id>` if desired (such as to integrate
729
640
with systems that use the ``id`` field to store value different from ``_id``.
730
641
731
642
643
+ Customizing Field Behavior
644
+ ==========================
645
+
646
+ Mongoid offers several options for customizing the behavior of fields.
647
+
648
+
649
+ Custom Getters And Setters
650
+ --------------------------
651
+
652
+ You can define custom getters and setters for fields to modify the values
653
+ when they are being accessed or written. The getters and setters use the
654
+ same name as the field. Use ``read_attribute`` and ``write_attribute``
655
+ methods inside the getters and setters to operate on the raw attribute
656
+ values.
657
+
658
+ For example, Mongoid provides the ``:default`` field option to write a
659
+ default value into the field. If you wish to have a field default value
660
+ in your application but do not wish to persist it, you can override the
661
+ getter as follows:
662
+
663
+ .. code-block:: ruby
664
+
665
+ class DistanceMeasurement
666
+ include Mongoid::Document
667
+
668
+ field :value, type: Float
669
+ field :unit, type: String
670
+
671
+ def unit
672
+ read_attribute(:unit) || "m"
673
+ end
674
+
675
+ def to_s
676
+ "#{value} #{unit}"
677
+ end
678
+ end
679
+
680
+ measurement = DistanceMeasurement.new(value: 2)
681
+ measurement.to_s
682
+ # => "2.0 m"
683
+ measurement.attributes
684
+ # => {"_id"=>BSON::ObjectId('613fa0b0a15d5d61502f3447'), "value"=>2.0}
685
+
686
+ To give another example, a field which converts empty strings to nil values
687
+ may be implemented as follows:
688
+
689
+ .. code-block:: ruby
690
+
691
+ class DistanceMeasurement
692
+ include Mongoid::Document
693
+
694
+ field :value, type: Float
695
+ field :unit, type: String
696
+
697
+ def unit=(value)
698
+ if value.blank?
699
+ value = nil
700
+ end
701
+ write_attribute(:unit, value)
702
+ end
703
+ end
704
+
705
+ measurement = DistanceMeasurement.new(value: 2, unit: "")
706
+ measurement.attributes
707
+ # => {"_id"=>BSON::ObjectId('613fa15aa15d5d617216104c'), "value"=>2.0, "unit"=>nil}
708
+
709
+
710
+ Custom Field Types
711
+ ------------------
712
+
713
+ You can define custom types in Mongoid and determine how they are serialized
714
+ and deserialized. You simply need to provide three methods on it for Mongoid
715
+ to call to convert your object to and from MongoDB friendly values.
716
+
717
+ .. code-block:: ruby
718
+
719
+ class Profile
720
+ include Mongoid::Document
721
+ field :location, type: Point
722
+ end
723
+
724
+ class Point
725
+
726
+ attr_reader :x, :y
727
+
728
+ def initialize(x, y)
729
+ @x, @y = x, y
730
+ end
731
+
732
+ # Converts an object of this instance into a database friendly value.
733
+ def mongoize
734
+ [ x, y ]
735
+ end
736
+
737
+ class << self
738
+
739
+ # Get the object as it was stored in the database, and instantiate
740
+ # this custom class from it.
741
+ def demongoize(object)
742
+ Point.new(object[0], object[1])
743
+ end
744
+
745
+ # Takes any possible object and converts it to how it would be
746
+ # stored in the database.
747
+ def mongoize(object)
748
+ case object
749
+ when Point then object.mongoize
750
+ when Hash then Point.new(object[:x], object[:y]).mongoize
751
+ else object
752
+ end
753
+ end
754
+
755
+ # Converts the object that was supplied to a criteria and converts it
756
+ # into a database friendly form.
757
+ def evolve(object)
758
+ case object
759
+ when Point then object.mongoize
760
+ else object
761
+ end
762
+ end
763
+ end
764
+ end
765
+
766
+ The instance method ``mongoize`` takes an instance of your object, and
767
+ converts it into how it will be stored in the database. In our example above,
768
+ we want to store our point object as an array in the form ``[ x, y ]``.
769
+
770
+ The class method ``demongoize`` takes an object as how it was stored in the
771
+ database, and is responsible for instantiating an object of your custom type.
772
+ In this case, we take an array and instantiate a ``Point`` from it.
773
+
774
+ The class method ``mongoize`` takes an object that you would use to set on
775
+ your model from your application code, and create the object as it would be
776
+ stored in the database. This is for cases where you are not passing your
777
+ model instances of your custom type in the setter:
778
+
779
+ .. code-block:: ruby
780
+
781
+ point = Point.new(12, 24)
782
+ venue = Venue.new(location: point) # This uses the mongoize instance method.
783
+ venue = Venue.new(location: [ 12, 24 ]) # This uses the mongoize class method.
784
+
785
+ The class method ``evolve`` takes an object, and determines how it is to be
786
+ transformed for use in criteria. For example we may want to write a query
787
+ like so:
788
+
789
+ .. code-block:: ruby
790
+
791
+ point = Point.new(12, 24)
792
+ Venue.where(location: point)
793
+
794
+ Note that when accessing custom fields from the document, you will get a
795
+ new instance of that object with each call to the getter. This is because
796
+ Mongoid is generating a new object from the raw attributes on each access.
797
+
798
+ We need the point object in the criteria to be transformed to a
799
+ MongoDB-friendly value when it is not as well, ``evolve`` is the method
800
+ that takes care of this. We check if the passed in object is a ``Point``
801
+ first, in case we also want to be able to pass in ordinary arrays instead.
802
+
803
+
732
804
.. _dynamic-fields:
733
805
734
806
Dynamic Fields
0 commit comments