簡體   English   中英

由於方法調用的緩存而導致的SearchLogic問題

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM