Идентификация предмета одним из нескольких способов - PullRequest
1 голос
/ 24 февраля 2010

Я разрабатываю форму, в которой вам нужно добавить отношение к другому объекту. Ладно, это нормально, но то, на чем я держусь, - это простой способ облегчить пользователю ввод объекта. Есть несколько способов, которыми пользователь может знать, как указать объект (уникальные идентификаторы).

Давайте рассмотрим пример привязки пользователя к задаче. В этом случае модели раскладываются так:

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

Как мне написать контроллер и просмотреть форму, если я хочу иметь возможность указать пользователя по имени пользователя, электронной почте или номеру телефона - я могу знать любой из них, и достаточно одного, чтобы точно указать пользователь, которого я хочу, clean way?

В настоящее время мое решение кажется грязным. У меня есть вид, похожий на:

<% 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 %> 

Затем я явно обрабатываю эти поля в контроллере, находя реального пользователя на основе того, какие из них заполнены:

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

Кажется, что это очень специфично, и в моих контроллерах много кода, особенно если у меня их много в форме. Даже не говорите со мной о том, когда вам нужно динамически добавлять нескольких пользователей в задачу - это становится еще более безумным в контроллере, разбирающем все.

Ответы [ 2 ]

1 голос
/ 24 февраля 2010

Я думаю, что самый ненавязчивый способ сделать это с помощью нескольких вызовов AJAX.

Я думаю о наблюдателе в текстовом поле, которое вызывает удаленную функцию. Эта функция должна обновлять вашу форму в соответствии с возможными ассоциациями, которые пользователь может выбрать с помощью переключателя или чего-то еще.

Это будет выглядеть примерно так:

UserController:

def select_user
  @user = case params[:query]
  when !/\w/ #phone no
    User.find_by_phone(params[:query])
  when /@/ # email
    User.find_by_email(params[:query])   
  else
    User.find_by_username(params[:query])
  end
end

просмотр / select_user.rjs:

page.replace_html :matched_user, :inline => <<"PARTIAL"
<%=hidden_field_tag "task[user_id]", @user.id%>
User: <%=@user%>
PARTIAL

форма задания

<%form_for @task do |f|%>
  ...
  <%= text_field_tag :query %>
  <%= observe_field :query, {:controller => :users, :action => :select_user}%>
  <div id="matched_user" />
<% end%>

Может работать не так, как рекламируется. Я сделал предположения и не проверял это. Но это должно поставить вас на правильный путь.

Когда дело доходит до нескольких пользователей, все, что действительно нужно изменить, - это тег скрытого поля и файл rjs. но не очень. Кроме того, ничто не мешает вам использовать более надежный механизм поиска.

0 голосов
/ 24 февраля 2010

Телефонные номера будут проблемой, если вы не обработаете ввод, чтобы убрать переносы, скобки и т. Д.

Сказав это, вот несколько вариантов.

1 Сверните свои собственные.

У пользователя:

def find_by_foo(search)
  # TODO: Pre-process anything in search that looks like a phone number.

  conditions = "username like ? or phone_number like ? or email like ?"

  wildcard_search = "%#{search}%"
  substitutions = []
  3.times do 
    substitutions << wildcard_search
  end

  User.find(:first, :conditions => ([conditions] + substitutions))
end

2 Бросать собственную глупость, когда searchlogic уже существует.

Из их примеров в разделе «Объединение областей»:

User.username_or_first_name_like("ben")
  => "username LIKE '%ben%' OR first_name like'%ben%'"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...