Créez un modèle pour stocker les informations de l'API Google Livres pour une manipulation et des tests intuitifs

Public cible

Ce que cet article atteint

Obtenez des informations de l'ID d'API Google Livres et stockez-les dans la classe

pry(main)> @google_book = GoogleBook.new_from_id('c1L4IzmUzicC')

pry(main)> @google_book.title
=> "Practical Rails Plugins"

pry(main)> @google_book.authors
=> ["Nick Plante", "David Berube"]

pry(main)> @google_book.image
=> "http://books.google.com/books/content?id=c1L4IzmUzicC&printsec=frontcover&img=1&zoom=5&edge=curl&imgtk=AFLRE73ENsMYFOfY27vluLqgI1cO-b80lA7enoeZzzcDGEhA5NWIj3djHvd6gvP1zlKoMoC4V0_7fKVuIjWQDYVs4FrDjHvxoqtRUcxHZ9L7isRtsHc2Cs5iS6DPAQQcTT20Oseo9gq_&source=gbs_api"

Rechercher par mot-clé et renvoyer plusieurs objets

pry(main)> @google_books = GoogleBook.search('Rails')

pry(main)> @google_books[0].title
=> "Rails d'entraînement"

pry(main)> @google_books.last.authors
=> ["Sam Ruby", "Dave Thomas", "David Heinemeier Hansson"]

pry(main)> @google_books.map { |google_book| google_book.title }
=> ["Rails d'entraînement",
 "Auto-apprentissage Ruby on Rails",
 "Recette de rails",
 "Ajax on Rails",
 "Programmation d'applications Ruby on Rails 4",
 "Comment utiliser Ruby on Rails 5 Méthode pratique de développement d'applications Rails enseignée par des ingénieurs de terrain",
 "Ruby on Rails 5 Super Primer",
 "Développement d'applications Web agiles avec Rails 3e édition",
 "Guide de développement pratique JRuby on Rails",
 "Développement d'applications Web agiles avec Rails 4e édition"]

pry(main)> @google_books.class
=> Array

Les informations stockées peuvent être enregistrées dans plusieurs tables


pry(main)> @google_book = GoogleBook.new_from_id('wlNHDwAAQBAJ')

pry(main)> @google_book.title                                   
=> "Comment utiliser Ruby on Rails 5 Méthode pratique de développement d'applications Rails enseignée par des ingénieurs de terrain"

pry(main)> @google_book.authors
=> ["Tomoaki Ota", "Shota Terashita", "Ryo Tezuka", "Ayumi Munezo", "Recruit Technologies Co., Ltd."]

pry(main)> @google_book.save
=> true


pry(main)> @book = Book.last

pry(main)> @book.title
=> "Comment utiliser Ruby on Rails 5 Méthode pratique de développement d'applications Rails enseignée par des ingénieurs de terrain"

pry(main)> @book.authors[0].name
=> "Tomoaki Ota"

pry(main)> @book.authors.size
=> 5

pry(main)> @book.authors.class
=> Author::ActiveRecord_Associations_CollectionProxy


pry(main)> @author = Author.last

pry(main)> @author.name
=> "Recruit Technologies Co., Ltd."

Quoi écrire dans cet article

Créez un modèle Google Book qui stocke les informations de l'API Google Books. Il y a deux avantages majeurs:

Cet article décrit également des exemples d'utilisation et des tests avec Controller.

Conception DB

La base de données stocke les informations suivantes sur le livre:

--"Titre" --"Auteur" --"URL de l'image"

Bien entendu, toute autre information trouvée dans l'API Google Livres peut être récupérée et enregistrée. Dans cet article, par souci d'explication, la quantité d'informations à acquérir est faible.

Diagramme ER

名称未設定ファイル.png

Préparez le tableau Livres et le tableau Auteurs. Puisqu'il peut y avoir plusieurs auteurs pour un livre, nous utiliserons la relation de livre has_many auteurs.

Cependant, vous souhaiterez peut-être afficher les auteurs représentatifs au lieu de tous les auteurs sur une page telle que "Liste des livres". Par conséquent, préparez la colonne «is_representative» dans la table des auteurs.

