Active Admin:如何在嵌套模型的 json 列上添加可排序

Active Admin: how to add sortable on nested model's json column

如何将 jsonb 订单查询传递到 Active Admin 列的 sortable: 选项?

我的模型结构如下:

# User Model
class User < ActiveRecord::Base
  has_one :level
end

# Level Model
class Level < ActiveRecord::Base
  belongs_to :user     
end

# Level Migration
create_table "levels", force: :cascade do |t|
  t.integer  "user_id"
  t.jsonb    "ranked_scores"
end

:ranked_scorejson结构是:

# level.ranked_scores
{"stage_1"=>111, "stage_2"=>222, "stage_3"=>333} 

我尝试使用 Level:ranked_scores 属性对 User 进行排序,如下所示:

# app/admin/user.rb

ActiveAdmin.register User do
  controller do
    def scoped_collection
      end_of_association_chain.includes(:level)
    end
  end

  index do
    column "Stage 1 Score", sortable: "level.ranked_scores -> 'stage_1'" do |user|
      user.level.ranked_scores['stage_1']
    end
  end
end

ActiveAdmin.register Level do
  belongs_to :user
end

生成的用于对列进行排序的 url 是

http://localhost:3000/admin?order=levels.ranked_scores%5B%27stage_1%27%5D_desc

但是 stage_1 的列未按降序排序。

对这里出了什么问题有什么想法吗?

您应该在 admin/user.rb 配置中做 2 处小改动,这将使其可用。

#1 -> 周围有空格,应将其删除以使 ActiveAdmin 满意。

这里的问题是由 ActiveAdmin 的 sort validation regexp 引起的,它与您的 sortable 选项不匹配。删除 -> 周围的空格可以被视为 ActiveAdmin 错误的解决方法。

#2 Level 的 table 应该引用为 levels,而不是 level.

最后我们有:

column "Stage 1 Score", sortable: "levels.ranked_scores->'stage_1'"

你得到了你想要的。

关于 ->> 运算符的注意事项

还有另一个 Postgres 运算符 ->>,它与 -> 非常相似。 See here.

两者的区别在于,->>总是return的文本值(字符串化json),而->可以returnjson 对象。在您的示例中,它们的用法完全相同,因为排名分数是数字。

但在一般情况下,您可能还需要 ->> 运算符。不幸的是,ActiveAdmin 仍然没有解决问题 #3173 和 #3085,。因此,您不能在当前版本的 ActiveAdmin 中使用 ->> 运算符。

不幸的是,我想不出任何解决方法,就像我们对 -> 运算符所做的那样。

您还可以使用 hack 来启用此运算符。需要在ActiveAdmin的源代码中添加2个字符。

您需要将此 line of code 更改为以下内容:

clause =~ /^([\w\_\.]+)(->>?'\w+')?_(desc|asc)$/

我们在两者之间添加了 >?。 2 个字符,如所承诺的那样。

对于 jsonb 列,您需要使用 ->> 而不是 ->,但这会导致 ActiveAdmin 验证出现问题(请参阅未解决的问题:https://github.com/activeadmin/activeadmin/issues/3173 and https://github.com/activeadmin/activeadmin/issues/3085) .

我不确定他们是否修复了它,你可以试试

index do
  column "Stage 1 Score", sortable: "levels.ranked_scores ->> 'stage_1'" do |user|
    user.level.ranked_scores['stage_1']
  end
end

我最近一直在为同样的老问题苦苦挣扎。此外,我想将 JSON 值排序为整数。

这是我的解决方案。它无需猴子修补 ActiveAdmin 错误即可工作,并提供比以前的答案更大的灵活性。

order_by(:json_field) do |order_clause|
  "(json_column->>'json_field')::int #{order_clause.order} NULLS LAST"
end

index do
  column :json_field, sortable: 'json_field'
end

参考 ActiveAdmin 自定义排序文档:https://activeadmin.info/3-index-pages/index-as-table.html