[RUBY] [Rails] Procédure d'implémentation de la fonction pour taguer les posts sans gem + la fonction pour affiner et afficher les posts par tags

Aperçu

__ ・ Implémentez une fonction qui vous permet de marquer vos propres messages. __ __ ・ Implémentez une fonction qui vous permet d'affiner la recherche en utilisant les balises attachées au message. __

supposition

·environnement Série Ruby 2.6 Série Rails 5.2

·Bibliothèque  Slim

__ ・ Modèle d'application Rails de l'environnement ci-dessus __ Procédure pour configurer l'application Rails et installer l'appareil et Slim

__ ↓ Image terminée ↓ __ ezgif.com-video-to-gif (2).gif

la mise en oeuvre

1. Conception et association de modèles

スクリーンショット 2020-06-13 20.14.13.png -User: Post = L'utilisateur a beaucoup de messages pour chaque personne, donc il y a une relation `1 to many `.

- Post: Tag = Un message a de nombreux tags ``, `` `` Un tag a aussi de nombreux messages , donc` Relation plusieurs-à-plusieurs. → Une table intermédiaire est requise en raison de la relation plusieurs-à-plusieurs = TagMap```

→ Une table intermédiaire est une table qui ne stocke que les clés externes (post_id et tag_id) de la table many-to-many (table post et tag dans ce cas), et gère les tables de l'autre uniquement avec la clé externe. Rend le possible.

2. Création de modèles

$ rails g devise User //Créer un modèle utilisateur à partir de l'appareil $ rails g migration add_columns_to_users name:string //colonne de nom ajoutée   $ rails g model Post content:string user:references //Création de modèle après   $ rails g model Tag tag_name:string //Création de modèles de balises   $ rails g model TagMap post:references tag:references //Création de modèles TagMap


 >> -Puisque les colonnes ne peuvent pas être ajoutées au modèle utilisateur créé par appareil, lors de l'ajout d'une colonne de nom, il est nécessaire de l'ajouter en tant que nouvelle migration.
  
 - <Nom de la table>: Une clé externe est définie pour la table spécifiée dans les références. (Obligatoire)


### 3. Vérifiez le fichier de migration créé
 > #### 3-1. Fichier de migration des utilisateurs
>>```db/migrate/[timestamps]_create_devise_users.rb
class DeviseCreateUsers < ActiveRecord::Migration[5.2]
  def change
    create_table :users do |t|
      ## Database authenticatable
      t.string :email,              null: false, default: ""
      t.string :encrypted_password, null: false, default: ""
 
    #<réduction>
 
  end
end

3-2. Ajouter une colonne de nom au tableau des utilisateurs

class AddUsernameToUsers < ActiveRecord::Migration[5.2] def change add_column :users, :name, :string end end


 > Fichier de migration #### 3-3.posts

>>```ruby:db/migrate/[timestamps]_create_posts.rb
class CreatePosts < ActiveRecord::Migration[5.2]
  def change
    create_table :posts do |t|
      t.text :content
      t.references :user, foreign_key: true
 
      t.timestamps
    end
  end
end

Fichier de migration #### 3-4.tags

class CreatePostTags < ActiveRecord::Migration[5.2] def change create_table :post_tags do |t| t.string :tag_name   t.timestamps end end end


 > Fichier de migration #### 3-5.tag_maps

>>```ruby:db/migrate/[timestamps]_create_tag_maps.rb
class CreatePostTagMaps < ActiveRecord::Migration[5.2]
  def change
    create_table :tag_maps do |t|
      t.references :post, foreign_key: true
      t.references :tag, foreign_key: true
 
      t.timestamps
    end
  end
end

4. Confirmation du fichier modèle créé

4-1. Fichier de modèle utilisateur

class User < ApplicationRecord

Include default devise modules. Others available are:

:confirmable, :lockable, :timeoutable, :trackable and :omniauthable

devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable   has_many :posts, dependent: :destroy end


 >> ・ `dependant :: destroy`: Une option qui peut être attachée à la classe parent afin que la classe enfant puisse être supprimée lorsque la classe parent est supprimée.

 > #### 4-2. Fichier modèle de publication

>>```ruby:app/models/user.rb
class Post < ApplicationRecord
  belongs_to :user
 
  has_many :tag_maps, dependent: :destroy
  has_many :tags, through: :tag_maps
end

