J'essaie d'utiliser la gemme searchlogic pour effectuer des recherches sur plusieurs tables Post has_many assets
. J'en ai besoin pour effectuer des jointures externes à gauche plutôt que des jointures internes dans le cas d'un actif inexistant. De ce que j'ai ci-dessous la requête est générée avec les jointures externes requises, et passe les trois premiers tests, mais échoue sur le dernier. Cependant, si je ne fais que le dernier test, il passe ensuite.Problèmes de SearchLogic dus à la mise en cache des appels de méthode
La raison de l'échec est que la var @search_logic_filter
est uniquement définie lors du premier test et est utilisée pour tous les tests restants.
La raison pour le réglage de la @search_logic_filter
de cette manière est qu'il est le seul appel à method_missing qui porte le param transmis à l'appel de méthode searchlogic dynamique de Post.title_or_body_or...like("fun")
est-il une meilleure façon de régler le filtre param?
test "find posts and assets by filter for user" do
customer = users(:customer)
create_post_for_user(customer, {:body => "Rails is fun", :tags => "rails ruby"})
create_post_for_user(customer, {:body => "Fun is what Emacs is all about", :title => "emacs"})
# File with post
asset_post = create_post_for_user(customer, {:body => "Ruby is pretty fun too",
:tags => "ruby"})
asset_post.assets << Asset.new(:upload_file_name => "ruby_tips",
:upload_file_size => 100,
:upload_content_type => "text")
asset_post.save
# search post
assert_equal 3, Post.find_for_user(customer.id, "fun").size
assert_equal 2, Post.find_for_user(customer.id, "ruby").size
assert_equal 1, Post.find_for_user(customer.id, "emacs").size
# search asset
puts "about to run last test"
assert_equal 1, Post.find_for_user(customer.id, "ruby_tips").size
end
class Post < ActiveRecord::Base
def self.find_for_user(user_id, filter, page=1)
Post.
user_id_equals(user_id).
title_or_body_or_tags_or_assets_upload_file_name_like(filter).all
end
class << self
def method_missing(name, *args, &block)
if name.to_s =~ /\w+_or_\w+_like$/
# ** only gets here once **
@search_logic_filter = args.first
super
elsif name == :assets_upload_file_name_like
# args is [] here which is the reason for the above setting of @search_logic_filter
named_scope :assets_upload_file_name_like, lambda {
{:joins => "left outer join assets on posts.id = assets.post_id",
:conditions => "assets.upload_file_name like '%#{@search_logic_filter}%'"}
}
assets_upload_file_name_like
else
super
end
end
end
end
** Mise à jour C'est la requête qui est exécutée pour le test final. Notez que le paramètre upload_file_name est 'fun', pas 'ruby_tips'. Le paramètre 'fun' existe pour tous les tests de la colonne upload_file_name, mais cela n'a d'importance que pour le dernier test.
SELECT `posts`.*
FROM `posts`
left outer join assets
on posts.id = assets.post_id
WHERE (
((posts.title LIKE '%ruby_tips%') OR (posts.body LIKE '%ruby_tips%') OR (posts.tags LIKE '%ruby_tips%') OR (assets.upload_file_name like '%fun%'))
AND (posts.user_id = 20549131)
)
Merci pour l'aide :) – chris