When model A has_one
model B, this means that B stores the foreign key into A, in the same way that model C has_many
model D means that D stores the foreign key into C. The has_one
relation simply expresses your desire to allow only one record in B to hold a particular foreign key into A. Given that, you should get rid of user_profile_id
from the users
schema, because it isn't used. Only user_id
from UserProfile
is used.
You can still have User
check for the presence of UserProfile
, but use validates_presence_of :user_profile
instead. This will check that the user object has an associated user_profile object.
Your UserProfile
object should not check directly for a user_id
since this id won't yet exist when creating a new user-user_profile pair. Instead use validates_presence_of :user
, which will check that the UserProfile
has an associated User
object before saving it. Then write has_one :user_profile, :inverse_of => :user
in User
, which lets the UserProfile
know about the presence of its User
object, even before either has been persisted and assigned an id.
Finally, you can include a before_create
block in User
to build the associated UserProfile
when creating a new user. (I believe) it will run validations after building a new user_profile, so these should pass.
In summary,
class User < ActiveRecord::Base
has_one :user_profile, :inverse_of => :user
validates_presence_of :user_profile
before_create { build_user_profile }
end
class UserProfile < ActiveRecord::Base
belongs_to :user
validates_presence_of :user
end
UPDATE
I was mistaken about the validation-callback order. The validation runs before the before_create
callback is called, which means User
is checking for the presence of a UserProfile
before one is even built.
One solution is to ask yourself what value you get from having separate user and user_profile models. Given that they are so tightly bound that one cannot exist without the other, would it make sense (and perhaps simplify a lot of your code) to just combine them into a single model?
On the other hand, if you really find that there is value in having two separate models, perhaps you shouldn't use validations to maintain their mutual existence. In my opinion, model validations should generally be used to let users know that the data they have submitted have errors they need to fix. However, the absence of a user_profile
from their user
object is not something they can fix. So, perhaps the better solution is to have the user
object build a user_profile
if there isn't one. Instead of just complaining if a user_profile
doesn't exist, you take it a step further and just build it. No validation required on either side.
class User < ActiveRecord::Base
has_one :user_profile
before_save { build_user_profile unless user_profile }
end
class UserProfile < ActiveRecord::Base
belongs_to :user
end