@@ -545,103 +545,14 @@ This is useful for storing different values in ``id`` and ``_id`` fields:
545545 # => #<Band _id: 5fc1c3f42c97a6590684046c, id: "42">
546546
547547
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-
638548Reserved Names
639549--------------
640550
641551Attempting to define a field on a document that conflicts with a reserved
642552method name in Mongoid will raise an error. The list of reserved names can
643553be obtained by invoking the ``Mongoid.destructive_fields`` method.
644554
555+
645556Field Redefinition
646557------------------
647558
@@ -729,6 +640,167 @@ alias can :ref:`be removed <unalias-id>` if desired (such as to integrate
729640with systems that use the ``id`` field to store value different from ``_id``.
730641
731642
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+
732804.. _dynamic-fields:
733805
734806Dynamic Fields
0 commit comments