首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >方法调用缓存导致的SearchLogic问题

方法调用缓存导致的SearchLogic问题
EN

Stack Overflow用户
提问于 2010-11-03 09:30:25
回答 1查看 116关注 0票数 1

我正在尝试使用搜索逻辑gem在几个表Post has_many assets上执行搜索。我需要它来执行左外部连接,而不是在不存在的资产事件中执行内部连接。

根据下面的内容,查询是使用所需的外部连接生成的,并且通过了前三个测试,但在最后一个测试中失败了。但是,如果我只运行最后一个测试,它就会通过。

失败的原因是@search_logic_filter变量仅在第一个测试中设置,并用于其余所有测试。

以这种方式设置@search_logic_filter的原因是,它是对method_missing的唯一调用,该调用携带传递给Post.title_or_body_or...like("fun")的动态搜索逻辑方法调用的参数

有没有更好的方法来设置过滤器参数?

代码语言:javascript
复制
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参数是“有趣的”,而不是“ruby”。对于upload_file_name列的所有测试,都存在'fun‘参数,但它只对最后一个测试有影响。

代码语言:javascript
复制
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)
)
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2010-11-03 12:12:45

您不应该以这种方式声明named_scope assets_upload_file_name_like。当它第一次被调用时,名为assets_upload_file_name_like的作用域被定义为根据当时@search_logic_filter的值生成的:conditions的值。您应该改为在lambda上设置该参数。

也不需要使用method_missing。只需在Post类中声明named_scope即可。另外,应该对查询进行过滤,以防止SQL注入攻击。

代码语言:javascript
复制
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
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4083546

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档