如何使用 Meilisearch 和 React 將極速且相關的搜尋功能整合到您的 Rails 應用程式中
將 Meilisearch 與您的 Rails 應用程式資料庫整合,並使用 React 建立即時搜尋體驗。

本教學課程最初於 2021 年 11 月發布,當時最新的 Meilisearch 版本為 0.24。現在已更新為與 Meilisearch v1.0 相容。
簡介
在本教學課程中,您將學習如何將 Meilisearch 與您的 Rails 應用程式資料庫整合,並使用 React 快速建立具有即時搜尋體驗的前端搜尋列。
我們將建立一個非常基本的應用程式;我們的主要重點將放在搜尋上。因此,我們不會詳細說明 Rails 或 React。
先決條件
若要依照本教學課程進行,您需要
- Node.js >=16.10
- yarn 1
- Ruby >= 2.7
- Ruby on Rails 7.0
理想情況下,您應該熟悉 Ruby on Rails 並且已經建立了一個簡單的 RoR 應用程式。如果不是這種情況,您仍然可以按照本教學課程進行,但正如我們在簡介中所述,說明將重點放在搜尋上。
步驟 1. 安裝 Meilisearch
安裝 Meilisearch 的方法有很多種。執行 Meilisearch 執行個體的簡單方法是使用Meilisearch Cloud,有 14 天免費試用期,無需信用卡。Meilisearch 是開放原始碼的。在本教學課程中,我們將使用 cURL 在本機執行它,這是一個可讓您從命令列發出 HTTP 要求和傳輸資料的工具。
開啟您的終端機並貼上以下程式碼
# Install Meilisearch curl -L https://install.meilisearch.com | sh # Launch Meilisearch ./meilisearch
步驟 2. 建立和設定您的 Rails 應用程式
現在您已經啟動並執行 Meilisearch,讓我們建立我們的 RoR 應用程式。 我們將建立一個名為 delicious_meals
的簡單食譜應用程式。在終端機上執行以下命令
rails new delicious_meals -j esbuild
讓我們產生我們的模型 Recipe
。它將有四個屬性
標題
食材
做法
飲食
進入專案資料夾並執行以下命令
bin/rails g model Recipe title:string ingredients:text directions:text diet:string
此命令也會在 db/migrate
目錄中產生移轉檔案。讓我們在資料表的每個資料行旁邊新增 null: false
選項,這樣如果欄位為空,就不會將任何食譜儲存到資料庫中。
class CreateRecipes < ActiveRecord::Migration[7.0] def change create_table :recipes do |t| t.string :title, null: false t.text :ingredients, null: false t.text :directions, null: false t.string :diet, null: false t.timestamps end end end
timestamps
資料行方法會在資料表中新增兩個額外欄位:created_at
和 updated_at
。
現在您可以使用以下命令建立資料庫並執行上述移轉
# Creates the database bin/rails db:create # Runs the migration bin/rails db:migrate
接下來,您需要產生具有其 index
動作的控制器。
bin/rails g controller Recipes index
我們將使用 index
檢視來顯示我們的食譜,並使用搜尋列搜尋它們。我們不會產生其餘的 CRUD 動作,因為這會超出本教學課程的目的。
建立控制器後,請修改 config/routes.rb
檔案,使其如下所示
Rails.application.routes.draw do # Maps requests to the root of the application to the index action of the 'Recipes controller' root "recipes#index" end
現在,root
路由對應到 RecipesController
的 index
動作。這樣一來,app/views/recipes/index.html.erb
的內容將會在應用程式的根目錄中轉譯。
您可以使用以下命令啟動應用程式來檢查一切是否如預期般運作
bin/dev
開啟您的瀏覽器視窗並瀏覽至 http://127.0.0.1:3000
。您應該會看到您的索引檢視顯示如下訊息
Recipes#index
在 app/views/recipes/index.html.erb 中找到我
步驟 3. 將 Meilisearch 新增至您的應用程式
現在我們有了應用程式的後端基礎知識,讓我們使用 meilisearch-rails
gem 將其連接到正在執行的 Meilisearch 執行個體。
執行以下命令來安裝它
bundle add meilisearch-rails
當本教學課程上次更新時,gem 的最新版本為 0.8.1。您可以在meilisearch-rails GitHub 儲存庫或Meilisearch 發現的 rubygems中查看最新版本。
在 config/initializers/
資料夾內建立一個名為 meilisearch.rb
的檔案,以設定您的 MEILISEARCH_HOST
和 MEILISEARCH_API_KEY
touch config/initializers/meilisearch.rb
如果您已逐字遵循步驟 1,您的 Meilisearch 主機應該是 https://127.0.0.1:7700
。由於我們沒有設定任何 API 金鑰,我們將註解掉具有 meilisearch_api_key
欄位的程式碼行
MeiliSearch::Rails.configuration = { meilisearch_url: 'https://127.0.0.1:7700', # meilisearch_api_key: '' }
您在生產環境中會需要主金鑰或私密金鑰,您可以在這裡深入了解。
如果您已設定主金鑰,則必須先更新您的組態,才能執行 Meilisearch(請參閱步驟 1)讓我們開啟我們的 app/models/recipe.rb
檔案,並在 Class
宣告中新增以下程式碼行
include MeiliSearch::Rails
我們還需要新增一個 meilisearch block
。請注意,Meilisearch block 內的設定並非強制性的。
class Recipe < ApplicationRecord include MeiliSearch::Rails meilisearch do # all attributes will be sent to Meilisearch if block is left empty displayed_attributes [:id, :title, :ingredients, :directions, :diet] searchable_attributes [:title, :ingredients, :directions, :diet] filterable_attributes [:diet] end end
讓我們分解每一行程式碼
設定顯示的屬性
displayed_attributes [:id, :title, :ingredients, :directions, :diet]
根據預設,Meilisearch 會顯示所有屬性。在這裡,我們指示 Meilisearch 只在搜尋回應中顯示指定的屬性,此設定會防止 Meilisearch 顯示 created_at
和 updated_at
欄位。
您可以在我們的說明文件中深入了解 displayed attributes
。
設定可搜尋的屬性
searchable_attributes [:title, :ingredients, :directions, :diet]
透過上面的程式碼行,我們正在做兩件事
- 我們首先告訴 Meilisearch 在執行搜尋查詢時僅在指定的屬性中搜尋。因此它不會嘗試在
id
、created_at
和updated_at
欄位中尋找相符項目。 - 我們還指定屬性的重要性順序。我們告訴 Meilisearch,標題中找到相符查詢字的文件的相關性高於做法中找到相符查詢字的文件。第一個文件更相關,並在搜尋結果中首先傳回。
請在我們的說明文件中深入了解 searchable fields
。
設定可篩選的屬性
filterable_attributes [:diet]
最後,我們告訴 Meilisearch,我們希望能夠根據飲食
類型精簡我們的搜尋結果。這將允許我們例如只搜尋素食食譜。
請瀏覽我們的說明文件,以深入了解篩選。
步驟 4. 為資料庫設定種子
若要測試我們的應用程式,我們需要在資料庫中加入一些資料。最快的方法是使用名為 faker 的 gem,以虛擬資料來填入資料庫。
將以下程式碼行新增至您開發群組內的 Gemfile
,儲存並執行 bundle install
gem 'faker', :git => 'https://github.com/faker-ruby/faker.git', :branch => 'master'
然後開啟 ./db/seeds.rb
檔案並新增以下程式碼,以 1000 個食譜填入您的資料庫
# Deletes existing recipes, useful if you seed several times Recipe.destroy_all # Creates 1000 fake recipes 1000.times do Recipe.create!( title: "#{Faker::Food.dish} by #{Faker::Name.unique.name}", ingredients: "#{Faker::Food.ingredient}, #{Faker::Food.ingredient}, #{Faker::Food.ingredient}", directions: Faker::Food.description, diet: ['omnivore', 'pescetarian', 'vegetarian', 'vegan'].sample ) end # Displays the following message in the console once the seeding is done puts 'Recipes created'
現在,在命令列中執行 bin/rails db:seed
。
步驟 5. 使用搜尋預覽測試搜尋
Meilisearch 提供現成的 Web 介面,可互動式地進行測試。開啟您的瀏覽器並前往 Meilisearch HTTP 位址,除非您在啟動時另行指定,否則該位址應為https://127.0.0.1:7700
。
將文件新增至索引是一種非同步作業,如果您沒有立即看到 1000 個文件,請別擔心。更新可能需要一些時間才能處理。在這裡深入了解非同步更新。
請確定在位於右上角、搜尋列旁邊的功能表中已選取 Recipe
索引。
如您所見,資料已自動新增至我們的 Meilisearch 實例中。唯一可見和可搜尋的屬性是那些我們在模型檔案的 meilisearch block
內指定的屬性。請注意,由於faker會隨機產生資料,您的搜尋結果可能與 GIF 中顯示的不同。
這對於測試 Meilisearch 及其某些功能很有幫助,但它並未展示我們在區塊中指定的 filterable_attributes
。我們需要一個用於生產環境的自訂 UI。
步驟 6. 將 React 加入 Rails 應用程式
將 ReactJS 與 Rails 一起使用有多種方法。我們選擇了最直接的一種:將其作為 JavaScript 依賴項安裝在我們的 Rails 應用程式中。
執行以下命令以安裝 ReactJS 及其用於處理 DOM 的 react-dom 套件
yarn add react react-dom
讓我們為 React 程式碼建立資料夾和檔案。
mkdir app/javascript/recipes touch app/javascript/recipes/index.jsx touch app/javascript/recipes/App.jsx
讓我們開啟 app/javascript/recipes/index.jsx
並新增必要的程式碼以渲染我們的 React 元素
import React from 'react'; import { createRoot } from 'react-dom/client'; import App from './App'; const container = document.getElementById('app'); const root = createRoot(container); root.render(<App/>);
開啟 app/javascript/application.js
並匯入我們剛剛建立的檔案
import "./recipes"
步驟 7. 整合前端搜尋欄
要整合前端搜尋欄,您需要安裝兩個套件
- React InstantSearch:一個開放原始碼程式庫,提供您自訂搜尋欄環境所需的所有前端工具
- Instant Meilisearch:Meilisearch 用戶端,用於建立您的 Meilisearch 實例與 React InstantSearch 程式庫之間的通訊
yarn add react-instantsearch-dom @meilisearch/instant-meilisearch
現在,您可以開啟您的 app/javascript/recipes/App.jsx
檔案,並將現有程式碼替換為 meilisearch-react
入門指南 中的程式碼。我們只需要使用我們的 Meilisearch 主機和 Meilisearch API 金鑰修改 searchClient
,以及 indexName
。它應該看起來像這樣
import React from "react" import { InstantSearch, Highlight, SearchBox, Hits } from 'react-instantsearch-dom'; import { instantMeiliSearch } from '@meilisearch/instant-meilisearch'; const searchClient = instantMeiliSearch( "https://127.0.0.1:7700", // Your Meilisearch host "" // Your Meilisearch API key, if you have set one ); const App = () => ( <InstantSearch indexName="Recipe" // Change your index name here searchClient={searchClient} > <SearchBox /> <Hits hitComponent={Hit} /> </InstantSearch> ); const Hit = ({ hit }) => <Highlight attribute="title" hit={hit} /> export default App
現在,前往您的 views
資料夾,並將 app/views/recipes/index.html.erb
的內容替換為以下程式碼
<div id="app"></div>
現在您可以執行 bin/dev
命令,開啟您的瀏覽器並導覽至 http://127.0.0.1:3000
並查看結果:
嗯,搜尋功能正常運作,但不是很美觀。幸運的是,InstantSearch 提供了一個 CSS 主題,您可以將以下連結插入 app/views/layouts/application.html.erb
的 <head>
元素中來新增。
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/instantsearch.css@7.4.5/themes/satellite-min.css" integrity="sha256-TehzF/2QvNKhGQrrNpoOb2Ck4iGZ1J/DI4pkd2oUsBc=" crossorigin="anonymous">
如果您想,您也可以自訂小工具或建立自己的小工具。有關更多詳細資訊,請查看 React InstantSearch 文件。
讓我們檢查一下渲染效果
還不錯,對吧?但是,我們再次缺少依飲食類型篩選結果的可能性。
步驟 8. 加入刻面搜尋
就像在您的 App.jsx
檔案中匯入 RefinementList
小工具一樣簡單
import { InstantSearch, Highlight, SearchBox, Hits, RefinementList } from 'react-instantsearch-dom';
並將其新增到我們的 InstantSearch
小工具中,指定我們想要篩選的屬性
<RefinementList attribute="diet" />
為了使其更美觀和實用,讓我們建立兩個 <div>
元素來分隔我們的元件。在左側,我們會找到篩選器,右側則是搜尋欄和結果。
您也可以新增「飲食類型」標題以及 ClearRefinements
小工具。它允許您只需按一下即可清除所有篩選器,而不必逐一取消選取它們。
現在,該檔案應該看起來像這樣
import React from "react" import { InstantSearch, Highlight, SearchBox, Hits, RefinementList, ClearRefinements } from 'react-instantsearch-dom'; import { instantMeiliSearch } from '@meilisearch/instant-meilisearch'; const searchClient = instantMeiliSearch( "https://127.0.0.1:7700", "" ); const App = () => ( <InstantSearch indexName="Recipe" // Change your index name here searchClient={searchClient} > <div className="left-panel"> <ClearRefinements /> <h2>Type of diet</h2> <RefinementList attribute="diet" /> </div> <div className="right-panel"> <SearchBox /> <Hits hitComponent={Hit} /> </div> </InstantSearch> ); const Hit = ({ hit }) => <Highlight attribute="title" hit={hit} /> export default App
為了使此功能運作,我們需要新增一些 CSS。讓我們建立一個 app/assets/stylesheets/recipes.css
檔案並新增以下程式碼行
.right-panel { margin-left: 210px; } .left-panel { float: left; width: 200px; }
為了使其更加美觀,讓我們在主體和搜尋欄中新增一些邊距和邊框,並變更字體
/* app/assets/stylesheets/recipes.css */ body { font-family: sans-serif; padding: 1em; } .ais-SearchBox { margin: 1em 0; } .right-panel { margin-left: 210px; } .left-panel { float: left; width: 200px; }
鏘鏘!🎉 您現在有一個漂亮的搜尋欄,可以隨打即搜!🥳
⚠️ 因為我們使用假資料來初始化我們的資料庫,所以食譜的 title
、ingredients
、directions
和 diet
類型不一定一致。
結論
我們已學習如何將我們的 Ruby on Rails 資料庫與 Meilisearch 同步,並直接在我們的 Rails 應用程式上自訂我們的搜尋設定,讓我們能夠以毫秒為單位搜尋我們的資料。最重要的是,我們還使用 React 建立了一個具有隨打即搜體驗的刻面搜尋介面。
多虧 Meilisearch Rails 和 Instant Meilisearch,我們已順利達成所有這一切。Meilisearch 為幾乎所有流行的語言或框架都提供了整合。請查看 Meilisearch 整合指南中的完整清單。
如果您有任何疑問,請在 Discord 上加入我們;我們總是很高興收到您的來信。有關 Meilisearch 的更多資訊,請查看我們的 Github 儲存庫 和 官方文件。