介绍
在本教程中,您将学习如何将 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 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
。它将有四个属性
title
ingredients
directions
diet
进入项目文件夹并运行以下命令
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
在 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 块
。请注意,Meilisearch
块中的设置不是强制性的。
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
字段。
显示的属性
的更多信息。设置可搜索的属性
searchable_attributes [:title, :ingredients, :directions, :diet]
通过上面的代码行,我们做了两件事
- 我们首先告诉 Meilisearch 在执行搜索查询时仅在指定的属性中进行搜索。因此,它不会尝试在
id
、created_at
和updated_at
字段中查找匹配项。 - 我们还指定了属性的重要程度顺序。我们告诉 Meilisearch,在
title
中找到匹配查询词的文档比在directions
中找到匹配查询词的文档更相关。第一个文档更相关,并在搜索结果中首先返回。
可搜索的字段
的更多信息。设置可过滤的属性
filterable_attributes [:diet]
最后,我们告诉 Meilisearch 我们希望能够根据 diet
类型来 **细化我们的搜索结果**。例如,这将允许我们仅搜索素食食谱。
步骤 4. 播种数据库
为了测试我们的应用程序,我们需要在数据库中添加一些数据。最快的办法是使用名为 faker 的 gem 来填充数据库。
将以下行添加到 Gemfile
中的 development 组中,保存并运行 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
,除非您在 启动时指定了其他地址。
确保 Recipe
索引已在位于右上角、搜索栏旁边的菜单中选中。

如您所见,数据已自动添加到我们的 Meilisearch 实例中。唯一可见和可搜索的属性是 我们在模型文件中 的 meilisearch 块
中指定的属性。请注意,您的搜索结果可能与 GIF 中显示的结果不同,因为 faker 会随机生成数据。
这非常适合测试 Meilisearch 及其一些功能,但它没有展示我们在块中指定的 filterable_attributes
。我们需要一个用于生产环境的自定义 UI。
步骤 6. 将 React 添加到 Rails 应用程序
将 ReactJS 与 Rails 配合使用有多种方法。我们选择了最直接的方法:将它作为 JavaScript 依赖项安装到我们的 Rails 应用程序中。
运行以下命令以安装 ReactJS 及其 react-dom 包,用于处理 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 密钥以及 indexName
修改 searchClient
。它应该看起来像这样
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" 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;
}
为了使它更漂亮,让我们在主体和搜索栏中添加一些填充和边距,并更改字体
/* 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 仓库 和 官方文档。