Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

How do I pass in a jsonb order query into the sortable: option for an Active Admin column?

My model is structured like this:

# 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

The :ranked_score json structure is:

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

I have tried to sort the User using a Level's :ranked_scores attribute as follows:

# 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

The url generated to sort the colums is

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

but the columns are not sorted in descending order for stage_1.

Any ideas for what is going wrong here?

like image 631
Puffo Avatar asked Aug 15 '15 15:08

Puffo


1 Answers

You should make 2 minor changes in admin/user.rb configuration which will make it workable.

#1 You have spaces around ->, which should be removed to make ActiveAdmin happy.

The problem here is caused by ActiveAdmin's sort validation regexp, which doesn't match your sortable option. Removing white spaces around -> can be considered as a workaround for ActiveAdmin's bug.

#2 Level's table should be referenced as levels, not level.

So finally we have:

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

And you get what you intended to have.

Note about the ->> operator

There is another Postgres operator, ->>, which is very similar to the ->. See here.

The difference between the two is, that ->> always returns text value (stringified json), while -> can return json object. In your example their use is absolutely identical, because ranked scores are numbers.

But in general case, you might need ->> operator as well. Unfortunately ActiveAdmin still haven't fixed issues #3173 and #3085, which @bigsolom mentions in his reply. So you can't use ->> operator with current version of ActiveAdmin.

Unfortunately I can't think about any workaround, like we did with -> operator.

Still there is a hack you can use to enable this operator as well. It requires adding 2 characters into the source code of ActiveAdmin.

You need to change this line of code to the following one:

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

we added >? in-between. 2 chars, as promised.

like image 96
dimakura Avatar answered Oct 15 '22 04:10

dimakura