将Rails 2应用程序转换为Rails 3,我必须替换gem searchlogic。现在,使用Rails 3.2.8和gem Ransack我想构建一个使用现有范围的搜索表单。例如:
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
声明的一些变体,但它们都不起作用。我需要一些帮助...
更新:以上范围仅为示例。我正在寻找一种方法来使用Ransack中的每个现有范围。在Ransack的前身MetaSearch中,有一个名为search_methods
的功能用于使用范围。 Ransack尚未开箱即用no support for this。
答案 0 :(得分:6)
ransack支持它开箱即用。你应该声明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 })
答案 1 :(得分:1)
Ransack让你为此创建自定义谓词,不幸的是文档留下了改进空间,但结帐:https://github.com/ernie/ransack/wiki/Custom-Predicates
此外,我相信您正在尝试解决的问题是他们的问题跟踪器。那里有一个很好的讨论:https://github.com/ernie/ransack/issues/34
答案 2 :(得分:0)
我写了一个名为siphon的gem,它可以帮助您将参数转换为activerelation范围。将它与搜索结合起来可以实现这一目标。
你可以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