diff options
author | Andrés Mejía <andmej@gmail.com> | 2011-08-27 23:10:25 -0500 |
---|---|---|
committer | Andrés Mejía <andmej@gmail.com> | 2011-08-30 16:33:37 -0500 |
commit | 84dad446c6a23a15f67b9d558e8039891a008bff (patch) | |
tree | 6c0560bca9644384c59f21a3807561d6a4ed102b /activerecord/lib | |
parent | 2350fecd2251584d770afc4bd1764b3fe526ff70 (diff) | |
download | rails-84dad446c6a23a15f67b9d558e8039891a008bff.tar.gz rails-84dad446c6a23a15f67b9d558e8039891a008bff.tar.bz2 rails-84dad446c6a23a15f67b9d558e8039891a008bff.zip |
Adding first_or_create, first_or_create!, first_or_new and first_or_build to Active Record.
This let's you write things like:
User.where(:first_name => "Scarlett").first_or_create!(:last_name => "Johansson", :hot => true)
Related to #2420.
Diffstat (limited to 'activerecord/lib')
-rw-r--r-- | activerecord/lib/active_record/base.rb | 1 | ||||
-rw-r--r-- | activerecord/lib/active_record/relation.rb | 43 |
2 files changed, 44 insertions, 0 deletions
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 374791deb1..2979ad1cb3 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -442,6 +442,7 @@ module ActiveRecord #:nodoc: class << self # Class methods delegate :find, :first, :first!, :last, :last!, :all, :exists?, :any?, :many?, :to => :scoped + delegate :first_or_create, :first_or_create!, :first_or_new, :first_or_build, :to => :scoped delegate :destroy, :destroy_all, :delete, :delete_all, :update, :update_all, :to => :scoped delegate :find_each, :find_in_batches, :to => :scoped delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins, :where, :preload, :eager_load, :includes, :from, :lock, :readonly, :having, :create_with, :to => :scoped diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index 15fd1a58c8..461237c7ad 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -94,6 +94,49 @@ module ActiveRecord scoping { @klass.create!(*args, &block) } end + # Tries to load the first record; if it fails, then <tt>create</tt> is called with the same arguments as this method. + # + # Expects arguments in the same format as <tt>Base.create</tt>. + # + # ==== Examples + # # Find the first user named Scarlett or create a new one. + # User.where(:first_name => 'Scarlett').first_or_create(:last_name => 'Johansson') + # # => <User id: 1, first_name: 'Scarlett', last_name: 'Johansson'> + # + # # Find the first user named Scarlett or create one with a different last name. + # # We already have one Scarlett, so she'll be returned. + # User.where(:first_name => 'Scarlett').first_or_create do |user| + # user.last_name = "O'Hara" + # end + # # => <User id: 1, first_name: 'Scarlett', last_name: 'Johansson'> + # + # # Find the first user named Andy or create several at a time. + # User.where(:first_name => 'Andy').first_or_create([{:last_name => 'García'}, {:last_name => 'Mejía'}]) + # # => [#<User id: 2, first_name: 'Andy', last_name: 'García'>, + # #<User id: 3, first_name: 'Andy', last_name: 'Mejía'>] + # + # # Find the first user with last name García or create several at a time. + # User.where(:last_name => 'García').first_or_create([{:first_name => 'Jorge'}, {:first_name => 'Andy'}]) + # # => <User id: 2, first_name: 'Andy', last_name: 'García'> + def first_or_create(*args, &block) + first || create(*args, &block) + end + + # Like <tt>first_or_create</tt> but calls <tt>create!</tt> so an exception is raised if the created record is invalid. + # + # Expects arguments in the same format as <tt>Base.create</tt>. + def first_or_create!(*args, &block) + first || create!(*args, &block) + end + + # Like <tt>first_or_create</tt> but calls <tt>new</tt> instead of <tt>create</tt>. + # + # Expects arguments in the same format as <tt>Base.new</tt>. + def first_or_new(*args, &block) + first || new(*args, &block) + end + alias :first_or_build :first_or_new + def respond_to?(method, include_private = false) arel.respond_to?(method, include_private) || Array.method_defined?(method) || |