Yes, the composite keys match your requirement, so you can leave them for the belongs_to associations. And I'm starting to think this may really be a bug. See if this works:
remove the :key => true from :currency and add this: validates_uniqueness_of :currency, :scope => [:loaner_id, :loanee_id] On Jan 13, 1:53 am, Zhi-Qiang Lei <[email protected]> wrote: > Excuse me, a little more discussion please. In my past design, there should > be ONLY ONE Loan record between two people in a specific currency. The > composite keys match this requirement, don't they? But to make it immutable. > > On Jan 13, 2011, at 3:17 AM, RipTheJacker wrote: > > > > > Those won't make it immutable, but the key does need to be unique. So, > > unless you can only have ONE Loan per Person you should probably > > change those too. Rather than making them keys you probably mean to > > have them as indexes, which I DataMapper does for you, and add an :id > > Serial primary key to the model, the same as it is in your MoneyFlow > > model. > > > On Jan 12, 12:28 am, Zhi-Qiang Lei <[email protected]> wrote: > >> Hi, > > >> This model also has two more keys, they make a composite keys. This will > >> also make it immutable? > > >>>>>> belongs_to :loaner, Person, :key => true > >>>>>> belongs_to :loanee, Person, :key => true > > >> On Jan 12, 2011, at 3:15 AM, RipTheJacker wrote: > > >>> Ok. It's because of this: > > >>> property :currency, Enum[*CURRENCY_CODES], :key => true > > >>> You can't have :key => true on an Enum property since it is not > >>> unique. > > >>> On Jan 10, 11:22 pm, Zhi-Qiang Lei <[email protected]> wrote: > >>>> Hi, > > >>>> I still get the error with your spec code, here is the backtrace. > > >>>> Failures: > > >>>> 1) Loan#count! when a loan exists from giver to receiver > >>>> Failure/Error: Loan.count!(money_flow) > >>>> DataMapper::ImmutableError: > >>>> Immutable resource cannot be modified > >>>> # > >>>> /Users/siegfried/.rvm/gems/ruby-1.9.2-p136/gems/dm-core-1.0.2/lib/dm-core/r > >>>> esource/state/immutable.rb:16:in `set' > >>>> # > >>>> /Users/siegfried/.rvm/gems/ruby-1.9.2-p136/gems/dm-core-1.0.2/lib/dm-core/m > >>>> odel/property.rb:251:in `amount=' > >>>> # ./lib/models.rb:49:in `count!' > >>>> # ./spec/models_spec.rb:64:in `block (4 levels) in <top (required)>' > >>>> # > >>>> /Users/siegfried/.rvm/gems/ruby-1.9.2-p136/gems/rspec-expectations-2.4.0/li > >>>> b/rspec/matchers/change.rb:17:in `call' > >>>> # > >>>> /Users/siegfried/.rvm/gems/ruby-1.9.2-p136/gems/rspec-expectations-2.4.0/li > >>>> b/rspec/matchers/change.rb:17:in `matches?' > >>>> # > >>>> /Users/siegfried/.rvm/gems/ruby-1.9.2-p136/gems/rspec-expectations-2.4.0/li > >>>> b/rspec/expectations/handler.rb:34:in `handle_matcher' > >>>> # > >>>> /Users/siegfried/.rvm/gems/ruby-1.9.2-p136/gems/rspec-expectations-2.4.0/li > >>>> b/rspec/expectations/extensions/kernel.rb:50:in `should_not' > >>>> # ./spec/models_spec.rb:63:in `block (3 levels) in <top (required)>' > >>>> # > >>>> /Users/siegfried/.rvm/gems/ruby-1.9.2-p136/gems/rspec-core-2.4.0/lib/rspec/ > >>>> core/example.rb:49:in `instance_eval' > >>>> # > >>>> /Users/siegfried/.rvm/gems/ruby-1.9.2-p136/gems/rspec-core-2.4.0/lib/rspec/ > >>>> core/example.rb:49:in `block (2 levels) in run' > >>>> # > >>>> /Users/siegfried/.rvm/gems/ruby-1.9.2-p136/gems/rspec-core-2.4.0/lib/rspec/ > >>>> core/example.rb:98:in `with_around_hooks' > >>>> # > >>>> /Users/siegfried/.rvm/gems/ruby-1.9.2-p136/gems/rspec-core-2.4.0/lib/rspec/ > >>>> core/example.rb:46:in `block in run' > >>>> # > >>>> /Users/siegfried/.rvm/gems/ruby-1.9.2-p136/gems/rspec-core-2.4.0/lib/rspec/ > >>>> core/example.rb:91:in `block in with_pending_capture' > >>>> # > >>>> /Users/siegfried/.rvm/gems/ruby-1.9.2-p136/gems/rspec-core-2.4.0/lib/rspec/ > >>>> core/example.rb:90:in `catch' > >>>> # > >>>> /Users/siegfried/.rvm/gems/ruby-1.9.2-p136/gems/rspec-core-2.4.0/lib/rspec/ > >>>> core/example.rb:90:in `with_pending_capture' > >>>> # > >>>> /Users/siegfried/.rvm/gems/ruby-1.9.2-p136/gems/rspec-core-2.4.0/lib/rspec/ > >>>> core/example.rb:45:in `run' > >>>> # > >>>> /Users/siegfried/.rvm/gems/ruby-1.9.2-p136/gems/rspec-core-2.4.0/lib/rspec/ > >>>> core/example_group.rb:261:in `block in run_examples' > >>>> # > >>>> /Users/siegfried/.rvm/gems/ruby-1.9.2-p136/gems/rspec-core-2.4.0/lib/rspec/ > >>>> core/example_group.rb:257:in `map' > >>>> # > >>>> /Users/siegfried/.rvm/gems/ruby-1.9.2-p136/gems/rspec-core-2.4.0/lib/rspec/ > >>>> core/example_group.rb:257:in `run_examples' > >>>> # > >>>> /Users/siegfried/.rvm/gems/ruby-1.9.2-p136/gems/rspec-core-2.4.0/lib/rspec/ > >>>> core/example_group.rb:231:in `run' > >>>> # > >>>> /Users/siegfried/.rvm/gems/ruby-1.9.2-p136/gems/rspec-core-2.4.0/lib/rspec/ > >>>> core/example_group.rb:232:in `block in run' > >>>> # > >>>> /Users/siegfried/.rvm/gems/ruby-1.9.2-p136/gems/rspec-core-2.4.0/lib/rspec/ > >>>> core/example_group.rb:232:in `map' > >>>> # > >>>> /Users/siegfried/.rvm/gems/ruby-1.9.2-p136/gems/rspec-core-2.4.0/lib/rspec/ > >>>> core/example_group.rb:232:in `run' > >>>> # > >>>> /Users/siegfried/.rvm/gems/ruby-1.9.2-p136/gems/rspec-core-2.4.0/lib/rspec/ > >>>> core/command_line.rb:27:in `block (2 levels) in run' > >>>> # > >>>> /Users/siegfried/.rvm/gems/ruby-1.9.2-p136/gems/rspec-core-2.4.0/lib/rspec/ > >>>> core/command_line.rb:27:in `map' > >>>> # > >>>> /Users/siegfried/.rvm/gems/ruby-1.9.2-p136/gems/rspec-core-2.4.0/lib/rspec/ > >>>> core/command_line.rb:27:in `block in run' > >>>> # > >>>> /Users/siegfried/.rvm/gems/ruby-1.9.2-p136/gems/rspec-core-2.4.0/lib/rspec/ > >>>> core/reporter.rb:12:in `report' > >>>> # > >>>> /Users/siegfried/.rvm/gems/ruby-1.9.2-p136/gems/rspec-core-2.4.0/lib/rspec/ > >>>> core/command_line.rb:24:in `run' > >>>> # > >>>> /Users/siegfried/.rvm/gems/ruby-1.9.2-p136/gems/rspec-core-2.4.0/lib/rspec/ > >>>> core/runner.rb:55:in `run_in_process' > >>>> # > >>>> /Users/siegfried/.rvm/gems/ruby-1.9.2-p136/gems/rspec-core-2.4.0/lib/rspec/ > >>>> core/runner.rb:46:in `run' > >>>> # > >>>> /Users/siegfried/.rvm/gems/ruby-1.9.2-p136/gems/rspec-core-2.4.0/lib/rspec/ > >>>> core/runner.rb:10:in `block in autorun' > > >>>> On Jan 11, 2011, at 7:05 AM, RipTheJacker wrote: > > >>>>> You should probably just change that spec. The element that you want > >>>>> to test is a proc (you hope) getting invoked inside of the subject > >>>>> block, which is a weird pattern, and you don't need the #let blocks > >>>>> really, since you only use those objects once. > > >>>>> Try: > > >>>>> describe "#count!" do > >>>>> specify "when a loan exists from giver to receiver" do > >>>>> loan = Loan.gen > >>>>> money_flow = MoneyFlow.gen(:giver => loan.loaner, :receiver => > >>>>> loan.loanee, :currency => loan.currency) > >>>>> expect do > >>>>> Loan.count!(money_flow) > >>>>> end.to_not change(Loan, :count) > >>>>> end > >>>>> end > > >>>>> I'm assuming you are using rspec 2, though it will work in rspec 1.x > >>>>> with a syntax change. If you still get that error, post the new > >>>>> backtrace here. At the very least the spec and the backtrace will be > >>>>> more meaningful this way, and may be easier to debug (I hope). > > >>>>> On Jan 10, 10:42 am, Zhi-Qiang Lei <[email protected]> wrote: > >>>>>> Hi, > > >>>>>> I have some code as follow. > > >>>>>> class Loan > >>>>>> include DataMapper::Resource > >>>>>> belongs_to :loaner, Person, :key => true > >>>>>> belongs_to :loanee, Person, :key => true > >>>>>> property :currency, Enum[*CURRENCY_CODES], :key => true > >>>>>> property :amount, Decimal, :scale => 2, :default => 0 > > >>>>>> def self.count!(money_flow) > >>>>>> loan = get(money_flow.currency, money_flow.giver_id, > >>>>>> money_flow.receiver_id) > >>>>>> loan.amount += money_flow.amount > >>>>>> end > > >>>>>> # more code... > >>>>>> end > > >>>>>> class MoneyFlow > >>>>>> include DataMapper::Resource > >>>>>> belongs_to :giver, Person > >>>>>> belongs_to :receiver, Person > > >>>>>> property :id, Serial > >>>>>> property :amount, Decimal, :scale => 2, :min => 0.01 > >>>>>> property :currency, Enum[*CURRENCY_CODES], :default => :CNY > > >>>>>> # more code... > >>>>>> end > > >>>>>> When I test the "count!" class method as follow: > > >>>>>> describe "#count!" do > >>>>>> subject { lambda { Loan.count!(money_flow) } } > >>>>>> context "when a loan exists from giver to receiver" do > >>>>>> let!(:loan) { Loan.gen } > >>>>>> let(:money_flow) { MoneyFlow.gen(:giver => loan.loaner, > >>>>>> :receiver => loan.loanee, :currency => loan.currency) } > >>>>>> it { should_not change(Loan, :count) } > >>>>>> end > >>>>>> end > > >>>>>> It tells me I got a Immutable Error. I feel strange on that. They have > >>>>>> keys, and I didn't destroy the record. Can you see why? Thanks. > > >>>>>> 1) Loan#count! when a loan exists from giver to receiver > >>>>>> Failure/Error: subject { lambda { Loan.count!(money_flow) } } > >>>>>> DataMapper::ImmutableError: > >>>>>> Immutable resource cannot be modified > >>>>>> # ./lib/models.rb:49:in `count!' > >>>>>> # ./spec/models_spec.rb:59:in `block (4 levels) in <top > >>>>>> (required)>' > >>>>>> # ./spec/models_spec.rb:63:in `block (4 levels) in <top > >>>>>> (required)>' > > >>>>>> On Jan 10, 2011, at 11:34 PM, Ted Han wrote: > > >>>>>>> Objects are immutable when they've been deleted or frozen for some > >>>>>>> reason. Deleting a record from your data store will always result in > >>>>>>> that record being frozen. > > >>>>>>> Is there a specific problem that you're having? > > >>>>>>> -T > > >>>>>>> On Mon, Jan 10, 2011 at 10:23 AM, Zhi-Qiang Lei > >>>>>>> <[email protected]> wrote: > >>>>>>> Dear All, > > >>>>>>> Could anyone answer me when a resource should be immutable? And why? > >>>>>>> Thanks. > > >>>>>>> Best regards, > >>>>>>> Zhi-Qiang Lei > >>>>>>> [email protected] > > >>>>>>> -- > >>>>>>> You received this message because you are subscribed to the Google > >>>>>>> Groups "DataMapper" 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 > >>>>>>> athttp://groups.google.com/group/datamapper?hl=en. > > >>>>>>> -- > >>>>>>> You received this message because you are subscribed to the Google > >>>>>>> Groups "DataMapper" 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 > >>>>>>> athttp://groups.google.com/group/datamapper?hl=en. > > >>>>>> Best regards, > >>>>>> Zhi-Qiang Lei > >>>>>> [email protected] > > >>>>> -- > >>>>> You received this > > ... > > read more » -- You received this message because you are subscribed to the Google Groups "DataMapper" 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/datamapper?hl=en.
