-->

洗劫:如何利用现有的范围是什么?(Ransack: How to use existing scop

2019-08-01 14:07发布

转换一个Rails 2应用到Rails 3,我不得不更换宝石searchlogic 。 现在,使用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 。 可悲的是,我不觉得这方面有任何文档。 我在想这Post类:

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

但是,这并不工作:

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

我尝试了一些变化中ransacker声明,但他们没有工作。 我需要一些帮助...

UPDATE:上面的范围仅仅是例子上。 我正在寻找一种方式来使用内搜查每一个现有的范围。 在元搜索,搜查的前身,有一个功能叫做search_methods使用范围。 洗劫了这个不支持开箱即用的呢。

Answer 1:

合并洗劫后支持它开箱https://github.com/activerecord-hackery/ransack/pull/390 。 你应该声明ransakable_scopes方法添加可视范围进行搜查。

从手动

从前面的部分继续,通过示波器搜索需要对模型类定义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 })


Answer 2:

洗劫让您创建此自定义谓词,不幸的是,文件余地但是改进结帐: https://github.com/ernie/ransack/wiki/Custom-Predicates

此外,我相信你正在试图解决的问题是在他们的问题跟踪器。 有一个很好的讨论,对那里: https://github.com/ernie/ransack/issues/34



Answer 3:

我写了一个名为宝石虹吸它可以帮助你转换参数代入activerelation范围。 与洗劫结合可以实现这一点。

你可以在这里阅读完整的解释 。 同时这里是它的要点

风景

= 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]具有搜查善。 我们需要找到一种方式,现在,该数据分发到窗体对象。 因此,首先让产品搜索它吞没控制器:

该控制器

# 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


文章来源: Ransack: How to use existing scope?