This problem is a good candidate for virtual attributes. Instead of trying to resolve the username, let the profile model suit you.
class Profile belongs_to :user # ... def username user.try(:username) end def username=(value) self.user = User.find_by_username(value) end end
Then in your form
<% form_for @profile do |f| %> <%= f.text_field :username %> <% end %>
When sending, the value of the username field is automatically transferred with all other valid activerecord attributes. ActiveRecord will look for username = setter and will allow communication. If the association returns nil (no record exists with the given username), then it will set the current user_id to nil, and the check will fail as expected.
You might want to tweak the error code to make it more meaningful.
EDIT: added example.
validate :ensure_username_exists def username=(value) self.user_id = User.find_by_username(value) || 0 end protected def ensure_username_exists if user_id == 0
source share