Default values for belongs_to and has_one

There really doesn't seem to be a *declarative* way to define a default
value for belongs_to and has_one associations

  class Person < ActiveRecord::Base
    belongs_to :address
  end

  p = Person.new
  p.address.city = 'Atlantis' # Bummer!

Of course, there's an easy way to avoid this

  class Person < ActiveRecord::Base
    belongs_to :address

    def after_initialize
      self.address ||= Address.new
    end
  end

It just doesn't feel right. What I'd rather write is this

  class Person < ActiveRecord::Base
    belongs_to :address, :default => true
  end

and alternatively

  class Person < ActiveRecord::Base
    belongs_to :address,
      :default => proc { |record| record.address ||= Address.new }
  end

Are there any reasons why ActiveRecord should *not* do something like
this?

Michael

Sounds logical. The only concern I'd have is that it would be
'implicit' and so you wouldn't know whether using person.address was its
'existing' address or its 'auto-magically created' address. Leaving it
explicit helps you have more understanding of which is new, which isn't.

It just doesn't feel right. What I'd rather write is this

  class Person < ActiveRecord::Base
    belongs_to :address, :default => true
  end

That would be reasonable, though I'd probably not use it as I for some
reason love explicitness :slight_smile:
-R

There really doesn't seem to be a *declarative* way to define a default
value for belongs_to and has_one associations

ran into this, if useful.
http://gilesbowkett.blogspot.com/2007/12/snazzy-resource.html

There really doesn't seem to be a *declarative* way to define a default
value for belongs_to and has_one associations

  class Person < ActiveRecord::Base
    belongs_to :address
  end

  p = Person.new
  p.address.city = 'Atlantis' # Bummer!

Hmm, I sniff the code smell of a violation of the /law|strong
suggestion/ of Demeter here.

Better to define a city= method on Person (if this is what you really
want) which hides the implementation.

Of course, there's an easy way to avoid this

  class Person < ActiveRecord::Base
    belongs_to :address

    def after_initialize
      self.address ||= Address.new
    end
  end

It just doesn't feel right. What I'd rather write is this

  class Person < ActiveRecord::Base
    belongs_to :address, :default => true
  end

and alternatively

  class Person < ActiveRecord::Base
    belongs_to :address,
      :default => proc { |record| record.address ||= Address.new }
  end

Are there any reasons why ActiveRecord should *not* do something like
this?

Well, I have to ask, presumably Person belongs_to Address (rather than
the other way around) because more than one person can have the same
Address. The normal relationship on the other side of belongs_to is
has_many. Whenever I see has_one (unless it uses :conditions/:order
or the like to pick out one of a has_many) I wonder why the two models
aren't combined, either directly or via STI.

> There really doesn't seem to be a *declarative* way to define a
> default value for belongs_to and has_one associations
>
> class Person < ActiveRecord::Base
> belongs_to :address
> end
>
> p = Person.new
> p.address.city = 'Atlantis' # Bummer!

Hmm, I sniff the code smell of a violation of the /law|strong
suggestion/ of Demeter here.

I don't. That law doesn't say only a single dot is allowed, does it?
Apart from being called a law, I'd like to see exactly what improvement
following that rule would effect in this particular case.

In my rails code I very rarely have assignments like the one above. What
I do have is views and particularly forms where I show and edit objects
and related objects, such as a person and their address. Partials lend
themselves to this and in such a case, I want to pass a valid object,
say an address, into the partial. In a sense I'm even following the Law
of Demeter in that way. Anyway, whenever person.address gets passed
into the address partial, I want it to be initialized with an
appropriate address object.

Better to define a city= method on Person (if this is what you really
want) which hides the implementation.

Even if I did that -- which I won't without positive indication --, it
would not remove the original problem. As a negative indication I'd
like to point out that adding #city=, #zip= etc. to Person dilutes the
responsibility of that model class. These attributes belong on an
Address model class. Now, if we take presenters into consideration,
there I'd be inclined to put all relevant accessors directly on the
presenter. But at any rate, that wouldn't touch the original issue.

Michael