Is there a "first_or_build" method on has_many associations?

m_x picture m_x · May 27, 2013 · Viewed 9.3k times · Source

In rails 3.2+, you can do this :

SomeModel.some_scope.first_or_initialize

Which means you can also do :

OtherModel.some_models.first_or_initialize

I find this pretty useful, but i'd like to have a first_or_build method on my has_many associations, which would act like first_or_initialize but also add a new record to the association as build does when needed.

update for clarification : yes, i know about first_or_initializeand first_or_create. Thing is, first_or_initializedoes not add the initialized record to the association's target as build does, and first_or_create... well... creates a record, which is not the intent.

I have a solution that works, using association extensions :

class OtherModel < ActiveRecord::Base

  has_many :some_models do 
    def first_or_build( attributes = {}, options = {}, &block )
      object = first_or_initialize( attributes, options, &block )
      proxy_association.add_to_target( object ) if object.new_record?
      object
    end
  end

end

I just wonder if :

  • built-in solutions to this problem already exist ?
  • my implementation has flaws i do not see ?

Answer

Bryan Corey picture Bryan Corey · Sep 10, 2013

I'm not sure if there is anything built into rails that will do exactly what you want, but you could mimic the first_or_initialize code with a more concise extension than you are currently using, which I believe does what you want, and wrap it into a reusable extension such as the following. This is written with the Rails 3.2 extend format.

module FirstOrBuild
  def first_or_build(attributes = nil, options = {}, &block)
    first || build(attributes, options, &block)
  end
end

class OtherModel < ActiveRecord::Base
  has_many :some_models, :extend => FirstOrBuild
end