views:

102

answers:

2

I have a model called Profile which is belong_to User, so there is 'user_id' for the database to keep track of. In the local admin interface I made for this model I wanted to provide the flexibility of allowing admin to enter an username to a field in the editing screen, and then resolve that to user_id for saving in controller.

However the question is, how do I check against that the username have a valid return? I found that in ActiveRecord::Validation there is no method for validating the existence of the association. How will you handle a situation like this?

Update: What I want to do is to validate that the username field in the form is indeed a real user, then I could save that user_id back to the profile admin is editing. Here 'return' means the user object returned.

+1  A: 

This is a useful reference for Active Record Associations: http://guides.rubyonrails.org/association_basics.html

To check for the existence of the association, just check association.nil?

if @profile.user.nil?
  ... something ...
end

To check if the username has a valid return, well I'm not quite sure what you mean. Could you expand on that?

Barry Gallagher
Updated. Thanks.
itsnotvalid
+5  A: 

This problem is a good candidate for virtual attributes. Instead of trying to resolve the username, let the profile model to the job for 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 submitted, the value for the username field is automatically passed with all the other real activerecord attributes. ActiveRecord will look for the username= setter and will resolve the association. If the association returns nil (no record exists with given username), then it will set current user_id to nil and validation will fail as expected.

You might want to customize the error code to make 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 # nil is allowed 
      errors.add(:user_id, "Username doesn't exists") 
      return false 
    end
  end
Simone Carletti
How about if the user_id is optional? Which here a profile may be belonged to nobody.
itsnotvalid
There are many ways to accomplish this. You might want to change username=() in order to return 0 in case the username doesn't exist, instead of nil. In this case you can check on save whether the value is == 0 and invalidate the object. 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 # nil is allowed errors.add(:user_id, "Username doesn't exists") return false end endThis is just one possible solution.
Simone Carletti
Sorry. I wrote an example but it seems comments can't contain code. :S
Simone Carletti
@weppos you may try to put that example back to the answer.
itsnotvalid
Done. I added the example.
Simone Carletti