2010-10-05 9 views
14

estoy usando la gema rails3-jquery-autocomplete encontrado aquí: http://github.com/crowdint/rails3-jquery-autocompleterieles joya rails3-jquery-autocompletar: ¿Cómo puedo consultar varios campos

Las instrucciones son claras para cómo consultar un único atributo de un modelo y soy capaz para hacer que funcione sin problemas

Mi modelo Person tiene dos atributos que me gustaría combinar y consultar, sin embargo. Son first_name y last_name. Me gustaría combinarlos en un pseudo-atributo llamado full_name. Actualmente, recibo este error:

ActiveRecord::StatementInvalid (SQLite3::SQLException: no such column: full_name: SELECT  "people".* FROM  "people" WHERE  (LOWER(full_name) LIKE 'cla%') ORDER BY full_name ASC LIMIT 10): 

No hay full_name atributo del modelo de persona, aunque no tengo el método siguiente en el archivo de modelo persona:

def full_name 
    "#{self.first_name} #{self.last_name}" 
end 

¿Cómo modificar el modelo de persona archivo para que las llamadas al full_name consulten la base de datos para que coincida con una combinación de first_name y last_name?

+0

la gema es mantenido [aquí] (https://github.com/bigtunacan/rails-jquery-autocomplete) –

Respuesta

9

Su pseudoatributo funciona solo en los registros ya recuperados, pero no tiene relación con la búsqueda de registros. Probablemente la solución más fácil es un llamado named scope como:

scope :search_by_name, lambda { |q| 
    (q ? where(["first_name LIKE ? or last_name LIKE ? or concat(first_name, ' ', last_name) like ?", '%'+ q + '%', '%'+ q + '%','%'+ q + '%' ]) : {}) 
} 

Por lo tanto, una llamada como:

Person.search_by_name(params[:q]) 

devolverá un conjunto de resultados correspondiente. También devolverá todas las entradas si no se aprobó ningún parámetro (o más específicamente, este alcance no agregará nada adicional), lo que lo convierte en un complemento fácil para la acción de índice.

+0

¡Gracias! Aprecio la ayuda. – Clay

+4

¿Alguien puede indicar cómo integrar esto con la gema autocompletar? (¿Cuáles deberían ser los argumentos para la llamada 'autocompletar' en el controlador? No me parece que la opción' scopes' funcionará para los ámbitos que requieren parámetros). – JellicleCat

+0

que es bastante útil cuando lo piensas; gracias por esta pista! – Ben

7

Lamentablemente, el método de alcance mencionado anteriormente no funcionó para mí. Mi solución fue simplemente sobrescribir el método get_autocomplete_items (anteriormente get_items).

Por lo que vale la pena, hay una función de MySQL (de otros db tienen también, pero estamos hablando de MySQL por el momento) que se adapta mejor al tipo de concatenación que estés usando:

def get_autocomplete_items(parameters) 
    items = Contact.select("DISTINCT CONCAT_WS(' ', first_name, last_name) AS full_name, first_name, last_name").where(["CONCAT_WS(' ', first_name, last_name) LIKE ?", "%#{parameters[:term]}%"]) 
end 

CONCAT_WS() de MySQL está pensado para unir cadenas con algún tipo de separador y es ideal para nombres completos.

Este fragmento de código dice básicamente devolver los nombres de los contactos con el "primer nombre" que coinciden con lo que el usuario está buscando cuando emparejamos los registros de contacto de la base de datos por un par concatenario de nombres y apellidos. Siento que es mejor que la declaración SQL anterior, ya que hace una búsqueda completa que coincidirá con el primer Y/o apellido en una declaración, no en tres instrucciones OR.

El uso de este "hn sm" coincidiría con "John Smith" ya que de hecho "hm sm" es COMO "John Smith". Además, tiene el beneficio adicional de también que devuelve el nombre y apellido concatenados de cada contacto. Es posible que desee el registro completo. Si ese es el caso, elimine la consulta select() de la línea anterior. Personalmente, tuve la necesidad de que el usuario buscara un nombre y que un campo de autocompletar devuelva todas las coincidencias posibles, no los registros.

Sé que esto es un poco tarde, ¡pero espero que ayude a alguien más!

+0

¡Gracias! – tmaximini

+0

pero siguiendo este enfoque, la actualización del campo hidden: id ya no funciona :-(<% = f.hidden_field: project_id,: id => "real_project_id"%> <% = autocomplete_field_tag ​​'fake_project', '' , autocomplete_project_name_hours_path,: update_elements => {: id => '# real_project_id'}%> <% else %> – tmaximini

0

Una alternativa a las sugerencias anteriores es definir una vista SQL en la tabla que contenga first_name y last_name. Su código SQL (en SQLite) podría ser:

CREATE VIEW Contacts AS 
SELECT user.id, (user.first_name || ' ' || users.last_name) AS fullname 
FROM persons; 

a continuación, definir un modelo para la tabla:

class Contact < ActiveRecord::Base 
    set_table_name "contacts" 
end 

ahora se puede utilizar rails3-jquery-autocompletar 'fuera de la caja' . Así que en su controlador que iba a escribir:

autocomplete :contact, :fullname 

En su archivo de vista simplemente hay que escribir:

f.autocomplete_field :contact, autocomplete_contact_fullname_path 

dejaré de configuración de la ruta como un ejercicio para el lector :-).

2

Esto es un truco y me gustaría que esta función se incluyera en la gema, pero como sesgo dijo que sobrescribir los get_autocomplete_items funciona como lo escribió, pero solo devolverá first_name y last_name de la columna del modelo. Para restablecer la funcionalidad que le solicitó frank blizzard, también debe devolver la identificación de la fila.

items = Contact.select("DISTINCT CONCAT_WS(' ', first_name, last_name) AS full_name, first_name, last_name, id").where(["CONCAT_WS(' ', first_name, last_name) LIKE ?", "%#{parameters[:term]}%"]) 

La diferencia entre la respuesta de mine y slant es id como último argumento del método de selección. Sé que es tarde, pero espero que ayude a alguien en el futuro.

Si no necesita la funcionalidad de comparar su cadena de búsqueda con la cadena concatenada y está tratando de hacer una consulta en tres columnas separadas, puede usar esta bifurcación de la gema: git: //github.com/ slash4/rails3-jquery-autocomplete.git. Ah, también ese tenedor solo funcionará con ActiveRecord, que es probablemente la razón por la que no lo extrajeron.

+0

Útil, gracias. Alternativa de PostgreSQL: parece que Postgres 9.1 tiene 'CONCAT_WS' pero estoy en 8.4. Afortunadamente mis campos no están NULLable así que puedo salirme con 'Person.select (" first_name, last_name, id ") where ([" LOWER (first_name || '' || last_name) LIKE LOWER (?) ","% # {Parameters [: term]}% "])'. Note la adición de 'LOWER' para que no distinga entre mayúsculas y minúsculas. No necesito el valor concatenado en la cláusula' SELECT' porque al igual que la pregunta original, tengo 'def full_name' en mi modelo que hace concatenación una vez que el registro es fo und. Todo lo que necesito en mi controlador es 'autocompletar: persona, nombre_completo'. –

4

La plena aplicación de autocompletar de varios campos:


Después de mi comentario, mi solución de integrar en jquery-autocompletar era tener una implementación personalizada de la autocompletar "interno".

1. Consulta de la base de datos

Si está utilizando ActiveRecord, puede utilizar la solución de DGM para su named_scope

Si está utilizando Mongoid, puede utilizar esta sintaxis en su lugar:

scope :by_first_name, ->(regex){ 
    where(:first_name => /#{Regexp.escape(regex)}/i) 
} 
scope :by_last_name, ->(regex){ 
    where(:last_name => /#{Regexp.escape(regex)}/i) 
} 
scope :by_name, ->(regex){ 
    any_of([by_first_name(regex).selector, by_last_name(regex).selector]) 
} 

EDIT: si desea una autocompleta más potente que pueda manejar acentos, coincidencias de partes de texto, etc. deberías probar el índice de texto mongoide.Créditos a the original answer there

index(first_name: 'text', last_name: 'text') 

scope :by_name, ->(str) { 
    where(:$text => { :$search => str }) 
} 

Y no se olvide de construir los índices después de añadir que rake db:mongoid:create_indexes

lo que puede hacer básicamente User.by_name(something)

2. Crear una acción de autocompletar en su controlador

Porque el proporcionado por jquery-autocomplete ... no hará lo que queremos.

Tenga en cuenta que deberá convertir el resultado a JSON para que pueda ser utilizado en el frontend jquery-autocomplete. Para esto he optado por utilizar la gema ActiveModel :: Serializador, pero no dude en utilizar algo más si lo prefiere, y omita el paso 3

En su controlador:

def autocomplete 
    @users = User.by_name(params[:term]) 
    render json: @users, root: false, each_serializer: AutocompleteSerializer 
end 

3. Vuelva a formatear la respuesta

Su serializador usando la gema activemodel:

he proporcionado el enlace a la versión 0.9, ya que elLa página principal deno contiene la documentación completa.

class AutocompleteSerializer < ActiveModel::Serializer 
    attributes :id, :label, :value 

    def label 
    object.name 
    # Bonus : if you want a different name instead, you can define an 'autocomplete_name' method here or in your user model and use this implementation 
    # object.respond_to?('autocomplete_name') ? object.autocomplete_name : object.name 
    end 

    def value 
    object.name 
    end 

4. Crear una ruta para su terminación automática

En sus rutas:

get '/users/autocomplete', to: 'users#autocomplete', as: 'autocomplete_user' 

5. divertirse en sus puntos de vista

Por último, en sus puntos de vista puede usar la sintaxis predeterminada de jquery-rails, pero recuerde cambiar e el camino!

<%= form_tag '' do 
    autocomplete_field_tag 'Name', '', autocomplete_user_path, :id_element => "#{your_id}", class: "form-control" 
end %> 

RQ: He utilizado algunas profundas formas anidadas de 2 niveles, así que fue un poco difícil de conseguir el elemento derecha Identificación your_id. En mi caso, tuve que hacer algo complicado, pero lo más probable es que sea simple para ti. Siempre se puede echar un vistazo a la DOM generados para recuperar el campo ID

+0

Eso se ve bastante resbaladizo. :) – DGM

+0

Slick, @CyrilDD, pero como indiqué en mi pregunta, estoy usando ActiveRecord, no Mongoid, por lo que necesito la respuesta de DGM para el wicket adherente, la implementación del modelo. – JellicleCat

+0

Sí, mencioné esto en el primer paso "consultar la base de datos". Por lo demás, no importa si usa ActiveRecord o Mongoid. Acabo de escribir esto para los tipos como yo que se preguntaban por qué la sintaxis DGM no funcionaba en mongoid :) –

1

Para realizar una búsqueda sensible a las mayúsculas utilizando @ método de Cyril rails4-autocomplete, yo tenía una ligera modificación en el ámbito con nombre @DGM proporciona

scope :search_by_name, lambda { |q| 
    q.downcase! 
    (q ? where(["lower(first_name) LIKE ? or lower(last_name) LIKE ? or concat(lower(first_name), ' ', lower(last_name)) like ?", '%'+ q + '%', '%'+ q + '%','%'+ q + '%' ]) : {}) 
} 

Esto convierte la entrada del registro en minúsculas y también convierte la cadena de búsqueda en minúsculas como lo hace la comparación

Cuestiones relacionadas