I have a site that's working well but for one bug that I just found. I
have a generic "update record" method that sets various values. After
it's done setting them, it saves the record. A before_save on the
record is supposed to generically detect any interesting changes that
occurred.

My technique works as desired when the properties being changed are on
the record itself. When the property is virtual, representing
aggregates of other records, it's falling down.

At the end is a standalone pared down example of what I'm
experiencing. The problem is seen on line 40, but rooted on line 29.
In a nutshell, it looks like myRecord.manyItems is returning an array
of cached items, even after I .update() one of the records in that
array.

In case you have trouble running the example, here's my output on ruby
1.8.6 (2007-09-24 patchlevel 111) [i386-mswin32] with Sequel 2.10.0:

Initially :: 1 + 2 = 3

Set own_value to 4:
...own_value changed from 1 to 4
...value changed from 3 to 6
AfterSave :: 4 + 2 = 6
Refetched :: 4 + 2 = 6

Set votes to 8:
...vote_total before change: 2
...vote_total SHOULD become 8
...vote_total ACTUALLY became 2
...value changed from 12 to 6
AfterSave :: 4 + 2 = 6
Refetched :: 4 + 8 = 12

Finally, here's the test code. Thanks for any light you can shed on
how I can get the vote_total method to not use cached data.

require 'rubygems'
require 'sequel'

DB = Sequel.sqlite
DB << <<ENDSQL
  CREATE TABLE ideas (
    id        INTEGER PRIMARY KEY AUTOINCREMENT,
    name      TEXT NOT NULL,
    own_value INTEGER NOT NULL
  );

  CREATE TABLE votes (
    id      INTEGER PRIMARY KEY AUTOINCREMENT,
    idea_id INTEGER NOT NULL,
    count   INTEGER NOT NULL
  );
ENDSQL

class Vote < Sequel::Model; end

class Idea < Sequel::Model
  has_many :votes

  def value
    own_value + vote_total
  end

  def vote_total
    votes.inject(0){ |sum,vote| sum + vote.count }
  end

  def votes=( new_votes )
    orig = vote_total
    puts "...vote_total before change: #{orig}"

    vote = Vote.filter( :idea_id=>self.pk ).first
    puts "...vote_total SHOULD become #{orig-vote.count+new_votes}"
    vote.update( :count=>new_votes )

    puts "...vote_total ACTUALLY became #{vote_total}"
  end

  before_save do
    old_idea = Idea[ pk ]
    %w| own_value value |.each{ |s|
      old_value, new_value = old_idea.send(s), self.send(s)
      if old_value != new_value
        puts "...#{s} changed from #{old_value} to #{new_value}"
      end
    }
  end

end

Idea << { :name=>"Peace", :own_value=>1 }
$i = Idea.first
Vote << { :idea_id=>$i.pk, :count=>2 }
puts "Initially :: #{$i.own_value} + #{$i.vote_total} = #{$i.value}"

puts "\nSet own_value to 4:"
$i.update( :own_value => 4 )
puts "AfterSave :: #{$i.own_value} + #{$i.vote_total} = #{$i.value}"
$i = Idea.first
puts "Refetched :: #{$i.own_value} + #{$i.vote_total} = #{$i.value}"

puts "\nSet votes to 8:"
$i.update( :votes => 8 )
puts "AfterSave :: #{$i.own_value} + #{$i.vote_total} = #{$i.value}"
$i = Idea.first
puts "Refetched :: #{$i.own_value} + #{$i.vote_total} = #{$i.value}"

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"sequel-talk" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/sequel-talk?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to