5 dæmi um bestu notkun Ruby
Hefurðu einhvern tíma velt því fyrir þér hvað við getum gert með Ruby? Jæja, loftið er líklega takmörkin, en við erum fús til að segja frá nokkrum meira eða minna þekktum dæmum...
Við munum búa til bókahillu-app sem skráir bækur með (eða án) höfundagagna.
Hér er tómt.Við munum búa til bókahillu-app sem skráir bækur með (eða án) höfunda gögn. Það verður eitt #vísitala aðgerð og nokkur fræ. Þetta verður dæmi um forrit til að sýna hvernig þú getur gefið notanda stjórn á inniföldu undirauðlindir í REST-líkum forritaskil.
innifelur Fyrirspurnarparametri til að hlaða tengdum auðlindum (höfundur).innifelur Símtaksparametrinn hefur sniðið streng: kommur aðskilin orð sem tákna innfelldar auðlindir.Við munum nota bláprentari sem serializer, vegna þess að hann er formatiðlaus og nokkuð sveigjanlegur. Þetta er eina gemmið sem við munum bæta við staðlaða verkfærakistu Rails.
Búum til dæmisforrit. Við bætum ekki við prófunarramma þar sem það er utan okkar verksviðs.
járnbrautir ný bókaskápur -T
Nú búa til Höfundur líkan:
rails g model author name:string
#=> invoke active_record
#=> create db/migrate/20211224084524_create_authors.rb
#=> create app/models/author.rb
Og Bók:
rails g model book author:references title:string
# => invoke active_record
# => create db/migrate/20211224084614_create_books.rb
# => create app/models/book.rb
Við munum þurfa nokkur fræ:
# db/seeds.rb
dumas = Author.create(name: 'Alexandre Dumas')
lewis = Author.create(name: 'C.S. Lewis')
martin = Author.create(name: 'Robert C. Martin')
Book.create(author: dumas, title: 'The Three Musketeers')
Book.create(author: lewis, title: 'The Lion, the Witch and the Wardrobe')
Book.create(author: martin, title: 'Clean Code')
Og nú erum við tilbúin að keyra flutninga og fræa gagnagrunninn:
rails db:migrate && rails db:seed
Bætum við á marga fyrir bækur í Höfundur líkan:
# app/models/author.rb
class Author < ApplicationRecord
has_many :books
end
Það er kominn tími til að skrifa stjórnanda sem skilar gögnum okkar. Við munum nota forritaskil Nafnorðarrými, svo skulum við fyrst bæta skammstöfun við beygingar:
# config/initializers/inflections.rb
ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.acronym 'API'
end
Ok, skulum bæta við serializerinn okkar við Gems-skrá:
# Bæta við Gemfile
gem 'blueprinter'
Og auðvitað skaltu setja það upp:
Sjálfvirk uppsetning
Þá getum við smíðað uppdrættina okkar:
# app/blueprints/author_blueprint.rb
class AuthorBlueprint < Blueprinter::Base
identifier :id
fields :name
end
# app/blueprints/book_blueprint.rb
class BookBlueprint < Blueprinter::Base
identifier :id
fields :title
association :author, blueprint: AuthorBlueprint
end
Bættu við grunnstjóra fyrir forritaskil:
# app/controllers/api/v1/base_controller.rb
module API
module V1
class BaseController < ActionController::API
end
end
end
Og drögin af okkar BókaStýring:
# app/controllers/api/v1/books_controller.rb
module API
module V1
class BooksController < BaseController
def index
books = Book.all
render json: BookBlueprint.render(books)
end
end
end
end
Við verðum einnig að skilgreina leiðarvalið auðvitað:
# config/routes.rb
Rails.application.routes.draw do
namespace :api do
namespace :v1 do
resources :books, only: :index
end
end
end
Skoðum hvað við höfum gert hingað til:
járnbrautir s
curl http://localhost:3000/api/v1/books
# => [{"id":1,"author":{"id":1,"name":"Alexandre Dumas"},"title":"Þrír muskétumennirnir"},{"id":2,"author":{"id":2,"name":"C.S. Lewis"},"title":"The Lion, the Witch and the Wardrobe"},{"id":3,"author":{"id":3,"name":"Robert C. Martin"},"title":"Clean Kóði"}]
Gögnin virðast vera í lagi, hvað með skráningar?
# beiðnisdagbók (n+1)
Byrjað GET "/api/v1/books" fyrir 127.0.0.1 kl. 2021-12-24 10:19:40 +0100
Unnið af API::V1::BooksController#index sem */*
Bóka hleðsla (0.1ms) SELECT "books".* FROM "books"
↳ app/controllers/api/v1/books_controller.rb:7:in `index'
Höfundar hleðsla (0.1ms) SELECT "authors".* FROM "authors" WHERE "authors"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
↳ app/controllers/api/v1/books_controller.rb:7:in `index'
Höfundur hlaðinn (0,1 ms) SELECT "authors".* FROM "authors" WHERE "authors"."id" = ? LIMIT ? [["id", 2], ["LIMIT", 1]]
↳ app/controllers/api/v1/books_controller.rb:7:in `index'
Hleðsla höfundar (0.1ms) SELECT "authors".* FROM "authors" WHERE "authors"."id" = ? LIMIT ? [["id", 3], ["LIMIT", 1]]
↳ app/controllers/api/v1/books_controller.rb:7:in `index'
Completed 200 OK in 6ms (Views: 0.1ms | ActiveRecord: 0.4ms | Allocations: 3134)
Með því að nota tengingu í serializerunum okkar kynntum við n+1 vandamál. Við viljum útrýma því með því að bæta við notanda stjórn á því hvað hann biður um í þessum enda punkti. Svo ætti hann að geta annaðhvort hlaðið eingöngu bækur eða sent includes-breytuna og fengið höfunda líka, en helst án n+1.
Skulum skilgreina fasti sem mun geyma upplýsingar um hvaða tengdar bækur notandi getur bætt við bækur#vísitala aðgerð:
# lib/constants/books/includes.rb
module Constants
module Books
module Includes
ALLOWED = {
index: %i[
author
].freeze
}.freeze
end
end
end
Næst skilgreinum við nafnarými fyrir tómar hlutastöðugar breytur:
# lib/constants/empty.rb
module Constants
module Empty
HASH = {}.freeze
end
end
Og hér er aðalþjónustan okkar fyrir leyfisveitingar. Ég held að kóðinn sé nokkuð sjálfskýrandi, nokkrir hlutar af galdur eru aðeins úthlutaðar í #gagnaupplýsingalykill_sjálfgefið og #default_purpose. Þessar aðferðir eru skilgreindar til að leyfa okkur Til að kalla leyfi felur í sér að senda eingöngu breytur í Rails-stjórnendum. Úttakið verður hashinn sem geymir sannur fyrir hverja leyfða innlimun.
# app/services/permit_includes.rb
require 'constants/empty'
require 'constants/books/includes'
class PermitIncludes
Empty = Constants::Empty
COMMA = ','
SLASH = '/'
INCLUDES_FORMAT = /A[a-z]+(,[a-z]+)*z/.freeze
ALLOWED_INCLUDES = {
books: Constants::Books::Includes::ALLOWED
}.freeze
def call(params, resources: default_resources_key(params), purpose: default_purpose(params))
return Empty::HASH unless includes_sent?(params)
return Empty::HASH unless includes_valid?(params)
requested_includes = parse_includes(params)
allowed_includes = filter_includes(requested_includes, resources, purpose)
allowed_includes.index_with(true)
end
private
def default_resources_key(params)
raise(ArgumentError, 'params :controller lykillinn verður að vera strengur') unless params[:controller].is_a?(String)
params[:controller].split(SLASH).last&.to_sym
end
def default_purpose(params)
raise(ArgumentError, 'params :action key must be a string') unless params[:action].is_a?(String)
params[:action].to_sym
end
def includes_sent?(params)
params.key?(:includes)
end
def includes_valid?(params)
return false unless params[:includes].is_a?(String)
params[:includes].match?(INCLUDES_FORMAT)
end
def parse_includes(params)
params[:includes].split(COMMA).map(&:to_sym)
end
def filter_includes(requested_includes, resources_key, purpose)
requested_includes & ALLOWED_INCLUDES[resources_key][purpose]
end
end
Nú þurfum við að nota lyklana til að hlaða includes og senda includes-hashinn sjálfan til serializer-sins:
# app/controllers/api/v1/books_controller.rb
module API
module V1
class BooksController < BaseController
def index
includes = PermitIncludes.new.call(params)
books = Book.includes(includes.keys).all
render json: BookBlueprint.render(books, includes: includes)
end
end
end
end
Og svona verðum við að fínstilla serializerinn okkar – við hleðjum tenginguna aðeins ef hún er innifalin:
# app/blueprints/book_blueprint.rb
class BookBlueprint (_field_name, _book, options) {
options[:includes] && options[:includes][:author]
}
end
Skoðum það aftur:
járnbrautir s
curl http://localhost:3000/api/v1/books
# => [{"id":1,"title":"The Three Musketeers"},{"id":2,"title":"The Lion, the Witch and the Wardrobe"},{"id":3,"title":"Clean Code"}]
# beiðnisdagbækur (við hleðjum aðeins bækur)
Byrjað GET "/api/v1/books" fyrir ::1 kl. 2021-12-24 10:33:41 +0100
Vinnsla með API::V1::BooksController#index sem */*
(0.1ms) SELECT sqlite_version(*)
↳ app/controllers/api/v1/books_controller.rb:8:in `index'
Bók hleðsla (0.1ms) SELECT "books".* FROM "books"
↳ app/controllers/api/v1/books_controller.rb:8:in `index'
Lokið 200 OK á 9ms (Sýnir: 0.1ms | ActiveRecord: 0.9ms | Úthlutanir: 4548)
Gott, við höfum ekki sent inn `include`-skrána, svo við höfum aðeins bækur án höfunda. Nú skulum við biðja um þær:
curl 'http://localhost:3000/api/v1/books?includes=author'
# => [{"id":1,"author":{"id":1,"name":"Alexandre Dumas"},"title":"Þrír muskétumennirnir"},{"id":2,"author":{"id":2,"name":"C.S. Lewis"},"title":"The Lion, the Witch and the Wardrobe"},{"id":3,"author":{"id":3,"name":"Robert C. Martin"},"title":"Clean Code"}]%
# beiðnisdagbækur (eytt n+1)
Hóf GET "/api/v1/books?includes=author" fyrir ::1 þann 2021-12-24 10:38:23 +0100
Unnið af API::V1::BooksController#index sem */*
Breytur: {"includes"=>"author"}
Bókaslóðun (0.1ms) SELECT "books".* FROM "books"
↳ app/controllers/api/v1/books_controller.rb:8:in `index'
Hlaða höfundi (0,2 ms) SELECT "authors".* FROM "authors" WHERE "authors"."id" IN (?, ?, ?) [["id", 1], ["id", 2], ["id", 3]]
↳ app/controllers/api/v1/books_controller.rb:8:in `index'
Lokið 200 OK á 17ms (Sýnir: 0.1ms | ActiveRecord: 0.7ms | Úthlutanir: 7373)
Frábært! Við fengum samtökin hlaðin og útrýmt. n+1 vandamál. Þjónustan má nota fyrir hvaða auðlind sem er; allt sem við þurfum að gera er að bæta leyfðar includes-fastastærðir í rétt snið og bæta þær við PermitIncludes::ALLOWED_INCLUDES.
Við verðum að muna að þetta ætti líklega að nota með síðaskiptingu (og varúð) vegna þess að innifalið tengsl geta “étið” mikið minni.