Rails - Как использовать Find or Create

У меня есть следующее:

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

Как я могу обновить это как find_or_create, так что если эта запись уже существует, она назначается @permission, а если она не существует, запись создается?

Ответы

Ответ 1

Связанная тема:

find_or_create_by в Rails 3 и обновление для создания записей

Вы можете расширить ActiveRecord с помощью собственного метода update_or_create (см. соответствующую тему), а затем вы можете использовать этот

@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

Или вы можете использовать метод find_or_create_by...:

@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

Ответ 2

Несмотря на то, что принятый ответ правильный, важно отметить, что в Rails 4 этот синтаксис будет меняться (и хэш-синтаксис). Вы должны написать следующее:

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

Что на самом деле выглядит намного ближе к вашему оригинальному методу! Подробнее см. Подраздел Устаревшие искатели.

Ответ 3

Я обновляю вопросы с версиями ответов. Потому что его важно.


Rails 4 (docs)

Существует несколько способов "найти или создать" объект, один из которых - find_or_create_by(args)

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

Но предпочтительный способ сообщества использует where

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

а затем вы можете сделать что-то вроде:

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

Rails 3 (docs)

Предположим, вы хотите найти клиента с именем "Andy", и если theres нет, создайте его и добавьте его заблокированный атрибут в значение false. Ты можешь сделайте это, выполнив:

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">

Ответ 4

Или вы хотите попробовать это, если у вас есть много полей для заполнения:

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

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

посмотреть это сообщение: Как передать несколько атрибутов find_or_create_by в Rails 3?