Comment ajouter un puissant moteur de recherche à votre backend Rails

Photo par Simon Abrams sur Unsplash

En tant que développeur Ruby on Rails, j'ai souvent eu à ajouter des fonctionnalités de recherche aux applications Web. En fait, presque toutes les applications sur lesquelles j'ai travaillé à un moment donné avaient besoin de capacités de moteur de recherche, alors que beaucoup d'entre elles avaient un moteur de recherche comme fonctionnalité principale la plus importante.

De nombreuses applications que nous utilisons tous les jours seraient inutiles sans un moteur de recherche performant. Par exemple, sur Amazon, vous pouvez trouver un produit particulier parmi plus de 550 millions de produits disponibles sur le site en quelques secondes, le tout grâce à une recherche en texte intégral combinée à des filtres de catégorie, des facettes et un système de recommandation.

Sur Airbnb, vous pouvez rechercher un appartement en combinant une recherche géospatiale avec des filtres sur les caractéristiques de la maison, telles que la dimension, le prix, les dates disponibles, etc.

Et Spotify, Netflix, Ebay, Youtube… tous reposent fortement sur un moteur de recherche.

Dans cet article, je vais décrire comment développer un backend API Ruby on Rails 5 avec Elasticsearch. Selon DB Engines Ranking, Elasticsearch est actuellement la plate-forme de recherche open source la plus populaire.

Cet article n'abordera pas les détails d'Elasticsearch et sa comparaison avec ses concurrents comme Sphinx et Solr. Il s'agira plutôt d'un guide étape par étape expliquant comment implémenter un backend d'API JSON avec Ruby on Rails et Elasticsearch, à l'aide d'une approche de développement piloté par les tests.

Cet article couvrira:

  1. Elasticsearch Setup pour les environnements de test, de développement et de production
  2. Configuration de l'environnement de test Ruby on Rails
  3. Indexation de modèles avec Elasticsearch
  4. Point de terminaison de l'API de recherche

Comme dans mon article précédent, Comment améliorer vos performances avec une architecture sans serveur, je vais tout décrire dans un didacticiel détaillé. Ensuite, vous pouvez l’essayer vous-même et disposer d’un exemple de travail simple pour construire quelque chose de plus complexe.

L'exemple d'application sera un moteur de recherche de film. Il aura un seul point de terminaison API JSON qui vous permettra d'effectuer une recherche en texte intégral sur les titres et les aperçus du film.

1. Configuration d'Elasticsearch

Elasticsearch est un moteur de recherche et d'analyse RESTful distribué capable de résoudre un nombre croissant de cas d'utilisation. En tant que cœur d’Elastic Stack, il stocke de manière centralisée vos données afin que vous puissiez découvrir ce qui est attendu et découvrir l’imprévu. - www.elastic.co/products/elasticsearch

Selon le classement des moteurs de recherche de DB-Engines, Elasticsearch est de loin la plate-forme de moteur de recherche la plus populaire à ce jour (en avril 2018). Et cela fait depuis fin 2015, lorsque Amazon a annoncé le lancement de AWS Elasticsearch Service, un moyen de démarrer un cluster Elasticsearch à partir de la console de gestion AWS.

Tendance du classement des moteurs de recherche DB

Elasticsearch est opensource. Vous pouvez télécharger votre version préférée de leur site Web et l'exécuter où vous le souhaitez. Bien que je suggère d'utiliser AWS Elasticsearch Service pour les environnements de production, je préfère laisser Elasticsearch s'exécuter sur ma machine locale pour les tests et le développement.

Commençons par télécharger la version la plus récente (actuellement) Elasticsearch (6.2.3) et décompressez-la. Ouvrir un terminal et courir

$ wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.2.3.zip
$ unzip elasticsearch-6.2.3.zip

Vous pouvez également télécharger Elasticsearch à partir de votre navigateur ici et le décompresser avec votre programme préféré.

2. Configuration de l'environnement de test

Nous allons créer une application dorsale avec l’API de Ruby on Rails 5. Il aura un modèle qui représente les films. Elasticsearch l'indexera, ce qui sera consultable via un noeud final d'API.

Tout d’abord, créons une nouvelle application de rails. Dans le même dossier que vous avez déjà téléchargé Elasticsearch, exécutez la commande permettant de générer une nouvelle application rails. Si vous débutez avec Ruby on Rails, veuillez vous reporter à ce guide de démarrage pour configurer votre environnement en premier.

