1

У меня есть модель Invitation, которая представляет приглашение присоединиться к подписке. В любой момент времени должно быть только Invitation с определенной комбинацией email/subscription_id, если в других записях с соответствующими email/subscription_id также есть state из 'declined'.Как я могу validate_uniqueness_of, если областью действия для двух атрибутов, только если один атрибут для сопоставления существующих записей не равен определенному значению?

я могу в настоящее время проверки на уникальность, учитывая, что электронная почта и subscription_id комбинация уникальна:

Моя Invitation модель:

validates :email, :uniqueness => { :scope => :subscription_id } 

Rspec (проходит):

it { should validate_uniqueness_of(:email).scoped_to(:subscription_id) } 

Однако я хочу пропустить проверку уникальности, если сопоставимые модели (базы) в базе данных имеют state, что равно 'declined'.

Если состояние существующей модели «отклонено», проверка должна пройти.

Первое, что приходит на ум:

validates :email, :uniqueness => { :scope => :subscription_id }, 
            :unless => lambda { |asset| asset.state == 'declined' } 

Но это неправильно, потому что он проверяет, является ли вновь созданная модель имеет состояние «отклонен», я хочу, чтобы проверить, если ранее существующие записи имеют состояние 'declined'.

Я также попытался это:

validates :email, :uniqueness => { :scope => :subscription_id, :message => 'subscriptionery do' }, 
            :if => lambda { |asset| asset.state == 'declined' } 

Но это не может за то, что я предполагаю, что это та же причина.

Как написать подтверждение, проверяющее дополнительную область?


Я чувствую, что писать что-то вроде следующего, но это только что сделал синтаксис, чтобы помочь объяснить мою идею:

it { should validate_uniqueness_of(:email).scoped_to(:subscription_id) } 
            unless MyModel.where(:email == new_object.email, 
                 :subscription_id == new_object.subscription_id, 
                 :state == 'declined') 

Update:

я сделал это и работало:

validates :email, uniqueness: { scope: :subscription_id, message: 'The email address %{value} is already associated with this subscription.' }, if: :state_of_others_are_not_declined?, on: :create 

def state_of_others_are_not_declined? 
    Invitation.where(email: email).where(subscription_id: subscription_id).where.not(state: 'declined').any? 
end 

ответ

1

Как это работает для вас;

validate :unique_email_with_subscription_and_state 


def unique_email_with_subscription_and_state 
    errors.add(:email,"YOUR MESSAGE") if Invitation.where(email: self.email, subscription_id: self.subscription_id).where.not(state: 'declined').any? 
end 

Это позволит выбрать все Invitiation S, где в email матчи, subscription_id матчи и state не отклонили. Если он найдет что-либо, он добавит error в :email.Что-то вроде этого

"SELECT invitations.* FROM invitatations WHERE email = '[email protected]' AND subscription_id = 2 AND state <> 'declined'" 

Это желаемый результат?

+0

Действительно близко к тому, что я должен работать так, как вы разместили это. Я уверен, что ваше решение сработало бы так же хорошо, как очень похоже на решение, которое я придумал. – Ecnalyr