使用唯一性约束更新nested_attributes_for错误

时间:2014-06-24 21:48:07

标签: ruby-on-rails ruby ruby-on-rails-4

所以我正在研究在rails中构建用户模型,这个用户模型将具有相关的电子邮件地址模型。电子邮件地址模型对电子邮件具有唯一性约束。现在我设置它,以便用户accept_nested_attributes_for:email_address。这在创建时效果很好,但在更新时我收到此错误:

ActiveRecord::JDBCError: org.postgresql.util.PSQLException:
ERROR: duplicate key value violates unique constraint 
"index_email_addresses_on_email"

我可以通过在rails控制台中执行此操作来重新创建此错误:

u = User.create(:name => "foo", :new_password => "Passw0rd",
        :email_address_attributes => {:email => "foo@bar.com"})
u.update({:name => "new name",
        :email_address_attributes => {:email => "foo@bar.com"}})

如何在不关心email_address的情况下更新名称。哪个没改变?

其他一些注释和代码:

我在电子邮件中为我的email_address编制索引,而我正在使用rails 4。

class User < ActiveRecord::Base

  belongs_to :email_address

  validates :email_address, :presence => true

  accepts_nested_attributes_for :email_address
end

class EmailAddress < ActiveRecord::Base
  validates_format_of :email, :with => RFC822::EmailAddress
  validates :email, :presence => true
  has_one :user
end

3 个答案:

答案 0 :(得分:1)

如果您不想验证除创建之外的电子邮件地址,您可以将其添加到验证中:

validates :email_address, presence: true, on: :create

答案 1 :(得分:1)

以这种方式更新email_address_attributes时,实际上是在为email_address添加新的user对象。您需要将电子邮件地址的ID作为属性传递,即:

u.update({:name => "new name",
    :email_address_attributes => {:id => u.email_address.id, :email => "foo@bar.com"}})

或者,您可以使用其他更新语句更新用户的电子邮件地址

u.update({:name => "new name"})
u.email_address.update({:email => "foo@bar.com"})

对于您的控制器,您只需将电子邮件地址的:id字段添加为允许的参数。

def user_params
  params.require(:user).permit(:name, email_address_attributes: [:id, :email])
end

Strong Parameters Rails Guide中有关于强参数的更多信息。查看More Example section以获得与您类似的设置。

答案 2 :(得分:1)

在“accepts_nested_attributes_for”中使用“:update_only”选项,如下所示:

accepts_nested_attributes_for :email_address, :update_only => true

这样,活动记录将更新子记录(如果已存在),而不是创建新记录。这应该照顾独特的约束。