Permalink
Browse files

Allow access to relations in overridden field setters. Fixes #1524.

  • Loading branch information...
1 parent 9e561d0 commit f9e89dc42b33279d4e3432ad3bce58316861b65e @durran durran committed Dec 30, 2011
View
@@ -68,6 +68,9 @@ For instructions on upgrading to newer versions, visit
* \#1530 Don't duplicate added values to arrays via dirty tracking if the
array is a foreign key field.
+* \#1524 Allow access to relations in overridden field setters by pre-setting
+ foreign key default values.
+
* \#1523 Allow disabling of observers via `disable`. (Jonas Schneider)
* \#1522 Fixed create indexes rake task for Rails 3.2. (Gray Manley)
View
@@ -179,6 +179,23 @@ def apply_defaults
end
end
+ # Provide a hash of foreign key defaults.
+ #
+ # @example Get a hash with fk defaults.
+ # document.attributes_with_foreign_key_defaults
+ #
+ # @return [ Hash ] A hash with default fk values.
+ #
+ # @since 2.4.0
+ def attributes_with_foreign_key_defaults
+ {}.tap do |attrs|
+ foreign_key_defaults.each do |name|
+ default = fields[name].eval_default(self)
+ attrs[name] = default if default
+ end
+ end
+ end
+
# Used for allowing accessor methods for dynamic attributes.
#
# @param [ String, Symbol ] name The name of the method.
View
@@ -125,7 +125,7 @@ def identify
def initialize(attrs = nil, options = nil)
_building do
@new_record = true
- @attributes ||= {}
+ @attributes ||= attributes_with_foreign_key_defaults
options ||= {}
process(attrs, options[:as] || :default, !options[:without_protection]) do
identify
View
@@ -36,10 +36,12 @@ module Fields
class_attribute :aliased_fields
class_attribute :defaults
class_attribute :fields
+ class_attribute :foreign_key_defaults
self.aliased_fields = {}
self.defaults = []
self.fields = {}
+ self.foreign_key_defaults = []
field(:_type, :type => String)
field(:_id, :type => BSON::ObjectId)
@@ -124,7 +126,8 @@ def field(name, options = {})
# @since 2.0.0.rc.6
def inherited(subclass)
super
- subclass.defaults, subclass.fields = defaults.dup, fields.dup
+ subclass.defaults, subclass.fields, subclass.foreign_key_defaults =
+ defaults.dup, fields.dup, foreign_key_defaults.dup
end
# Is the field with the provided name a BSON::ObjectId?
@@ -177,6 +180,7 @@ def add_field(name, options = {})
Mappings.for(type, options[:identity]).instantiate(name, options).tap do |field|
fields[name] = field
defaults << name unless field.default_val.nil?
+ foreign_key_defaults << name if field.foreign_key?
create_accessors(name, meth, options)
process_options(field)
create_dirty_methods(name)
@@ -81,6 +81,18 @@ def eval_default(doc)
end
end
+ # Is this field a foreign key?
+ #
+ # @example Is the field a foreign key?
+ # field.foreign_key?
+ #
+ # @return [ true, false ] If the field is a foreign key.
+ #
+ # @since 2.4.0
+ def foreign_key?
+ !!options[:identity]
+ end
+
# Is the field localized or not?
#
# @example Is the field localized?
@@ -0,0 +1,9 @@
+class Doctor < Person
+ field :specialty
+ has_and_belongs_to_many :users, :validate => false, :inverse_of => nil
+
+ def specialty=(text)
+ users.push(User.new)
+ super
+ end
+end
@@ -167,7 +167,3 @@ def foo
'i_am_foo'
end
end
-
-class Doctor < Person
- field :specialty
-end
@@ -331,6 +331,21 @@
person.title.should == "Sir"
end
+ context "when accessing a relation from an overridden setter" do
+
+ let(:doctor) do
+ Doctor.new(:specialty => "surgery")
+ end
+
+ it "allows access to the relation" do
+ doctor.users.first.should be_a(User)
+ end
+
+ it "properly allows super calls" do
+ doctor.specialty.should eq("surgery")
+ end
+ end
+
context "when initialize callbacks are defined" do
context "when accessing attributes" do
@@ -27,6 +27,23 @@
end
end
+ describe "#foreign_key?" do
+
+ let(:field) do
+ described_class.instantiate(
+ :vals,
+ :metadata => Person.relations["posts"],
+ :type => Array,
+ :default => [],
+ :identity => true
+ )
+ end
+
+ it "returns true" do
+ field.should be_foreign_key
+ end
+ end
+
describe "#serialize" do
context "when the array is object ids" do
@@ -2,6 +2,23 @@
describe Mongoid::Fields::Internal::ForeignKeys::Object do
+ describe "#foreign_key?" do
+
+ let(:field) do
+ described_class.instantiate(
+ :vals,
+ :metadata => Person.relations["posts"],
+ :type => Object,
+ :default => [],
+ :identity => true
+ )
+ end
+
+ it "returns true" do
+ field.should be_foreign_key
+ end
+ end
+
describe "#serialize" do
context "when the array is object ids" do
@@ -13,6 +13,13 @@
end
end
+ describe "#foreign_key?" do
+
+ it "returns false" do
+ field.should_not be_foreign_key
+ end
+ end
+
describe "#selection" do
context "when providing a single value" do
@@ -123,6 +123,37 @@
end
end
+ describe "#foreign_key_defaults" do
+
+ context "on parent classes" do
+
+ let(:person) do
+ Person.new
+ end
+
+ it "does not return subclass foreign key defaults" do
+ person.foreign_key_defaults.should eq([
+ "preference_ids", "user_account_ids", "house_ids",
+ "ordered_preference_ids", "administrated_event_ids"
+ ])
+ end
+ end
+
+ context "on subclasses" do
+
+ let(:doctor) do
+ Doctor.new
+ end
+
+ it "contains the parent and child foreign key defaults" do
+ doctor.foreign_key_defaults.should eq([
+ "preference_ids", "user_account_ids", "house_ids",
+ "ordered_preference_ids", "administrated_event_ids", "user_ids"
+ ])
+ end
+ end
+ end
+
describe ".field" do
it "returns the generated field" do

0 comments on commit f9e89dc

Please sign in to comment.