Я использую объект формы на основе ActiveModel для обработки регистрации (регистрации) для приложения. Класс signup
абстрагирует информацию для account
и user
(основной пользователь для учетной записи).Rails 4: Проверка связанных моделей ActiveRecord при использовании объекта формы
Однако, я нахожу, что я дублирую логику проверки для account
и user
внутри класса signup
. Когда я писал свои спецификации (используя rspec), я понял, что это дублирование, вероятно, указывает на проблему с тем, как я обрабатываю это.
Есть ли способ пройти проверку в классе signup
на модели account
и user
без дублирования? Таким образом, валидация остается в этих моделях, и я могу ссылаться/называть ее в классе signup
.
Ниже signup
класс у меня есть это работает, но, кажется, дублирования кода ...
class Signup
include ActiveModel::Model
# Scopes
#----------------------------------------------------------------------
# NOOP
# Macros
#----------------------------------------------------------------------
attr_accessor :slug, :email, :password, :password_confirmation
# Associations
#----------------------------------------------------------------------
# NOOP
# Validations
#----------------------------------------------------------------------
validate :verify_unique_email
validate :verify_unique_slug
validates :email, presence: true, format: { with: /@/, message: "is invalid" }
validates :password, presence: true, length: { minimum: 8 }, confirmation: true
validates :password_confirmation, presence: true
validates :slug,
presence: true,
format: { with: /\A[\w-]+\z/, message: "is invalid" },
exclusion: { in: %w[signup signups login] }
# Methods
#----------------------------------------------------------------------
def account
@account ||= Account.new
end
def user
@user ||= account.build_primary_user
end
def save
account.active = true
account.slug = slug
user.email = email
user.password = password
user.password_confirmation = password_confirmation
if valid?
ActiveRecord::Base.transaction do
account.save!
user.save!
end
true
else
false
end
end
def save!
save
end
private
def verify_unique_email
if User.exists?(email: email)
errors.add :email, "is invalid"
end
end
def verify_unique_slug
if Account.exists?(slug: slug)
errors.add :slug, "has already been taken"
end
end
end
Вот account
модель, обратите внимание на дублирование в валидаций:
class Account < ActiveRecord::Base
has_one :primary_user, -> { where(primary: true) }, class_name: User
has_many :users, dependent: :destroy
validates :slug,
uniqueness: true,
presence: true,
format: { with: /\A[\w-]+\z/, message: "is invalid" },
exclusion: { in: %w[signup signups login] }
end
К сожалению, я склонен согласиться с тем, что включенный модуль может быть самым чистым DRY-решением для моей конкретной проблемы. Я надеялся, что есть способ сказать что-то эквивалентное: 'signup.errors = account.errors + user.errors', но, похоже, нет чистого способа реализовать это без возможности исправления Rails, которые у меня есть довольно строгая политика против. Я проверю ваше решение и приму его, если это сработает. –
В моем конкретном случае я решил придерживаться дублирования валидаций, поскольку позже я могу иметь отдельные проверки в классе 'signup', но извлечение длинных повторных проверок в отдельный модуль является лучшим решением, которое я видел до сих пор. Я рассмотрел делегирование валидации связанным объектам, копирование фактического массива 'object.errors' и т. Д., И ни одно из них не является« чистым »решением. –
Вы пробовали validates_associated, возможно, с помощью пользовательских сообщений? – aceofspades