Vous vous demandez peut-être aussi: "Si vous souhaitez obtenir des informations de l'API Google Livres, vous n'avez pas besoin de les avoir dans votre propre base de données?" L'histoire de la conception et de l'échec est répertoriée ci-dessous. Conçu pour acquérir cette ressource uniquement avec l'API Google Books et a échoué

En résumé, la conclusion est que les informations contenues dans le livre devraient être conservées dans sa propre base de données.

Fichier de migration

Si vous créez un fichier de migration, il ressemblera à ce qui suit.

Table des livres

db/migrate/20202020202020_create_books


class CreateBooks < ActiveRecord::Migration[5.2]
  def change
    create_table :books do |t|
      t.string :google_books_api_id, null: false
      t.string :title, null: false
      t.string :image
      t.date :published_at

      t.timestamps
    end

    add_index :books, :googlebooksapi_id, unique: true
  end
end

L'ID d'API Google Livres est toujours requis, spécifiez donc null: false De plus, comme il est peu probable que l'ID d'API Google Livres soit dupliqué, attribuez-lui une clé unique.

Un livre qui n'a pas de titre est considéré comme inexistant, spécifiez donc null: false.

Au contraire, soyez prudent lorsque vous spécifiez null: false pour d'autres informations. Cela est dû au fait que les informations proviennent d'une API externe et que certains livres peuvent ne pas avoir ces informations, ce qui peut provoquer une situation dans laquelle «ne peut pas être enregistré dans la base de données».

Tableau des auteurs

db/migrate/20202020202021_create_authors


class CreateAuthors < ActiveRecord::Migration[5.2]
  def change
    create_table :authors do |t|
      t.references :book, foreign_key: true
      t.string :name, null: false
      t.boolean :is_representative, null: false

      t.timestamps
    end
  end
end

Méthode pour accéder à l'API Google Livres

Tout d'abord, ajoutez un module qui atteint l'API sous ʻapp / lib / `.

app/lib/google_books_api.rb


module GoogleBooksApi
  def url_of_creating_from_id(googlebooksapi_id)
    "https://www.googleapis.com/books/v1/volumes/#{googlebooksapi_id}"
  end
  #Obtenez l'URL de l'API à partir de l'ID d'API Google Livres

  def url_of_searching_from_keyword(keyword)
    "https://www.googleapis.com/books/v1/volumes?q=#{keyword}&country=JP"
  end
  #Obtenez l'URL de l'API à rechercher à partir du mot-clé

  def get_json_from_url(url)
    JSON.parse(Net::HTTP.get(URI.parse(Addressable::URI.encode(url))))
  end
  #Récupérez la chaîne JSON à partir de l'URL et créez l'objet JSON
end

Il existe deux types d'API Google Livres utilisés dans cet article.

https://www.googleapis.com/books/v1/volumes/:ID Vous pouvez l'obtenir par l'URL. L'URL suivante est un exemple. https://www.googleapis.com/books/v1/volumes/aB4B13xGEv4C

Si vous ne savez pas quelles informations vous pouvez obtenir de l'API Google Livres, consultez l'URL ci-dessus. Vous pouvez voir que vous pouvez obtenir des titres, des dates de publication, des liens d'achat, des ISBN, etc.

https://www.googleapis.com/books/v1/volumes?q=search?: Mot-clé Vous pouvez l'obtenir par l'URL. L'URL suivante est un exemple. https://www.googleapis.com/books/v1/volumes?q=search?Rails

Si vous souhaitez connaître d'autres spécifications de l'API Google Books, veuillez vous référer au document officiel. Getting Started

J'utilise une gemme appelée ʻaddressablepour échapper à l'URL. Ajoutez la gemme suivante au Gemfile et àbundle install`.

Gemfile


gem 'addressable'

