[英]SearchLogic problems due to caching of method calls
我正在尝试使用searchlogic gem在几个表上执行搜索Post has_many assets
。 如果资产不存在,我需要它执行左外部联接,而不是内部联接。
从我下面的内容中,查询是使用所需的外部联接生成的,并通过了前三个测试,但在最后一个测试中失败。 但是,如果我只运行最后一个测试,则它会通过。
失败的原因是@search_logic_filter
var仅在第一个测试上设置,并且用于所有其余测试。
以这种方式设置@search_logic_filter
的原因是,它是对method_missing的唯一调用,该调用带有传递给Post.title_or_body_or...like("fun")
的动态searchlogic方法调用的Post.title_or_body_or...like("fun")
有没有更好的方法来设置过滤器参数?
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
** update这是为最终测试运行的查询。 请注意,upload_file_name参数是“ fun”,而不是“ ruby_tips”。 “ fun”参数存在于upload_file_name col的所有测试中,但仅对最后一个测试重要。
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)
)
您不应named_scope assets_upload_file_name_like
这种方式声明named_scope assets_upload_file_name_like
。 当它被称为第一次, assets_upload_file_name_like
命名范围被定义与用于值:conditions
根据的值产生@search_logic_filter
在那个时候。 您应该改为在lambda
上设置参数。
也不需要使用method_missing
。 只需在Post
类中声明named_scope
。 另外,应过滤查询以防止SQL注入攻击。
class Post < ActiveRecord::Base
named_scope :assets_upload_file_name_like, lambda { |file_name| {
:joins => "left outer join assets on posts.id = assets.post_id",
# Prevent SQL injection.
:conditions => ["assets.upload_file_name like ?", "%#{file_name}%"]
}}
end
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.