AnApprentice
AnApprentice

Reputation: 110960

Rails - How to use Find Or Create

I have the following:

@permission = @group.permissions.create(
  :user_id => @user.id,
  :role_id => 2,
  :creator_id => current_user.id)

How can I update that to be find_or_create, so that if this record already exists, it's assigned to @permission, and if it doesn't exist, the record is created?

Upvotes: 17

Views: 53775

Answers (4)

Blair Anderson
Blair Anderson

Reputation: 20171

I'm updating questions with versioned answers. Because its important.


Rails 4 (docs)

There are a few ways to "find or create" an object, one is find_or_create_by(args)

Client.find_or_create_by(email: "[email protected]", phone: "4255551212")

But the community preferred way is using where

client = Client.where(email: "[email protected]", phone: "4255551212").first_or_create

and then you can do something like:

client = Client.where(client_params.slice(:email, :phone)).first_or_create
client.update(client_params)

Rails 3 (docs)

Suppose you want to find a client named ‘Andy’, and if there’s none, create one and additionally set his locked attribute to false. You can do so by running:

client = Client.where(:first_name => 'Andy').first_or_create(:locked => false)
# => #<Client id: 1, first_name: "Andy", orders_count: 0, locked: false, created_at: "2011-08-30 06:09:27", updated_at: "2011-08-30 06:09:27">

Upvotes: 7

Gavin Miller
Gavin Miller

Reputation: 43825

While the accepted answer is correct it's important to note that in Rails 4 this syntax will be changing (and the hash syntax). You should be writing the following:

@permission = Permission.where(
  user_id: @user.id, 
  role_id: 2, 
  creator_id: current_user.id).first_or_create

Which actually looks much closer to your original method! See the sub-section Deprecated Finders for more details.

Upvotes: 52

lkahtz
lkahtz

Reputation: 4796

Or you wanna try this if you have many fields to fill in:

conditions = { :user_id => @user.id, 
               :role_id => 2,
               :creator_id => current_user.id }

    @permission = group.permissions.find(:first, :conditions => conditions) || group.permissions.create(conditions)

see this post: How can I pass multiple attributes to find_or_create_by in Rails 3?

Upvotes: 2

fl00r
fl00r

Reputation: 83680

Related topic:

find_or_create_by in Rails 3 and updating for creating records

You can extend ActiveRecord with your own update_or_create method (see related topic) and then you can use this

@permission = Permission.update_or_create_by_user_id_and_role_id_and_creator_id(@user.id, 2, current_user.id) do |p|
  p.group_id = @group.id
end

Or you can use find_or_create_by... method:

@permission = Permission.find_or_create_by_user_id_and_role_id_and_creator_id(@user.id, 2, current_user.id)
@permission.group = @group
@permission.save

Upvotes: 19

Related Questions