Search code examples
datamapperruby-datamapper

How do you use a row from one table as a property in another table using Datamapper?


The specific instance I am referring to is here. I want to use a row from the Grid table to be the value of the Grid property in the Driver table. But I cannot get updates in the Grid table to persist through to the Grid property on the Driver table I want to use a row from the Race table to be the value of the Race property in the Driver table.

Here is the code for the datamapper stuff.

require "rubygems"
require "json"
require "sinatra"
require "sinatra/reloader"
require "sqlite3"
require "data_mapper"

DataMapper::setup(:default, "sqlite3://#{Dir.pwd}/season.db")


class Driver
    include DataMapper::Resource
    property :id, String, :key => true
    property :ptd, Integer
    property :races, Integer
    property :grid, Object
    property :race, Object
    property :hcScore, Integer
    property :domScore, Integer
end

class Grid
    include DataMapper::Resource
    property :id, String, :key => true
    property :AUS_Q, Integer
    property :MAL_Q, Integer
    property :CHI_Q, Integer
    property :BAH_Q, Integer
end

class Race
    include DataMapper::Resource
    property :id, String, :key => true
    property :AUS_R, Integer
    property :MAL_R, Integer
    property :CHI_R, Integer
    property :BAH_R, Integer
end

class Team

    include DataMapper::Resource
    property :id, String, :key =>  true
    property :domScore, Integer
    property :drivers, Object
end

DataMapper.finalize.auto_migrate!

In irb I will do something like

irb(main):001:0> require "./season.rb"
=> true
irb(main):002:0> v = Driver.create id: "VET"
=> #<Driver @id="VET" @ptd=nil @races=nil @grid=nil @race=nil @hcScore=nil @domScore=nil>
irb(main):003:0> g = Grid.create id: "VET"
=> #<Grid @id="VET" @AUS_Q=nil @MAL_Q=nil @CHI_Q=nil @BAH_Q=nil>
irb(main):004:0> v.grid = Grid.get "VET"
=> #<Grid @id="VET" @AUS_Q=nil @MAL_Q=nil @CHI_Q=nil @BAH_Q=nil>
irb(main):005:0> v.save
=> true
irb(main):006:0> g.update(:AUS_Q => 6)
=> true
irb(main):007:0> v
=> #<Driver @id="VET" @ptd=nil @races=nil @grid=#<Grid @id="VET" @AUS_Q=nil @MAL_Q=nil @CHI_Q=nil @BAH_Q=nil> @race=nil @hcScore=nil @domScore=nil>
irb(main):008:0> Grid.get "VET"
=> #<Grid @id="VET" @AUS_Q=6 @MAL_Q=nil @CHI_Q=nil @BAH_Q=nil>
irb(main):009:0> AUS_Q = 6 in the Grid table but in the Driver table it continues to be nil!

As you can see - AUS_Q in the Driver table continues to be nil even though I set it to be 6 in the Grid table.

Chances are I am doing it wrong and there is an easier way to do this. I encourage all corrections and smackdowns.


Solution

  • I would suggest that you use belongs_to to create association between resources, and that you use an identity map, like this:

    require "sqlite3"
    require "data_mapper"
    
    class Driver
        include DataMapper::Resource
        property :id, String, :key => true
        belongs_to :grid, :required => false
    end
    
    class Grid
        include DataMapper::Resource
        property :id, String, :key => true
        property :AUS_Q, Integer
    end
    
    DataMapper::setup(:default, "sqlite3://#{Dir.pwd}/season.db")
    DataMapper.finalize.auto_migrate!
    
    DataMapper.repository(:default) do
      v = Driver.create id: "VET"
      g = Grid.create id: "VET"
      v.grid = Grid.get "VET"
      v.save
      g.update(:AUS_Q => 6)
      puts v.grid.AUS_Q
      puts Grid.get("VET").AUS_Q
    end
    

    Everything you do within the block initiated by DataMapper.repository(:default) do will use an identity map. Thus, identical objects in the database will result in identical objects in memory.