Creating a "Foo has_many bars" association where bar isn't a


#1

Hi

Let’s say we have model Foo. Each Foo instance can have several bars.
Those bars are primitive, so they shouldn’t be models. For example,
Foo might be a type of convention, and the bars might be years the
convention was held in. Naively, we would have a conventions_years
date, and put:

has_many :years

inside class Convention. But then we’d get an error, since for
has_many to work, there must be a Year model. Which is silly: why
would we have a Year model, then get the actual year by Year#year…?

So what’s the Railish take on this? Can you have a has_many
association with the “many” as simple values, not full models? What
did I miss?

-Alder


#2

On May 8, 2006, at 2:29 PM, Alder G. wrote:

would we have a Year model, then get the actual year by Year#year…?

So what’s the Railish take on this? Can you have a has_many
association with the “many” as simple values, not full models? What
did I miss?

This is a case of persisting “values objects” rather than
“entities.” (I like to think of the difference as “would I compare
these by value or by id?”)

Active Record provides the composed_of and serialize class methods to
map columns to custom classes or to store them as YAML.

Using serialize:

create table conventions (id serial primary key, years text);

class Convention
serialize :years, Set
end

foscon = Convention.new
foscon.years << 2005
foscon.save!
foscon[‘years’] == foscon.years.to_yaml

Using composed_of:

Currency = Struct.new(:code)

create table markets (id serial primary key, currency_code char

(3));
class Market
composed_of :currency, :mapping => %w(currency_code code)
end

japan = Market.new(:currency => Currency.new(‘JPY’))
japan.save!
japan.currency_code == ‘JPY’
japan.currency == Currency.new(‘JPY’)

Active Record does not handle mappings such as:

create table conventions (id serial primary key)

create table conventions_years (convention_id not null primary

key references conventions(id), year)
class Conventions
# Returns a Set of 2001, 2002, etc.
has_many :years, :collection => Set, :value => ‘year’

 # However, you may:
 has_many :convention_years
 def years() convention_years.map { |y| y.year }.to_set end

end

Best,
jeremy


#3

On 5/9/06, Jeremy K. removed_email_address@domain.invalid wrote:

has_many to work, there must be a Year model. Which is silly: why
Active Record provides the composed_of and serialize class methods to
foscon = Convention.new
foscon.years << 2005
foscon.save!
foscon[‘years’] == foscon.years.to_yaml

Nice. A small problem here is that after

foscon = Convention.new

foscon.years is nil, so it doesn’t have the << (or most any other)
method. You can ammend this with

foscon.years = Set.new

but I’m sure there’s a more proper common practice?

japan = Market.new(:currency => Currency.new(‘JPY’))
class Conventions
jeremy


Rails mailing list
removed_email_address@domain.invalid
http://lists.rubyonrails.org/mailman/listinfo/rails

The rest of your response acquainted me with a comprehensive set of
tools relevant to the task. Thanks, Jeremy!

-Alder