[RUBY] [Rails 6.0] Ich habe versucht, eine Tag-Suchfunktion zu implementieren (eine Funktion zum Eingrenzen nach Tags) [no gem]

Ich habe eine Tag-Suchfunktion in einer App implementiert, die ich gerade entwickle, daher werde ich sie hier als Memorandum zusammenfassen. Ich habe es nicht gewagt, Edelsteine zu verwenden, also konnte ich das Wesentliche verstehen.

【Umgebung】

Funktionsübersicht

Wenn Sie ein Tag in das neue Post-Formular eingeben, wird das eingegebene Tag in der Post-Liste und in der Seitenleiste angezeigt. Mit dieser Funktion können Sie die Beiträge mit diesem Tag eingrenzen, indem Sie auf das in der Seitenleiste angezeigte Tag klicken.

Geben Sie ein Tag aus dem Post-Formular ein tagu_qiita.png

Das in ↑ eingegebene Tag wird in der Seitenleiste und in der Beitragsliste angezeigt Durch Klicken auf das in der Seitenleiste angezeigte Tag können Sie die Artikel eingrenzen, die dieses Tag enthalten. (Da dies ein Beispiel ist, nur ein Fall) tagu_qiita2.png

Montagevorgang

Ich gehe davon aus, dass das Artikelmodell und das Post-Modell bereits erstellt wurden. (Hier handelt es sich um ein Artikelmodell. Bitte ersetzen Sie es selbst.)

Erstellen Sie zunächst das Tag-Modell und das Tagmap-Modell wie gewohnt.

$ rails g model Tagmap item:references tag:references 
$ rails g model tag tag_name:string

Da Tagmap dem Artikelmodell und dem Tag-Modell zugeordnet ist, werden Verweise an den Datentyp angehängt. Wenn Sie dies tun, wird Rails einen guten Job machen. Wenn Sie also mehr wissen möchten, gehen Sie bitte auf Google.

Migrationsdatei


class CreateTagmaps < ActiveRecord::Migration[6.0]
  def change
    create_table :tagmaps do |t|
      t.references :item, null: false, foreign_key: true
      t.references :tag, null: false, foreign_key: true

      t.timestamps
    end
  end
end

Dies ist indiziert.


class CreateTags < ActiveRecord::Migration[6.0]
  def change
    create_table :tags do |t|
      t.string :tag_name, null: false

      t.timestamps
    end
    add_index :tags, :tag_name, unique: true
  end
end

Migrieren Sie dann wie gewohnt.

$ rails db:migrate

Verband

item.rb


has_many :tagmaps, dependent: :destroy
has_many :tags, through: :tagmaps

tag.rb


class Tag < ApplicationRecord
  has_many :tagmaps, dependent: :destroy
  has_many :items, through: :tagmaps
end

Tag ist auch mit Tagmaps verknüpft. ↑

Mit gründlich können Sie über Tagmaps auf Elemente zugreifen.

tagmap.rb


class Tagmap < ApplicationRecord
  belongs_to :item
  belongs_to :tag
end

↑ Rails beschreibt automatisch das zugehörige Teil im Referenzformular!

Controller- und Modellbeschreibung

items_controller.rb


  def index
    if params[:search].present?
      items = Item.items_serach(params[:search])
    elsif params[:tag_id].present?
      @tag = Tag.find(params[:tag_id])
      items = @tag.items.order(created_at: :desc)
    else
      items = Item.all.order(created_at: :desc)
    end
    @tag_lists = Tag.all
    @items = Kaminari.paginate_array(items).page(params[:page]).per(10)
  end

Ich werde den Code hier erklären. Die Indexaktion verwendet die if-Anweisung, um die drei Muster zu trennen, und der der Elementvariablen zugewiesene Wert wird gemäß diesem Ergebnis geändert.

    1. Wenn das Suchformular Eingaben enthält
  1. Wann: tag_id wird in params empfangen (Wird aktiviert, wenn tag_id beim Klicken als Parameter empfangen wird. Funktion zum Eingrenzen nach Tag)
    1. Wenn die Seite normal angezeigt wird Da auch die Pagenierungsfunktion eingestellt ist, sind die in der Elementvariablen gespeicherten Variablen in 3 Mustern und jedes optimierte kann angezeigt werden. Pagenation verwendet einen Edelstein namens Kaminari.

items_controller


  def create
    @item = Item.new(item_params)
    tag_list = params[:item][:tag_name].split(nil)
    @item.image.attach(params[:item][:image])
    @item.user_id = current_user.id
    if @item.save
       @item.save_items(tag_list)
      redirect_to items_path
    else
      flash.now[:alert] = 'Buchung fehlgeschlagen'
      render 'new'
    end
  end

Der Punkt in der Erstellungsaktion des Elementcontrollers ist der Zuordnungsteil zur Variablen tag_list in der dritten Zeile. rubys ** String # split ** teilt den String durch das durch das erste Argument angegebene Trennzeichen (diesmal null) und gibt das Ergebnis als Array von Strings zurück. Wenn Sie einen Block angeben, wird der Block nicht zurückgegeben, sondern mit einer geteilten Zeichenfolge aufgerufen. Wenn Sie Tag-Daten senden, die durch ein 1-Byte-Leerzeichen '' vom Formular getrennt sind, werden sie nach dem Entfernen der führenden und nachfolgenden Leerzeichen durch eine leere Zeichenfolge getrennt. Dieses Mal werden wir dies verwenden.

Die vom neuen Postformular gesendeten Parameter werden durch ein Leerzeichen (Null) getrennt, angeordnet und mithilfe der in der Elementklasse definierten Methode ** save_items ** in der Datenbank gespeichert. (Bitten Sie den Benutzer, Tags in das durch Leerzeichen getrennte Formular einzugeben.)

item.rb


 #Fuzzy-Suche nach Suchmethode, Titel und Inhalt
 def self.items_serach(search)
   Item.where(['title LIKE ? OR content LIKE ?', "%#{search}%", "%#{search}%"])
 end

 def save_items(tags)
   current_tags = self.tags.pluck(:tag_name) unless self.tags.nil?
   old_tags = current_tags - tags
   new_tags = tags - current_tags

   # Destroy
   old_tags.each do |old_name|
     self.tags.delete Tag.find_by(tag_name:old_name)
   end

   # Create
   new_tags.each do |new_name|
     item_tag = Tag.find_or_create_by(tag_name:new_name)
     self.tags << item_tag
   end
 end

↑ Wenn beim Speichern von Tag-Daten unter den vom Formular gesendeten Tag-Daten bereits ein Tag-Name vorhanden ist, verwenden Sie die Zupfmethode aus der Spalte tag_name der Tags-Tabelle, um alle Daten einmal abzurufen und auf current_tags zu setzen. Ersatz. (Wenn alles neu ist, ist es gleich Null.) Sie können alte Tags (old_tags) definieren, indem Sie das vom Controller übergebene Array von Tags als Argument von current_tags subtrahieren. Hierbei handelt es sich um einen Satz bereits vorhandener Tag-Daten. Dies liegt daran, dass Ruby gemeinsame Elemente durch Subtrahieren eines Arrays extrahieren kann.

** Konkretes Beispiel: **


tags(tag_list = params[:item][:tag_name].split(nil)Anordnung, die vom Controller kommt) = ["Rails" "ruby" "React"]
current_tags(Tag-Daten, die derzeit in der Datenbank vorhanden sind) = ["Rails" "ruby" "Vue.js"]

old_tags = ["Rails" "ruby" "Vue.js" "Docker"] -  ["Rails" "ruby" "React"] 
old_tags = ["Rails" "ruby"] 
↑ Das gemeinsame Element der beiden Arrays bleibt erhalten (alte bereits vorhandene Tags können berechnet werden)

Beschreibung anzeigen

** Auszug aus der Beschreibung des neuen Beitragsformulars (UIkit wird für das CSS-Framework verwendet) **


.uk-form.new_post_form
  = form_with(model: [@tag,@item], local: true) do |f|
    .uk-margin-small
      = f.text_field :title, placeholder: "Geben Sie einen Titel ein (bis zu 35 Zeichen)", class: 'uk-input'
    .uk-margin-small
      = f.text_field :tag_name, placeholder: "Geben Sie bis zu 5 Tags ein, die sich auf Programmiertechnologie und Rekrutierungsanforderungen beziehen und durch Leerzeichen getrennt sind(Beispiel Ruby Rails)", class: 'uk-input uk-form-small'

** Teilausschnitt aus der Seitenleiste **

haml:index.html.haml


%li.search_friend_by_categorize
  .uk-text-secondary.uk-text-bold
Suche nach Tag
  %ul.uk-flex.uk-flex-wrap
    - @tag_lists.each do |list|
      %li
        = link_to list.tag_name, items_path(tag_id: list.id), class: 'tag_list'

Anzeigen von Tags in einer Liste der veröffentlichten Artikel

haml:index.html.haml


 %p.tag_list_box
   - item.tags.each do |tag|
     = link_to "##{tag.tag_name}", items_path(tag), class: 'smaller tag_list'

Die Ansicht sieht so aus. Es ist nicht besonders schwierig!

Vielen Dank für das Lesen bis zum Ende!

Ich habe es in Eile geschrieben, daher kann es zu Fehlern kommen. Wenn Sie Anregungen oder Eindrücke haben, würde ich mich freuen, wenn Sie einen Kommentar abgeben könnten! !!

Recommended Posts

[Rails 6.0] Ich habe versucht, eine Tag-Suchfunktion zu implementieren (eine Funktion zum Eingrenzen nach Tags) [no gem]
[Rails] Implementierungsverfahren der Funktion zum Markieren von Posts ohne Gem + die Funktion zum Eingrenzen und Anzeigen von Posts nach Tags
Tag-Funktion zu Rails hinzufügen. Verwenden Sie Acts-as-Taggable-On
[Für Anfänger von Rails] Mehrfachsuchfunktion ohne Gem implementiert
Ich möchte eine Funktion in der Rails Console definieren
Implementieren Sie eine verfeinerte Suchfunktion für mehrere Modelle ohne Rails5-Juwel.
Fügen Sie eine Suchfunktion in Rails hinzu.
Ich möchte eine Browsing-Funktion mit Ruby on Rails hinzufügen
Hash-Tag-Suche wie Insta und Twitter in Rails implementiert (kein Juwel)
Ich habe versucht, mit Rails eine Gruppenfunktion (Bulletin Board) zu erstellen
Ich habe ein Rails-Post-Formular erstellt, kann aber nicht posten (Formular-Tag) / Es tritt kein Fehler auf
Mit Rails in eine Tag-zu-URL-Zeichenfolge konvertieren
Buchungsfunktion implementiert durch asynchrone Kommunikation in Rails
Lassen Sie uns eine Suchfunktion mit Rails (Ransack) machen
Ich habe versucht, eine Nachrichtenfunktion der Rails Tutorial-Erweiterung (Teil 1) zu erstellen: Erstellen Sie ein Modell
[Ruby on Rails] So implementieren Sie die Tagging- / inkrementelle Suchfunktion für Posts (ohne Gem)
Ich möchte ein kleines Symbol in Rails verwenden
Ich habe versucht, eine Anmeldefunktion mit Java zu erstellen
So schreiben Sie eine Datumsvergleichssuche in Rails
Ich möchte der Kommentarfunktion eine Löschfunktion hinzufügen
Ich habe versucht, eine Antwortfunktion für die Rails Tutorial-Erweiterung (Teil 3) zu erstellen: Ein Missverständnis der Spezifikationen wurde behoben
[Ruby on Rails] Beim Ausführen von RSpec wird aufgrund einer anderen Gem-Version eine Warnung angezeigt.
Ich habe versucht, eine Nachrichtenfunktion für die Erweiterung Rails Tutorial (Teil 2) zu erstellen: Erstellen Sie einen Bildschirm zum Anzeigen