$ rails new movies-search --api; cd films-recherche

Lorsque vous utilisez l'option «api», tous les middlewares utilisés principalement pour les applications de navigateur ne sont pas inclus. Exactement ce que nous voulons. En savoir plus à ce sujet directement sur le guide ruby ​​on rails.

Ajoutons maintenant toutes les gemmes dont nous aurons besoin. Ouvrez votre Gemfile et ajoutez le code suivant:

# Gemfile
...
# Intégration Elasticsearch
gem 'elasticsearch-model'
gem 'elasticsearch-rails'
groupe: développement,: test do
  ...
  # Cadre de test
  gem 'rspec'
  gem 'rspec-rails'
fin
groupe: test do
  ...
  # Nettoyer la base de données entre les tests
  gem 'database_cleaner'
  # Démarrer et arrêter par programme ES pour les tests
  gem 'elasticsearch-extensions'
fin
...

Nous ajoutons deux gemmes Elasticsearch qui fourniront toutes les méthodes nécessaires pour indexer notre modèle et exécuter des requêtes de recherche sur celui-ci. rspec, rspec-rails, database_cleaner et elasticsearch-extensions sont utilisés pour les tests.

Après avoir sauvegardé votre Gemfile, lancez l’installation groupée pour installer tous les Gems ajoutés.

Maintenant, configurons Rspec en lançant la commande suivante:

les rails génèrent rspec: install

Cette commande créera un dossier de spécification et y ajoutera spec_helper.rb et rails_helper.rb. Ils peuvent être utilisés pour personnaliser rspec en fonction des besoins de votre application.

Dans ce cas, nous allons ajouter un bloc DatabaseCleaner à rails_helper.rb afin que chaque test s’exécute dans une base de données vide. De plus, nous modifierons spec_helper.rb afin de démarrer un serveur de test Elasticsearch à chaque démarrage de la suite de tests et de le fermer à nouveau une fois la suite de tests terminée.

Cette solution est basée sur l’article de Rowan Oulton, Testing Elasticsearch in Rails. Beaucoup d'applaudissements pour lui!

Commençons par DatabaseCleaner. Dans spec / rails_helper.rb, ajoutez le code suivant:

# spec / rails_helper.rb
...
RSpec.configure do | config |
  ...
config.before (: suite) do
    DatabaseCleaner.strategy =: transaction
    DatabaseCleaner.clean_with (: troncation)
  fin
config.around (: each) faire | exemple |
    DatabaseCleaner.cleaning do
      exemple.run
    fin
  fin
fin

Ensuite, considérons la configuration du serveur de test Elasticsearch. Nous devons ajouter des fichiers de configuration pour que Rails sache où trouver notre exécutable Elasticsearch. Il indiquera également sur quel port nous voulons l’exécuter, en fonction de l’environnement actuel. Pour ce faire, ajoutez une nouvelle configuration yaml à votre dossier de configuration:

# config / elasticsearch.yml
développement: & default
  es_bin: '../elasticsearch-6.2.3/bin/elasticsearch'
  hôte: 'http: // localhost: 9200'
  port: '9200'
tester:
  es_bin: '../elasticsearch-6.2.3/bin/elasticsearch'
  hôte: 'http: // localhost: 9250'
  port: '9250'
mise en scène:
  <<: * défaut
production:
  es_bin: '../elasticsearch-6.2.3/bin/elasticsearch'
  hôte: 'http: // localhost: 9400'
  port: '9400'

Si vous n'avez pas créé l'application Rails dans le même dossier que celui où vous avez téléchargé Elasticsearch, ou si vous utilisez une version différente d'Elasticsearch, vous devrez ajuster le chemin es_bin ici.

Maintenant, ajoutez un nouveau fichier dans votre dossier d’initialisation qui lira à partir de la configuration que nous venons d’ajouter:

# config / initializers / elasticsearch.rb
si File.exists? ("config / elasticsearch.yml")
   config = YAML.load_file ("config / elasticsearch.yml") [Rails.env] .symbolize_keys
   Elasticsearch :: Model.client = Elasticsearch :: Client.new (config)
fin

Enfin, modifions spec_helper.rb pour inclure la configuration de test Elasticsearch. Cela signifie qu'il faut démarrer et arrêter un serveur de test Elasticsearch et créer / supprimer des index Elasticsearch pour notre modèle Rails.

