Rails 4,验证嵌套模型

时间:2015-07-19 12:58:35

标签: ruby-on-rails-4

我有2个型号:

class Person
  has_one :user
  validates :document, uniqueness: true, on: :create

class User
  belongs_to :person
  accepts_nested_attributes_for :person

然后我有users的表单,其中包含有关person

的信息
<%= form_for @user do |f| %>
  <%= f.fields_for :person do |person_fields| %>
    <%= person_fields.label "Document" %>
    <%= person_fields.text_field :document %>
  <% end %>  
  <%= f.label "Username" %>
  <%= f.text_field :username %>
<% end %>

例如,当我选择/users/edit/1时,它会为用户加载其人员属性。如果我更改username并保存,则表示the document number is already at use,仅绕person绕过uniqueness create验证。

我在这里遗漏了什么吗?这样的验证不应该适用于嵌套表单吗?

1 个答案:

答案 0 :(得分:0)

嵌套属性允许您通过父级(has_one,has_many)保存关联记录的属性,而不是通过子级(belongs_to)保存父级的属性。

您的模型关系不正确;根据Rails api,嵌套属性对于通过父级的子级有效,而不是通过子级的父级,如下面的模型中所指定的那样。

您的模特

class Person
  has_one :user
  validates :document, uniqueness: true, on: :create

class User
  belongs_to :person
  accepts_nested_attributes_for :person (sets up nested attributes for parent)

您可以通过父级设置子级的嵌套属性,例如

建议更改

class Person
  has_one :user
  validates :document, uniqueness: true, on: :create
  accepts_nested_attributes_for :user

class User
  belongs_to :person

仅当模型中的嵌套关​​联设置正确时,嵌套在表单上才有效。

补充工具栏:美丽:Inverse_of

这是一个侧边栏,但在此背景下相关。 Inverse_of为您提供从子项到父项的反向引用。 Rails spec for :inverse_of。您应该尝试一下,看看它如何适用于您的应用。这是一件非常好的事情。

    class Person
      has_one :user, inverse_of: person
      validates :document, uniqueness: true, on: :create
      accepts_nested_attributes_for :user

   class User
     belongs_to :person, inverse_of: user

调试问题(已添加)

我添加了on ::创建验证到我的一个模型作为测试。我会要求你做一个没有模型嵌套的类似测试;我认为在模型中为on:create测试逻辑是有用的,它将验证控制器的动作。然后才会在嵌套属性上进行分层。你觉得怎么样?

create =&gt;上的重复字段ROLLBACK

Started POST "/locations" for 127.0.0.1 at 2015-07-20 08:03:36 -0500
Processing by LocationsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"Fxxx", "location"=>{"name"=>"Foo", "food_trailer"=>"true", "street"=>"100 Main", "city"=>"Fredericksburg", "state"=>"Texas", "country"=>"US", "phone"=>"", "website"=>"", "short_desc"=>"A Texan, Ms. Diana has been cookin' up barbecue for 50 years and, spreadin' the “barbecue love” in Paris (France!) since 2010.", "known_for"=>"Tings", "meats_beef"=>"0", "meats_beef_ribs"=>"0", "meats_pork"=>"1", "meats_pork_ribs"=>"0", "meats_chicken"=>"0", "meats_turkey"=>"0", "meats_sausage"=>"0", "meats_venison"=>"0", "sauce"=>"0", "sides"=>"None"}, "commit"=>"Add Restaurant"}
  [1m[36mUser Load (0.0ms)[0m  [1mSELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1[0m  [["id", 8]]
  [1m[35m (0.0ms)[0m  BEGIN
  [1m[36mLocation Exists (46.9ms)[0m  [1mSELECT  1 AS one FROM "locations" WHERE "locations"."short_desc" = 'A Texan, Ms. Diana has been cookin'' up barbecue for 50 years and, spreadin'' the “barbecue love” in Paris (France!) since 2010.' LIMIT 1[0m
  [1m[35mLocation Exists (0.0ms)[0m  SELECT  1 AS one FROM "locations" WHERE ("locations"."latitude" IS NULL AND "locations"."longitude" IS NULL) LIMIT 1
  [1m[36m (46.9ms)[0m  [1mROLLBACK[0m

编辑时重复字段=&gt; COMMIT

Started PATCH "/locations/46" for 127.0.0.1 at 2015-07-20 08:04:30 -0500
Processing by LocationsController#update as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"xxx", "location"=>{"name"=>"Grillrestaurant Rusticana", "street"=>"Grillparzerstraße 5, 81675", "city"=>"München", "state"=>"Alabama", "country"=>"US", "phone"=>"", "website"=>"", "short_desc"=>"A Texan, Ms. Diana has been cookin' up barbecue for 50 years and, spreadin' the “barbecue love” in Paris (France!) since 2010.", "known_for"=>"", "meats_beef"=>"0", "meats_beef_ribs"=>"0", "meats_pork"=>"0", "meats_pork_ribs"=>"0", "meats_chicken"=>"0", "meats_turkey"=>"0", "meats_sausage"=>"0", "meats_venison"=>"0", "sauce"=>"0", "sides"=>""}, "commit"=>"Save changes to Restaurant", "id"=>"46"}
  [1m[36mLocation Load (0.0ms)[0m  [1mSELECT  "locations".* FROM "locations" WHERE "locations"."id" = $1 LIMIT 1[0m  [["id", 46]]
  [1m[35m (0.0ms)[0m  BEGIN
  [1m[36mLocation Exists (0.0ms)[0m  [1mSELECT  1 AS one FROM "locations" WHERE ("locations"."latitude" = 48.1334073 AND "locations"."id" != 46 AND "locations"."longitude" = 11.6100255) LIMIT 1[0m
  [1m[35mSQL (15.6ms)[0m  UPDATE "locations" SET "short_desc" = $1, "meats_beef" = $2, "meats_pork" = $3, "meats_beef_ribs" = $4, "meats_pork_ribs" = $5, "meats_chicken" = $6, "meats_turkey" = $7, "meats_sausage" = $8, "meats_venison" = $9, "sauce" = $10, "latitude" = $11, "updated_at" = $12 WHERE "locations"."id" = $13  [["short_desc", "A Texan, Ms. Diana has been cookin' up barbecue for 50 years and, spreadin' the “barbecue love” in Paris (France!) since 2010."], ["meats_beef", "f"], ["meats_pork", "f"], ["meats_beef_ribs", "f"], ["meats_pork_ribs", "f"], ["meats_chicken", "f"], ["meats_turkey", "f"], ["meats_sausage", "f"], ["meats_venison", "f"], ["sauce", "f"], ["latitude", 48.13340729999999], ["updated_at", "2015-07-20 13:04:30.437500"], ["id", 46]]
  [1m[36m (46.9ms)[0m  [1mCOMMIT[0m
相关问题