
STI :child_key option causes DataMapper to try to save both keys
Reported by Ashley Moran | September 15th, 2009 @ 11:46 AM | in 1.0.0
This also appears to be a 0.10RC2 regression. I'm pretty sure we've seen the same error on 0.10RC1, which means we may have done something to work around it.
This is the SQL that gets generated:
INSERT INTO "hats" ("type", "person_id", "employee_id") VALUES ('felt', 1, 1)
but it should be:
INSERT INTO "hats" ("type", "person_id") VALUES ('felt', 1)
Failing spec:
require 'rubygems'
DM_GEMS_VERSION = "0.10.0"
DO_GEMS_VERSION = "0.10.0"
gem "data_objects", DO_GEMS_VERSION
gem "do_sqlite3", DO_GEMS_VERSION
gem "dm-core", DM_GEMS_VERSION
gem "dm-types", DM_GEMS_VERSION
gem "dm-validations", DM_GEMS_VERSION
require "data_objects"
require "dm-core"
require "dm-types"
require "dm-validations"
require 'spec'
DataMapper.setup(:default, "sqlite3::memory:")
class Hat
include DataMapper::Resource
property :id, Serial
property :type, String
belongs_to :employee, :child_key => [ :person_id ]
end
class Person
include DataMapper::Resource
property :id, Serial
property :type, Discriminator
end
class Employee < Person
has 1, :hat
def initialize(options = {})
self.hat = Hat.new(:type => "felt")
super
end
end
Spec::Runner.configure do |config|
config.before(:each) do
Hat.auto_migrate!
Person.auto_migrate!
end
end
describe "STI subclass can't construct" do
it "tries to save both keys, the one specified in :child_key and an 'implicit' one from the STI base class" do
@employee = Employee.new
lambda { @employee.save }.should_not raise_error
end
end
Comments and changes to this ticket
-
Jonathan Stott (namelessjon) October 16th, 2009 @ 12:12 PM
- Tag set to 0.10.1, relationships, sti
- State changed from new to confirmed
-
Dan Kubb (dkubb) March 10th, 2010 @ 03:31 AM
- State changed from confirmed to resolved
- Assigned user set to Dan Kubb (dkubb)
- Milestone set to 1.0.0
In the the case in Ashley's comment above, there are relationships on both sides pointing to the other model, but because they aren't named using the naming convention, there's no way for DM to know they should be made inverses of each other. Specifying the :child_key explicitly is the only sane way I can think of to make this work. If there are alternative ideas, I would be open to hear them.
The original case can also be explained:
The algorithm for identifying inverse relationships is relatively simple: it looks at the target model and tries to find a relationship with the expected name, a target model equal to it's source and a parent_key/child_key equal to it's own. In this case "has 1, :hat" wouldn't match the "employee" relationship in Hat because the parent_key is different from what it'd set up by default.
Changing both relationships to use the same :parent_key, or removing the :parent_key altogether results in the attached specs passing with edge dm-core (not tested with other dm-core's in the 0.10 series, but I would expect all of them to work the same in this regard)
Please Sign in or create a free account to add a new ticket.
With your very own profile, you can contribute to projects, track your activity, watch tickets, receive and update tickets through your email and much more.
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »
People watching this ticket
Tags
Referenced by
-
939 Assigning a parent to a child does not work the same as assigning a child to a parent I will add a comment in #1042