Trouble with composed_of


#1

I’m trying to use composed_of within my model. I have a field in my
database named ‘card1’, which is simply a string. I have this in my
model

class Player < ActiveRecord::Base
composed_of :card1, :class_name => ‘Card’
end

class Card
attr_reader :value, :suit

def initialize(s)
@value = s[0].chr
@suit = s[1].chr
end
end

The accessor method works fine…in my fixture I have a Player created
with card1: As, and I can do
players(:first).card1.suit # => ‘s’

But I can’t assign it:
players(:first).card = nil

Causes
NoMethodError: You have a nil object when you didn’t expect it!
The error occured while evaluating nil.card1
(eval):3:in card1=' test/unit/player_test.rb:51:intest_validate_cards’

There is no validation for card1 in the Player class. For some reason
I simply can’t assign card1. What am I doing wrong?

Pat


#2

On Mar 18, 2006, at 10:04 PM, Pat M. wrote:

But I can’t assign it:
players(:first).card = nil

I think that should be:

players(:first).card1 = nil

I’m sort of guessing that’s an email typo, though.

I wouldn’t be surprised if composed_of assignment
expects a composed_of object on assignment, i.e.
it wants to assign a Card object, not a nil object.


– Tom M.


#3

On 3/19/06, Tom M. removed_email_address@domain.invalid wrote:

class Card
players(:first).card1.suit # => ‘s’
I wouldn’t be surprised if composed_of assignment

Yeah, that’s just an email typo. Anyway, setting it to a Card object
isn’t any better…
players(:first).card1 = Card.new ‘Jd’

results in

  1. Error:
    test_validate_cards(PlayerTest):
    NoMethodError: undefined method card1' for #<Card:0x227263c @suit="d", @value="J"> (eval):3:incard1=’
    test/unit/player_test.rb:51:in `test_validate_cards’

It’s obviously parsing the suit and rank fine…I don’t understand what
the problem is.

Pat


#4

On 3/19/06, Pat M. removed_email_address@domain.invalid wrote:

with card1: As, and I can do

http://lists.rubyonrails.org/mailman/listinfo/rails
@suit=“d”, @value=“J”>
(eval):3:in card1=' test/unit/player_test.rb:51:intest_validate_cards’

It’s obviously parsing the suit and rank fine…I don’t understand what
the problem is.

Pat

I’ve kind of gotten around it…I made another attribute in the Card
class named create_str, and did the mapping as
composed_of :card1, :class_name => ‘Card’, :mapping => %w(card1
create_str)

The Card class looks like
class Card
attr_reader :suit, :rank, :create_str

def to_s
“#{@rank}#{@suit}”
end

def initialize(create_str)
@create_str = create_str

@rank = create_str[0].chr
@suit = create_str[1].chr

end
end

I still can’t set card1 to nil though. I want to be able to make it
nil though, so I’m not really sure what to do.

composed_of looked like it’s what I needed, but I’m basically unable
to figure it out…

Pat


#5

On 3/19/06, Pat M. removed_email_address@domain.invalid wrote:

end
The accessor method works fine…in my fixture I have a Player created
I’m sort of guessing that’s an email typo, though.
removed_email_address@domain.invalid
NoMethodError: undefined method `card1’ for #<Card:0x227263c
I’ve kind of gotten around it…I made another attribute in the Card

composed_of looked like it’s what I needed, but I’m basically unable
to figure it out…

Pat

Well here’s my solution. It’s kind of ugly and it bugs me that it’s
so un-Railsy…but I don’t know of a better way. I’d appreciate input
from anyone else.

Pat

def card1
if self[:card1].nil? || self[:card1] == ‘’
nil
else
@card1_card ||= Card.new self[:card1]
end
end

def card1=©
@card1_card = c
self[:card1] = “#{c}”
end

def card2
if self[:card2].nil? || self[:card2] == ‘’
nil
else
@card2_card ||= Card.new self[:card2]
end
end

def card2=©
@card2_card = c
self[:card2] = “#{c}”
end