How to override lib/spree/search/base.rb

2019-05-08 00:48发布

问题:

I need to override the get_products_conditions_for method in this class, what's the best way of doing this?

I've tried adding this to an initializer:

Spree::Search::Base.class_eval do
    def get_products_conditions_for(base_scope, query)
      base_scope.like_any([:name, :description], query.split) | base_scope.joins("JOIN taggings on taggings.taggable_id = spree_products.id JOIN tags on tags.id = taggings.tag_id").where("tags.name = ?", query.split)
    end
end

which results in this error when starting the server: uninitialized constant Spree::Search (NameError)

I've also tried adding this to "/lib/spree/search/base.rb" and "/lib/spree/search/tags_search.rb"

module Spree::Search
  class TagsSearch < Spree::Search::Base

    def get_products_conditions_for(base_scope, query)
      base_scope.like_any([:name, :description], query.split) | base_scope.joins("JOIN taggings on taggings.taggable_id = spree_products.id JOIN tags on tags.id = taggings.tag_id").where("tags.name = ?", query.split)
    end

  end
end

and then Spree::Config.searcher = TagsSearch in application.rb...

I've even tried completely replacing the file by placing a replica in the same directory structure within the app, either nothing happens, or I get the mentioned errors...

What I'm trying to do is integrate acts_as_taggable_on which is done and working, however the search obviously does not return results from these tags...

EDIT: Ok so after Steph's answer I've tried:

module Spree::Search
  class TagsSearch < Spree::Search::Base

    def get_products_conditions_for(base_scope, query)
      base_scope.like_any([:name, :description], query.split) | base_scope.joins("JOIN taggings on taggings.taggable_id = spree_products.id JOIN tags on tags.id = taggings.tag_id").where("tags.name = ?", query.split)
    end

  end
end

in app/models/search/tags_search.rb and Steph's code suggestion in lib/spree/search/tags_search.rb

and this:

config.to_prepare do
    Spree::Core::Search::Base.send(:include, TagsSearch)
  end

in config/environments/development.rb

which results in the following when starting the server:

uninitialized constant TagsSearch (NameError)

回答1:

I need to override the get_products_conditions_for method in this class, what's the best way of doing this?

In this particular case, I inherited the class and overrode the required method.

As in Spree 3,

  1. In config/initializers/spree.rb, Spree.config block config.searcher_class= Spree::MySearch
  2. Create a file lib/spree/my_search.rb with the following content:

    module Spree
      class MySearch < Spree::Core::Search::Base
        def method_to_be_overridden
          # Your new definition here
        end
      end
    end
    

    Note: The above is the prescribed way to alter searcher class in Spree



回答2:

I'd recommend using ActiveSupport::Concern, which might look something like this:

module YourAwesomeModule
  extend ActiveSupport::Concern

  included do
    alias :spree_get_products_conditions_for :get_products_conditions_for
    def get_products_conditions_for(base_scope, query)
      custom_get_products_conditions_for(base_scope, query)
    end
  end

  module InstanceMethods
    def custom_get_products_conditions_for(base_scope, query)
      #your stuff
    end 
  end
end

Spree::Core::Search::Base.send(:include, YourAwesomeModule)

This is doing a couple of things:

  • Using ActiveSupport::Concern is a nice/clean way to extend class and instance methods for a give class.
  • Alias preserves the Spree method. You don't have to do this bit if you don't want to.

While in development, because default config settings result in non-caching classes but not reloading lib/ modules, you might need to add this inside config/environments/development.rb:

config.to_prepare do
  Spree::Core::Search::Base.send(:include, YourAwesomeModule)
end