# spec / spec_helper.rb
nécessite 'elasticsearch / extensions / test / cluster'
besoin de 'yaml'
RSpec.configure do | config |
  ...
  # Démarrer un cluster en mémoire pour Elasticsearch si nécessaire
  es_config = YAML.load_file ("config / elasticsearch.yml") ["test"]
  ES_BIN = es_config ["es_bin"]
  ES_PORT = es_config ["port"]
config.before: all, elasticsearch: true do
    Elasticsearch :: Extensions :: Test :: Cluster.start (commande: ES_BIN, port: ES_PORT.to_i, noeuds: 1, délai d'expiration: 120) sauf si Elasticsearch :: Extensions :: Test :: Cluster.running? (Commande: ES_BIN, sur: ES_PORT.to_i)
  fin
# Arrêtez le cluster elasticsearch après le test
  config.after: suite do
    Elasticsearch :: Extensions :: Test :: Cluster.stop (commande: ES_BIN, port: ES_PORT.to_i, noeuds: 1) si Elasticsearch :: Extensions :: Test :: Cluster.running? (Commande: ES_BIN, sur: ES_PORT. to_i)
  fin
# Créer des index pour tous les modèles de recherche élastiques
  config.before: each, elasticsearch: true do
    ActiveRecord :: Base.descendants.each do | model |
      si model.respond_to? (: __ elasticsearch__)
        commencer
          modèle .__ elasticsearch __. create_index!
          modèle .__ elasticsearch __. refresh_index!
        rescue => Elasticsearch :: Transport :: Transport :: Errors :: NotFound
          # Cela tue les erreurs "Index n'existe pas" en cours d'écriture sur la console
        sauvetage => e
          STDERR.puts "Une erreur s'est produite lors de la création de l'index elasticsearch pour # {model.name}: # {e.inspect}"
        fin
      fin
    fin
  fin
# Supprimer les index de tous les modèles de recherche élastiques pour assurer un état de propreté entre les tests
  config.after: each, elasticsearch: true do
    ActiveRecord :: Base.descendants.each do | model |
      si model.respond_to? (: __ elasticsearch__)
        commencer
          modèle .__ elasticsearch __. delete_index!
        rescue => Elasticsearch :: Transport :: Transport :: Errors :: NotFound
          # Cela tue les erreurs "Index n'existe pas" en cours d'écriture sur la console
        sauvetage => e
          STDERR.puts "Une erreur s'est produite lors de la suppression de l'index elasticsearch pour # {model.name}: # {e.inspect}"
        fin
      fin
    fin
  fin
fin

Nous avons défini quatre blocs:

  1. un bloc before (: all) qui démarre un serveur de test Elasticsearch, sauf s'il est déjà en cours d'exécution
  2. un bloc after (: suite) qui arrête le serveur de test Elasticsearch, s'il est en cours d'exécution
  3. un bloc before (: each) qui crée un nouvel index Elasticsearch pour chaque modèle configuré avec Elasticsearch
  4. un bloc after (: each) qui supprime tous les index Elasticsearch

Ajouter elasticsearch: true garantit que seuls les tests marqués avec elasticsearch exécuteront ces blocs.

Je trouve que cette configuration fonctionne très bien lorsque vous exécutez tous vos tests une fois, par exemple avant un déploiement. Par contre, si vous utilisez une approche de développement piloté par les tests et que vous exécutez vos tests très souvent, vous devrez probablement modifier légèrement cette configuration. Vous ne souhaitez pas démarrer et arrêter votre serveur de test Elasticsearch à chaque exécution de test.

Dans ce cas, vous pouvez commenter le bloc after (: suite) où le serveur de test est arrêté. Vous pouvez l’arrêter manuellement ou à l’aide d’un script chaque fois que vous n’en avez plus besoin.

nécessite 'elasticsearch / extensions / test / cluster'
es_config = YAML.load_file ("config / elasticsearch.yml") ["test"]
ES_BIN = es_config ["es_bin"]
ES_PORT = es_config ["port"]
Elasticsearch :: Extensions :: Test :: Cluster.stop (commande: ES_BIN, port: ES_PORT.to_i, noeuds: 1)

3. Indexer les modèles avec Elasticsearch

Nous commençons maintenant à implémenter notre modèle de film avec des capacités de recherche. Nous utilisons une approche de développement piloté par les tests. Cela signifie que nous écrivons d'abord les tests, les voyons échouer, puis écrivons du code pour les faire passer.

Nous devons d’abord ajouter le modèle de film qui comporte quatre attributs: un titre (String), une vue d'ensemble (Texte), un image_url (String) et une valeur de vote moyenne (Float).

$ rails g model Titre du film: string overview: text image_url: string vote_average: float
$ rails db: migrer

Il est maintenant temps d’ajouter Elasticsearch à notre modèle. Écrivons un test qui vérifie que notre modèle est indexé.

# spec / models / movie_spec.rb
nécessite 'rails_helper'
RSpec.describe Movie, elasticsearch: true,: type =>: model do
  il 'devrait être indexé' do
     s'attendre à (Movie .__ elasticsearch __. index_exists?). to be_truthy
  fin
fin

Ce test vérifie si un index elasticsearch a été créé pour Movie. N'oubliez pas qu'avant le début des tests, nous créons automatiquement un index elasticsearch pour tous les modèles répondant à la méthode __elasticsearch__. Cela signifie pour tous les modèles qui incluent les modules elasticsearch.

Exécutez le test pour le voir échouer.

bundle exec rspec spec / models / movie_spec.rb

La première fois que vous exécutez ce test, vous devriez voir que le serveur de test Elasticsearch est en train de démarrer. Le test échoue car nous n’avons ajouté aucun module Elasticsearch à notre modèle Movie. Laissez-nous réparer cela maintenant. Ouvrez le modèle et ajoutez Elasticsearch suivant à inclure:

# app / models / movie.rb
class Movie 

Cela ajoutera quelques méthodes Elasticsearch à notre modèle Movie, telles que la méthode __elasticsearch__ manquante (qui a généré l'erreur lors du test précédent) et la méthode de recherche que nous utiliserons plus tard.

Exécutez le test à nouveau et voyez-le passer.

bundle exec rspec spec / models / movie_spec.rb

Génial. Nous avons un modèle de film indexé.

Par défaut, Elasticsearch :: Model configurera un index avec tous les attributs du modèle, en déduisant automatiquement leurs types. D'habitude ce n'est pas ce que nous voulons. Nous allons maintenant personnaliser l'index du modèle afin qu'il présente le comportement suivant:

  1. Seuls le titre et l'aperçu doivent être indexés
  2. La création de racines doit être utilisée (ce qui signifie que la recherche d '"acteurs" doit également renvoyer les films contenant le texte "acteur", et inversement)

Nous souhaitons également que notre index soit mis à jour chaque fois qu'un film est ajouté, mis à jour ou supprimé.

Traduisons cela en tests en ajoutant le code suivant à movie_spec.rb

# spec / models / movie_spec.rb
RSpec.describe Movie, elasticsearch: true,: type =>: model do
  ...
décrire '#search' do
    avant (: chacun) faire
      Movie.create (
        titre: "Vacances romaines",
        aperçu: "Un film américain de comédie romantique de 1953 ...",
        image_url: "wikimedia.com/Roman_holiday.jpg",
        vote_average: 4.0
      )
      Film .__ elasticsearch __. Refresh_index!
    fin
    il "devrait indexer le titre" faire
      expect (Movie.search ("Vacances"). records.length) .to eq (1)
    fin
    il "devrait indexer la vue d'ensemble" faire
      expect (Movie.search ("comédie"). records.length) .to eq (1)
    fin
    il "ne devrait pas index image_path" do
      expect (Movie.search ("Roman_holiday.jpg"). records.length) .to eq (0)
    fin
    il "ne devrait pas indexer vote_average" do
      expect (Movie.search ("4.0"). records.length) .to eq (0)
    fin
  fin
fin

Nous créons un film avant chaque test, car nous avons configuré DatabaseCleaner pour que chaque test soit isolé. Film .__ elasticsearch __. Refresh_index! est nécessaire pour être sûr que le nouvel enregistrement est immédiatement disponible pour la recherche.

Comme auparavant, lancez le test et constatez son échec.

On dirait que notre film n'est pas indexé. C’est parce que nous n’avons pas encore dit à notre modèle ce qu’il faut faire lorsque les données du film changent. Heureusement, cela peut être corrigé en ajoutant un autre module à notre modèle de film:

class Movie 

Avec Elasticsearch :: Model :: Callbacks, chaque fois qu'un film est ajouté, modifié ou supprimé, son document sur Elasticsearch est également mis à jour.

Voyons comment la sortie du test change.

D'accord. Le problème est que notre méthode de recherche renvoie également des requêtes correspondant aux attributs vote_average et image_url. Pour résoudre ce problème, nous devons configurer le mappage d'index Elasticsearch. Nous devons donc indiquer précisément à Elasticsearch les attributs de modèle à indexer.

# app / models / movie.rb
class Movie 
# ElasticSearch Index
  index des paramètres: {number_of_shards: 1} do
    mappages dynamiques: 'false' do
      index: titre
      index: vue d'ensemble
    fin
  fin
fin

Exécutez le test à nouveau et voyez-le passer.

Cool. Ajoutons maintenant un radical pour qu’il n’y ait aucune différence entre «acteur» et «acteur». Comme toujours, nous allons d’abord écrire le test et le voir échouer.

décrire '#search' do
    avant (: chacun) faire
      Movie.create (
        titre: "Vacances romaines",
        aperçu: "Un film américain de comédie romantique de 1953 ...",
        image_url: "wikimedia.com/Roman_holiday.jpg",
        vote_average: 4.0
      )
      Film .__ elasticsearch __. Refresh_index!
    fin
...
il "devrait s'appliquer à la suite du titre" do
      expect (Movie.search ("Vacances"). records.length) .to eq (1)
    fin
il "devrait s'appliquer stemming to overview" do
      expect (Movie.search ("film"). records.length) .to eq (1)
    fin
fin

Notez que nous testons les deux manières: les vacances devraient aussi revenir en vacances, et le film devrait également renvoyer les films.

Pour que ces tests passent à nouveau, nous devons modifier le mappage d'index. Nous le ferons cette fois en ajoutant un analyseur anglais aux deux champs:

class Movie 
# ElasticSearch Index
  index des paramètres: {number_of_shards: 1} do
    mappages dynamiques: 'false' do
      index: titre, analyseur: 'anglais'
      index: vue d'ensemble, analyseur: 'anglais'
    fin
  fin
fin

Exécutez à nouveau vos tests pour les voir réussir.

Elasticsearch est une plate-forme de recherche très puissante et nous pourrions ajouter de nombreuses fonctionnalités à notre méthode de recherche. Mais cela n’entre pas dans le cadre de cet article. Nous allons donc nous arrêter ici et passer à la construction de la partie contrôleur de l'API JSON par laquelle la méthode de recherche est utilisée.

4. Point de terminaison de l'API de recherche

L'API de recherche que nous construisons devrait permettre aux utilisateurs d'effectuer une recherche en texte intégral sur la table Movies. Notre API a un seul point de terminaison défini comme suit:

URL:
 GET / api / v1 / films
Paramètres:
 * q = [chaîne] obligatoire
Exemple d'URL:
 GET / api / v1 / movies? Q = Roma
Exemple de réponse:
[{"_index": "movies", "_ type": "movie", "_ id": "95088", "_ score": 11.549209, "_ source": {"id": 95088, "titre": "Rome" , "overview": "Un portrait impressionniste de la ville à travers le regard de l’un de ses citoyens les plus célèbres.", "image_url": "https://image.tmdb.org/t/p/w300/ rqK75R3tTz2iWU0AQ6tLz3KMOU1.jpg "," vote_average ": 6.6," created_at ":" 2018-04-14T10: 30: 49.110Z "," updated_at ":" 2018-04-14T10: 30: 49.110Z "}}, ... ]

Nous définissons ici notre point de terminaison en fonction de certaines meilleures pratiques. Conception d’API RESTful:

  1. L'URL doit coder l'objet ou la ressource, tandis que l'action à entreprendre doit être codée par la méthode HTTP. Dans ce cas, la ressource est constituée des films (collection) et nous utilisons la méthode HTTP GET (car nous demandons des données à la ressource sans produire d’effet secondaire). Nous utilisons des paramètres d'URL pour définir plus précisément comment ces données doivent être obtenues. Dans cet exemple, q = [chaîne], qui spécifie une requête de recherche. Pour en savoir plus sur la conception d’API RESTful, consultez l’article de Mahesh Haldar intitulé Directives de création d’API RESTful - Meilleures pratiques.
  2. Nous ajoutons également des versions à notre API en ajoutant v1 à notre URL de point de terminaison. La gestion des versions de votre API est très importante car elle vous permet d'introduire de nouvelles fonctionnalités incompatibles avec les versions précédentes sans détruire tous les clients développés pour les versions précédentes de votre API.

D'accord. Commençons par la mise en œuvre.

Comme toujours, nous commençons par des tests infructueux. Dans le dossier de spécifications, nous allons créer la structure de dossiers qui reflète la structure de notre URL d'URL de point de terminaison API. Cela signifie contrôleurs → api → v1 → movies_spec.rb

Vous pouvez le faire manuellement ou à partir de votre terminal en exécutant:

mkdir -p spec / controllers / api / v1 &&
appuyez sur spec / controllers / api / v1 / movies_spec.rb

Les tests que nous allons écrire ici sont des tests de contrôleurs. Ils n'ont pas besoin de vérifier la logique de recherche définie dans le modèle. Au lieu de cela, nous allons tester trois choses:

  1. Une requête GET à / api / v1 / movies? Q = [chaîne] appellera Movie.search avec le paramètre [chaîne]
  2. La sortie de Movie.search est renvoyée au format JSON.
  3. Un statut de réussite est retourné
Un test de contrôleur doit tester le comportement du contrôleur. Un test de contrôleur ne doit pas échouer à cause de problèmes dans le modèle.
(Prescription 20 - Prescriptions de test Rails 4. Noel Rappin)

Transformons cela en code. Dans spec interne / controllers / api / v1 / movies_spec.rb, ajoutez le code suivant:

# spec / controllers / api / v1 / movies_spec.rb
nécessite 'rails_helper'
RSpec.describe Api :: V1 :: MoviesController, tapez:: request do
  # Rechercher un film avec le titre du film
  décrire "GET / api / v1 / movies? q =" do
    let (: title) {"titre du film"}
    let (: url) {"/ api / v1 / movies? q = # {titre}"}
il "appelle Movie.search avec les paramètres corrects"
      attendre (Film). à recevoir (: recherche) .with (titre)
      obtenir l'URL
    fin
il "retourne la sortie de Movie.search" do
      autoriser (film). à recevoir (: recherche) .et_retourner ({})
      obtenir l'URL
      expect (response.body) .to eq ({}. to_json)
    fin
il 'retourne un statut de réussite' do
      autoriser (Film). à recevoir (: recherche) .avec (titre)
      obtenir l'URL
      attendre (réponse) .to être_succès
    fin
  fin
fin

Le test échouera immédiatement car Api :: V1 :: MoviesController n’est pas défini. Commençons donc par le faire. Créez la structure de dossiers comme auparavant et ajoutez le contrôleur de films.

mkdir -p app / controllers / api / v1 &&
appuyez sur app / controllers / api / v1 / movies_controller.rb

Ajoutez maintenant le code suivant à app / controllers / api / v1 / movies_controller.rb:

# app / controllers / api / v1 / movies_controller.rb
module Api
  module V1
    class MoviesController 

Il est temps de lancer notre test et de le voir échouer.

Tous les tests échouent car nous devons encore ajouter une route pour le noeud final. Dans config / routes.rb, ajoutez le code suivant:

# config / routes.rb
Rails.application.routes.draw do
  espace de noms: api do
    espace de noms: v1 do
      ressources: films, seulement: [: index]
    fin
  fin
fin

Relancez vos tests et voyez ce qui se passe.

La première erreur nous dit que nous devons ajouter un appel à Movie.search dans notre contrôleur. Le second se plaint de la réponse. Ajoutons le code manquant au movies_controller:

# app / controllers / api / v1 / movies_controller.rb
module Api
  module V1
    class MoviesController 

Exécutez le test et voyez si nous avons terminé.

Ouaip. C'est tout. Nous avons mis au point une application backend vraiment basique permettant aux utilisateurs de rechercher un modèle via une API.

Vous pouvez trouver le code complet sur mon dépôt GitHub ici. Vous pouvez remplir votre table de films avec certaines données en exécutant rails db: seed afin de voir l'application en action. Cela importera environ 45 000 films à partir d’un ensemble de données téléchargé de Kaggle. Consultez le fichier Lisez-moi pour plus de détails.

Si vous avez aimé cet article, merci de le recommander en cliquant sur l’icône clap que vous trouverez au bas de cette page afin que davantage de personnes puissent le voir sur Medium.