__ ・ L'option through est utilisée pour s'associer à la table des tags via la table tag_maps. En faisant cela, vous pouvez obtenir les balises associées à Post en utilisant Post.tags`. Cela peut être utilisé lorsque vous souhaitez attacher l'étiquette à la publication et l'afficher sur l'écran des détails de la publication. __

__ ・ Lors de l'utilisation de l'option through, il faut d'abord l'associer à la table intermédiaire. __

__- En ajoutant l'option dependant :: destroy à la table intermédiaire, la relation entre Post et Tag sera supprimée en même temps que Post est supprimé. __

4-4.Fichier modèle de balise

class Tag < ApplicationRecord has_many :tag_maps, dependent: :destroy, foreign_key: 'tag_id' has_many :posts, through: :tag_maps end


 >> __` ・ Après avoir été associé à la table tag_maps, il est associé à la table posts via tag_maps`. Vous pouvez obtenir les messages associés aux balises avec `Tag.posts`. Cela peut être utilisé lorsque vous souhaitez rechercher des articles avec une balise spécifique, telle que "sports". __

 > #### 4-5. Fichier modèle TagMap

>>```ruby:app/models/tag_map.rub
class PostTagMap < ApplicationRecord
  belongs_to :post
  belongs_to :tag
 
  validates :post_id, presence: true
  validates :tag_id, presence: true
end

__ ・ Puisqu'il appartient à plusieurs messages et à plusieurs balises, il est associé à appartient_to. __

__ ・ Lors de la construction de la relation entre Post et Tag, il est absolu qu'il existe deux clés externes, alors validez-les. __

5. Paramètres de routage

Rails.application.routes.draw do devise_for :users   root to: 'posts#index'   resources :posts end


 >> __ ・ À ce stade, pour le moment, définissez le routage fourni par le dispositif, le chemin racine et le chemin vers la ressource des messages. __

## Tout d'abord, implémentez à partir de la fonction qui peut baliser les messages

### 6. Créez un contrôleur

 > #### 6-1. Écrivez le code pour créer des messages et des balises dans l'action de création du contrôleur de messages.

>>```ruby:app/controllers/posts_controller.rb
class PostsController < ApplicationController
 
 def create
    @post = current_user.posts.new(post_params)           
    tag_list = params[:post][:tag_name].split(nil)  
    if @post.save                                         
      @post.save_tag(tag_list)                         
      redirect_back(fallback_location: root_path)          
    else
      redirect_back(fallback_location: root_path)          
    end
 end
  
 private
   def post_params
     params.require(:post).permit(:content)
   end
end

__ Décomposons le code ci-dessus. __

@post = current_user.posts.new(post_params)

 >> __ · En définissant `current_user.posts`, l'identifiant de l'utilisateur connecté sera sauvegardé dans le user_id de la table des messages, mais si ʻUser et Post ne sont pas associés, une erreur se produira. Masu`. Les paramètres forts sont utilisés comme argument. __

>>```ruby:Récupérez les tags qui ont été envoyés
tag_list = params[:post][:tag_name].split(nil)

__ ・ params [: post] [: tag_name]: Depuis le formulaire, référez-vous à l'objet @post et envoyez le nom de la balise ensemble, alors récupérez-le sous cette forme. Par exemple, il est envoyé comme "" sports "" étude "" travail "". __

__ ・ .split (nil): Dispose les valeurs envoyées séparées par des espaces. Dans l'exemple ci-dessus, cela ressemble à ["sports" "étude" "travail"]. La raison de l'organisation est que lors de l'enregistrement ultérieur de cette valeur dans la base de données, il est nécessaire de la récupérer un par un par un traitement itératif. __

@post.save_tag(tag_list)

 __ ・ `Processus pour enregistrer le tableau de balises acquises précédemment dans la base de données`. La définition de save_tag qui effectue le traitement sera décrite plus loin. __

 > #### 6-2. Écrivez le code pour obtenir le message et la balise dans l'action d'indexation.

>>```ruby:app/controllers/posts_controller.rb
def index
    @tag_list = Tag.all              #Get all pour afficher la liste des balises dans la vue.
    @posts = Post.all                #Obtenez tout pour afficher la liste des articles dans la vue.
    @post = current_user.posts.new   #Voir le formulaire_Utilisé pour le modèle avec.
end

def show @post = Post.find(params[:id]) #Obtenez le message sur lequel vous avez cliqué. @post_tags = @post.tags #Obtenez la balise associée au post sur lequel vous avez cliqué. end


### 7. Définissez la méthode d'instance save_tag dans le fichier de modèle Post.

 > __ ・ Définissez le contenu de la méthode d'instance save_tag décrite plus haut dans l'action de création. __

