Forum: Ruby on Rails Creating a "Foo has_many bars" association where bar isn't a

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
B780ee0ee1480454a85df58536702f63?d=identicon&s=25 Alder Green (Guest)
on 2006-05-08 23:30
(Received via mailing list)
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
24d2f8804e6bb4b7ea6bd11e0a586470?d=identicon&s=25 Jeremy Kemper (Guest)
on 2006-05-09 00:16
(Received via mailing list)
On May 8, 2006, at 2:29 PM, Alder Green 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
B780ee0ee1480454a85df58536702f63?d=identicon&s=25 Alder Green (Guest)
on 2006-05-09 10:11
(Received via mailing list)
On 5/9/06, Jeremy Kemper <jeremy@bitsweat.net> 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
> Rails@lists.rubyonrails.org
> 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
This topic is locked and can not be replied to.