J'ai essayé de créer une fonction de message de l'extension Rails Tutorial (Partie 1): Créer un modèle

Ceci est la suite de la section sur la création d'extensions dans le chapitre 14 du didacticiel Rails.

La fonction de réponse a été exécutée jusqu'à la dernière fois. Le deuxième ajout de fonction consiste à créer une fonction de message.

Examiner les exigences fonctionnelles

Pour le tutoriel

Twitter prend en charge la possibilité d'envoyer des messages directs. Implémentons cette fonctionnalité dans un exemple d'application

Puisqu'il y en a, vérifiez la fonction de Twitter.

(Indice: vous aurez besoin d'un modèle de message et d'une expression régulière correspondant au nouveau micro-message).

Le modèle Message est-il une fonctionnalité Rails? Je vais chercher sur le net.

Tout d'abord, vérifiez la fonction de Twitter.

L'autre personne doit vous suivre, à condition que vous puissiez envoyer des DM. Je créerai cette fonctionnalité plus tard.

Il existe également une fonction pour afficher read, mais cette fonction est abandonnée.

Vous pouvez configurer pour recevoir une notification push / notification par SMS (notification par courrier électronique court) / notification par courrier électronique lorsque vous recevez un DM. Je renoncerai également à cette fonction.

Vous pouvez également désactiver les DM de comptes spécifiques pour les empêcher de recevoir des notifications. J'abandonnerai également cette fonction.

Il existe également une fonction pour refuser les DM d'un compte spécifique. Vous pouvez bloquer votre adversaire. J'abandonnerai également cette fonction.

Vous pouvez supprimer le DM reçu. Je vais faire cette fonction. L'expéditeur ne peut pas supprimer le DM une fois qu'il a été envoyé.

DM et courrier ont des écrans différents.

Lorsque j'ai vérifié si le nombre maximal de caractères était différent, il était de 140 caractères jusqu'en juillet 2015 et de 10 000 caractères par la suite. Cette fois, j'utiliserai 140 caractères.

Après avoir vérifié si plusieurs destinations peuvent être utilisées, il y avait une fonction pour créer un groupe et parler avec plusieurs comptes. On dit qu'il a été achevé en janvier 2015, je vais donc abandonner cette fonction.

J'ai compris la fonction de Twitter, et j'ai pu imaginer la fonction à créer cette fois.

J'ai vérifié si le modèle Message est une fonction de Rails, mais je n'ai pas pu trouver un tel article. J'ai trouvé un article pour faire une fonction de chat par moi-même et un article pour faire un chat en temps réel, mais cela ne semble pas pertinent.

Résumé des fonctions

  1. Vous pouvez envoyer un message.
  2. Un seul destinataire, pas plusieurs destinataires.
  3. Jusqu'à 140 caractères.
  4. Vous pouvez envoyer à n'importe qui sans aucune restriction. Cette fonction de restriction sera créée ultérieurement.
  5. Ne créez pas de fonction d'affichage de lecture.
  6. Ne créez pas de fonction de notification lorsque DM est reçu.
  7. Le DM reçu peut être supprimé.
  8. L'expéditeur ne peut pas supprimer le DM envoyé

Conception de modèle

Définissez les spécifications du modèle. Relisez le tutoriel où vous créez un Micropost. Au chapitre 13, nous faisons d'abord un modèle en 13.1. Je vais faire un modèle de DM de la même manière.

Nom de colonne attribut
id integer
content text
sender_id integer
receiver_id integer
created_at datetime
updated_at datetime

Modèle de figure DM

Ici, le récepteur est également lié au modèle utilisateur. Je pense que cette relation est la même que lorsque j'ai fait le modèle suivant, j'ai donc relu le tutoriel.

Tenez compte des spécifications lors de la suppression de l'utilisateur

En relation, la suppression de l'utilisateur supprime également la relation. J'ai décidé de ne pas le supprimer dans DM. Ceci est différent.

En relation, ne pas suivre supprime également la relation. En DM, même si le destinataire supprime le DM, le DM ne disparaît pas et ne disparaît pas de l'écran de l'expéditeur. Il disparaît simplement de l'écran du destinataire. Réfléchissons à ce que cela signifie. La suppression de DM ne signifie pas qu'elle n'a pas été effectuée, mais le fait qu'il a été envoyé demeure. Comme le courrier électronique, lorsque le destinataire supprime le courrier électronique reçu, le courrier électronique envoyé par l'expéditeur n'est pas supprimé. Je l'ai essayé sur Twitter et c'était certain.