Au fait, Rails charge automatiquement ʻapp / ** / **. Rb`. Par conséquent, vous pouvez utiliser les trois méthodes ci-dessus dans la classe tant que vous «incluez GoogleBooks Api» et «incluez» dans la classe que vous souhaitez utiliser.

Modèle pour stocker des informations

Créez un modèle qui stocke les informations de l'API Google Livres sous forme d'objet comme suit.

app/models/google_book.rb


class GoogleBook
  include ActiveModel::Model
  include ActiveModel::Attributes
  include ActiveModel::Validations

  attribute :googlebooksapi_id, :string
  attribute :authors
  attribute :image, :string
  attribute :published_at, :date
  attribute :title, :string

  validates :googlebooksapi_id, presence: true
  validates :title, presence: true

  class << self
    include GoogleBooksApi

    def new_from_item(item)
      @item = item
      @volume_info = @item['volumeInfo']
      new(
        googlebooksapi_id: @item['id'],
        authors: @volume_info['authors'],
        image: image_url,
        published_at: @volume_info['publishedDate'],
        title: @volume_info['title'],
      )
    end

    def new_from_id(googlebooksapi_id)
      url = url_of_creating_from_id(googlebooksapi_id)
      item = get_json_from_url(url)
      new_from_item(item)
    end

    def search(keyword)
      url = url_of_searching_from_keyword(keyword)
      json = get_json_from_url(url)
      items = json['items']
      return [] unless items

      items.map do |item|
        GoogleBook.new_from_item(item)
      end
    end

    private

    def image_url
      @volume_info['imageLinks']['smallThumbnail'] if @volume_info['imageLinks'].present?
    end
  end

  def save
    return false unless valid?

    book = build_book
    return false unless book.valid?

    ActiveRecord::Base.transaction do
      book.remote_image_url = image if image.present?
      book.save
      authors.each.with_index do |author, index|
        author = book.authors.build(name: author)
        author.is_representation = index.zero?
        author.save
      end
    end
    true
  end

  def find_book_or_save
    if Book.find_by(googlebooksapi_id: googlebooksapi_id) || save
      Book.find_by(googlebooksapi_id: googlebooksapi_id)
    else
      false
    end
  end

  private

  def build_book
    Book.new(
      googlebooksapi_id: googlebooksapi_id,
      published_at: published_at,
      title: title,
    )
  end
end

Ça fait longtemps lol Je vais expliquer un par un.

ActiveModel

  include ActiveModel::Model
  include ActiveModel::Attributes
  include ActiveModel::Validations

ActiveModel est comme "ActiveRecord qui ne fonctionne pas avec la base de données".

Guide de base des modèles actifs-Rails

Attribut ActiveModel

  attribute :googlebooksapi_id, :string
  attribute :authors
  (Ce qui suit est omis)

ʻActiveModel :: Attributes est ʻinclude, donc il peut être utilisé. ʻAuthors` est censé contenir un tableau, mais il semble qu'il n'y ait pas de type d'attribut correspondant au tableau, c'est donc la manière de l'écrire.

ActiveModel :: Attributes est trop bon.

ActiveModel valide

  validates :googlebooksapi_id, presence: true
  validates :title, presence: true

Il n'y a pas de livre sans identifiant de l'API Google Books et un livre sans titre (semble-t-il), alors mettez-y "validetes". Si un livre sans identifiant pour l'API Google Books est stocké en tant qu'objet, il peut renvoyer "false" lors de l'utilisation de la méthode "valid?". (Il sera décrit plus tard, mais il est utilisé dans la méthode save)

Comment définir une méthode de classe

  class << self

new_from_id est une méthode que vous souhaitez utiliser comme méthode de classe comme GoogleBook.new_from_id ('c1L4IzmUzicC'). Il existe d'autres moyens de définir des méthodes de classe, mais la méthode class << slef semble être recommandée.

Raison de la définition de la méthode de classe Ruby avec la classe << self (translation)

Créer une instance à partir d'un ID

    def new_from_id(googlebooksapi_id)
      url = url_of_creating_from_id(googlebooksapi_id)
      item = get_json_from_url(url)
      new_from_item(item)
    end

La commande est un peu en désordre, mais je vais expliquer new_from_id avant new_from_item.

