Rails에서 태그 지정 기능 구현

17256 단어 RubyRails

입문


현재 제작된 응용 프로그램으로 라벨 기능을 설치했기 때문에 설치 방법을 남겼다.
Rails에는 acts-as-taggable-on이라는 gem가 있는데 표기 기능의 실현을 간소화할 수 있지만 관련 연습을 바탕으로 자체적으로 실현된다.
현재 제작된 응용 프로그램의 PK, FK의 ER 그림은 다음과 같습니다.

운영 환경


이 글은 다음과 같은 환경에서 동작 확인을 진행하였다.
ruby 2.7.1
rails 6.0.3
DB MySQL

모델 생성하기


단면 모델이 이미 제작된 것을 전제로 진행한다.
우선, tag 모형과 tag_재배치ship 모델을 만듭니다.
$ rails g model tag name:string
$ rails g model tag_relationship profile:references tag:references
복합 포인트 인덱스를 늘입니다.
이렇게 하면 같은 표시를 두 번 저장할 수 없습니다.
XXXXXXXXXXXXXX_create_tag_relationships.rb
class CreateTagRelationships < ActiveRecord::Migration[6.0]
  def change
    create_table :tag_relationships do |t|
      t.references :profile, foreign_key: true
      t.references :tag, foreign_key: true

      t.timestamps
    end
    add_index :tag_relationships, [:profile_id, :tag_id], unique: true
  end
end
태그 이름null:false을 입력해야 하기 때문입니다.
XXXXXXXXXXXXXX_create_tags.rb
class CreateTags < ActiveRecord::Migration[6.0]
  def change
    create_table :tags do |t|
      t.string :name, null: false

      t.timestamps
    end
  end
end

모델 연관 및 검증


기본적인 중간표를 사용하는 다대다의 실현이다.
has_many through도 정의합니다.이것은 단면 모델에서도 마찬가지다.
라벨 이름은 독특하니 반드시 유지해야 하기 때문에 다음과 같은 검증을 해야 한다.
tag.rb
class Tag < ApplicationRecord
  has_many :tag_relationships, dependent: :destroy
  has_many :profiles, through: :tag_relationships

  validates :name, uniqueness: true, presence: true
end
tag_relationship.rb
class TagRelationship < ApplicationRecord
  belongs_to :profile
  belongs_to :tag

  validates :tag_id, presence: true
  validates :profile_id, presence: true
end
profile.rb
class Profile < ApplicationRecord
  belongs_to :user
  has_many :tag_relationships, dependent: :destroy
  has_many :tags, through: :tag_relationships
end

뷰 작성


현재 제작된 응용 프로그램에서는 새로 프로필을 등록할 때도 라벨profiles/new.html.erb을 등록하여 실현하기를 희망합니다.
라벨의 부분만 발췌하다.f.text_field :tag,params[:profile][:tag]에서 파라미터를 수신할 수 있습니다.
profiles/new.html.erb
<div class="input-field col s12">
  <i class="material-icons prefix">local_offer</i>
  <%= f.text_field :tag, placeholder: "タグを複数つけるには' , 'で区切ってください" %>
</div>
표시할 때, each에서 그룹에 저장된 태그를 반복합니다.
profiles/show.html.erb
<% @user_profile.tags.each do |tag| %>
  <div class="chip">
    <%= tag.name %>
    <i class="close material-icons">close</i>
  </div>
<% end %>

컨트롤러 생성


사용자와 프로필 사용has_one은 일대일 관계이기 때문에build에서'실례명.build_연관명'으로 사용됩니다.
기본 정보와 함께 보내는 태그를 저장할 수 있습니다.
profiles_controller.rb
  def new
    @user_profile = current_user.build_profile
  end

  def create
    @user_profile = current_user.build_profile(profile_params) # profile_paramsはストロングパラメーター 
    tag_list = params[:profile][:tag].split(',') # viewでカンマ区切りで入力してもらうことで、入力された値をsplit(',')で配列にしている。
    if @user_profile.save
      @user_profile.save_tags(tag_list) # save_tagsというインスタンスメソッドを使って保存している。
      flash[:notice] = "プロフィールの設定が完了しました"
      redirect_to root_url
    else
      render 'new'
    end
  end
