Nested attributes allow you to save attributes on associated records through the parent (has_one, has_many), not on the parent through the child (belongs_to).
Your model relationship is not correct; According to Rails api nested attributes are valid for the child through the parent, not the parent through the child as you have specified in your models below.
Your models
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)
You could set up nested attributes for the child via the parent, as such
Suggested change
class Person
has_one :user
validates :document, uniqueness: true, on: :create
accepts_nested_attributes_for :user
class User
belongs_to :person
Nesting on your form will work only if the nesting associations in the model are set up properly.
Sidebar: The beauty of :Inverse_of
This is a sidebar, but relevant in this context. Inverse_of gives you a reverse reference from the child to the parent. Rails spec for :inverse_of. You should try this out and see how it works for your app. It's a very good thing.
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
Debugging questions (added)
I added the on: :create validation to one of my models as a test. I would ask you do a similar test without the model nesting; I think it's informative to test the logic in the model for the on: create, which will validate the controller actions. And only then layer on the nesting attributes. What do you think?
Duplicate field on create => 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
Duplicate field on edit => 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