
has n and belongs_to with different name is not working well
Reported by Sylvain | May 18th, 2010 @ 04:49 PM
Here's a simple program:
require 'rubygems'
require 'dm-core'
DataMapper::Logger.new(STDOUT, :debug)
DataMapper.setup(:default, 'sqlite3::memory:')
class Rainbow
include DataMapper::Resource
property :id, Serial
property :location, String
has n, :colors
end
class Color
include DataMapper::Resource
property :id, Serial
property :name, String
belongs_to :beautiful_rainbow, 'Rainbow'
end
DataMapper.auto_migrate!
rainbow = Rainbow.new :location => "Paris"
rainbow.save!
color = Color.new :name => 'blue'
rainbow.colors << color
color.save!
color2 = Color.new :name => 'yellow'
color2.beautiful_rainbow = rainbow
color2.save!
when using dm-core 0.10.2, jruby 1.5.0,
here's the result:
~ (0.000) SELECT sqlite_version(*)
~ (0.000) DROP TABLE IF EXISTS "rainbows"
~ (0.000) DROP TABLE IF EXISTS "colors"
~ (0.000) CREATE TABLE "rainbows" ("id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "location" VARCHAR(50))
~ (0.000) CREATE TABLE "colors" ("id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "name" VARCHAR(50), "beautiful_rainbow_id" INTEGER NOT NULL, "rainbow_id" INTEGER NOT NULL)
~ (0.000) CREATE INDEX "index_colors_beautiful_rainbow" ON "colors" ("beautiful_rainbow_id")
~ (0.000) CREATE INDEX "index_colors_rainbow" ON "colors" ("rainbow_id")
~ (0.000) INSERT INTO "rainbows" ("location") VALUES ('Paris')
~ colors.beautiful_rainbow_id may not be NULL (code: 0, sql state: , query: INSERT INTO "colors" ("name", "rainbow_id") VALUES ('blue', 1), uri: )
C:/jruby-1.5.0/lib/ruby/gems/1.8/gems/dm-core-0.10.2/lib/dm-core/adapters/data_objects_adapter.rb:269:in `with_connection': colors.beautiful_rainbow_id may not be NULL (code: 0, sql state: , query: INSERT INTO "colors" ("name", "rainbow_id") VALUES ('blue', 1), uri: ) (DataObjects::SQLError)
from C:/jruby-1.5.0/lib/ruby/gems/1.8/gems/dm-core-0.10.2/lib/dm-core/adapters/data_objects_adapter.rb:59:in `execute'
from C:/jruby-1.5.0/lib/ruby/gems/1.8/gems/dm-core-0.10.2/lib/dm-core/adapters/data_objects_adapter.rb:110:in `create'
from C:/jruby-1.5.0/lib/ruby/gems/1.8/gems/dm-core-0.10.2/lib/dm-core/adapters/data_objects_adapter.rb:83:in `each'
from C:/jruby-1.5.0/lib/ruby/gems/1.8/gems/dm-core-0.10.2/lib/dm-core/adapters/data_objects_adapter.rb:83:in `create'
from C:/jruby-1.5.0/lib/ruby/gems/1.8/gems/dm-core-0.10.2/lib/dm-core/repository.rb:129:in `create'
from C:/jruby-1.5.0/lib/ruby/gems/1.8/gems/dm-core-0.10.2/lib/dm-core/resource.rb:864:in `_create'
from C:/jruby-1.5.0/lib/ruby/gems/1.8/gems/dm-core-0.10.2/lib/dm-core/resource.rb:927:in `save_self'
from C:/jruby-1.5.0/lib/ruby/gems/1.8/gems/dm-core-0.10.2/lib/dm-core/resource.rb:912:in `_save'
from C:/jruby-1.5.0/lib/ruby/gems/1.8/gems/dm-core-0.10.2/lib/dm-core/resource.rb:1085:in `run_once'
from C:/jruby-1.5.0/lib/ruby/gems/1.8/gems/dm-core-0.10.2/lib/dm-core/resource.rb:911:in `_save'
from C:/jruby-1.5.0/lib/ruby/gems/1.8/gems/dm-core-0.10.2/lib/dm-core/resource.rb:362:in `save!'
from C:\Documents and Settings\SYUD7403\My Documents\NetBeansProjects\datamapper_bug\lib\main.rb:30
if we remove color part (just color2), here's the
result:
~ (0.000) SELECT sqlite_version(*)
~ (0.000) DROP TABLE IF EXISTS "rainbows"
~ (0.000) DROP TABLE IF EXISTS "colors"
~ (0.000) CREATE TABLE "rainbows" ("id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "location" VARCHAR(50))
~ (0.000) CREATE TABLE "colors" ("id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "name" VARCHAR(50), "beautiful_rainbow_id" INTEGER NOT NULL, "rainbow_id" INTEGER NOT NULL)
~ (0.000) CREATE INDEX "index_colors_beautiful_rainbow" ON "colors" ("beautiful_rainbow_id")
~ (0.000) CREATE INDEX "index_colors_rainbow" ON "colors" ("rainbow_id")
~ (0.000) INSERT INTO "rainbows" ("location") VALUES ('Paris')
~ colors.rainbow_id may not be NULL (code: 0, sql state: , query: INSERT INTO "colors" ("name", "beautiful_rainbow_id") VALUES ('yellow', 1), uri: )
C:/jruby-1.5.0/lib/ruby/gems/1.8/gems/dm-core-0.10.2/lib/dm-core/adapters/data_objects_adapter.rb:269:in
with_connection': colors.rainbow_id may not be NULL (code: 0, sql state: , query: INSERT INTO "colors" ("name", "beautiful_rainbow_id") VALUES ('yellow', 1), uri: ) (DataObjects::SQLError)
from C:/jruby-1.5.0/lib/ruby/gems/1.8/gems/dm-core-0.10.2/lib/dm-core/adapters/data_objects_adapter.rb:59:in `execute'
from C:/jruby-1.5.0/lib/ruby/gems/1.8/gems/dm-core-0.10.2/lib/dm-core/adapters/data_objects_adapter.rb:110:in `create'
from C:/jruby-1.5.0/lib/ruby/gems/1.8/gems/dm-core-0.10.2/lib/dm-core/adapters/data_objects_adapter.rb:83:in `each'
from C:/jruby-1.5.0/lib/ruby/gems/1.8/gems/dm-core-0.10.2/lib/dm-core/adapters/data_objects_adapter.rb:83:in `create'
from C:/jruby-1.5.0/lib/ruby/gems/1.8/gems/dm-core-0.10.2/lib/dm-core/repository.rb:129:in `create'
from C:/jruby-1.5.0/lib/ruby/gems/1.8/gems/dm-core-0.10.2/lib/dm-core/resource.rb:864:in `_create'
from C:/jruby-1.5.0/lib/ruby/gems/1.8/gems/dm-core-0.10.2/lib/dm-core/resource.rb:927:in `save_self'
from C:/jruby-1.5.0/lib/ruby/gems/1.8/gems/dm-core-0.10.2/lib/dm-core/resource.rb:912:in `_save'
from C:/jruby-1.5.0/lib/ruby/gems/1.8/gems/dm-core-0.10.2/lib/dm-core/resource.rb:1085:in `run_once'
from C:/jruby-1.5.0/lib/ruby/gems/1.8/gems/dm-core-0.10.2/lib/dm-core/resource.rb:911:in `_save'
from C:/jruby-1.5.0/lib/ruby/gems/1.8/gems/dm-core-0.10.2/lib/dm-core/resource.rb:362:in `save!'
from C:\Documents and Settings\SYUD7403\My Documents\NetBeansProjects\datamapper_bug\lib\main.rb:34</code>
As you can see, the issue is that datamapper don't do the link from rainbow to color via "beautiful_raibow_id" but via "rainbow_id" which is wrong.
Comments and changes to this ticket
-
Dan Kubb (dkubb) May 19th, 2010 @ 04:30 AM
- State changed from new to resolved
- Assigned user set to Dan Kubb (dkubb)
The problem is that both sides of the relationship are using names that DataMapper cannot match up. It would have no way of knowing that :colors and :beautiful_rainbow are inverses without being told, since it is possible to have unidirectional relationships between models, and models can have multiple relationships between them with different names. (although it is advisable for clarity to always specify both sides of the relationship)
You can specify the :inverse on the has() side of the relationship like this:
has n, :colors, :inverse => :beautiful_rainbow
Attached is the script provided, modified to work with this change.
-
Dan Kubb (dkubb) May 19th, 2010 @ 04:32 AM
BTW, I should also mention that it looks like you were using Resource#save! expecting that it would raise an exception when the resource is not saved, but what it actually does is executes the save method without any hooks or validation. Errors are more likely in this scenario, and will propagate up the stack, but it is probably better to only use Resource#save! in very limited cases.
-
Sylvain May 19th, 2010 @ 07:42 AM
Hi,
Thanks for the answer,
I search the way to give the "inverse" way to do that but didn't find it in the documentation.
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 »