I'm designing a form where you need to add a relation to another object. Okay that's normally fine, but what I am hung up on is a clean way to make it easy for the user to enter the object. There are multiple ways that the user could know how to specify the object (unique identifiers).
Let's take the example of associating a user to a task. In this case, the models are laid out like this:
class User
has_many :tasks
# fields: phone_number, email, username
validates_uniqueness_of :phone_number
validates_uniqueness_of :email
validates_uniqueness_of :username
# other methods, validations, etc which are not important.
end
class Task
belongs_to :user
# other methods, validations, etc which are not important.
end
How would I write the controller and view form, if I want to be able to specify the user by username, email, or phone_number - I might know any one of these, and just one is enough to specify exactly the user that I want, in a clean way?
Currently my solution seems messy. I have a view similar to:
<% form_for @task do |f| %>
... Other stuff
User - choose one of the following ways: <br />
Username: <%= text_field_tag :user_name %> <br />
or phone number: <%= text_field_tag :user_phone %> <br />
or email: <%= text_field_tag :user_email %> <br />
... More other stuff
<% end %>
I then handle these fields explicitly in the controller, finding the actual user based on which ones are filled in:
class TasksController
def create
@task = Task.new(params[:task])
if params[:user_name]
@task.user = User.find_by_username(params[:user_name])
elsif params[:user_phone]
@task.user = User.find_by_phone_number(params[:user_phone])
elsif params[:user_email]
@task.user = User.find_by_email(params[:user_email])
end
if @task.save
redirect_to @task
else
render :action => 'new'
end
end
end
This seems like it's very specific, and there is a lot of code in my controllers, especially if I have lots of these on a form. Don't even talk to me about when you need to dynamically add multiple users to a task - it gets even more crazy in the controller parsing everything out.