Vous pouvez obtenir les informations (JSON) d'un livre comme ʻitem en utilisant ʻurl_of_creating_from_id et get_json_from_url du module Google Books Api mentionné ci-dessus. Passez cet élément à new_from_item.

Créer une instance à partir de ʻitem`

    def new_from_item(item)
      @item = item
      @volume_info = @item['volumeInfo']
      new(
        googlebooksapi_id: @item['id'],
        authors: @volume_info['authors'],
        image: image_url,
        published_at: @volume_info['publishedDate'],
        title: @volume_info['title'],
      )
    end

Comme vous pouvez le voir en observant le contenu de l'API Google Books, beaucoup d'informations se trouvent dans ʻitem ['volumeInfo'] . Définissez les informations que vous souhaitez récupérer comme il convient et utilisez new () pour créer une instance. Seule ʻimage_url est implémentée de la manière suivante.

Implémentation de ʻimage_url`

    private

    def image_url
      @volume_info['imageLinks']['smallThumbnail'] if @volume_info['imageLinks'].present?
    end

Certains livres ne contiennent pas volume_info ['imageLinks'], donc si vous essayez de l'utiliser avec juste volume_info ['imageLinks'] ['small Thumbnail'], vous obtiendrez une erreur de ʻundefind. il y a. Implémentez comme ci-dessus pour éviter d'émettre ʻundefind.

De plus, cette méthode ʻimage_url est peu susceptible d'être utilisée en dehors de la classe, alors définissez-la sous private`.

Une méthode de classe qui renvoie les résultats de la recherche sous forme de groupe d'instances

    def search(keyword)
      url = url_of_searching_from_keyword(keyword)
      json = get_json_from_url(url)
      items = json['items']
      return [] unless items

      items.map do |item|
        GoogleBook.new_from_item(item)
      end
    end

Si vous utilisez l'API Google Livres qui renvoie des résultats de recherche, vous obtiendrez plusieurs «éléments». ʻItems est sous la forme [item1, item2, item3, ...] ʻen tant que tableau. En faisant new_from_item (item) un par un dans la méthode map, il peut être retourné sous la forme d'un tableau [googlebook1, googlebook2, googlebook3, ...].

Si le mot-clé est inapproprié, l'API qui renvoie les résultats de la recherche ne renverra pas d''items, donc même dans ce cas, l'erreur ʻundefind se produira. Par conséquent, en insérant une ligne de return [] sauf items, si ʻitems` n'existe pas, un tableau vide est retourné.

L'explication de la méthode save et de la méthode find_book_or_save reste toujours, mais je pense qu'il est plus facile de comprendre d'abord comment l'utiliser dans le contrôleur, donc je voudrais passer à l'explication du contrôleur.

Exemple d'utilisation dans Controller

Je pense qu'il y a deux façons d'utiliser la classe GoogleBook: "écran de recherche" et "enregistrement des ressources (créer)".

routage

config/routes.rb


  resources :books, only: %i[create show], shallow: true do
    collection do
      get :search
    end
  end

Définissez à l'avance le routage ci-dessus. Je vais omettre l'explication car elle ne sera pas synchronisée avec la ligne principale.

Contrôleur d'écran de recherche

app/controllers/books_controller.rb


class BooksController < ApplicationController
  def search
    @search_form = SearchBooksForm.new(search_books_params)
    books = GoogleBook.search(@search_form.keyword)
    @books = Kaminari.paginate_array(books).page(params[:page])
  end

  private

  def search_books_params
    params.fetch(:q, keyword: '').permit(:keyword)
  end
end

Excusez-moi pour cet article, mais le formulaire de recherche est implémenté à la manière de l'article suivant. [Ruby on Rails] Envoyez les mots-clés de recherche au contrôleur à l'aide d'objets de formulaire

Transmettez le mot-clé de recherche reçu (@ search_form.keyword) à GoogleBook.search et recevez les résultats de la recherche sous forme de tableau d'instances générées à partir de la classe GoogleBook.

Après cela, c'est facultatif, mais je voulais afficher les résultats de la recherche dans la pagination de kaminari, alors je l'ai passé à Kaminari.paginate_array et je l'ai utilisé.

Contrôleur d'enregistrement de ressources ver.1 (exemple NG écrit uniquement avec des méthodes conventionnelles)

Voici ce que je veux faire.

app/models/google_book.rb


class BooksController < ApplicationController
  def create
    google_book = GoogleBook.new_from_id(create_book_params[:googlebooksapi_id])
    @book = Book.build(
              googlebooksapi_id: google_book.googlebooksapi_id,
              published_at: google_book.published_at,
              title: google_book.title,
            )
    if @book.valid?
      @book.remote_image_url = google_book.image if google_book.image.present?
      @book.save
      google_book.authors.each.with_index do |author, index|
        @author = @book.authors.build(name: author)
        @author.is_representation = index.zero?
        @author.save
      end
      redirect_to @book
    else
      redirect_to search_books_path, danger: 'Échec de l'affichage de la page'
    end
  end

  private

  def create_book_params
    params.permit(:googlebooksapi_id)
  end
end

Cependant, il existe divers problèmes avec la mise en œuvre ci-dessus.

--Il est devenu un gros contrôleur -Je n'ai pas joué de livres en double --Je ne peux pas utiliser ʻActiveRecord :: Base.transaction` même si j'enregistre des données pour plusieurs ressources.

