วิธีส่งตัวกรองเริ่มต้นไปยัง Filterrific get

ในที่สุดฉันก็ได้ filterrific ของฉันใช้งานได้และมันเป็นอัญมณีที่ยอดเยี่ยม หากไม่ซับซ้อนเล็กน้อยสำหรับมือใหม่อย่างฉัน

หน้าดัชนีเดิมของฉันกรองบันทึกที่ใช้งานอยู่โดยอิงจากข้อมูลที่อยู่ใกล้กับผู้ใช้ดังนี้:

def index 

location_ids = Location.near([session[:latitude], session[:longitude]], 50, order: '').pluck(:id)
@vendor_locations = VendorLocation.includes(:location).where(location_id: location_ids)

@appointments = Appointment.includes(:vendor).
  where(vendor_id: @vendor_locations.select(:vendor_id))

end

ดังนั้นสิ่งนี้จะดึงการนัดหมายทั้งหมดกับผู้ขายในพื้นที่ แต่ฉันจะส่งต่อสิ่งนี้ไปยังการค้นหา Filterrific ได้อย่างไร:

@filterrific = initialize_filterrific(
  params[:filterrific],
  select_options:{ sorted_by: Appointment.options_for_sorted_by, with_service_id: Service.options_for_select },
  ) or return

@appointments = @filterrific.find.page(params[:page])

respond_to do |format|
  format.html
  format.js
end

ดูเหมือนว่า Filterrerrific กำลังโหลดการนัดหมายทั้งหมดตามค่าเริ่มต้น แต่ฉันต้องการจำกัดไว้เฉพาะรายการที่อยู่ใกล้เคียง ฉันพลาดอะไรไป?


person Seth Merritt    schedule 24.12.2016    source แหล่งที่มา


คำตอบ (1)


สิ่งที่คุณดูเหมือนจะขาดหายไปคือพารามิเตอร์ default_filter_params สำหรับมาโครกรองในโมเดล (คำถามของคุณไม่ได้ระบุว่าคุณได้ปรับเปลี่ยนโมเดล VendorLocation เนื่องจากนั่นคือออบเจ็กต์ที่คุณต้องการกรอง นั่นคือสิ่งที่ควรเรียกมาโคร บางทีคุณอาจละเว้นมันออกจากคำถามของคุณ...)

จากเอกสารโมเดล:

filterrific(
    default_filter_params: { sorted_by: 'created_at_desc' },
    available_filters: [
      :sorted_by,
      :search_query,
      :with_country_id,
      :with_created_at_gte
    ]
  )

คุณอาจพบสิ่งนี้แล้ว มันอยู่ในหน้าแรกของเอกสารประกอบ แต่มีสิ่งที่สำคัญกว่าในแอปพลิเคชันตัวอย่างที่คุณต้องการ (ฉันก็พบสิ่งนี้เหมือนกันเมื่อฉันเพิ่งใช้ Filterrific เป็นครั้งแรก)

ข้อมูลในหน้าเริ่มต้นไม่เพียงพอที่จะช่วยให้คุณเริ่มต้นได้เลย คุณต้องอ่านเพิ่มเติมอีกเล็กน้อยเพื่อดูวิธีอื่นๆ ที่คุณอาจต้องเปลี่ยนโมเดล การเข้าถึงโมเดล และมุมมอง เพื่อสนับสนุน Filterrific

ส่วนที่ทำให้การตั้งค่าตัวกรองเริ่มต้นมีผลคือ default_filter_params แฮช (NOT select_options ซึ่งมีตัวเลือกสำหรับ "select" หรือที่เรียกว่ากล่องดรอปดาวน์ นั่นไม่ใช่สิ่งที่คุณต้องการเลย เว้นแต่ว่าคุณกำลังใช้ตัวกรองแบบดรอปดาวน์) แฮชนี้เก็บเอาไว้ รายการขอบเขตที่จำเป็นต้องใช้ตามค่าเริ่มต้น (คีย์แฮช) และพารามิเตอร์ขอบเขตจะถูกใช้เป็นค่าแฮช

แฮช default_filter_params นั้นอาจไม่ใช่สิ่งเดียวที่คุณขาดหายไป... คุณต้องกำหนดขอบเขต ActiveRecord เหล่านั้นสำหรับตัวกรองแต่ละตัวที่คุณต้องการใช้ในโมเดล และตั้งชื่อสิ่งเหล่านี้ใน available_filters ตามด้านบนเพื่อให้พร้อมใช้งานสำหรับตัวกรอง:

