ผู้ดูแลระบบที่ใช้งานอยู่: วิธีเพิ่มการจัดเรียงในคอลัมน์ json ของโมเดลที่ซ้อนกัน

ฉันจะส่งแบบสอบถามลำดับ jsonb ไปยังตัวเลือก sortable: สำหรับคอลัมน์ Active Admin ได้อย่างไร

โมเดลของฉันมีโครงสร้างดังนี้:

# 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_score json คือ:

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

ฉันได้ลองเรียงลำดับ User โดยใช้แอตทริบิวต์ :ranked_scores ของ Level ดังนี้:

# 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

มีความคิดเห็นเกี่ยวกับสิ่งที่เกิดขึ้นที่นี่หรือไม่?


person Puffo    schedule 15.08.2015    source แหล่งที่มา
comment
แบบสอบถามฐานข้อมูลใดที่จะดำเนินการ?   -  person Timo Schilling    schedule 15.08.2015
comment
โดยพื้นฐานแล้วฉันต้องเข้าถึง user.level.ranked_scores['stage_1'] ตามลำดับ   -  person Puffo    schedule 16.08.2015
comment
ตัวอย่างของคุณแสดงว่าคุณกำลังใช้ sortable: "level.ranked_scores -> 'stage_1'" ในขณะนี้ แบบสอบถามฐานข้อมูลมีลักษณะอย่างไรหากคุณใช้การเรียงลำดับ   -  person Timo Schilling    schedule 16.08.2015
comment
จากคอนโซล Rails ของฉัน ผลลัพธ์ต่อไปนี้จะปรากฏขึ้นเมื่อพยายามใช้การเรียงลำดับ: | พารามิเตอร์: {order=›levels.ranked_scores['stage_1']_desc} SELECT COUNT(count_column) FROM (SELECT 1 AS count_column FROM users LIMIT 30 OFFSET 0) subquery_for_count SELECT COUNT() FROM users SELECT COUNT(count_column) FROM (เลือก 1 AS count_column จากผู้ใช้ จำกัด 30 OFFSET 0) ผู้ใช้ subquery_for_count SELECT จากผู้ใช้ จำกัด 30 OFFSET 0 เลือกระดับ * จากระดับ WHERE Levels.user_id IN (1, 2, 3, 4, 5, 6, 7) เลือกผู้ใช้.* จากผู้ใช้ | มันมีประโยชน์ไหม @TimoShilling?   -  person Puffo    schedule 16.08.2015
comment
@TimoSchilling - ฉันมีปัญหาที่คล้ายกันและผลลัพธ์ที่คล้ายกัน - ฉันได้ทดสอบแบบสอบถามที่ฉันใช้ในคอนโซล psql และมันทำงานตามที่คาดไว้ แต่จากผู้ดูแลระบบที่ใช้งานอยู่ มันจะไม่เรียงลำดับและในบันทึกของเซิร์ฟเวอร์ ฉัน' ฉันเห็นว่ามีประโยชน์น้อยกว่าเหมือนเดิม subquery_for_count   -  person dax    schedule 03.09.2015
comment
สำหรับบันทึก คำถามของฉันเป็นดังนี้: column 'Gold earned', sortable: "cast(payload ->> 'gold_earned' as integer) " do |gold|   -  person dax    schedule 03.09.2015
comment
@dax ฉันคิดว่าฉันแก้ไขปัญหาของคุณแล้ว (ดูคำตอบของฉันด้านล่าง)   -  person dimakura    schedule 06.09.2015


คำตอบ (2)


คุณควรทำการเปลี่ยนแปลงเล็กน้อย 2 ครั้งในการกำหนดค่า admin/user.rb ซึ่งจะทำให้สามารถใช้งานได้

#1 คุณมีช่องว่างประมาณ -> ซึ่งควรลบออกเพื่อทำให้ ActiveAdmin พอใจ

ปัญหานี้มีสาเหตุมาจาก regexp การตรวจสอบความถูกต้องของการเรียงลำดับ ซึ่งไม่ตรงกับตัวเลือกการจัดเรียงของคุณ การลบช่องว่างรอบๆ -> ถือเป็นวิธีแก้ปัญหาชั่วคราวสำหรับข้อบกพร่องของ ActiveAdmin

ตารางของ #2 Level ควรอ้างอิงเป็น levels ไม่ใช่ level

ในที่สุดเราก็มี:

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