Pensez à un seau avec DM, comme un e-mail. Il s'agit d'un modèle dans lequel l'expéditeur et le destinataire ont des compartiments séparés. Lorsque vous envoyez un DM, vous en mettez un dans le compartiment de l'expéditeur et un dans le compartiment du destinataire. J'ai senti que mettre exactement le même message dans deux seaux était un double.

Je vais donc garder un bucket et ajouter un indicateur de suppression afin que le destinataire sache qu'il est supprimé.

J'ai recherché sur le net des attributs à mettre vrai ou faux et j'ai trouvé qu'il y avait un booléen et que je devrais toujours mettre la valeur par défaut. La raison en est que nul et faux sont traités de la même manière en rubis. https://qiita.com/jnchito/items/a342b64cd998e5c4ef3d

Ceci est le modèle modifié.

Nom de colonne attribut
id integer
content text
sender_id integer
receiver_id integer
deleted boolean
created_at datetime
updated_at datetime

Modèle de figure DM

Développement de modèles DM

Créez une branche thématique.

ubuntu:~/environment/sample_app (master) $ git checkout -b create-dm

Générez un modèle dm.

ubuntu:~/environment/sample_app (create-dm) $ rails generate model dm content:text user:references
      create    db/migrate/20201102003220_create_dms.rb
      create    app/models/dm.rb
      create      test/models/dm_test.rb
      create      test/fixtures/dms.ymlrails generate mode dm content:text user:references

Changez la migration. J'ai créé l'index car il y a deux façons possibles, l'une est de spécifier l'expéditeur et de le récupérer en série chronologique, et l'autre est de spécifier le destinataire pour le récupérer en série chronologique. Pour la gestion des null du drapeau supprimé, je me suis référé à l'article précédent sur le net.

db/migrate/20201102003220_create_dms.rb


class CreateDms < ActiveRecord::Migration[5.1]
  def change
    create_table :dms do |t|
      t.text :content
      t.integer :sender_id
      t.integer :reciever_id
      t.boolean :deleted, default: false, null: false

      t.timestamps
    end
    add_index :dms, [:sender_id, :created_at]
    add_index :dms, [:receiver_id, :created_at]
  end
end

Mettez à jour la base de données.

ubuntu:~/environment/sample_app (create-dm) $ rails db:migrate

Utilisateur associé et DM. Lisez 14.1.2 "Association utilisateur / relation" dans le didacticiel.

app/models/user.rb


class User < ApplicationRecord
  has_many      :microposts, dependent: :destroy
  has_many      :active_relationships,class_name:  "Relationship",
                                      foreign_key: "follower_id",
                                      dependent:    :destroy
  has_many      :passive_relationships, class_name: "Relationship",
                                        foreign_key: "followed_id",
                                        dependent:  :destroy
  has_many      :following, through: :active_relationships, source: :followed                    
  has_many      :followers, through: :passive_relationships, source: :follower
  has_many      :sent_dms,class_name: "Dm",
                          foreign_key: "sender_id"
  has_many      :received_dms,class_name: "Dm",
                              foreign_key: "receiver_id"

app/models/dm.rb


class Dm < ApplicationRecord
  belongs_to :sender,   class_name: "User"
  belongs_to :receiver, class_name: "User"
end

Dessinez un diagramme pour organiser les relations.

id name
1 Michael
2 Archer

modèle d'utilisateur

has_many

sender_id receiver_id content
1 2 ...
1 3 ...

modèle dm

has_many

id name
2 Archer
3 ...

modèle d'utilisateur Figure Relation utilisateur et DM

Méthodes utilisables

Les méthodes qui seront disponibles sont:

Méthode Utilisation
user.sent_dms Renvoie un ensemble de DM envoyés par l'utilisateur
sent_dms.sender Renvoie l'expéditeur
sent_dms.receiver Retourne le destinataire
user.sent_dms.create(receiver_id: other_user.id) Créer un DM en établissant un lien avec l'utilisateur
user.sent_dms.create!(receiver_id: other_user.id) Créer un DM en liant avec l'utilisateur (erreur de sortie en cas d'échec)
user.sent_dms.build(receiver_id: other_user.id) Renvoie un nouvel objet DM associé à l'utilisateur
user.sent_dms.find_by(id:1) Renvoie DM avec l'ID 1 associé à l'utilisateur

Essayez-le sur la console. Créez dm1.

>> user1 = User.first
>> user2 = User.second
>> dm1 = user1.sent_dms.create(receiver_id: user2.id, content: "hoge dm1")

L'objet Utilisateur de l'expéditeur et du destinataire a été renvoyé.

