aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/relation.rb
diff options
context:
space:
mode:
authorAndrés Mejía <andmej@gmail.com>2011-08-27 23:10:25 -0500
committerAndrés Mejía <andmej@gmail.com>2011-08-30 16:33:37 -0500
commit84dad446c6a23a15f67b9d558e8039891a008bff (patch)
tree6c0560bca9644384c59f21a3807561d6a4ed102b /activerecord/lib/active_record/relation.rb
parent2350fecd2251584d770afc4bd1764b3fe526ff70 (diff)
downloadrails-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/active_record/relation.rb')
-rw-r--r--activerecord/lib/active_record/relation.rb43
1 files changed, 43 insertions, 0 deletions
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) ||