Skip to content

Commit 8ce4e5c

Browse files
committed
Merge branch 'master' into pr-5036
* master: MONGOID-5128 Scoped associations (mongodb#5017) MONGOID-5005 - .sum, .count, and similar aggregables now ignore sort if not limiting/skipping (mongodb#5049) MONGOID-5098 Improve specs for timezone handling (specs only; no behavior change) (mongodb#5023) MONGOID-5151 Respect aliased fields in pluck/distinct by having Document.database_field_name recursively consider embedded docs (mongodb#5047) RUBY-2675 test coverage on the Mongoid side (mongodb#5030) MONGOID-4592 Add examples of using read_attribute and write_attribute to implement custom field behavior (mongodb#5082) MONGOId-5185 Remove tests for _id serialization (mongodb#5081) MONGOID-5103 Implement eq symbol operator (mongodb#5076) Fix MONGOID-5006 Link default auth source documentation to driver instead of incorrectly claiming "admin" is always the default (mongodb#5048) Create security policy following github's template (mongodb#5070)
2 parents e8483e6 + ee710c1 commit 8ce4e5c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1549
-170
lines changed

SECURITY.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Security Policy
2+
3+
## Supported Versions
4+
5+
Use this section to tell people about which versions of your project are
6+
currently being supported with security updates.
7+
8+
| Version | Supported |
9+
| ------- | ------------------ |
10+
| 7.3 | :white_check_mark: |
11+
| 7.2 | :white_check_mark: |
12+
| 7.1 | :white_check_mark: |
13+
| 7.0 | :white_check_mark: |
14+
| < 7.0 | :x: |
15+
16+
## Reporting a Vulnerability
17+
18+
Please [follow the instructions here](https://docs.mongodb.com/manual/tutorial/create-a-vulnerability-report/)
19+
to report a vulnerability.

docs/reference/associations.txt

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -969,6 +969,61 @@ the model. However, since Mongoid doesn't know what type of data should be
969969
allowed in the field, the field is created with a type of Object. It is a
970970
good idea to explicitly define the field with the appropriate type.
971971

972+
973+
.. _association-scope:
974+
975+
Custom Scopes
976+
-------------
977+
978+
You may set a specific scope on an association using the ``:scope`` parameter.
979+
The scope is an additional filter that restricts which objects are considered
980+
to be a part of the association - a scoped association will return only
981+
documents which satisfy the scope condition.. The scope may be either:
982+
983+
- a ``Proc`` with arity zero, or
984+
- a ``Symbol`` which references a :ref:`named scope <named-scopes>` on the
985+
associated model.
986+
987+
.. code-block:: ruby
988+
class Trainer
989+
has_many :pets, scope: -> { where(species: 'dog') }
990+
has_many :toys, scope: :rubber
991+
end
992+
993+
class Pet
994+
belongs_to :trainer
995+
end
996+
997+
class Toy
998+
scope :rubber, where(material: 'rubber')
999+
belongs_to :trainer
1000+
end
1001+
1002+
.. note::
1003+
1004+
It is possible to add documents that do not satisfy an association's scope
1005+
to that association. In this case, such documents will appear associated
1006+
in memory, and will be saved to the database, but will not be present when
1007+
the association is queried in the future. For example:
1008+
1009+
.. code-block:: ruby
1010+
1011+
trainer = Trainer.create!
1012+
dog = Pet.create!(trainer: trainer, species: 'dog')
1013+
cat = Pet.create!(trainer: trainer, species: 'cat')
1014+
1015+
trainer.pets #=> [dog, cat]
1016+
1017+
trainer.reload.pets #=> [dog]
1018+
1019+
.. note::
1020+
1021+
Mongoid's syntax for scoped association differs from that of Active Record.
1022+
Mongoid uses the ``:scope`` keyword argument for consistency with other
1023+
association options, whereas in Active Record the scope is a positional
1024+
argument.
1025+
1026+
9721027
Validations
9731028
-----------
9741029

docs/reference/configuration.txt

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ can be configured.
139139
- myhost3.mydomain.com:27017
140140
options:
141141
# These options are Ruby driver options, documented in
142-
# https://docs.mongodb.com/ruby-driver/current/tutorials/ruby-driver-create-client/
142+
# https://docs.mongodb.com/ruby-driver/current/reference/create-client/
143143

144144
# Change the default write concern. (default = { w: 1 })
145145
write:
@@ -168,7 +168,13 @@ can be configured.
168168
# on 2.4 and 2.6 is :plain)
169169
auth_mech: :scram
170170

171-
# The database or source to authenticate the user against. (default: admin)
171+
# Specify the auth source, i.e. the database or other source which
172+
# contains the user's login credentials. Allowed values for auth source
173+
# depend on the authentication mechanism, as explained in the server documentation:
174+
# https://docs.mongodb.com/manual/reference/connection-string/#mongodb-urioption-urioption.authSource
175+
# If no auth source is specified, the default auth source as
176+
# determined by the driver will be used. Please refer to:
177+
# https://docs.mongodb.com/ruby-driver/current/reference/authentication/#auth-source
172178
auth_source: admin
173179

174180
# Force the driver to connect in a specific way instead of auto-
@@ -291,7 +297,7 @@ can be configured.
291297
use_utc: false
292298

293299
The Ruby driver options may be found in
294-
`the driver documentation <https://docs.mongodb.com/ruby-driver/current/tutorials/ruby-driver-create-client/>`_.
300+
`the driver documentation <https://docs.mongodb.com/ruby-driver/current/reference/create-client/>`_.
295301

296302
ERb Preprocessing
297303
=================
@@ -596,7 +602,7 @@ be executed sequentially during socket creation.
596602
in an application.
597603

598604
For more information about TLS context hooks, including best practices for
599-
assigning and removing them, see `the Ruby driver documentation <https://docs.mongodb.com/ruby-driver/current/tutorials/ruby-driver-create-client/#modifying-sslcontext>`_.
605+
assigning and removing them, see `the Ruby driver documentation <https://docs.mongodb.com/ruby-driver/current/reference/create-client/#modifying-sslcontext>`_.
600606

601607
Usage with Forking Servers
602608
==========================

docs/reference/fields.txt

Lines changed: 162 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -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-
638548
Reserved Names
639549
--------------
640550

641551
Attempting to define a field on a document that conflicts with a reserved
642552
method name in Mongoid will raise an error. The list of reserved names can
643553
be obtained by invoking the ``Mongoid.destructive_fields`` method.
644554

555+
645556
Field Redefinition
646557
------------------
647558

@@ -729,6 +640,167 @@ alias can :ref:`be removed <unalias-id>` if desired (such as to integrate
729640
with 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

734806
Dynamic Fields

0 commit comments

Comments
 (0)