>> dm1.sender
=> #<User id: 1, name: "Example User", email: "[email protected]", created_at: "2020-10-26 01:37:04", updated_at: "2020-10-26 01:37:04", password_digest: "$2a$10$2TZtcwmSTCfl9Bigz2nYGO8U1YA8ksfNXUr2O/fSGOY...", remember_digest: nil, admin: true, activation_digest: "$2a$10$EaQUKa6hfGEHosjnICR4VuYMxfOxunTOsPGQYUimNLn...", activated: true, activated_at: "2020-10-26 01:37:03", reset_digest: nil, reset_sent_at: nil, unique_name: "Example">
>> dm1.receiver
=> #<User id: 2, name: "Van Zemlak", email: "[email protected]", created_at: "2020-10-26 01:37:04", updated_at: "2020-10-26 01:37:04", password_digest: "$2a$10$H22BJeNVA3hYdEw/a5RArekRy73q/0AtvidwRiVpoUK...", remember_digest: nil, admin: false, activation_digest: "$2a$10$xm7AJE4Q3fzq3gi5tmVnyeld8wahxMHN/dE2Sn2jSUW...", activated: true, activated_at: "2020-10-26 01:37:04", reset_digest: nil, reset_sent_at: nil, unique_name: "Craig1">

Recherchez dans la liste des DM pour l'utilisateur, recherchez dm par identifiant.

