diff --git a/CHANGELOG.md b/CHANGELOG.md index d7e41bbb6a..968c2e9fc5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -110,6 +110,8 @@ For instructions on upgrading to newer versions, visit ### Resolved Issues +* mongoid/moped\#82 Aliased fields now work with `Criteria#distinct`. + * \#2423 Fixed embedded document's `update_all` to perform the correct $set when using off a criteria. diff --git a/lib/mongoid/contextual/mongo.rb b/lib/mongoid/contextual/mongo.rb index ed996756f9..31c7d2462e 100644 --- a/lib/mongoid/contextual/mongo.rb +++ b/lib/mongoid/contextual/mongo.rb @@ -97,7 +97,7 @@ def destroy # # @since 3.0.0 def distinct(field) - query.distinct(field) + query.distinct(klass.database_field_name(field)) end # Iterate over the context. If provided a block, yield to a Mongoid diff --git a/lib/mongoid/fields.rb b/lib/mongoid/fields.rb index 37d91d6bef..930977d891 100644 --- a/lib/mongoid/fields.rb +++ b/lib/mongoid/fields.rb @@ -108,6 +108,21 @@ def attribute_names self.class.attribute_names end + # Get the name of the provided field as it is stored in the database. + # Used in determining if the field is aliased or not. + # + # @example Get the database field name. + # model.database_field_name(:authorization) + # + # @param [ String, Symbol ] name The name to get. + # + # @return [ String ] The name of the field as it's stored in the db. + # + # @since 3.0.7 + def database_field_name(name) + self.class.database_field_name(name) + end + # Is the provided field a lazy evaluation? # # @example If the field is lazy settable. @@ -189,6 +204,22 @@ def attribute_names fields.keys end + # Get the name of the provided field as it is stored in the database. + # Used in determining if the field is aliased or not. + # + # @example Get the database field name. + # Model.database_field_name(:authorization) + # + # @param [ String, Symbol ] name The name to get. + # + # @return [ String ] The name of the field as it's stored in the db. + # + # @since 3.0.7 + def database_field_name(name) + normalized = name.to_s + aliased_fields[normalized] || normalized + end + # Defines all the fields that are accessible on the Document # For each field that is defined, a getter and setter will be # added as an instance method to the Document. diff --git a/lib/mongoid/indexes.rb b/lib/mongoid/indexes.rb index 8766e582dc..7d181bc11f 100644 --- a/lib/mongoid/indexes.rb +++ b/lib/mongoid/indexes.rb @@ -115,10 +115,9 @@ def normalize_index_options(options) # # @since 3.0.7 def normalize_spec(spec) - spec.inject({}) do |normal, (name, direction)| - field_name = aliased_fields[name.to_s] || name - normal[field_name.to_sym] = direction - normal + spec.inject({}) do |normalized, (name, direction)| + normalized[database_field_name(name).to_sym] = direction + normalized end end end diff --git a/lib/mongoid/multi_parameter_attributes.rb b/lib/mongoid/multi_parameter_attributes.rb index ab7b54d04a..d5e9715fe0 100644 --- a/lib/mongoid/multi_parameter_attributes.rb +++ b/lib/mongoid/multi_parameter_attributes.rb @@ -66,7 +66,7 @@ def process_attributes(attrs = nil, role = :default, guard_protected_attributes multi_parameter_attributes.each_pair do |key, values| begin values = (values.keys.min..values.keys.max).map { |i| values[i] } - field = self.class.fields[aliased_fields[key] || key] + field = self.class.fields[database_field_name(key)] attributes[key] = instantiate_object(field, values) rescue => e errors << Errors::AttributeAssignmentError.new( diff --git a/lib/mongoid/persistence.rb b/lib/mongoid/persistence.rb index 01d303d937..c5bf30f7c8 100644 --- a/lib/mongoid/persistence.rb +++ b/lib/mongoid/persistence.rb @@ -159,7 +159,7 @@ def update_attribute(name, value) unless attribute_writable?(normalized) raise Errors::ReadonlyAttribute.new(normalized, value) end - write_attribute(aliased_fields[normalized] || normalized, value) + write_attribute(database_field_name(normalized), value) save(validate: false) end diff --git a/lib/mongoid/validations/uniqueness.rb b/lib/mongoid/validations/uniqueness.rb index bcc9e23ec1..33ffa9ccff 100644 --- a/lib/mongoid/validations/uniqueness.rb +++ b/lib/mongoid/validations/uniqueness.rb @@ -167,8 +167,7 @@ def filter(value) # @since 2.3.0 def scope(criteria, document, attribute) Array.wrap(options[:scope]).each do |item| - normalized = item.to_s - name = document.aliased_fields[normalized] || normalized + name = document.database_field_name(item) criteria = criteria.where(item => document.attributes[name]) end criteria = criteria.where(deleted_at: nil) if document.paranoid? diff --git a/spec/app/models/band.rb b/spec/app/models/band.rb index 6f467d9b65..df56b27688 100644 --- a/spec/app/models/band.rb +++ b/spec/app/models/band.rb @@ -12,6 +12,7 @@ class Band field :upserted, type: Boolean, default: false field :created, type: DateTime field :sales, type: BigDecimal + field :y, as: :years, type: Integer embeds_many :records, cascade_callbacks: true embeds_many :notes, as: :noteable, cascade_callbacks: true, validate: false diff --git a/spec/mongoid/contextual/mongo_spec.rb b/spec/mongoid/contextual/mongo_spec.rb index 78509f35e6..df2149b1b7 100644 --- a/spec/mongoid/contextual/mongo_spec.rb +++ b/spec/mongoid/contextual/mongo_spec.rb @@ -256,8 +256,8 @@ describe "#distinct" do before do - Band.create(name: "Depeche Mode") - Band.create(name: "New Order") + Band.create(name: "Depeche Mode", years: 30) + Band.create(name: "New Order", years: 25) end context "when limiting the result set" do @@ -289,6 +289,21 @@ context.distinct(:name).should eq([ "Depeche Mode", "New Order" ]) end end + + context "when providing an aliased field" do + + let(:criteria) do + Band.criteria + end + + let(:context) do + described_class.new(criteria) + end + + it "returns the distinct field values" do + context.distinct(:years).should eq([ 30, 25 ]) + end + end end describe "#each" do