iT邦幫忙

2023 iThome 鐵人賽

DAY 11
0
SideProject30

用 Rails 打造你的電商網站系列 第 11

Day 11 茫茫商品中一鍵認出你

  • 分享至 

  • xImage
  •  

商品越來越多,使用者不可能一頁頁慢慢找

我們在後台也是一樣,要快速找到一件商品並且修改刪除

就需要搜尋功能啦!

我們今天會先介紹比較簡單的搜尋功能 Ransack

Ransack 是什麼

提供搜尋工具的套件,裡面包含了多樣的功能

為什麼使用 Ransack

個人覺得 Ransack 算是比較入門的搜尋工具

使用上其實蠻簡單的

提供的方法也都很便利

而且像是 pagy 這些套件也都有支援

不過就沒辦法使用模糊搜尋

但我們之後會再介紹另一款搜尋工具

可以拿來做模糊搜尋

Ransack 怎麼使用

step 1. 安裝 Ransack

gem 'ransack'

step 2. 設定 Ransack

預設的搜尋關鍵字為 q ,不過 q 應該沒人看的懂

所以我們先把它改成 query

# config/initializers/ransack.rb

Ransack.configure do |config|
  config.search_key = :query
end

step 3. 在 model 設定哪些欄位需要被搜尋

我們先用 name 來搜尋就好

# app/models/drink.rb
  
  ...
  def self.ransackable_attributes(auth_object = nil)
    ["name"]
  end
end
  

到 rails console 試試看

name_start 後面的 _start 是 Ransack 提供的 match 方法,後續我們在做詳細說明

一開始搜出來會是一個 Ransack 的實體,需要加上 result 才會跑出搜尋結果

# rails console

> aa = Drink.ransack(name_start: '阿')

Ransack::Search<class: Drink, base: Grouping <conditions: [Condition <attributes: ["name"], predicate: start, values: ["阿"]>], combinator: and>>

> aa.result

[#<Drink:0x00000001085e3270
  id: 16,
  name: "阿薩姆奶茶",
  description: "就是回憶中的阿薩姆奶茶",
  price: 40,
  capacity: 600,
  ingredient: [],
  created_at: Sat, 23 Sep 2023 12:51:09.575584000 UTC +00:00,
  updated_at: Sat, 23 Sep 2023 12:51:09.575584000 UTC +00:00,
  deleted_at: nil>] 

這樣就輕鬆完成搜尋了

不過我們如果要在商品頁面(含所有商品)做搜尋的話,會需要依照 polymorphic 的方式去搜尋(還記得昨天我們是用 Product 去撈所有資料嗎?忘記可回上一章複習)

step 4. 使用 polymorphic 做搜尋

一樣先到 Product 設定可以讓 ransack 搜尋的欄位

# app/models/product.rb

class Product < ApplicationRecord
  ...
  def self.ransackable_attributes(auth_object = nil)
    ["productable_type"]
  end
end

不過因為 Product 跟 Polymorphic 是有關聯,我們需要多加一個關聯方法

# app/models/product.rb

class Product < ApplicationRecord
  ...
  def self.ransackable_associations(auth_object = nil)
    ["productable"]
  end
end

而我們會去搜尋的是 dessert 以及 drink 這兩個 table

所以需要在他們的 model 檔案中加上 product 關聯設定,才有辦法進行搜尋

# app/models/drink.rb

class Drink < ApplicationRecord
  ...
  def self.ransackable_associations(auth_object = nil)
    ["product"]
  end
end

我們到 rails console 試試看,搜尋的時候需要明確指定 of_Drink_type ,讓 Ransack 知道他需要去 joins 哪個 table

# rails console

> Product.ransack(productable_of_Drink_type_name_eq: '阿薩姆奶茶').result

Product Load (1.2ms)  SELECT "products".* FROM "products" LEFT OUTER JOIN "drinks" ON "drinks"."deleted_at" IS NULL AND "drinks"."id" = "products"."productable_id" AND "products"."productable_type" = 'Drink' WHERE "products"."deleted_at" IS NULL AND "drinks"."name" = '阿薩姆奶茶'
 => 
[#<Product:0x000000010a605328
  id: 12,
  productable_type: "Drink",
  productable_id: 16,
  created_at: Sat, 23 Sep 2023 19:31:44.004810000 UTC +00:00,
  updated_at: Sat, 23 Sep 2023 19:31:44.004810000 UTC +00:00,
  deleted_at: nil>] 

如此一來我們就完成了 Polymorphic 的搜尋

step 5. 將搜尋框框放到 View

我們目前只知道怎麼在 Rails console 中做搜尋

如果要放在 View 呢?

需要使用 search_form_for 的方法(是 Ransack 提供給我們的)

一開始設定 Ransack 所要抓的 search keyword 為 query ,所以我們這邊就帶 @query

search_field 這邊要放的比較複雜,因為同時可以搜尋 drink 與 dessert

而我們又是需要用 polymorphic 的關聯去搜尋,

所以需要多加上 of_Drink_type 跟 of_Dessert_type 去搜尋

# app/views/products/index.html.erb

...

<div class="mb-4">
  <%= search_form_for @query do |q| %>
    <%= q.search_field :productable_of_Drink_type_name_or_productable_of_Dessert_type_name_cont, class: 'rounded-md mr-4' %>
    <%= q.submit '搜尋', class: 'border-2 p-2 rounded-md bg-slate-500 text-white cursor-pointer' %>
  <% end %>
</div>

...

在 Controller 中把搜尋結果找出來

搜尋框會帶回一包 params ,我們要請 Ransack 依照這包 params 去幫我們找到符合條件的資料,並且丟給 @query

我們要將結果渲染到頁面上,所以 pagy 的參數需要改成 @query.result

app/controllers/products_controller.rb

class ProductsController < ApplicationController
  def index
    @query = Product.ransack(params[:query])

    @pagy, @products = pagy(@query.result)
  end
end

上述就大概完成了搜尋功能囉

Ransack matcher

Ransack 提供多種的搜尋結果比對方式,詳情可參照官網

假設我們今天要搜尋 Drink 中的 name 欄位

可以看搜尋的模式是要哪種

如果是要一模一樣

就可使用 name_matches_all 或者是 name_eq

如果要類似的話就可以使用 name_cont 這個方法還蠻常用到的

那麼如果是要搜尋開頭呢? 使用 name_start

搜尋數字的話可以使用 *_lt *_lteq *_gt *_gteq 等等

還有其他多種設定,可以參考官網手冊


上一篇
Day 10 區分前台與後台
下一篇
Day 12 為會員做權限管理
系列文
用 Rails 打造你的電商網站30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言