Beitrag und Benutzer zuordnen. Unter der Annahme, dass der beabsichtigte Leser das Rails-Tutorial abgeschlossen hat, werde ich die Erklärung der Bedeutung weglassen, aber fügen wir dem Artikel "Gehört zu: Benutzer" und "Hat: Viele: Beiträge" zum Benutzer hinzu.
$ rails g migration AddUserIdToPosts user:references
Wenn ein Datensatz vorhanden ist, wird er in der Nicht-Null-Einschränkung abgefangen, und die Migration führt zu einem Fehler. Daher wird db: reset durchgeführt (grob).
$ rails db:reset
$ rails db:migrate
app/models/post.rb
...
class Post < ApplicationRecord
+ belongs_to :user
+
...
app/models/user.rb
...
include DeviseTokenAuth::Concerns::User
+ has_many :posts, dependent: :destroy
+
...
Versuchen Sie nach dem Zuordnen der beiden Tabellen, "Rails c" zu verwenden, um festzustellen, ob dies funktioniert.
$ rails c
[1] pry(main)> user = User.create!(name: "hoge", email: "[email protected]", password: "password")
[2] pry(main)> post = Post.create!(subject: "test", body: "testtest", user: user)
[3] pry(main)> user.posts
Post Load (0.3ms) SELECT "posts".* FROM "posts" WHERE "posts"."user_id" = $1 [["user_id", 1]]
=> [#<Post:0x000000000488dbb0
id: 1,
subject: "test",
body: "testtest",
created_at: Tue, 08 Sep 2020 08:36:20 UTC +00:00,
updated_at: Tue, 08 Sep 2020 08:36:20 UTC +00:00,
user_id: 1>]
[4] pry(main)> post.user
=> #<User id: 1, provider: "email", uid: "[email protected]", name: "hoge", email: "[email protected]", created_at: "2020-09-08 08:36:11", updated_at: "2020-09-08 08:36:11">
Anscheinend können Sie sicher Beiträge von Benutzer und Benutzer von Beitrag anrufen.
Ich möchte die ID, den Namen und die E-Mail-Adresse des Benutzers von der Posts-API erhalten. Zu diesem Zeitpunkt sollten der Serializer und der Controller repariert sein. Zumindest muss der Serializer nur funktionieren. Beachten Sie jedoch, dass eine große Menge nutzlosen SQL-Codes, das als N + 1-Problem bezeichnet wird, fließt und die Leistung sinkt, wenn Sie den Controller nicht ändern.
app/serializers/post_serializer.rb
...
class PostSerializer < ActiveModel::Serializer
attributes :id, :subject, :body
+ belongs_to :user
Dadurch bleibt der Benutzer zusammen.
$ curl localhost:8080/v1/posts/1
{"post":{"id":1,"subject":"test","body":"testtest","user":{"id":1,"provider":"email","uid":"[email protected]","name":"hoge","email":"[email protected]","created_at":"2020-09-08T08:36:11.972Z","updated_at":"2020-09-08T08:36:11.972Z"}}}
Es ist gut, dass sie zusammenhalten, aber ich habe viele unnötige Informationen vom Benutzer. Es gibt keinen Serializer für den Benutzer, also fügen wir ihn hinzu.
Der Serializer wird beim Erstellen des Modells automatisch generiert. Da das Modell jedoch mit devise_token_auth erstellt wurde, wird der Befehl manuell ausgeführt. Darüber hinaus funktioniert activeModelSerializer nicht für die Antwort json des Controllers, die automatisch von devise_token_auth generiert wird. Wenn Sie es aktivieren möchten, müssen Sie den Devise Controller überschreiben, aber dieses Mal werde ich es weglassen.
Aus dem Postmodell im zukünftigen Benutzer
$ rails g serializer user
app/serializers/user_serializer.rb
# frozen_string_literal: true
class UserSerializer < ActiveModel::Serializer
attributes :id, :name, :email
end
$ curl localhost:8080/v1/posts/1
{"post":{"id":1,"subject":"test","body":"testtest","user":{"id":1,"name":"hoge","email":"[email protected]"}}}
Dies ist vorerst in Ordnung.
Jetzt erstellen wir mehrere Benutzer- / Post-Daten mit Rails c und klicken auf "curl localhost: 8080 / v1 / posts". Ich kann die Daten sicher abrufen, aber wenn ich zum Terminal gehe, wird mit "Rails s" gestartet ...
Started GET "/v1/posts" for 127.0.0.1 at 2020-09-08 08:48:08 +0000
Processing by V1::PostsController#index as */*
Post Load (0.3ms) SELECT "posts".* FROM "posts" ORDER BY "posts"."created_at" DESC LIMIT $1 [["LIMIT", 20]]
↳ app/controllers/v1/posts_controller.rb:12:in `index'
[active_model_serializers] User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 3], ["LIMIT", 1]]
[active_model_serializers] ↳ app/controllers/v1/posts_controller.rb:12:in `index'
[active_model_serializers] CACHE User Load (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 3], ["LIMIT", 1]]
[active_model_serializers] ↳ app/controllers/v1/posts_controller.rb:12:in `index'
[active_model_serializers] CACHE User Load (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 3], ["LIMIT", 1]]
[active_model_serializers] ↳ app/controllers/v1/posts_controller.rb:12:in `index'
[active_model_serializers] User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 2], ["LIMIT", 1]]
...
[active_model_serializers] ↳ app/controllers/v1/posts_controller.rb:12:in `index'
[active_model_serializers] CACHE User Load (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
[active_model_serializers] ↳ app/controllers/v1/posts_controller.rb:12:in `index'
[active_model_serializers] Rendered ActiveModel::Serializer::CollectionSerializer with ActiveModelSerializers::Adapter::Json (30.42ms)
Completed 200 OK in 34ms (Views: 32.5ms | ActiveRecord: 0.8ms | Allocations: 21448)
Obwohl weggelassen, fließt eine große Menge an SQL auf diese Weise. Dies ist das N + 1-Problem.
Da der mit dem Beitrag verknüpfte Benutzer jeweils einen Datensatz gefunden und abgerufen hat, fließt eine große Menge nutzloser SQL.
Dies ist in Ordnung, wenn Sie es zum Zeitpunkt der Veröffentlichung von "Post.all" einfügen.
app/controllers/v1/posts_controller.rb
def index
- posts = Post.order(created_at: :desc).limit(20)
+ posts = Post.includes(:user).order(created_at: :desc).limit(20)
render json: posts
end
Started GET "/v1/posts" for 127.0.0.1 at 2020-09-08 08:51:50 +0000
Processing by V1::PostsController#index as */*
Post Load (0.2ms) SELECT "posts".* FROM "posts" ORDER BY "posts"."created_at" DESC LIMIT $1 [["LIMIT", 20]]
↳ app/controllers/v1/posts_controller.rb:12:in `index'
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" IN ($1, $2, $3) [["id", 3], ["id", 2], ["id", 1]]
↳ app/controllers/v1/posts_controller.rb:12:in `index'
[active_model_serializers] Rendered ActiveModel::Serializer::CollectionSerializer with ActiveModelSerializers::Adapter::Json (5.32ms)
Completed 200 OK in 41ms (Views: 32.7ms | ActiveRecord: 5.1ms | Allocations: 17394)
Es gibt jetzt zwei Benutzer und Beiträge, einen für jede Tabelle.
Vorerst scheint die Bewegung der Anwendung behoben worden zu sein, aber wenn Sie rspec in diesem Zustand verschieben, wird sie in der Tat großartig moosiert. Nächstes Mal werden wir rspec und seed überprüfen.
→ Erstellen einer Bulletin Board-API mit Zertifizierungsberechtigung in Rails 6 # 13 Erteilen des Authentifizierungsheaders [Zur Serialisierungstabelle]
Recommended Posts