我正在构建一个允许用户管理其电子邮件地址的快速Rails项目。用户可以收到许多电子邮件,但这些电子邮件中只有一封(且只有一封)必须标记为“主要”(用于登录),如果没有主电子邮件,用户就无法存在。
我一直在努力让这个工作正常 - 对我来说似乎太圆了。我需要构建一个用户,然后是电子邮件,但我不想将用户保存到数据库中,除非电子邮件有效,直到保存用户才会将用户保存(因为{{1}约束)。
接受嵌套资源似乎不适用于validates :user, presence: true
(适用于.new
),如果我的电子邮件未通过验证,则用户仍然显示为有效。
从单一表单构建/验证多个/依赖模型时,一直很难找到好的资源(或SO问题)。
Rails最常用的方法是什么?
.create
has_many :emails
has_one :primary_email, -> { where(primary: true) }, class_name: "Email"
accepts_nested_attributes_for :primary_email
validates :first_name, presence: true
validates :last_name, presence: true
validates :birthday, presence: true
validates :password_digest, presence: true
belongs_to :user
validates :user, presence: true
validates :address, presence: true, uniqueness: {
case_sensitive: false
}
电子邮件模型还包含以下字段:
答案 0 :(得分:1)
class User
user has_many :emails
user has_one :primary_email, -> { where(primary: true) }, class_name: "Email", autosave: true
after_initialize {
build_primary_email if new_record?
}
end
class Email
# use gem https://github.com/balexand/email_validator
validates :my_email_attribute, :email => true
end
因此,在用户初始化其构建一个primary_email以便该记录已经关联之后,或者至少它是否可以保存。自动保存工作非常酷 - 如果由于验证错误而无法保存主电子邮件,则用户也不能。应该开箱即用,我现在在公共汽车上,无法检查它。欢呼声
进一步的信息:http://api.rubyonrails.org/classes/ActiveRecord/AutosaveAssociation.html
如果任何关联的验证失败,它们的错误消息将应用于父级。这意味着,父模型(在您的情况下为User)有错误,这就是为什么要保存不可能!这就是你要找的东西。
答案 1 :(得分:1)
我会将主要电子邮件存储为公共字段,并以其他方式存储其他电子邮件。我更愿意将其他电子邮件存储在另一个字段中,即Array,而不是在关联的表中。您不应将主电子邮件存储在另一个表中。试想一下,每当您需要授权用户或只是收到他的电子邮件时,您都会对db执行额外请求。
答案 2 :(得分:0)
意味着要在几个月前发布。
将用户和电子邮件在不同模型中规范化而不将主电子邮件存储为用户属性的解决方案是使用List<SimpleQuestion> listOfQ = new List<SimpleQuestion>();
listOfQ.Add(new SimpleQuestion(1, "1"));
listOfQ.Add(new SimpleQuestion(2, "2"));
listOfQ.Add(new SimpleQuestion(3, "3"));
List<Question> testQuestions = new List<Question>();
testQuestions.Add( new Question(1,1,"1"));
testQuestions.Add( new Question(2,2,"2"));
testQuestions.Add( new Question(3,3,"1"));
List<Question> list = (from q in listOfQ
join a in testQuestions on q.IdQuestion equals a.IdQuestion
where a.Answer == q.Answer
select a
).ToList();
:
inverse_of
class User < ActiveRecord::Base
has_many :emails, inverse_of: :user, dependent: :destroy
accepts_nested_attributes_for :emails
validates :emails, presence: true
end
这允许使用内存中对象执行验证,而不是通过数据库调用(即,验证对象关联,而不是数据库中存在id /记录)。因此,它们都通过了验证,并且都可以保存在同一个事务中。
请参阅:https://viget.com/extend/exploring-the-inverse-of-option-on-rails-model-associations