Docunext


Ruby DataMapper Associations

November 23rd, 2009

After some initial excitement learning about DataMapper, I became concerned that it might not be all it that I thought it was.

Thankfully, it is!

I was concerned about the associations capability. The documentation sounded great, but got a little fuzzy on me.

I finally figured it out, and here's a quick and simple explanation of what I was concerned about. This should be an interesting example as it also involves single table inheritance:

class Entry
  include DataMapper::Resource
  property :id,Serial
  property :memorandum,String
  property :status,Integer
  property :fiscal_period_id,Integer
  has n, :credits
  has n, :debits
end
class Amount
  include DataMapper::Resource
  property :id,Serial
  property :entry_id,Integer
  property :type,Discriminator
  property :amount,String
  property :account_id,Integer
  property :memorandum,String
  belongs_to :entry
  belongs_to :account
end
class Credit < Amount; end
class Debit < Amount; end

Can you guess what type of data model this is? That's right - a double entry accounting system!

Entries and credit and debit amounts are bound by foreign key constraints. Inasmuch, they are often grouped into result sets.

The DataMapper docs clearly explain how to get the entries, like this:

get '/entries' do
    @myitems = Entry.all()
    erb :entry_list
end

But how can I get the credits and debits as well? It took a minute to figure it out, but I don't have to do anything at all. DataMapper does it for me. Impressive!

To be more specific, I'll include this erb template, which is accesses the @myitems object, and what an object it turns out to be!

<div class="accounts">
<ul>
<% @myitems.each do | item | %>
<li>Entries: <%= item.id %>,<%= item.memorandum %>
<br /><% item.credits.each do | credit | %>
Credits: <%= credit.id %>,<%= credit.amount %><br/>
<% end %>
<br /><% item.debits.each do | debit | %>
Debits: <%= debit.id %>,<%= debit.amount %><br/>
<% end %>
</li>
<% end %>
</ul>
</div>

See what happens? I iterate through the entries, and on each entry, I'm able to access the associated data objects. C'est incroilable!

I'm not too crazy about erb templates, and I think that's one of the reasons why I had such a hard time figuring out the way DataMapper associations work.

Wait! I'm not done yet. Another question I had involved how to create entry rows and associated amount rows.

post '/new/entry' do
    @entry = Entry.new(:memorandum => params[:entry_name])
    @entry.save
    @credit = @entry.credits.create(:amount => '5.00')
    @debit = @entry.debits.create(:amount => '2.00')
    @debit = @entry.debits.create(:amount => '3.00')
    redirect '/entries'
end

There is no error checking going on there, and the entry amounts are hard-coded, but it was enough for me to learn how DataMapper associations assist with the creation of data.

NOTE: This code is from a Sinatra app I'm working on, hence the:

post '/new/entry' do

syntax.

Yearly Indexes: 2003 2004 2006 2007 2008 2009 2010 2011 2012 2013 2015 2019 2020 2022