>> user1.sent_dms
  Dm Load (0.2ms)  SELECT  "dms".* FROM "dms" WHERE "dms"."sender_id" = ? LIMIT ?  [["sender_id", 1], ["LIMIT", 11]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Dm id: 2, content: "hogehoge", sender_id: 1, receiver_id: 2, deleted: false, created_at: "2020-11-02 02:27:35", updated_at: "2020-11-02 02:27:35">, #<Dm id: 3, content: "hoge dm1", sender_id: 1, receiver_id: 2, deleted: false, created_at: "2020-11-03 00:21:40", updated_at: "2020-11-03 00:21:40">]>

>> user1.sent_dms.find_by(receiver_id: 2)
  Dm Load (0.4ms)  SELECT  "dms".* FROM "dms" WHERE "dms"."sender_id" = ? AND "dms"."receiver_id" = ? LIMIT ?  [["sender_id", 1], ["receiver_id", 2], ["LIMIT", 1]]
=> #<Dm id: 2, content: "hogehoge", sender_id: 1, receiver_id: 2, deleted: false, created_at: "2020-11-02 02:27:35", updated_at: "2020-11-02 02:27:35">

J'ai besoin d'une liste de DM pour le destinataire. Lisez le tutoriel car suivi a la même structure. La méthode est probable, alors essayez-la sur la console.

>> user2.received_dms
  Dm Load (0.1ms)  SELECT  "dms".* FROM "dms" WHERE "dms"."receiver_id" = ? LIMIT ?  [["receiver_id", 2], ["LIMIT", 11]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Dm id: 2, content: "hogehoge", sender_id: 1, receiver_id: 2, deleted: false, created_at: "2020-11-02 02:27:35", updated_at: "2020-11-02 02:27:35">, #<Dm id: 3, content: "hoge dm1", sender_id: 1, receiver_id: 2, deleted: false, created_at: "2020-11-03 00:21:40", updated_at: "2020-11-03 00:21:40">]>

J'ai un modèle, mais je me demande si j'ai toutes les méthodes dont j'ai besoin pour mes besoins.

Examinez à nouveau l'écran Twitter. L'écran DM a une structure parent-enfant et l'écran parent est une liste d'utilisateurs qui ont interagi les uns avec les autres dans le passé. Lorsque vous sélectionnez un utilisateur, c'est un écran qui répertorie les échanges DM.

Une méthode obligatoire est celle qui renvoie une liste d'utilisateurs avec lesquels vous avez interagi dans le passé. Lorsque j'ai recherché find sur le net, j'ai trouvé que la condition OR peut être utilisée dans where. https://qiita.com/nakayuu07/items/3d5e2f8784b6f18186f2 Essayez-le sur la console.

>> Dm.where(sender_id: 1).or(Dm.where(receiver_id: 1))                                                                                         
  Dm Load (0.1ms)  SELECT  "dms".* FROM "dms" WHERE ("dms"."sender_id" = ? OR "dms"."receiver_id" = ?) LIMIT ?  [["sender_id", 1], ["receiver_id", 1], ["LIMIT", 11]]
=> #<ActiveRecord::Relation [#<Dm id: 2, content: "hogehoge", sender_id: 1, receiver_id: 2, deleted: false, created_at: "2020-11-02 02:27:35", updated_at: "2020-11-02 02:27:35">, #<Dm id: 3, content: "hoge dm1", sender_id: 1, receiver_id: 2, deleted: false, created_at: "2020-11-03 00:21:40", updated_at: "2020-11-03 00:21:40">]>
>> Dm.where(sender_id: 2).or(Dm.where(receiver_id: 2))                                                                                        
  Dm Load (0.1ms)  SELECT  "dms".* FROM "dms" WHERE ("dms"."sender_id" = ? OR "dms"."receiver_id" = ?) LIMIT ?  [["sender_id", 2], ["receiver_id", 2], ["LIMIT", 11]]
=> #<ActiveRecord::Relation [#<Dm id: 2, content: "hogehoge", sender_id: 1, receiver_id: 2, deleted: false, created_at: "2020-11-02 02:27:35", updated_at: "2020-11-02 02:27:35">, #<Dm id: 3, content: "hoge dm1", sender_id: 1, receiver_id: 2, deleted: false, created_at: "2020-11-03 00:21:40", updated_at: "2020-11-03 00:21:40">]>

Cette recherche ne permet pas la fonction des écrans parent et enfant. Tous les DM de tous les adversaires sont mélangés. À ce stade, il s'est avéré que les spécifications n'étaient pas pleinement explorées. La fonction de création d'un écran pour chaque partenaire DM sera promue si elle peut être créée ultérieurement.

Test de modèle

Faites un test du modèle. Faire la validation DM en référence à Micropost. Lisez 13.1.2 "Validation Micropost" dans le tutoriel. Le fichier DM de l'appareil est un échantillon, supprimez-le.

test/models/dm_test.rb


class DmTest < ActiveSupport::TestCase

  def setup
    @sender   = users(:michael)
    @receiver = users(:archer)
    @dm = Dm.new(content: "hogehoge1", sender_id: @sender.id, receiver_id: @receiver.id)
  end

  test "should be valid" do
    assert @dm.valid?
  end
  
  test "sender should be present" do
    @dm.sender_id = nil
    assert_not @dm.valid?
  end

  test "receiver should be present" do
    @dm.receiver_id = nil
    assert_not @dm.valid?
  end

  test "contentr should be present" do
    @dm.content = nil
    assert_not @dm.valid?
  end

  test "contentr should be at most 140 characters" do
    @dm.content = "a" * 141
    assert_not @dm.valid?
  end

end

Ajoutez une validation pour le même que micropost. Le test est maintenant VERT.

app/models/dm.rb


class Dm < ApplicationRecord
  belongs_to :sender,   class_name: "User"
  belongs_to :receiver, class_name: "User"
  validates :content, presence: true, length: { maximum: 140 }
end

Changez la méthode lors de la création d'un DM de la manière habituellement correcte.

test/models/dm_test.rb


  def setup

    @dm = @sender.sent_dms.build(content: "hogehoge1", receiver_id: @receiver.id)
  end

Fait revenir les DM dans l'ordre chronologique. Lisez 13.1.4 "Amélioration des micropostes". Écrivez d'abord le test.

test/models/dm_test.rb


class DmTest < ActiveSupport::TestCase
...
  test "order should be most recent first" do
    assert_equal sent_dms(:most_recent), Dm.first
  end
end

Créez des données de relation parent-enfant dans l'appareil. https://qiita.com/seimiyajun/items/ffefdfc74b9fce76a538 Je l'ai mentionné.

test/fixtures/dms.yml


morning:
  content: "Good morning!"
  sender:   michael
  receiver: archer
  created_at:  <%= 10.minutes.ago %>

Définis de manière à ce qu'ils soient organisés dans l'ordre de created_at. Le test est maintenant VERT.

app/models/dm.rb


class Dm < ApplicationRecord
  belongs_to :sender,   class_name: "User"
  belongs_to :receiver, class_name: "User"
  default_scope -> { order(created_at: :desc) }
  validates :content, presence: true, length: { maximum: 140 }
end

Pensez à ajouter: détruire. Lorsque l'utilisateur a été supprimé, le DM précédent a été décidé de rester. Ajoutez ce test. Reportez-vous au Listing 13.20.

test/models/user_test.rb GREEN


test "associated dms should not be destroyed" do
    @user.save
    @user.sent_dms.create!(content: "Lorem ipsum", receiver_id: users(:archer).id)
    assert_no_difference 'Dm.count' do
      @user.destroy
    end
  end
end

Le modèle a été achevé jusqu'à présent.

Temps requis

8,5 heures du 31/10 au 06/11.

Recommended Posts

J'ai essayé de créer une fonction de message de l'extension Rails Tutorial (Partie 1): Créer un modèle
J'ai essayé de créer une fonction de message pour l'extension Rails Tutorial (Partie 2): Créer un écran à afficher
J'ai essayé de faire une fonction de réponse de l'extension Rails Tutorial (Partie 3): Correction d'un malentendu des spécifications
J'ai créé une fonction de réponse pour l'extension Rails Tutorial (Partie 2): Changer de modèle
J'ai créé une fonction de réponse pour l'extension Rails Tutorial (Partie 1)
J'ai créé une fonction de réponse pour l'extension Rails Tutorial (Partie 5):
J'ai essayé de créer une fonction de groupe (babillard) avec Rails
[Rails] Implémentation de la fonction de catégorie multicouche en utilisant l'ascendance "J'ai essayé de créer une fenêtre avec Bootstrap 3"
J'ai essayé de créer une fonction de connexion avec Java
Tutoriel pour créer un blog avec Rails pour les débutants Partie 1
[Rails] J'ai essayé de créer une mini application avec FullCalendar
Je souhaite créer un modèle spécifique d'ActiveRecord ReadOnly
Tutoriel pour créer un blog avec Rails pour les débutants Partie 2
J'ai créé un client RESAS-API en Java
Tutoriel pour créer un blog avec Rails pour les débutants Partie 0
J'ai créé une fonction de réponse pour l'extension Rails Tutorial (Partie 4): une fonction qui rend l'utilisateur unique
J'ai essayé d'implémenter le traitement Ajax de la fonction similaire dans Rails
J'ai créé une application d'apprentissage automatique avec Dash (+ Docker) part2 ~ Façon basique d'écrire Dash ~
J'ai essayé de créer une classe parent d'objet de valeur dans Ruby
J'ai essayé de créer une application de clonage LINE
J'ai créé une application d'apprentissage automatique avec Dash (+ Docker) part3 ~ Practice ~
J'ai essayé d'implémenter une fonction équivalente à Felica Lite avec HCE-F d'Android
Rails6 Je veux créer un tableau de valeurs avec une case à cocher
J'ai essayé de créer une compétence Clova en Java
Je souhaite définir une fonction dans la console Rails
J'ai essayé de créer une fonction / écran d'administrateur de site commercial avec Java et Spring
[Rails] Implémentation de la fonction tutoriel
J'ai essayé de créer un environnement de développement java8 avec Chocolatey
Je souhaite implémenter une fonction d'édition des informations produit ~ part1 ~
Je veux créer une fonction avec kotlin et java!
Je souhaite créer un formulaire pour sélectionner la catégorie [Rails]
Une série d'étapes pour créer des livrables pour les portefeuilles avec Rails
J'ai essayé de créer un environnement de développement padrino avec Docker
J'ai essayé de convertir l'exemple d'application en microservice selon l'idée du livre "Microservice Architecture".
[Rails 6.0, Docker] J'ai essayé de résumer la construction de l'environnement Docker et les commandes nécessaires pour créer un portfolio
Préparation à la création de l'application Rails
Je souhaite ajouter une fonction de navigation avec ruby on rails
J'ai essayé d'implémenter la fonction de prévisualisation d'image avec Rails / jQuery
J'ai essayé de créer un environnement de développement Spring MVC sur Mac
[Unity] J'ai essayé de créer un plug-in natif UniNWPathMonitor en utilisant NWPathMonitor
J'ai essayé de créer une application simple en utilisant Dockder + Rails Scaffold
[Java] J'ai essayé de faire un labyrinthe par la méthode de creusage ♪
(Ruby on Rails6) Créer une fonction pour modifier le contenu publié
En utilisant la fonction de détection de visage de Watson Visual Recognition, j'ai essayé de transformer une image corporelle entière d'une personne en une image de la partie du visage uniquement.
J'ai essayé de créer une application d'apprentissage automatique avec Dash (+ Docker) part1 ~ Construction de l'environnement et vérification du fonctionnement ~
J'ai essayé de créer un exemple de programme en utilisant le problème du spécialiste des bases de données dans la conception pilotée par domaine
J'ai essayé de créer une simple application Android de reconnaissance faciale en utilisant OpenCV
[Rails] Je souhaite envoyer des données de différents modèles dans un formulaire
[Rails] J'ai essayé d'implémenter une transaction qui combine plusieurs processus DB
Notes de personnes qui ont trébuché en essayant de créer un projet Rails
[iOS] J'ai essayé de créer une application de traitement de type insta avec Swift
J'ai essayé de créer une API Web qui se connecte à DB avec Quarkus
J'ai créé un bot de transaction d'arbitrage de monnaie virtuelle et essayé de gagner de l'argent