Associer le poste et l'utilisateur.
J'omettrai l'explication de la signification car il est supposé que le lecteur visé a terminé le didacticiel Rails, mais ajoutons appartient_to: user
pour publier et has_many: posts
à l'utilisateur.
$ rails g migration AddUserIdToPosts user:references
S'il y a un enregistrement, il sera pris dans la contrainte non nulle et la migration entraînera une erreur, donc db: reset sera effectué (approximatif)
$ 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
+
...
Après avoir associé les deux tables, essayez d'utiliser rails c
pour voir si cela fonctionne.
$ 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">
Apparemment, vous pouvez appeler en toute sécurité les messages de l'utilisateur et de l'utilisateur à partir de la publication.
Je souhaite obtenir l'identifiant, le nom et l'adresse e-mail de l'utilisateur à partir de l'API posts. À ce moment-là, le sérialiseur et le contrôleur doivent être corrigés. Au minimum, vous n'avez besoin que du sérialiseur pour fonctionner, mais sachez que si vous ne modifiez pas le contrôleur, une grande quantité de SQL inutile appelé problème N + 1 coulera et les performances chuteront.
app/serializers/post_serializer.rb
...
class PostSerializer < ActiveModel::Serializer
attributes :id, :subject, :body
+ belongs_to :user
Cela incitera l'utilisateur à rester ensemble.
$ 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"}}}
C'est bien qu'ils restent ensemble, mais j'ai beaucoup d'informations inutiles de la part de l'utilisateur. Il n'y a pas de sérialiseur pour l'utilisateur, ajoutons-le donc.
Le sérialiseur est généré automatiquement lorsque le modèle est créé, mais comme le modèle a été créé avec devise_token_auth, la commande est exécutée manuellement. De plus, activeModelSerializer ne fonctionne pas pour la réponse json du contrôleur générée automatiquement par devise_token_auth. Si vous voulez l'activer, vous devez remplacer le contrôleur de périphérique, mais cette fois je l'omettrai.
Du modèle de poste au futur utilisateur
$ 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]"}}}
C'est OK pour le moment.
Maintenant, créons plusieurs utilisateurs / plusieurs données post avec rails c et appuyez sur curl localhost: 8080 / v1 / posts
.
Je peux obtenir les données en toute sécurité, mais lorsque je passe au terminal, il démarre avec rails s
...
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)
Bien que omis, une grande quantité de SQL s'écoule de cette manière. C'est le problème N + 1.
Puisque l'utilisateur associé à la publication est trouvé et récupéré un enregistrement à la fois, une grande quantité de flux SQL inutiles.
C'est OK si vous l'incluez au moment où Post.all
arrive.
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)
Il y a maintenant deux utilisateurs et messages, un pour chaque table.
Pour le moment, le mouvement de l'application semble avoir été figé, mais en fait, si vous déplacez rspec dans cet état, il se moussera largement. La prochaine fois, nous vérifierons rspec et seed.
→ Création d'une API de tableau d'affichage avec autorisation de certification dans Rails 6 # 13 Accorder l'en-tête d'authentification [Vers la table de sérialisation]
Recommended Posts