>```ruby:app/models/post.rb
class Post < ApplicationRecord
 
  #<réduction>
 
  def save_tag(sent_tags)
    current_tags = self.tags.pluck(:tag_name) unless self.tags.nil?
    old_tags = current_tags - sent_tags
    new_tags = sent_tags - current_tags
 
    old_tags.each do |old|
      self.post_tags.delete PostTag.find_by(post_tag_name: old)
    end
 
    new_tags.each do |new|
      new_post_tag = PostTag.find_or_create_by(post_tag_name: new)
      self.post_tags << new_post_tag
    end
  end
end

current_tags = self.tags.pluck(:tag_name) unless self.tags.nil?

 > __ ・ Si une balise associée à @post a été enregistrée par l'action de création plus tôt, récupérez tous les "noms de balises sous forme de tableau". __

>```ruby:Obtenir d'anciennes balises
old_tags = current_tags - sent_tags

__ ・ Old_tags sont les tags qui existent dans le @post actuellement acquis, à l'exclusion des tags envoyés. __

new_tags = sent_tags - current_tags

 > __ ・ Les nouveaux_tags sont les balises qui sont envoyées, à l'exclusion des balises qui existent actuellement. __

>```ruby:Supprimer les anciennes balises
old_tags.each do |old|
    self.tags.delete Tag.find_by(tag_name: old)
end

__- Supprimer les anciennes balises. __

new_tags.each do |new| new_post_tag = Tag.find_or_create_by(tag_name: new) self.post_tags << new_post_tag end

 > __- Enregistrez la nouvelle balise dans la base de données. __

 > __ ・ La raison pour laquelle il faut du temps pour acquérir et supprimer les anciennes balises et les nouvelles balises comme décrit ci-dessus, au lieu de simplement acquérir et enregistrer les balises une par une, est, par exemple, lors de l'édition d'un article. Parce qu'il faut que ça marche.
 Cependant, je suis désolé, j'omettrai cette fois l'implémentation de la fonction d'édition. __

### 8. Créez une vue.

 > #### 8-1. Créez une vue de la liste des articles.

>>```ruby:app/views/posts/index.html.slim
liste de balises h3
- @tag_list.each do |list|
  span
    = link_to list.tag_name, tag_posts_path(tag_id: list.id)
    = "(#{list.posts.count})"
 
hr
 
poteau h3
= form_with(model: @post, url: posts_path, local: true) do |f|
  = f.text_area :content
  br
  = "Vous pouvez ajouter plusieurs balises en entrant un espace."
  = "Exemple: musique, sports littéraires"
  = f.text_field :tag_name
  br
  = f.submit
 
hr
 
Liste des messages h3
- @posts.each do |post|
    = link_to post.content, post

Décomposons le code ci-dessus.

 >> __ ・ Toutes les balises acquises par l'action d'index sont affichées, et ʻun lien vers le chemin pour afficher les messages liés à cette balise est fourni`. Cliquer sur ce lien vous amènera à afficher les messages associés à cette «balise». La définition du routage pour obtenir ce lien et la création de l'action seront décrites plus loin. __

 >> __ ・ `" (# {list.posts.count}) "` compte et affiche le nombre de messages qui ont actuellement cette balise. __

>>```ruby:Nouveau formulaire de message (peut être étiqueté)
= form_with(model: @post, url: posts_path, local: true) do |f|
  = f.text_area :content
  br
  = "Vous pouvez ajouter plusieurs balises en entrant un espace."
  = "Exemple: musique, sports littéraires"
  = f.text_field :tag_name
  br
  = f.submit

__ ・ = f.text_field: tag_name: En écrivant cette ligne, les balises saisies dans le formulaire seront envoyées à l'action de création en tant que paramètres params [: post] [: tag_name]. .. __

8-2. Créez une vue de la page de détail de l'article.

Détails de l'article h1   p= @post.content   br   = "marque: "

 >> __ ・ La partie qui affiche l'étiquette est la même que la méthode décrite dans l'affichage de la liste. Dans ce cas, la partie appelée «tag associé à un article spécifique» est différente. __

 __ · Ceci termine l'implémentation de la fonction qui vous permet de baliser les messages. __

## Mettre en œuvre une fonction pour affiner et afficher les articles par balises

### 1. Ajoutez un routage.

