Topic: Creating a custom attribute

Hello everyone!
I've recently ran into this issue: I had a relation that needed to belong to two different models. Namely, Items could be given or taken by either Characters or Clans. Therefore, a simple:

class Item < ActiveRecord::Base
  belongs_to :giver, { :class_name => 'Character', :foreign_key => 'from' }
end

wouldn't be enough. So i've split that:
class Item < ActiveRecord::Base
  def giver
    if (@giver.nil? || @giver.id != from)
      @giver = Transactioner.find_by_id(from)
    end
    return @giver
  end
  def giver=(value)
    if (value.kind_of? Transactioner)
      @giver = value
      from = @giver.id
    else
      @giver = nil
      from = nil
    end
    return @giver
  end
end

The set and retrieve works excellent. However, Items.new(myHash) ignores the :giver key in the passed hash. Is there a way to specify `giver` as a native attribute?

Thanks,
Merw.

Re: Creating a custom attribute

The 'giver' attribute will be an instance of a Giver model but you CAN use the giver_id to get what you want.  The following lines of code are equivalent:

[code lang="ruby"]
@item.giver = Giver.find(3)
@item.giver_id = 3
[/code]

Re: Creating a custom attribute

If I understand you correctly, polymorphic association should be what you need. This allows you to specify the "type" in the relationship, so one attribute can relate to two different models. Maybe something like this:

class Item < ActiveRecord::Base
  belongs_to :giver, :polymorphic => true
end

class Character < ActiveRecord::Base
   has_many :items, :as => :giver
end

class Clan < ActiveRecord::Base
   has_many :items, :as => :giver
end


Then in your items table have two columns: giver_id and giver_type. The type should be a string and will be automatically assigned to the name of the giver class by ActiveRecord upon setting a giver.

Last edited by ryanb (2006-08-06 21:30:13)

Railscasts - Free Ruby on Rails Screencasts

Re: Creating a custom attribute

@Danger: Huh?
@RyanB: I know changing my data model would solve some tricks, but this is not the case. It would be quite erronous to modify the data model in this phase of development. (By the way: Character and Clan have unique ids among themselves.)

My question, again, is:

How do I make Rails know that 'giver' should be taken in account when making actions like 'Item.new' or 'Item.to_xml' and so forth?...

Last edited by Merwllyra (2006-08-07 14:50:32)

Re: Creating a custom attribute

I just tested it, and passing :giver in a call to "new" calls "giver=" method. Is it not doing this for you? I'm running edge rails so perhaps this behaves differently in the current release.

As for having to_xml work, you can try overriding attribute_names and adding giver:

def attribute_names
  super + ['giver']
end

I'd still recommend taking a look at alternative ways at handling the relationship (such as polymorphic association). It is a much better long-term solution. Relying on hacks such as this is bound to cause problems later.

Railscasts - Free Ruby on Rails Screencasts

Re: Creating a custom attribute

Ough, finally 5 hours of (distributed) research paid off. You're right, RyanB, it does work. My error was somewhere else. But the thing that lead me to thinking that "giver=" wasn't called was the stupid Documentation that reads:

new(attributes = nil) {|self if block_given?| ...}
-----
[...] In both instances, valid attribute keys are determined by the column names of the associated table

Last edited by Merwllyra (2006-08-08 03:40:28)

Posts [ 6 ]

Pages 1