【问题标题】:Ransack: How to use existing scope?Ransack:如何使用现有范围?
【发布时间】:2012-10-08 15:09:34
【问题描述】:

将 Rails 2 应用程序转换为 Rails 3,我必须替换 gem searchlogic。现在,使用带有 gem Ransack 的 Rails 3.2.8 我想构建一个使用现有范围的搜索表单。示例:

class Post < ActiveRecord::Base
  scope :year, lambda { |year| 
    where("posts.date BETWEEN '#{year}-01-01' AND '#{year}-12-31'") 
  }
end  

据我所知,这可以通过定义自定义ransacker 来实现。可悲的是,我没有找到任何关于此的文档。我在Postclass 中试过这个:

ransacker :year, 
          :formatter => proc {|v| 
            year(v)
          }

但这不起作用:

Post.ransack(:year_eq => 2012).result.to_sql
=> TypeError: Cannot visit ActiveRecord::Relation

我尝试了ransacker 声明的一些变体,但它们都不起作用。我需要一些帮助...

更新: 上述范围仅作为示例。我正在寻找一种方法来使用 Ransack 中的每个现有范围。在 Ransack 的前身 MetaSearch 中,有一个名为 search_methods 的功能用于使用范围。 Ransack 有开箱即用的no support for this

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3 arel ransack


    【解决方案1】:

    ransack 在合并 https://github.com/activerecord-hackery/ransack/pull/390 后支持开箱即用。您应该声明 ransakable_scopes 方法以添加对 ransack 可见的范围。

    来自手册

    继续上一节,按范围搜索需要在模型类上定义一个 ransackable_scopes 的白名单。白名单应该是一个符号数组。默认情况下,所有类方法(例如作用域)都被忽略。范围将应用于匹配真值,或者如果范围接受值,则应用于给定值:

    class Employee < ActiveRecord::Base
      scope :activated, ->(boolean = true) { where(active: boolean) }
      scope :salary_gt, ->(amount) { where('salary > ?', amount) }
    
      # Scopes are just syntactical sugar for class methods, which may also be used:
    
      def self.hired_since(date)
        where('start_date >= ?', date)
      end
    
      private
    
      def self.ransackable_scopes(auth_object = nil)
        if auth_object.try(:admin?)
          # allow admin users access to all three methods
          %i(activated hired_since salary_gt)
        else
          # allow other users to search on `activated` and `hired_since` only
          %i(activated hired_since)
        end
      end
    end
    
    Employee.ransack({ activated: true, hired_since: '2013-01-01' })
    
    Employee.ransack({ salary_gt: 100_000 }, { auth_object: current_user })
    

    【讨论】:

      【解决方案2】:

      Ransack 让您为此创建自定义谓词,不幸的是,文档留下了改进空间,但结帐:https://github.com/ernie/ransack/wiki/Custom-Predicates

      另外,我相信您要解决的问题在他们的问题跟踪器上。那里正在进行很好的讨论:https://github.com/ernie/ransack/issues/34

      【讨论】:

      • 谢谢,但我正在寻找更通用的解决方案来使用 Ransack 中的范围。这在 Searchlogic (RIP) 和 MetaSearch 中也是可能的。
      【解决方案3】:

      我编写了一个名为 siphon 的 gem,它可以帮助您将参数转换为 activerelation 范围。结合ransack就可以做到这一点。

      您可以read full explanation here。同时这里是它的要点

      视图

      = form_for @product_search, url: "/admin/products", method: 'GET' do |f|
        = f.label "has_orders"
        = f.select :has_orders, [true, false], include_blank: true
        -#
        -# And the ransack part is right here... 
        -#
        = f.fields_for @product_search.q, as: :q do |ransack|
          = ransack.select :category_id_eq, Category.grouped_options
      ```
      

      好的,现在params[:product_search] 拥有范围,params[:product_search][:q] 拥有搜查的好处。现在,我们需要找到一种方法将这些数据分发给表单对象。所以首先让 ProductSearch 在控制器中吞下它:

      控制器

      # products_controller.rb
      def index
        @product_search = ProductSearch.new(params[:product_search])
        @products ||= @product_formobject.result.page(params[:page])
      end
      

      表单对象

      # product_search.rb
      class ProductSearch
        include Virtus.model
        include ActiveModel::Model
      
        # These are Product.scopes for the siphon part
        attribute :has_orders,    Boolean
        attribute :sort_by,       String
      
        # The q attribute is holding the ransack object
        attr_accessor :q
      
        def initialize(params = {})
          @params = params || {}
          super
          @q = Product.search( @params.fetch("q") { Hash.new } )
        end
      
        # siphon takes self since its the formobject
        def siphoned
          Siphon::Base.new(Product.scoped).scope( self )
        end
      
        # and here we merge everything
        def result
          Product.scoped.merge(q.result).merge(siphoned)
        end
      end
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-02-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多