0

У меня есть модель под названием PaymentNotifications. Он используется для записи платежей только в том случае, если они действительны для Paypal. Мне нужно проверить, что код транзакции, который они мне дают, тот же, который я получаю от них после отправки формы.Рефакторинг ActiveRecord пользовательские проверки

Все это работает. Что я тогда проверить, если она действует на основе некоторых критериев следующим образом:

В контроллере я следующее:

tx = params[:tx] 
paypal_data = get_data_from_paypal(tx) 
res_hash = create_hash(paypal_data) 
@payment_notification = PaymentNotification.new(:params => res_hash, :quotation_id => res_hash['invoice'],:status => res_hash["payment_status"],:transaction_id => res_hash["txn_id"]) 
if paypal_data["SUCCESS"] && @payment_notification.is_valid?(tx) && @payment_notification.save 
    redirect_to thankyou_path(:id => @payment_notification.quotation_id) 
else 
    render '/pages/error' 
end 

Тогда в модели я запускаю мой метод is_valid?

validates :params, :quotation_id, :status, :transaction_id, presence: true 
validates :transaction_id, :uniqueness => true 

def is_valid?(tx) 
    amount_paid_valid?(params["payment_gross"]) && transaction_valid?(tx) && is_quotation_unpaid? 
end 

def transaction_valid?(tx) 
    if tx != transaction_id 
    errors.add(:transaction_id, "This transaction is not valid") 
    return false 
    else 
    return true 
    end 
end 

def is_quotation_unpaid? 
    if quotation.unpaid? 
    return true 
    else 
    errors.add(:quotation_paid, "This quotation has already been paid.") 
    return false 
    end 
end 

def amount_paid_valid?(amount_paid) 
    if amount_paid.to_i == quotation.price.to_i 
    return true 
    else 
    errors.add(:amount_paid, "The amount paid does not match the price quoted.") 
    return false 
    end 
end 

ПРИМЕЧАНИЕ: :amount_paid и :quotation_paid не являются атрибутами. Это просто ключи для сообщений об ошибках.

Я думаю, что здесь не хватает лодки, так как должен быть способ сделать это с помощью валидаций, встроенных в Rails, но пока я еще не очень хорош в Rails. Может ли кто-нибудь помочь мне реорганизовать это так, чтобы его было легче поддерживать и соответствовать лучшим практикам?

ответ

1

Основная проблема заключается в том, что вы переопределяете то, что Rails уже имеет, а именно, метод проверки, является ли объект AR действительным. Если вы используете свой метод, а не встроенный #valid?, ваши объекты будут продолжать передавать такие действия, как #save и #create, даже если они не должны.

Для того, чтобы привести свои собственные методы в складку и включить их при вызове встроенной проверки, просто использовать их в качестве пользовательских валидаций в вашей модели, например, так:

validates :params, :quotation_id, :status, :transaction_id, presence: true 
validates :transaction_id, :uniqueness => true 
validate :amount_paid_should_match_quote, :quotation_should_be_unpaid 
validates_associated :transaction 

private 

def amount_paid_should_match_quote 
    if amount.to_i != quotation.price.to_i 
    errors.add(:amount, "does not match the price quoted") 
    end 
end 

def quotation_should_be_unpaid 
    if quotation.paid? 
    errors.add(:quotation, "has already been paid") 
    end 
end 

Несколько пунктов для оплаты Обратите внимание на:

  1. Методы проверки не должны принимать аргументы, поскольку они являются экземплярами методов, которые тестируют существующие атрибуты.
  2. Избегайте ссылок на параметры в ваших моделях. Обработка запросов - это работа контроллеров.
  3. Вам просто нужно обработать сценарии без прохождения в ваших методах. Не беспокойтесь о возврате true, когда объекты действительны, это до Rails.
  4. Не следует писать методы для проверки ассоциаций. Просто используйте для этого validates_associated.
  5. Это помогает, если вы переименуете свои собственные методы, чтобы более описать фактическое поведение, которое они пытаются обеспечить. Я попытался дать вам предложение, но вы можете использовать все, что захотите.

Подробнее о пользовательских проверках можно узнать на странице Rails Guides Validations documentation.

+0

Огромное спасибо депе, что является удивительным ответом, который должен служить моделью для других, чтобы соответствовать. Я буду выполнять все ваши предложения и учиться у них. Одна вещь, которую я должен был отметить, нет никакой связи с транзакцией. Это просто используется для записи идентификатора транзакции, отправленного с PayPal. Мне нужно проверить, совпадает ли идентификатор транзакции от PayPal, который они отправляют после отправки формы. Поэтому я не проверяю ассоциацию, я проверяю, что совпадение идентификатора, поэтому я должен поддерживать этот метод. – chell

+0

Эй, рад помочь. Об ассоциации, я думал, что 'transaction_id' был внешним ключом для' own_to' с моделью Transaction. Но все в порядке.Совет по проверке ассоциаций по-прежнему остается в принципе. – depa

Смежные вопросы