En particulier, le problème du Fat Controller doit être traité. En premier lieu, je pense que le processus lié à l'enregistrement dans cette base de données est le processus dont le modèle «Google Book» est responsable. Par conséquent, nous définirons la logique de sauvegarde comme une méthode d'instance de GoogleBook.

Méthode Save qui réalise l'enregistrement sur plusieurs tables

app/models/google_book.rb


  def save
    return false unless valid?
    book = build_book

    ActiveRecord::Base.transaction do
      book.remote_image_url = image if image.present?
      book.save
      if authors.present?
        authors.each.with_index do |author, index|
          author = book.authors.build(name: author)
          author.is_representative = index.zero?
          author.save
        end
      end
    end
    true
  end

  private

  def build_book
    Book.new(
      googlebooksapi_id: googlebooksapi_id,
      published_at: published_at,
      title: title,
    )
  end

Je veux retourner «true» si la sauvegarde réussit et «false» si elle échoue pour qu'elle ressemble à la méthode «save» de «ActiveRecord». Par conséquent, dans une ligne de return false sauf si valide?, False est renvoyé quand il échoue avec valid?. Vous pouvez également retourner «true» en cas de succès en insérant une ligne de «true» à la fin du succès.

En l'enveloppant dans ʻActiveRecord :: Base.transaction, vous pouvez exécuter une restauration lorsque plusieurs ressources sont enregistrées et échouent au milieu. Dans ce cas, même si quelque chose ne va pas avec ʻauthor.save dans la seconde moitié, vous pouvez annuler la book.save dans la première moitié.

book.remote_image_url = image if image.present? est la logique de téléchargement d'images avec Carrierwave. Puisqu'il s'écarte de la ligne principale, je vais omettre l'explication cette fois.

ʻAuthor.is_representative = index.zero? Est-ce une ligne pour faire de l'auteur dans le premier index du tableau ʻauthors" l'auteur représentatif ". C'est aussi la raison pour laquelle nous utilisons ʻeach.with_index` pour transformer le tableau.

Contrôleur d'enregistrement des ressources ver.2 (l'enregistrement en double est effectué)

app/controllers/books_controller.rb


class BooksController < ApplicationController
  def create
    google_book = GoogleBook.new_from_id(create_book_params[:googlebooksapi_id])
    if google_book.save
      @book = Book.find_by(googlebooksapi_id: google_book.googlebooksapi_id)
      redirect_to @book
    else
      redirect_to search_books_path, danger: 'Échec de l'affichage de la page'
    end
  end

  private

  def create_book_params
    params.permit(:googlebooksapi_id)
  end
end

