Ruby Sunspot:如何在搜索块之间重构公共代码?

时间:2012-10-09 16:25:50

标签: ruby metaprogramming sunspot

如何将Sunspot search do块中的公共代码重构为可以从多个位置调用的方法?我怀疑这可能更像是一个Ruby元编程问题,而不是一个特定于太阳黑子的问题,但是这里有。

我有一个使用太阳黑子的模型:

class Book
  def self.basic_search(params)    
    search do
      # boilerplate...
      facet :category
      paginate page: params[:p], per_page: APP_CONFIG[:results_per_page]

      # bespoke basic_search search code goes here
    end    
  end

  def self.curated_search(params)    
    search do
      # boilerplate...
      facet :category
      paginate page: params[:p], per_page: APP_CONFIG[:results_per_page]

      # bespoke curated_search code goes here
    end    
  end

end

然后我尝试像这样重构代码:

class Book
  def self.basic_search(params)    
    search do
      boilerplate params
      # bespoke basic_search search code goes here
    end    
  end

  def self.curated_search(params)    
    search do
      boilerplate params
      # bespoke curated_search code goes here
    end    
  end

  def self.boilerplate(params)
    facet :category
    paginate page: params[:p], per_page: APP_CONFIG[:results_per_page]
  end

end

由于样板方法被定义为Book上的类方法,因此不出所料导致:

undefined method 'boilerplate' for #<Sunspot::DSL::Search:0x007f92b4177a98

我怀疑需要使用instance_eval,但对Ruby不熟悉我不太清楚如何应用它。

2 个答案:

答案 0 :(得分:2)

这就是我想出来的。

def self.basic_search(params)    
  search do
    boilerplate(self, params)  # here, self is a sunspot search instance

    # bespoke basic_search search code goes here
  end    
end

def self.curated_search(params)    
  search do
    boilerplate(self, params)  # here, self is a sunspot search instance

    # bespoke curated_search code goes here
  end    
end

def self.boilerplate(sunspot, params)
  sunspot.instance_eval do 
    facet :category
    paginate page: params[:p], per_page: APP_CONFIG[:results_per_page]
  end
end

答案 1 :(得分:0)

要解决具体问题,请尝试使用范围来调用Book.boilerplate。如错误消息所示,search do...end块内的内容在Sunspot::DSL::Search内评估,而不是在Book内评估。

请参阅以下示例。简化了Foo - >的可读性BookBar - &gt; Search

原创方式w / duplication

class Foo
  def self.bar()
    p 1
  end

  def self.baz()
    p 1
  end
end

去重复。请注意,在太阳黑子示例中,最常用的方法定义挂钩或类似的东西用于定义Book上的方法,而不是使用硬编码的传递。关键是Bar可以调用quux中的Foo

class Foo
  # Following two methods inserted via DSL magic. #Simplified for readability.
  def self.bar
    Bar.bar
  end

  def self.baz
    Bar.baz
  end

  def self.quux()
    p 1
  end
end

class Bar
  def self.bar
    Foo.quux
  end

  def self.baz
    Foo.quux
  end
end

然而,在您的特定情况下,这仍然可能没有做您想要的,因为被评估的参数可能应该在Search而不是Book进行评估。根据{{​​1}}进行param缓存的方式,你应该考虑尝试这样的事情。

search