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.
I think the most unobtrusive way of doing this is with a few AJAX calls.
I’m thinking an observer on a text field that calls a remote function. That function should update your form with matching potential associations, that the user can select with a radio button or something.
It would look like something like this:
UserController:
views/select_user.rjs:
task form
May not work as advertised. I made assumptions and haven’t tested it. But it should put you on the right track.
When it comes to multiple users all that really needs to change is the hidden field tag and the rjs file. but not by much. There’s also nothing stopping you from using a more robust search mechanism.