C'est assez rafraîchissant, mais il y a encore des problèmes. Il est possible que l'identifiant de l'API Google Books soit dupliqué, c'est-à-dire que le même livre sera enregistré.

Implémentation savoureuse de find_or_create_by

Ce que nous voulons réaliser est le suivant.

--Si le livre est déjà dans la table des livres, retournez le modèle correspondant à cet enregistrement

En termes de ʻActiveRecord, vous voulez obtenir un comportement similaire à find_or_create_by. En tant que méthode d'instance de GoogleBook, implémentez-la comme méthode find_book_or_save` comme suit.

app/models/google_book.rb


  def find_book_or_save
    if Book.find_by(googlebooksapi_id: googlebooksapi_id) || save
      Book.find_by(googlebooksapi_id: googlebooksapi_id)
    else
      false
    end
  end

Contrôleur d'enregistrement des ressources ver.3 (terminé)

app/controllers/books_controller.rb


class BooksController < ApplicationController
  def create
    google_book = GoogleBook.new_from_id(create_book_params[:googlebooksapi_id])
    if (@book = google_book.find_book_or_save)
      redirect_to @book
    else
      redirect_to search_books_path, danger: 'Échec de l'affichage de la page'
    end
  end

  private

  def create_book_params
    params.permit(:googlebooksapi_id)
  end
end

Ecrire un test avec RSpec

Il y a trois types de tests à traiter cette fois.

Je ne suis pas sûr de savoir comment écrire le test, alors j'ai hâte de vous signaler lol

Tester la méthode pour accéder à l'API Google Livres

spec/lib/google_books_api_spec.rb


require 'rails_helper'

describe GoogleBooksApi do
  let(:test_class) { Struct.new(:google_books_api) { include GoogleBooksApi } }
  let(:google_books_api) { test_class.new }

  it 'Vous pouvez obtenir un genre qui renvoie plusieurs données en appuyant sur l'API pour rechercher' do
    url = google_books_api.url_of_searching_from_keyword('Rails')
    expect(google_books_api.get_json_from_url(url)['kind']).to eq 'books#volumes'
  end

  it 'Vous pouvez obtenir un genre qui renvoie des données spécifiques en appuyant sur l'API pour obtenir des informations sur le livre à partir de ID' do
    GOOGLE_BOOKS_API_ID_SAMPLE = 'aB4B13xGEv4C'.freeze
    url = google_books_api.url_of_creating_from_id(GOOGLE_BOOKS_API_ID_SAMPLE)
    expect(google_books_api.get_json_from_url(url)['kind']).to eq 'books#volume'
    expect(google_books_api.get_json_from_url(url)['id']).to eq GOOGLE_BOOKS_API_ID_SAMPLE
  end
end

Pour savoir comment tester le module, je me suis référé au site suivant.

[Ruby on Rails] Même les débutants veulent faire des tests unitaires de méthodes! !!

Test du modèle de "Google Book"

Tout d'abord, définissez FactoryBot.

spec/factories/google_book.rb