save_tags 방법은 다음과 같습니다.
profile.rb
  def save_tags(profile_tag)
    profile_tag.each do |tag|
      new_tag = Tag.find_or_create_by(name: tag)
      self.tags << new_tag
    end
  end
"find_or_create_by"메서드는 매개변수에 지정된 값이 있으면 값을 가져오고 없으면 생성합니다.말 그대로find나create의 방법이다.
self.tags << profile_tag는 프로필과 관련된 탭의 배열에 새로운 탭을 추가했습니다.
<>뿐만 아니라push 방법도 같은 방식으로 요소를 추가할 수 있습니다.

태그 편집 기능


간략한 파일을 편집할 때 태그를 변경할 수도 있습니다.
부분 뷰를 발췌합니다.
profiles/edit.html.erb
<div class="input-field col s12">
  <i class="material-icons prefix">local_offer</i>
  <%= f.text_field :tag, value: @tag_list, placeholder: "タグを複数つけるには' , 'で区切ってください" %>
</div>
value: @tag_list 기존 값을 표시합니다.
편집 작업 설명 @tag_list 은 보기에 기존 값을 표시합니다.
pluck 함수를 사용하여 수신기의 열을 쉽게 얻을 수 있습니다.
이번에는 @user_profile.tags.pluck(:name)이기 때문에 프로필과 관련된 탭의name열을 그룹으로 가져옵니다.
join (',') 에서 가져온 그룹을','로 구분된 문자열로 설정합니다.
profiles_controller.rb
  def edit
    @user = Profile.find(params[:id]).user
    @user_profile = @user.profile
    @tag_list = @user_profile.tags.pluck(:name).join(',')
  end

  def update
    @user = Profile.find(params[:id]).user
    @user_profile = @user.profile
    tag_list = params[:profile][:tag].split(',')
    if @user_profile.update(profile_params)
      @user_profile.save_tags(tag_list)
      flash[:notice] = "プロフィールの変更が完了しました"
      redirect_to root_url
    else
      render 'edit'
    end
  end
이번 중복 처리는 간단하기 때문에pluck 함수를 사용하지 않아도'&:방법'을 사용하면 같은 정도의 기술량으로 라벨의 이름을 얻을 수 있습니다.@user_profile.tags.map(&:name).join(',')그러나 이번 상황에서pluck는 SQL에서만 지정한 열을 취하기 때문에 맵보다 빠르다.(틀리면 지적해 주세요.)그래서 이렇게 플러그를 사용합니다.
save_tags 방법을 업데이트에서도 사용할 수 있도록 합니다.
profile.rb
  def save_tags(profile_tag)
    current_tags = self.tags.pluck(:name) unless self.tags.nil?
    old_tags = current_tags - profile_tag
    new_tags = profile_tag - current_tags

    # 古いタグを削除
    old_tags.each do |old_tag|
      self.tags.delete(Tag.find_by(name: old_tag))
    end

    # 新しいタグを追加
    new_tags.each do |new_tag|
      add_tag = Tag.find_or_create_by(name: new_tag)
      self.tags << add_tag
    end
  end
문자열의 배열도 다음과 같이 계산할 수 있다.
a = ["first", "second", "third"]
b = ["first", "third", "forth"]
a - b => ["second"]
b - a => ["forth"]
그것으로 낡은 라벨과 새 라벨을 분리하여 각각 처리한다.

마지막


이렇게 하면 표지의 생성, 편집 기능이 완성된다.
아직 사용자에게 좋은 형식이라고 말할 수 없기 때문에 js 등을 사용하여 사용자에게 사용하기 쉬운 것을 개선하고 싶습니다.

참고 자료


pluck 방법에 대한 편리한 일
pluck과map의 차이를 조사하다
Rails에서 Gem을 사용하지 않고 태그 기능을 수행할 때 설명

좋은 웹페이지 즐겨찾기