ActiveRecord through Drb: problem with ids

Hi,

I'm trying to use ActiveRecord objects through Drb, and I'm facing a strange thing:

Firstly, I'm using the following database:

···

------------------------------------------------------
-- SQL
------------------------------------------------------
CREATE TABLE gardens
(
  lock_version integer DEFAULT 0,
  id integer NOT NULL AUTO_INCREMENT,
  name varchar(50),

  PRIMARY KEY (id)
) TYPE=INNODB;

CREATE TABLE flowers
(
  lock_version integer DEFAULT 0,
  id integer NOT NULL AUTO_INCREMENT,
  garden_id integer NOT NULL,
  name varchar(50),
  color varchar(50),
  
  PRIMARY KEY (id),
  FOREIGN KEY (garden_id) REFERENCES gardens (id)
) TYPE=INNODB;
------------------------------------------------------

Now if I launch this server code:

------------------------------------------------------
-- Drb / ActiveRecord Server
------------------------------------------------------
#!/usr/local/bin/ruby
require 'rubygems'
require 'drb'
require 'active_record'
require 'active_record/transactions'

ActiveRecord::Base.establish_connection(
   :adapter => "mysql",
   :username => "root",
   :host => "localhost",
   :password => "",
   :database => "flowers"
)

# We build the ActiveRecord objects
class Garden < ActiveRecord::Base
  include DRbUndumped
  has_many :flowers
end

class Flower < ActiveRecord::Base
  include DRbUndumped
  belongs_to :garden
end

# We add some data
Garden.transaction do
g = Garden.new("name" => "garden1")
g.flowers << Flower.new("name" => "flower1", "color" => "color1")
g.flowers << Flower.new("name" => "flower2", "color" => "color2")
g.save
g = Garden.new("name" => "garden2")
g.flowers << Flower.new("name" => "flower3", "color" => "color3")
g.save
end

# We create the server and instanciate it
class Server
  def find(i)
    Garden.find(i)
  end
end

s = Server.new

# We query the server
g = s.find(1)
puts "#{g.id} | #{g.name}"
g.flowers.each do |f|
  puts "#{f.id} | #{f.garden_id} | #{f.name}"
end

# We make the server available thruogh Drb
DRb.start_service('druby://localhost:9000', s)
DRb.thread.join
------------------------------------------------------

... I get what I was expecting, that is:

------------------------------------------------------
1 | garden1
1 | 1 | flower1
2 | 1 | flower2
------------------------------------------------------

Now I'm trying to call the server through Drb, with exactly the same code:

------------------------------------------------------
-- Drb / ActiveRecord Client, version 1
------------------------------------------------------
#!/usr/local/bin/ruby
require 'drb'

DRb.start_service()
obj = DRbObject.new(nil, 'druby://localhost:9000')

g = obj.find(1)
puts "#{g.id} | #{g.name}"
g.flowers.each do |f|
  puts "#{f.id} | #{f.garden_id} | #{f.name}"
end
------------------------------------------------------

... I get:

------------------------------------------------------
ar_client.rb:8: warning: Object#id will be deprecated; use Object#object_id
67884862 | garden1
ar_client.rb:10: warning: Object#id will be deprecated; use Object#object_id
67882632 | 1 | flower1
ar_client.rb:10: warning: Object#id will be deprecated; use Object#object_id
67880122 | 1 | flower2
------------------------------------------------------

Where do these warnings come from? And why these ids?

II follow the warning message, and change the code a little bit:

------------------------------------------------------
-- Drb / ActiveRecord Client, version 2
------------------------------------------------------
#!/usr/local/bin/ruby
require 'drb'

DRb.start_service()
obj = DRbObject.new(nil, 'druby://localhost:9000')

g = obj.find(1)
puts "#{g.object_id} | #{g.name}"
g.flowers.each do |f|
  puts "#{f.object_id} | #{f.garden_id} | #{f.name}"
End
------------------------------------------------------

... I get:

------------------------------------------------------
67884862 | garden1
67882642 | 1 | flower1
67880142 | 1 | flower2
------------------------------------------------------

Warning disappeared, but Ids are still wrong.

Does anyone understand what happens here?

----------------------------------
Philippe Lang, Ing. Dipl. EPFL
Attik System
rte de la Fonderie 2
1700 Fribourg
Switzerland
http://www.attiksystem.ch

Tel: +41 (26) 422 13 75
Fax: +41 (26) 422 13 76

obj = DRbObject.new(nil, 'druby://localhost:9000')

g = obj.find(1)
puts "#{g.id} | #{g.name}"
g.flowers.each do |f|
puts "#{f.id} | #{f.garden_id} | #{f.name}"
end
------------------------------------------------------

... I get:

------------------------------------------------------
ar_client.rb:8: warning: Object#id will be deprecated; use Object#object_id
67884862 | garden1
ar_client.rb:10: warning: Object#id will be deprecated; use Object#object_id
67882632 | 1 | flower1
ar_client.rb:10: warning: Object#id will be deprecated; use Object#object_id
67880122 | 1 | flower2
------------------------------------------------------

certain methods are treated specially by drb. it was a mistake for rails to
override Object#id for exatly this kind of scenario - many peice of code
require it.

you need to do something like

class << ActiveRecord
   alias "id__", "id"
end

and then use this method.

Warning disappeared, but Ids are still wrong.

Does anyone understand what happens here?

you are calling Object#id/object_id - no ActiveRecord#id - check out the drb
source to see why.

-a

···

On Fri, 25 Aug 2006, Philippe Lang wrote:
--
to foster inner awareness, introspection, and reasoning is more efficient than
meditation and prayer.
- h.h. the 14th dalai lama

This is a total guess but it seems like DRB is not proxying
the call to 'id' across the net to the remote object. Instead
you seem to be getting the object_id
of the local proxy object instead of the Active Record version
of 'id' from the real object at the server.

Warning, I don't have any special knowledge of DRB or AR internals,
this was just the first thing that came to mind when I saw your post.

Gary Wright

···

On Aug 25, 2006, at 9:56 AM, Philippe Lang wrote:

Warning disappeared, but Ids are still wrong.

Does anyone understand what happens here?

Consdering that Object#id is marked deprecated - I think it was a good decision. I'd rather say it's a problem with DrB that it doesn't use object_id instead

···

On 25-aug-2006, at 16:38, ara.t.howard@noaa.gov wrote:

certain methods are treated specially by drb. it was a mistake for rails to
override Object#id for exatly this kind of scenario - many peice of code
require it.

--
Julian 'Julik' Tarkhanov
please send all personal mail to
me at julik.nl

hi,

I just found this thread because I had a similar problem. I don't think
it has something to do with drb, in fact my problem was that a "find" on
an activerecord returned a nil object. Here is the gotcha : nil is still
an object and has an id ... which has nothing to do with database id's.
As ruby's author knows it's an usual pitfall, calling that method
produces a warning.

I think the alias workaround is great, here is the syntax I used :

class ActiveRecord::Base
  alias_method :id__, :id
end

This way you can use the method id__ for any ActiveRecord::Base
descendant. Useful to spot some bugs !

···

--
Posted via http://www.ruby-forum.com/.