FactoryBot.define do
  factory :google_book do
    googlebooksapi_id { 'wlNHDwAAQBAJ' }
    authors do
      [
        'Tomoaki Ota',
        'Shota Terashita',
        'Ryo Tezuka',
        'Ayumi Munezo',
        'Recruit Technologies Co., Ltd.'
      ]
    end
    image { 'http://books.google.com/books/content?id=wlNHDwAAQBAJ&printsec=frontcover&img=1&zoom=5&edge=curl&imgtk=AFLRE70j5lrdzOYN-iUu8w-G_JJKpEhnpUGAgqyZd7rj4jHu59NcAU48eQ75T4fkdyyZD6dMlwjjw0sAdQSKY_HiEdNBMMeyDn4DUmOcY-oLHFRAnxPXocc_T_PA7NYdSlZdwKckhCMy&source=gbs_api' }
    published_at { '2018-01-24' }
    title { 'Comment utiliser Ruby on Rails 5 Méthode pratique de développement d'applications Rails enseignée par des ingénieurs de terrain' }
  end
end

Rails sur place. Vient ensuite le corps principal du test du modèle.

app/models/google_book_spec.rb


require 'rails_helper'

RSpec.describe GoogleBook, type: :model do
  it 'Avoir une usine valide' do
    google_book = build(:google_book)
    expect(google_book).to be_valid
  end

  it 'Non valide lorsque l'ID d'API Google Livres n'existe pas' do
    google_book = build(:google_book, googlebooksapi_id: nil)
    google_book.valid?
    expect(google_book.errors.messages[:googlebooksapi_id]).to include('Entrez s'il vous plait')
  end

  it 'Invalide lorsque le titre n'existe pas' do
    google_book = build(:google_book, title: nil)
    google_book.valid?
    expect(google_book.errors.messages[:title]).to include('Entrez s'il vous plait')
  end

  it 'Être capable de générer l'instance souhaitée à partir de l'ID de l'API Google Livres' do
    googlebooksapi_id = 'YEfUBgAAQBAJ'
    google_book = GoogleBook.new_from_id(googlebooksapi_id)
    expect(google_book.title).to eq 'Programmation de jeux 2D à partir du support SpriteKit Swift'
    expect(google_book.googlebooksapi_id).to eq googlebooksapi_id
    expect(google_book.authors).to eq %w[Yoshitaka Yamashita Tomotsune Murata Tomoai Hara Hidehiko Kondo]
    expect(google_book.author).to eq 'Yoshitaka Yamashita'
  end

  it 'Renvoie plusieurs résultats de recherche à partir des mots-clés appropriés et le titre contient les mots-clés' do
    keyword = 'Ruby'
    keyword_count = 0
    google_books = GoogleBook.search(keyword)
    expect(google_books.size).to be >= 5 #Peut renvoyer 5 résultats de recherche ou plus
    google_books.each do |google_book|
      if google_book.title.include?(keyword)
        keyword_count += 1
      end
    end
    expect(keyword_count).to be >= 5 #Peut renvoyer 5 titres ou plus, y compris le mot-clé Ruby
  end

  it 'Ne pas renvoyer les résultats de recherche à partir de mots clés inappropriés' do
    keyword = 'bbvjnaovnaov' #adapté
    google_books = GoogleBook.search(keyword)
    expect(google_books.size).to be 0
  end

  describe 'Lors de la sauvegarde' do
    context 'Lorsque vous ne disposez que d'informations inappropriées' do
      let(:google_book) { build(:google_book, googlebooksapi_id: nil) }
      it 'Échec de l'enregistrement' do
        expect { google_book.save }.to change { Book.count }.by(0).and change { Author.count }.by(0)
      end
      it 'Retour faux' do
        expect(google_book.save).not_to be_truthy
      end
    end

    context 'Lorsque vous avez les bonnes informations' do
      let(:google_book) { build(:google_book, authors: [
                                  'Tomoaki Ota',
                                  'Shota Terashita',
                                  'Ryo Tezuka',
                                  'Ayumi Munezo',
                                  'Recruit Technologies Co., Ltd.'
                                ])
      }
      it 'Que peut-on sauver' do
        expect { google_book.save }.to change { Book.count }.by(1).and change { Author.count }.by(5)
      end
      it 'Revenir vrai' do
        expect(google_book.save).to be_truthy
      end
    end

    context 'Même si vous ne disposez pas uniquement des informations de l'auteur' do
      let(:google_book) { build(:google_book, authors: nil) }
      it 'Que peut-on sauver' do
        expect { google_book.save }.to change { Book.count }.by(1).and change { Author.count }.by(0)
      end
      it 'Revenir vrai' do
        expect(google_book.save).to be_truthy
      end
    end
  end
end

Je viens de tester la validation et chaque méthode, donc je ne pense pas que cela nécessite beaucoup d'explications.

Demander des spécifications lors de l'enregistrement d'un livre

spec/requests/books_spec.rb


require 'rails_helper'

RSpec.describe 'Books', type: :request do
  it 'Être en mesure d'enregistrer un livre qui est l'identifiant de l'API Google Livres appropriée' do
    expect {
      post '/books', params: { googlebooksapi_id: 'xPbRxgEACAAJ' }
    }.to change { Book.count }.by(1)
    expect(response).to redirect_to book_path(Book.last.id)
  end

  it 'Échec de l'enregistrement d'un livre qui a déjà été enregistré et passage à l'écran des détails' do
    same_google_books_api_id = 'xPbRxgEACAAJ'
    create(:book, googlebooksapi_id: same_google_books_api_id)
    expect {
      post '/books', params: { googlebooksapi_id: same_google_books_api_id }
    }.to change { Book.count }.by(0)
    expect(response).to redirect_to book_path(Book.find_by(googlebooksapi_id: same_google_books_api_id))
  end
end

Le contrôleur correspondant est celui du "Resource Registration Controller ver.3 (Completed)". ~~ Le test est facile et facile à expliquer ~~

C'est tout. Je voudrais l'améliorer, je vous serais donc reconnaissant de bien vouloir signaler les erreurs ou les domaines à améliorer.

Recommended Posts

Créez un modèle pour stocker les informations de l'API Google Livres pour une manipulation et des tests intuitifs
Créez une base de données propre pour les tests avec FastAPI et effectuez le test Unittest de l'API avec pytest
Créez une API REST à l'aide du modèle appris dans Lobe et TensorFlow Serving.
Créez une commande pour rechercher des composés similaires dans la base de données cible avec RDKit et vérifiez le temps de traitement
Créez une carte thermique de tweet avec l'API Google Maps
Comment publier un ticket depuis l'API Shogun
Obtenez des données de Poloniex, un bureau de change virtuel, via l'API et utilisez le Deep Learning pour prédire le prix du lendemain.
Créez un fichier audio avec la fonction de synthèse vocale de Google Text To Speak et vérifiez le texte comme guide de parole pendant 3 minutes.
Créez un script pour votre compétence Pepper dans une feuille de calcul et chargez SayText directement à partir du script
Analysez l'API Researchmap avec Python et créez automatiquement un fichier Word pour la liste des succès
Envoyer un message du serveur à l'extension Chrome à l'aide de Google Cloud Messaging pour Chrome
J'ai essayé d'obtenir diverses informations de l'API codeforces
Je veux créer un Dockerfile pour le moment.
Je veux obtenir des informations de fstab à la destination de la connexion ssh et exécuter la commande
[Affichage de la carte] Affichez une carte à partir de l'adresse enregistrée par l'utilisateur à l'aide de l'API JavaScript de Google Maps et de l'API de géocodage!
Créer une API qui renvoie les données d'un modèle à l'aide de turicreate
Créez un alias pour Route53 vers CloudFront avec l'API AWS
Comment obtenir des abonnés et des abonnés de Python à l'aide de l'API Mastodon
Créer une API REST pour faire fonctionner dynamodb avec le Framework Django REST
[Rails] google maps api Comment publier et afficher des informations cartographiques
Créez un arbre de décision à partir de 0 avec Python et comprenez-le (5. Entropie des informations)
Je souhaite créer une API qui retourne un modèle avec une relation récursive dans Django REST Framework
Comment enregistrer les informations de point caractéristique de l'image dans un fichier et l'utiliser pour la mise en correspondance
J'ai trouvé un moyen de créer un modèle 3D à partir d'une photo Partie 02 Chargement d'images et dessin de sommets
Créer un bot pour retweeter les informations sur le virus corona
Créez un modèle pour votre planning Django
Comment créer un référentiel à partir d'un média
[LINE Messaging API] Je souhaite envoyer un message du programme à tout le monde LINE
Utilisez la commande [shell] pour compresser par zip n'importe quel fichier pour créer un fichier et supprimer le fichier d'origine.
Comment utiliser OAuth et API de compte de service avec le client API Google pour python
Instructions pour connecter Google Colab. À l'environnement d'exécution local dans un environnement Windows
Créez un filtre pour obtenir un jeton d'accès avec l'API Graph (Flask)
J'ai essayé de créer un modèle avec l'exemple d'Amazon SageMaker Autopilot