I created a patch on Lighthouse [1] that makes has_one associations
with conditions provided with a hash be built or created with those
conditions. As it is explained in the doc added:
"Record creation from the association is scoped if a hash is used.
has_one :account, :conditions => {:enabled => true} will create an
enabled account with @company.create_account or
@company.build_account"
I needed to support this in an app I'm working on, and I think it's a
small patch that might be useful for others too. The ticket has been
there with a couple of days so I thought that maybe through this
message someone will be interested and comment on it
I like the concept and think it should be expanded to other
associations. We already define certain attributes of associated
objects for selecting, the symmetry of having build/create defaults is
handy.
I could use it on a current project right now:
has_many :trial_memberships, :conditions => {:state => 'trial',
:starts_on => Time.now}
@company.trial_memberships.build(other_opts_that_merge)
or
@company.trial_memberships.create
would set initial state and starts_on values for objects associated
through these associations.
Comments:
1) :conditions is a bad name choice (even if the concept is not
expanded to other association types). Other associations already use
:conditions to define database selects
(example from the docs: has_many :approved_comments, :class_name =>
'Comment', :conditions => ['approved = ?', true])
Use :build_options, :build_attributes, :initial_attributes, etc.
2) HasMany and HABTM Associations already have a mechanism that could
be used for setting initial attributes (the Association callbacks).
has_many : trial_memberships, :before_add =>
:set_initial_state_to_trial, :set_starts_at_to_now
has_one/belongs_to don't have these callbacks.
I'd love to see all associations get callbacks. these could be used
internally for setting initial attributes on associated objects,
making
has_many : trial_memberships, :initial_attriubtes => {:state =>
'trial', :starts_at => Time.now}
a shorthand syntax for
has_many : trial_memberships, :after_add =>
:set_initial_state_to_trial, :set_starts_at_to_now
I like the concept and think it should be expanded to other
associations. We already define certain attributes of associated
objects for selecting, the symmetry of having build/create defaults is
handy.
I could use it on a current project right now:
has_many :trial_memberships, :conditions => {:state => 'trial',
:starts_on => Time.now}
@company.trial_memberships.build(other_opts_that_merge)
or
@company.trial_memberships.create
would set initial state and starts_on values for objects associated
through these associations.
Actually, I think that behaviour is already there for has_many and
habtm (and what this patch does is extend the same behavior to
has_one):
:conditions - Specify the conditions that the associated objects must
meet in order to be included as a WHERE SQL fragment, such as price >
5 AND name LIKE ‘B%’. Record creations from the association are scoped
if a hash is used. has_many :posts, :conditions => {:published =>
true} will create published posts with @blog.posts.create or
@blog.posts.build
Comments:
1) :conditions is a bad name choice (even if the concept is not
expanded to other association types). Other associations already use
:conditions to define database selects
(example from the docs: has_many :approved_comments, :class_name =>
'Comment', :conditions => ['approved = ?', true])
Use :build_options, :build_attributes, :initial_attributes, etc.
2) HasMany and HABTM Associations already have a mechanism that could
be used for setting initial attributes (the Association callbacks).
has_many : trial_memberships, :before_add =>
:set_initial_state_to_trial, :set_starts_at_to_now
has_one/belongs_to don't have these callbacks.
I'd love to see all associations get callbacks. these could be used
internally for setting initial attributes on associated objects,
making
has_many : trial_memberships, :initial_attriubtes => {:state =>
'trial', :starts_at => Time.now}
a shorthand syntax for
has_many : trial_memberships, :after_add =>
:set_initial_state_to_trial, :set_starts_at_to_now
I feel that callbacks for has_one/belongs_to associations might be too
much, but maybe it could be a good progression from this patch.
Thanks for looking at it and sharing your comments
Isn't this stuff that is taken care of by :default on a column when
creating migrations?
If you do it at the database level, then all your records will have
those defaults. On the contrary it's just that has_one association
that you might want to have some defaults based on the conditions you
have. For example with "has_one :account, :conditions => {:enabled =>
true}", you only want the account from that model to be enabled by
default, but for a regular account you would still want it to be
false.
Oooops, you're totally right. I guess I've always used the array
syntax for :conditions. In that case, :conditions is definitely the
best name for the option and the patch brings has_one into alignment
with other association types.
Clearly I haven't been using this feature on the collection
association types, but now that I know about it, I'll be refactoring
away some sloppier code. I'd like to have it available for has_one +1.