>```ruby:config/routes.rb
Rails.application.routes.draw do
  devise_for :users
  root to: 'posts#index'
  resources :posts
 
  #Acheminement vers des actions pour afficher les publications filtrées par balises
  resources :tags do
    get 'posts', to: 'posts#search'
  end
end

__ ・ En imbriquant, vous pouvez utiliser le chemin pour passer à la page de publication associée à une balise spécifique appelée tag_posts_path (tag_id: tag.id) comme décrit précédemment. __

2. Créez une action de recherche dans le contrôleur de messages.

def search @tag_list = Tag.all #Obtenir toutes les balises pour afficher toutes les balises sur cette page d'affichage de la liste de publications @tag = Tag.find(params[:tag_id]) #Obtenez le tag cliqué @posts = @tag.posts.all #Afficher tous les messages associés à la balise cliquée end


### 3. Créez une vue de page qui affiche une liste de publications restreinte par des balises.

 > __ ・ Commencez par créer un fichier search.html.slim dans le répertoire app / views / posts. __

>```ruby:app/views/posts/search.html.slim
Liste des messages h2
 
#Liste de balises
- @tag_list.each do |list|
  span
    = link_to list.tag_name, tag_posts_path(post_tag_id: list.id)
    = "(#{list.posts.count})"
br
#Liste de messages réduite par tag
= "La balise est ─"
strong= "#{@tag.tag_name}"
= "─ Liste des messages"
br
- @posts.each do |post|
  = link_to post.content, post
br
= link_to 'domicile', root_path

__ ・ La partie liste de balises est la même que la partie index. __

= "La balise est ─" strong= "#{@tag.tag_name}" = "─ Liste des messages"

 > __ ・ Dans cette partie, la balise correspondante est affichée afin que vous puissiez voir quel type de balise a été réduit. __

 __ · Ceci termine l'implémentation de la fonction d'affichage des publications réduites par des balises. Comme vous pouvez le voir, il y a des chevauchements dans la vue, donc si vous partialisez et refactorisez ces parties, la vue sera plus propre et meilleure. __

## Article très utile
 [Notes sur l'implémentation de la fonction de balise dans Rails sans utiliser de gem](https://qiita.com/tobita0000/items/daaf015fb98fb918b6b8)


Recommended Posts

[Rails] Procédure d'implémentation de la fonction pour taguer les posts sans gem + la fonction pour affiner et afficher les posts par tags
[Rails 6.0] J'ai essayé d'implémenter une fonction de recherche de balises (une fonction pour affiner par balises) [no gem]
[Rails] Comment afficher une liste de messages par catégorie
[Rails] Implémentation de la fonction de balise à l'aide de la fonction agit-as-taggable-on et de la fonction de complétion d'entrée de balise à l'aide de tag-it
[Rails] Je vais expliquer la procédure d'implémentation de la fonction follow en utilisant form_with.
Utilisez la méthode where pour affiner en vous référant à la valeur d'un autre modèle.
[Rails] Procédure de mise en œuvre lorsque des fonctions publiques / privées sont ajoutées à la fonction de publication
[Rails] Implémentation de la fonction glisser-déposer (avec effet)
Politique de mise en œuvre pour enregistrer et afficher dynamiquement le fuseau horaire dans les rails
[Rails] Implémentation de la fonction de catégorie
[Rails] Implémentation de la fonction tutoriel
[Rails] Implémentation d'une fonction similaire
Emplacement de la définition de la méthode Résumé de la vérification Lorsque défini dans le projet et Rails / Gem
[Rails] Comment obtenir l'URL de la source de transition et la rediriger
[Rails] Comment omettre l'affichage de la chaîne de caractères de la méthode link_to
[Rails] Lire le RSS du site et renvoyer le contenu au premier plan
[Rails] N'utilisez pas la méthode de sélection uniquement pour réduire les colonnes!
twitter-4 sélections d'erreurs avec la fonction de connexion Twitter créée par omniauth gem et comment les traiter
[Rails] Implémentation de la fonction d'importation CSV
[Rails] Implémentation asynchrone de la fonction similaire
[Rails] À propos de la mise en œuvre de la fonction similaire
[Rails] Implémentation de la fonction de retrait utilisateur
[Rails] Implémentation de la fonction d'exportation CSV
[Rails] Implémentation de la fonction de catégorie d'ascendance gemme
[Rails] Commentaire mémo de procédure d'implémentation
Fonction Strict_loading pour supprimer l'occurrence de problème N + 1 ajoutée à partir des rails 6.1
[Rails] Articles pour les débutants pour organiser et comprendre le flux de form_with
Comment faire de https le schéma de l'URL générée par l'assistant d'URL de Rails