我正在使用辉煌的gem flag_shih_tzu在单个整数列上创建按位布尔标志,而不需要为每个标志创建单独的DB列。我已经很喜欢这个宝石很多年了,而且它非常适合以你通常所期望的方式与ActiveRecord属性进行交互。
然而,它与Ransack和Active Admin开箱即用效果不佳。 Active Admin要求我为每个标志添加允许的参数:
permit_params do
:identity_verified
end
用于:identity_verified“flag”属性甚至可以显示在过滤器或索引列中,这很好;我不介意。但我遇到的真正问题是当我尝试使用:identity_verified标志作为过滤器时(当然是布尔值),Active Admin使用Any / Yes / No显示正常的选择选项,但是当我第一次提交时过滤查询,我得到一个例外:undefined method identity_verified_eq for Ransack::Search
。
好的,所以我做了一些研究,发现我需要为:identity_verified添加ransacker
。那样做了,我不再得到例外,但是搜索者似乎根本没有做任何事情。事实上,我故意在块中输入语法错误以引发异常,但Active Admin只返回所有用户,无论他们是否:identity_verified。 ransacker
块中的代码似乎甚至无法执行。任何人都可以帮我弄清楚如何为:identity_verified?
以下是代码:
用户模型:
# ===============
# = FlagShihTzu =
# ===============
has_flags 1 => :guest,
2 => :prospect,
3 => :phone_verified,
4 => :identity_verified,
# ==============
# = Ransackers =
# ==============
# this avoids the identity_verified_eq missing method exception, but
# doesn't appear to do anything else
ransacker :identity_verified, args: [:ransacker_args] do |args|
asdf # <-- should cause an exception
Arel.sql(identity_verified_condition)
end
Active Admin:
ActiveAdmin.register User do
permit_params do
:identity_verified
end
# ...
filter :identity_verified, as: :boolean
# ...
end
Identity Verified过滤器在Active Admin中显示为布尔选择,就像我期望的那样,但是当我提交过滤器时(如上所述),我将所有用户都恢复,并且ransacker块甚至没有似乎被执行了。我看过Ransack examples。我已经挖掘了所有四个宝石的代码(包括Formtastic),我仍然无法解决它。
以下是Active Admin对查询提交的POST URL:
http://example.com/admin/users?q%5Bidentity_verified%5D=true&commit=Filter&order=id_desc
这是Rails日志,用于确认:identity_verified param正在传递:
Processing by Admin::UsersController#index as HTML
Parameters: {"utf8"=>"✓", "q"=>{"identity_verified"=>"true"}, "commit"=>"Filter", "order"=>"id_desc"}
同样,ransacker块的内部似乎没有被执行。我需要理解为什么,如果有的话,如何编写正确的Arel语句,以便我可以过滤此标志。
帮助?
答案 0 :(得分:1)
恢复这个问题,因为这是G *的第一个结果,在这里搜索&#34;标志shih tzu activeadmin&#34;。此外,OP的解决方案似乎并不理想,因为它的负载和为这部分中满足标志条件的所有记录实例化AR对象:
results = object_class.send("#{flag}")
results = results.map(&:id)
所以,这是我目前为他人提供的解决方案:
# config/initializers/ransack.rb
Ransack.configure do |config|
config.add_predicate 'flag_equals',
arel_predicate: 'eq',
formatter: proc { |v| (v.downcase == 'true') ? 1 : 0 },
validator: proc { |v| v.present? },
type: :string
end
# app/concerns/has_flags.rb
module HasFlags
extend ActiveSupport::Concern
included { include FlagShihTzu }
class_methods do
def flag_ransacker(flag_name, flag_col: 'flags')
ransacker(flag_name) do |parent|
Arel::Nodes::InfixOperation.new('DIV',
Arel::Nodes::InfixOperation.new('&', parent.table[flag_col], flag_mapping[flag_col][flag_name]),
flag_mapping[flag_col][flag_name])
end
end
end
end
# app/models/foo.rb
class Foo < ActiveRecord::Base
include HasFlags
has_flags 1 => :bar, 2 => :baz
flag_ransacker :bar
end
# app/admin/foos.rb
ActiveAdmin.register Foo do
filter :bar_flag_equals, as: :boolean, label: 'Bar'
end
答案 1 :(得分:0)
所以,在幸运地找到这篇文章ActiveAdmin Filters with Ransack之后,我终于想出了答案。它的要点是使用DSL正确定义Active Admin过滤器,更重要的是,模型中适当的ransacker用于要过滤的FlagShihTzu标志。
这是一个有效的例子:
模型/ user.rb:
class User
include FlagShihTzu
# define the flag
has_flags 1 => :identity_verified
# convenience method to define the necessary ransacker for a flag
def self.flag_ransacker(flag)
ransacker flag.to_sym,
formatter: proc { |true_false|
if true_false == "true"
results = object_class.send("#{flag}")
else
results = object_class.send("not_#{flag}")
end
results = results.map(&:id)
results = results.present? ? results : nil
}, splat_params: true do |parent|
parent.table[:id]
end
end
管理员/ user.rb:
ActiveAdmin.register User do
# A method used like a standard ActiveAdmin::Resource `filter` DSL call, but for FlagShizTzu flags
# A corresponding `flag_ransacker` call must be made on the model, which must include
# the FlagShizTzuRansack module defined in app/concerns/models/flag_shih_tzu_ransack.rb
def flag_filter(flag)
@resource.flag_ransacker flag.to_sym # call the ransacker builder on the model
flag = flag.to_s
filter_name = "#{flag}_in" # we use the 'in' predicate to allow multiple results
filter filter_name.to_sym,
:as => :select,
:label => flag.gsub(/[\s_]+/, ' ').titleize,
:collection => %w[true false]
end
flag_filter :identity_verified
end
瞧,这是一个用于旗帜标志的边栏过滤器。关键是在过滤器声明中的标志名称末尾添加in
谓词,而不是排除它,默认为eq
Ransack谓词。使用pry和调试器来定义ransacker本身需要反复试验,但主要基于上述帖子。
最终,我最终将两个文件中的内联方法拉出到我包含在必要模型中的模块和需要它们的AA资源定义中。
应用程序/关切/模型/ flag_shih_tzu_ransack.rb:
# Used to define Ransackers for ActiveAdmin FlagShizTzu filters
# See app/admin/support/flag_shih_tzu.rb
module FlagShihTzuRansack
extend ActiveSupport::Concern
module ClassMethods
# +flags are one or more FlagShihTzu flags that need to have ransackers defined for
# ActiveAdmin filtering
def flag_ransacker(*flags)
object_class = self
flags.each do |flag|
flag = flag.to_s
ransacker flag.to_sym,
formatter: proc { |true_false|
if true_false == "true"
results = object_class.send("#{flag}")
else
results = object_class.send("not_#{flag}")
end
results = results.map(&:id)
results = results.present? ? results : nil
}, splat_params: true do |parent|
parent.table[:id]
end
end
end
end
end
应用程序/管理/支持/ flag_shih_tzu.rb:
# Convenience extension to filter on FlagShizTzu flags in the AA side_bar
module Kandidly
module ActiveAdmin
module DSL
# used like a standard ActiveAdmin::Resource `filter` DSL call, but for FlagShizTzu flags
# A corresponding `flag_ransacker` call must be made on the model, which must include
# the FlagShizTzuRansack module defined in app/concerns/models/flag_shih_tzu_ransack.rb
def flag_filter(flag)
@resource.flag_ransacker flag.to_sym # call the ransacker builder on the model
flag = flag.to_s
filter_name = "#{flag}_in" # we use the 'in' predicate to allow multiple results
filter filter_name.to_sym,
:as => :select,
:label => flag.gsub(/[\s_]+/, ' ').titleize,
:collection => %w[true false]
end
end
end
end
ActiveAdmin::ResourceDSL.send :include, Kandidly::ActiveAdmin::DSL
然后更清洁,在模型中:
class User
include FlagShihTzu
include FlagShihTzuRansack
# define the flag
has_flags 1 => :identity_verified
端
并在资源定义中:
ActiveAdmin.register User do
flag_filter :identity_verified
end
可能有更优雅的方法实现,但有一个有效的解决方案,我正在继续。希望这能帮助那些投票赞成这个问题的人。 Ransack文档有点不尽如人意。感谢Russ在Jaguar Design Studio上的帖子,以及https://github.com/activerecord-hackery/ransack/issues/36上的评论者,他们帮助我更好地理解了Ransack的工作原理。最后,我不得不深入挖掘宝石以获得我的最终解决方案,但如果没有他们的贡献,我就不知道从哪里开始。