Rails - 新用户构建依赖的电子邮件并验证两者?

时间:2015-08-21 20:42:30

标签: ruby-on-rails validation associations

我正在构建一个允许用户管理其电子邮件地址的快速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

UsersController

belongs_to :user

validates :user, presence: true
validates :address, presence: true, uniqueness: {
  case_sensitive: false
}

修改

电子邮件模型还包含以下字段:

  • label = string,例如。 '个人','工作'等
  • primary = boolean,是否标记为主电子邮件
  • confirmation_code =创建时自动生成,用于确认所有权
  • confirm =布尔值,是否已确认

3 个答案:

答案 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();

User.rb

inverse_of

Email.rb

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