How do you use a row from one table as a property in another table using Datamapper? - 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.

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.

Related

Multiple models accessing same table

I am new to Datamapper and Ruby on Rails. I have an en existing model A, now I want to create another version of model A, v2_A. The difference between A and V2_A is that I have changed a few belongs_to from A to v2_A by changing :required => true to :required => false like following.
class A
include DataMapper::Resource
property :p1, ...
...
belongs_to :b, :required =>true
end
class v2_A
include DataMapper::Resource
property :p1, ...
...
belongs_to :b, :required =>false
end
So basically all column names in resulting tables will be same. Whenever I am doing rake db:autoupgrade a new table v2_A is being created which is not desired. I am asking is it possible both of the models access the same table A i.e. I don't want v2_A to create another table just because of that.
i am not sure about DataMapper::Resource
But i guess in your model you can write
self.table_name = "name_of_your_table"
In both of the model.

How to set a foreign key in rails?

I'm trying to save a object that has a foreign key attribute. I do not understand why it's not working. The foreign key is defined as not null in the database.
class Store < ActiveRecord::Base
attr_accessible :latitude, :longitude, :description
validates :store_group, :presence => true
validates :description, :presence => true, :length => {:maximum => 500}
validates :latitude, :presence => true
validates :longitude, :presence => true
belongs_to :store_group
end
class StoreGroup < ActiveRecord::Base
attr_accessible :name, :description, :image
validates :name, :presence => { :message => "Store group can not be empty" }
end
So, I'm trying to save a store:
group = StoreGroup.new(:name=>"name",:description=>"description",:image=>"image")
store = Store.new(:store_group=>group,:latitude=>1,:longitude=>1,:description=>"description")
store.save
However, MySQL raises an exception:
Mysql2::Error: Column 'store_group' cannot be null: INSERT INTO `stores` (`created_at`, `store_group`, `description`, `latitude`, `longitude`, `updated_at`) VALUES ('2013-02-17 04:09:15', NULL, 'description', 1.0, 1.0, '2013-02-17 04:09:15')
Why?
Thanks in advance :)
You are trying to create/save store_group object through store. Thus use:
accepts_nested_attributes_for :store_group
in your Store model
Read here about accepts_nested_attributes_for
First off, it may be easier in the long run if you add a has_many :stores to StoreGroup, for instance if you ever want to retrieve all of the stores that belong to a particular StoreGroup. Secondly, you should add the store via its StoreGroup, and since you already have an association there it's fairly straightforward (note the change to Store.create):
group = StoreGroup.create(name: "name", description: "description", image: "image")
group.stores << Store.create(lat: 1, long: 1, desc: "description")
This method will automatically set :store_group_id and save the new Store instance as a "child" of its StoreGroup. Note that you'll also want to change your code to account for existing StoreGroups, so that you can add stores to existing StoreGroups later. Using .first_or_create with a .where(...) clause is idiomatic for rails 3.2.x, though there are dynamic finders with create powers in previous versions of Rails (find_or_create_by_name_and_store_group_id, as an example).
Lastly, remove validates :store_group because association validations don't work that way. If you really must, use validates :store_group_id.

DataMapper association

I'm trying to design a schema for an email solution so that I could access the incoming and sent messages on the User object using DataMapper. The associations "inbox" and "sent" don't do what's intended. What am I doing wrong? Thanks in advance!
I've the following so far (after reading a bit and copying the friends example from DM website) --
class User
include DataMapper::Resource
property :id, Serial
property :name, String, :required=>true
property :email, String, :required=>true, :unique=>true
property :password, String, :required=>true
has n, :messages, :child_key=>[:source_id, :target_id]
has n, :inbox, 'Message', :through=>:messages, :via=>:target
has n, :sent, 'Message', :through=>:messages, :via=>:source
end
class Message
include DataMapper::Resource
property :id, Serial
property :subject, String, :required=>true
property :body, String
belongs_to :source, 'User', :key=>true
belongs_to :target, 'User', :key=>true
end
I'm answering my own question -- hope it helps someone
The following change fixes the problem I've been having --
class User
...
has n, :inbox, 'Message', :child_key=>[:target_id]
has n, :sent, 'Message', :child_key=>[:source_id]
end
Everything else, remains the same...

DataMapper can't save to mysql and create object with id = nil

I am following the tinyclone example in Cloning Internet Application with Ruby and is trying to create an object to be stored into mysql.
However, whenever I try to create a Url object (see code below), the result is always
"=> Url #id=nil #original="http://www.gmail.com" #link_identifier=nil"
The id is not created nor the data is stored in the database. The link to the sql database is correct as I already tried dropping the database and recreating it using DataMapper.auto_migrate!
Can anyone help? Thanks.
DataMapper.setup(:default,'mysql://root#localhost/tinyclone')
class Url
include DataMapper::Resource
property :id, Serial
property :original, String, :length => 255
belongs_to :link
end
class Link
include DataMapper::Resource
property :identifier, String, :key => true
property :created_at, DateTime
has 1, :url
has n, :visits
end
DataMapper.finalize
url = Url.create(:original => 'http://www.gmail.com')
=> #<Url #id=nil #original="http://www.gmail.com" #link_identifier=nil>
In your Url model Link is a required association. You can't create a url without a link because validation will fail. If you want to be able to create urls without associating them with a link you can write belongs_to :link, :required => false

Datamapper Many-To-Many relation

Article has many authors, editors, translaters, etc. All of class Person.
Is it possible to generate join model? Or, in this case, solution is to create each join models manually.
class Article
include DataMapper::Resource
property :id, Serial
property :published_date, Date
property :status, Enum[ :pending, :accepted, :declined, :modified, :new ], :default => :new
property :visible, Boolean, :default => false
timestamps :at
has n, :authors, 'Person', :through => Resource
end
class Person
include DataMapper::Resource
property :id, Serial
property :name, String
property :about, Text
property :gender, Enum[ :male, :female ]
property :birthday, Date
timestamps :at
has n, :articles, :through => Resource
end
looks like it impossible. Only manual model creation.