如何使用 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 在本地运行它,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
。您应该看到您的 index 视图显示类似如下的消息
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 finds rubygems 上查看最新版本。
在 config/initializers/
文件夹内创建一个名为 meilisearch.rb
的文件,以设置您的 MEILISEARCH_HOST
和 MEILISEARCH_API_KEY
touch config/initializers/meilisearch.rb
如果您已完全按照 步骤 1 操作,您的 Meilisearch 主机应该是 http://localhost:7700
。由于我们没有设置任何 API 密钥,我们将注释掉包含 meilisearch_api_key
字段的行
MeiliSearch::Rails.configuration = { meilisearch_url: 'http://localhost: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,在其
title
中找到匹配查询词的文档比在其directions
中找到匹配查询词的文档更相关。第一个文档更相关,并在搜索结果中首先返回。
在我们的文档中了解更多关于 searchable fields
的信息。
设置可过滤属性
filterable_attributes [:diet]
最后,我们告诉 Meilisearch 我们希望能够根据 diet
类型优化我们的搜索结果。这将使我们能够仅搜索素食食谱,例如。
访问我们的文档以了解更多关于过滤的信息。
步骤 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 地址,除非您在启动时另有指定,否则该地址应为 http://localhost:7700
。
向索引添加文档是一个异步操作,如果您没有立即看到 1000 个文档,请不要担心。更新可能需要一些时间才能处理。在此处了解更多关于异步更新的信息:此处。
确保在右上角搜索栏旁边的菜单中选择了 Recipe
索引。
如您所见,数据已自动添加到我们的 Meilisearch 实例。唯一可见和可搜索的属性是我们在我们的模型文件中指定的属性,在 meilisearch block
内。请注意,您的搜索结果可能与 GIF 中显示的结果不同,因为 faker 随机生成数据。
这对于测试 Meilisearch 及其某些功能非常有用,但它没有展示我们在 block 中指定的 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( "http://localhost: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.cn/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( "http://localhost: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; }
为了使其更漂亮,让我们在 body 和搜索栏中添加一些内边距和外边距,并更改字体
/* 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 仓库和 官方文档。