40 votes

ActiveRecord trouver commence par

Question très simple - comment puis-je faire une recherche pour trouver tous les enregistrements où le nom commence avec une certaine chaîne dans ActiveRecord. J'ai vu toutes sortes de bits partout sur Internet où les clauses verbatim LIKE SQL sont utilisés - mais d'après ce que j'ai entendu ce n'est pas la «correcte» façon de le faire.

Existe-t-il une « bonne » façon de rails?

97voto

Gareth Points 42402

Si vous cherchez à faire la recherche dans la base de données, alors vous aurez besoin d'utiliser SQL.

Et, bien sûr, vous aurez besoin de faire la recherche dans la base de données sinon vous avez besoin de charger tous les objets dans Ruby (ce qui n'est pas une bonne chose).

Donc, vous aurez besoin de quelque chose comme

où `` est une variable avec la chaîne que vous recherchez.

Dans rails 3.0, cela devient :

10voto

Owen Points 5680

Je vous recommande fortement de le Searchlogic plugin.

Ensuite, c'est aussi simple que:

@search = Model.new_search(params[:search])
@search.condition.field_starts_with = "prefix"
@models = @search.all

Searchlogic est assez intelligent, comme ActiveRecord, pour reprendre le nom du champ dans l' starts_with condition. Il prendra également en charge tous pagination.

Cette méthode aidera à prévenir l'injection SQL et aussi seront la base de données agnostique. Searchlogic finit par la manipulation de la recherche différemment en fonction de l'adaptateur de base de données que vous utilisez. Vous aussi vous n'avez pas à écrire du SQL!

Searchlogic a beaucoup de documentation et est facile à utiliser (je suis nouveau sur Ruby et Rails de moi-même). Quand je suis coincé, l'auteur du plugin, même répondu à un e-mail directement à l'intérieur de quelques heures de m'aider à résoudre mon problème. Je ne peux pas le recommander Searchlogic assez...comme vous pouvez le dire.

8voto

Larry Points 419

Avertissement: je suis nouveau à Ruby et Rails, et je suis encore en train d'apprendre le Ruby Façon de faire les choses, mais j'ai été codant pour plus de la moitié de ma vie, et professionnellement depuis une décennie. DRY est un concept avec lequel je suis très familier. Voici comment j'ai mis en œuvre. Il est très similaire à narsk réponse, je pense que c'est aussi bon.

# name_searchable.rb
# mix this into your class using
#   extend NameSearchable
module NameSearchable
  def search_by_prefix (prefix)
    self.where("lower(name) LIKE '#{prefix.downcase}%'")
  end
end

Et puis dans votre modèle:

class User < ActiveRecord::Base
  extend NameSearchable
  ...
end

Et puis, quand vous voulez l'utiliser:

User.search_by_prefix('John')   #or
User.search_by_prefix("#{name_str}")

Une seule chose à faire appel:

Traditionnels de bases de données relationnelles ne sont pas très bonnes à satisfaire à ces types de requêtes. Si vous êtes à la recherche pour une très sensible de la mise en œuvre qui ne sera pas tuer vos bases de données en vertu de la charge, vous devriez probablement utiliser une solution qui est adapté à la place. Des exemples comprennent Solr ou Sphinx, et il y a beaucoup d'autres. Avec cette mise en œuvre, depuis que vous SÉCHEZ, vous pouvez remplacer la mise en œuvre avec un indexeur en un seul endroit et vous être prêt pour le rock.

4voto

narsk Points 461

Très bien comme la réponse ci-dessus, mais si vous utilisez ActiveRecord ... 2.1 ou plus, vous pouvez utiliser une portée nommée qui vous permettrait d'utiliser ce "finder" sur les dossiers récupérés à travers les associations:

Utilisé comme:

(retourne tous les utilisateurs de votre base de données avec un nom comme "Samson".

Ou:

Utilisateurs hors de cette association seulement avec un nom comme "Samson".

2voto

Dave Sag Points 2652

Maintenant, en 2012 j'ai pensé que je jetterais dans cette mise à jour pour narsk de réponse.

named_scope est devenue tout simplement scope il y a un moment donc, l'exemple devient

class User
  scope :name_starts_with, lambda {|str|
    :conditions => ['lower(name) like ?', "#{str.downcase}%"]
  }
end

Remarque j'ai enlevé la première % de narsk de la solution que l'OP est de demander un 'starts_with' pas un 'contient' match.

Maintenant, vous pouvez faire des choses comme

User.name_starts_with("b").each do {|bs| puts bs.inspect}
bob = User.name_starts_with("bob").first

… etc

Notez que des étendues toujours le retour des collections, jamais les résultats individuels. Qui m'a jeté quand j'ai d'abord commencer avec AR et j'ai encore réussi à oublier que chaque maintenant et encore.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X