และคุณจะได้สิ่งที่คุณตั้งใจจะมี

หมายเหตุเกี่ยวกับตัวดำเนินการ ->>

มีโอเปอเรเตอร์ Postgres อีกตัวหนึ่งคือ ->> ซึ่งคล้ายกับ -> มาก ดูที่นี่

ข้อแตกต่างระหว่างทั้งสองคือ ->> จะส่งกลับค่าข้อความ (stringified json) เสมอ ในขณะที่ -> สามารถส่งคืนวัตถุ json ได้ ในตัวอย่างของคุณการใช้งานจะเหมือนกันทุกประการ เนื่องจากคะแนนที่ได้รับการจัดอันดับเป็นตัวเลข

แต่ในกรณีทั่วไป คุณอาจต้องใช้ตัวดำเนินการ ->> ด้วยเช่นกัน น่าเสียดายที่ ActiveAdmin ยังไม่ได้แก้ไขปัญหา #3173 และ #3085 ซึ่ง @bigsolom กล่าวถึงในการตอบกลับของเขา ดังนั้นคุณจึงไม่สามารถใช้ตัวดำเนินการ ->> กับ ActiveAdmin เวอร์ชันปัจจุบันได้

ขออภัย ฉันไม่สามารถคิดถึงวิธีแก้ปัญหาใดๆ ได้เหมือนที่เราทำกับโอเปอเรเตอร์ ->

ยังมีแฮ็คที่คุณสามารถใช้เพื่อเปิดใช้งานโอเปอเรเตอร์นี้ได้เช่นกัน ต้องเพิ่มอักขระ 2 ตัวลงในซอร์สโค้ดของ ActiveAdmin

คุณต้องเปลี่ยนบรรทัดของโค้ดนี้ ไปที่รายการต่อไปนี้:

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

เราได้เพิ่ม >? ไว้ระหว่างนั้น 2 ตัวอักษรตามที่สัญญาไว้

person dimakura    schedule 05.09.2015
comment
+1 นี่ดูเหมือนจะเป็นทางออกที่ดี น่าเสียดายที่เราต้องการแฮ็กเพื่อใช้ตัวดำเนินการ ->> แต่ช่างเถอะ.. - person dax; 07.09.2015
comment
@dax ฉันจะโพสต์คำขอดึงให้พวกเขา ดังนั้นฉันหวังว่าจะไม่จำเป็นต้องใช้ในเร็วๆ นี้ - person dimakura; 07.09.2015
comment
@dimakura ตามคำแนะนำของคุณ ตอนนี้แบบสอบถามส่งผลต่อการเรียงลำดับคอลัมน์ - อย่างไรก็ตาม มันไม่ได้เรียงลำดับตามค่าที่ได้รับจากการสืบค้น ฉันคิดว่ามันสั่งตามความยาวของเชือก ฉันพยายามส่งแบบสอบถามเป็นจำนวนเต็มโดยใช้ความคิดเห็นของ @dax: cast(levels.ranked_scores->'stage_1' as integer) แต่แล้วเราก็กลับมาเหมือนเดิมโดยไม่ส่งผลกระทบต่อการเรียงลำดับคอลัมน์ - person Puffo; 08.09.2015
comment
@Puffo วิธีที่คุณจัดรูปแบบ {"stage_1"=>111, "stage_2"=>222, "stage_3"=>333} ฉันคิดว่ามันเป็นตัวเลข ฉันจะตรวจสอบอีกครั้งวันนี้หากสามารถทำได้ในกรณีของสตริง - person dimakura; 08.09.2015
comment
อ่า @dimakura นั่นเป็นส่วนสุดท้ายของปัญหา - ฉันเปลี่ยนความคงอยู่ของคะแนนให้เป็นจำนวนเต็มและมันก็ใช้งานได้อย่างมีเสน่ห์! ขอบคุณ! - person Puffo; 08.09.2015
comment
ใช้ได้กับฉัน ใช้ได้กับ OP ฉันคิดว่าค่าหัวเป็นของคุณ ขอบคุณ @dimakura! - person dax; 08.09.2015

สำหรับคอลัมน์ jsonb คุณต้องใช้ ->> แทน -> แต่จะทำให้เกิดปัญหากับการตรวจสอบความถูกต้องของ ActiveAdmin (ดูปัญหาที่เปิดอยู่: https://github.com/activeadmin/activeadmin/issues/3173 และ 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
person bigsolom    schedule 05.09.2015