scope :with_created_at_gte, lambda { |ref_date|
  where('created_at >= ?', ref_date)
end

สิ่งสำคัญคือขอบเขตเหล่านี้ทั้งหมดต้องมีอาร์กิวเมนต์ (ค่ามาจากค่าของฟิลด์ตัวกรองบนหน้ามุมมอง คุณต้องเพิ่มสิ่งเหล่านี้ลงในมุมมองของคุณ แม้ว่าคุณต้องการซ่อนไม่ให้ผู้ใช้เห็นก็ตาม) สิ่งสำคัญคือต้องส่งคืนการเชื่อมโยง ActiveRecord เสมอ

นี่เป็นเหมือนสิ่งที่คุณต้องการมากขึ้น:

scope :location_near, lambda { |location_string|
  l = Location.near(location_string).pluck(:id)
  where(location_id: l)
end

ปัญหาของแนวทางนี้คือ ในกรณีของคุณ ไม่มี location_string หรือตัวแปรตำแหน่งใดๆ เลย คุณมีหลายพิกัดสำหรับพารามิเตอร์ตำแหน่งของคุณ แต่คุณไม่ใช่คนแรกที่มีปัญหานี้เลย!

ปัญหานี้ อธิบายได้เกือบจะทุกประการกับปัญหาที่คุณตั้งไว้เพื่อแก้ไข ผู้เขียน Filterrific แนะนำให้ฝังฟิลด์ตำแหน่งลงในฟิลด์ฟอร์มที่ซ่อนอยู่ใน fields_for ที่ซ้อนกัน เพื่อให้ฟอร์มยังสามารถส่งผ่านอาร์กิวเมนต์เดียวเข้าไปในขอบเขตได้ (ดังเช่นใน with_distance_fields):

<%= f.fields_for :with_distance do |with_distance_fields| %>
  <%= with_distance_fields.hidden_field :lat, value: current_user.lat %>
  <%= with_distance_fields.hidden_field :lng, value: current_user.lng %>
  <%= with_distance_fields.select :distance_in_meters, 
    @filterrific.select_options[:with_distance] %>
<% end %>

... ทำการเปลี่ยนแปลงในมุมมองของคุณ และเพิ่มขอบเขตการจับคู่ที่มีลักษณะดังนี้ (คัดลอกมาจากปัญหา GitHub ที่เชื่อมโยง):

scope :with_distance,  -> (with_distance_attrs) {
  ['lng' => '-123', 'lat' => '49', 'distance_in_meters' => '2000']
  where(%{
    ST_DWithin(
      ST_GeographyFromText(
        'SRID=4326;POINT(' || courses.lng || ' ' || courses.lat || ')'
      ),
      ST_GeographyFromText('SRID=4326;POINT(%f %f)'),
      %d
    )
  } % [with_distance_attrs['lng'], with_distance_attrs['lat'], with_distance_attrs['distance_in_meters']])
}

ดังนั้น ขอบเขต :with_distance ของคุณควรอยู่ในโมเดล VendorLocation และควรมีลักษณะดังนี้:

scope :with_distance,  -> (with_distance_attrs) {
  lat = with_distance_attrs['lat']
  lng = with_distance_attrs['lng']
  dist = with_distance_attrs['distance']
  location_ids = Location.near([lat, lng], dist, order: '').pluck(:id)
  where(location_id: location_ids)
end

สุดท้ายแต่ไม่ท้ายสุด คุณอาจสังเกตเห็นว่าฉันลบการเรียกของคุณไปที่ includes(:location) ฉันรู้ว่าคุณตั้งใจ และฉันพบว่ามันไม่ชัดเจนนักในเอกสารประกอบ แต่คุณยังคงสามารถโหลดได้อย่างกระตือรือร้นและปรับ ActiveRecord ให้เหมาะสมใน แบบสอบถามเดียวก่อนที่จะส่งผ่านตัวกรองไปยัง Filterrific โดยกำหนดวิธีดัชนีของคอนโทรลเลอร์ของคุณในลักษณะนี้:

def index
  @appointments = Appointment.includes(:vendor).
    filterrific_find(@filterrific).page(params[:page])
end

หวังว่านี่จะช่วยได้!

person Kingdon    schedule 01.05.2017
comment
ผู้ลงคะแนนเสียงแบบขับรถ... เหตุใดคำตอบนี้จึงไม่ถือว่ามีประโยชน์ - person Kingdon; 03.08.2017
comment
ขอบคุณ เอกสารประกอบเกี่ยวกับ ....filterrific_find(@filteriffic)... เกี่ยวกับ Active Relation ไม่ใช่เรื่องง่ายที่จะหาได้จากซอร์สโค้ด จากนั้นฉันก็พบคำถามและคำตอบนี้! - person Steve Folly; 31.01.2018
comment
ขอบคุณ! Filterrific เป็นเรื่องยากมากที่จะเข้าใจในตอนแรก แต่เมื่อฉันเข้าใจวิธีใช้อย่างถูกต้อง มันก็มีประสิทธิภาพมากขึ้น เมื่ออ่านย้อนกลับไปก็รู้สึกตกใจเล็กน้อยที่คิดออกหมดแล้ว - person Kingdon; 31.01.2018