[Rails] STI 사용 후 DB가 시원해졌어요.

12904 단어 STIRails
STI를 사용하면 책상이 시원하다.

개요

  • 축구선수에 등록해서 더 많은 정보를 얻고 싶습니다.
  • Player 모형 제작.
  • 제공하고자 하는 정보 중 ポジション,所属(일본 대표 또는 올림픽 대표),タイプ(속도, 역량과 기술 등)는 다대다 디자인이다.
  • 스파이크를 등록하여 여러 정보를 갖도록 한다.
  • Spike 모형 제작.
  • 보유할 정보 중 適応グラウンド는 다대다 디자인이다.
  • ↓ 처음에는 이렇게 디자인했어요.

    보시다시피 지루하고 많을 때 가지고 싶은 정보를 추가할 때마다 두 개의 표를 추가해야 합니다.
    따라서 STI를 사용하는 것이 좋습니다.

    매끄러워 갖고 싶은 정보를 많이 늘리고 싶을 때도 테이블을 다시 만들 필요가 없다.

    사용법




    빨간 테두리가 파란색 테두리에 저장되고 type을 누르면 Tags표에 저장된다고 상상해 보세요.
    데이터 취득은 유형에 따라 진행할 수 있다.
    빨간색 상자를 파란색 상자에 저장하려면 빨간색 상자의 모델을 만들어 Tag 모델을 상속합니다.

    관계


    playre.rb
    class Player < ApplicationRecord
      has_many :player_tags, dependent: :destroy
      has_many :tags, through: :player_tags
    end
    
    player_tag.rb
    class PlayerTag < ApplicationRecord
      belongs_to :player
      belongs_to :tag
    end
    
    tag.rb
    class Tag < ApplicationRecord
      has_many :player_tags, dependent: :destroy
      has_many :players, through: :player_tags
      has_many :spike_tags, dependent: :destroy
      has_many :spikes, through: :spike_tags
    end
    
    spike.rb
    class Spike < ApplicationRecord
      has_many :spike_tags, dependent: :destroy
      has_many :tags, through: :spike_tags
    end
    
    spike_tag.rb
    class SpikeTag < ApplicationRecord
      belongs_to :spike
      belongs_to :tag
    end
    
    
    여기까진 보통 다대다 관계야.
    STI를 사용하려면 Tag 모델을 상속하는 빨간색 상자 모델을 만들어야 합니다.

    Tag 모델 상속


    position.rb
    class PositionTag < Tag
    end
    
    belongs.rb
    class BelongsTag < Tag
    end
    
    genre.rb
    class GenreTag < Tag
    end
    
    ground.rb
    class GroundTag < Tag
    end
    
    color.rb
    class ColorTag < Tag
    end
    
    앞으로 더 많은 정보와 더 많은 정보를 얻고 싶다면 이렇게 type열에 깊이 들어가고 싶은 모델을 만들어 Tag모델을 계승시키면 된다.

    관계 추가

    player.position_tags 또는 spike.ground_tags 관계를 추가하여 데이터를 얻습니다.
    playre.rb
    class Player < ApplicationRecord
      has_many :player_tags, dependent: :destroy
      has_many :tags, through: :player_tags
      # 追加
      has_many :position_tags, through: :player_tags
      has_many :genre_tags, through: :player_tags
      has_many :belongs_tags, through: :player_tags
    end
    
    player_tag.rb
    class PlayerTag < ApplicationRecord
      belongs_to :player
      belongs_to :tag
      # 追加
      has_many :ground_tags, through: :spike_tags
      has_many :color_tags, through: :spike_tags
    end
    
    여기는 "어? 모르겠어 왜?"적분position_tags 또는 ground_tags의 책상은 어디에 있습니까?
    결론은 Tags 테이블의 type 열의 내용과 각각의 관계가 조합된다는 것입니다.
    Rails의 type 열은 STI 전용 특수 열이므로 평소에 사용하지 않도록 주의하십시오.

    데이터 삽입


    실제로 이런 사용법은 없지만 절차를 추적하고 싶어 태그에 데이터를 삽입한 부분만 기술하고 있다.
    views/players/new.html.slim
    = form_with model: @player, local: true do |f|
      .form-group
        = f.label :name
        = f.text_field :name, class: "form-control"
      .form-group
        = f.label :position
        = f.text_field :position, class: "form-control"
      .action.mt-3
        = f.submit class: "btn btn-primary"
    
    이 내용을 보내면params[:player][:position] 서버에 저장되어 서버에 요청을 제출합니다.
    여러 문자열을 보내려면 임의의 문자열/ 또는 ,로 구분하십시오.
    이번 입력FW/MF 요청입니다.
    players.controller.rb
    def create
      player = Player.new(player)
      position_tag_names = params[:player][:position]
      player.save
      # ポイント
      player.position_tags = position_tag_names.split('区切りたい文字列').map { |name| PositionTag.find_or_create_by(name: name) }
    end
    
    
    
    
    private
    
    def player_params
      params.require(:player).permit(:name)
    end
    
    ポイント 이하 1문은 간이다.
    나는 본래 모형으로 처리하는 것이 가장 좋다고 생각한다.position_tag_names 임의로 분할하고자 하는 문자열 (/ 이나 , 을 만들 때마다string (split) 을 하나씩 배열에 넣고 (map) 등록하거나 미리 등록하면 이string을 되돌려줍니다.(find_or_create_by)
    데이터베이스를 확인한 후 다음과 같이 등록합니다.
    id
    type
    name
    created_at
    updated_at
    1
    PositionTag
    FW
    ~~~~~~~~~~
    ~~~~~~~~~~
    2
    PositionTag
    MF
    ~~~~~~~~~~
    ~~~~~~~~~~

    데이터를 꺼내보도록 하겠습니다.


    단말기
    [1] pry(main)> player = Player.first
       (1.4ms)  SET NAMES utf8,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
      Player Load (0.5ms)  SELECT  `players`.* FROM `players` ORDER BY `players`.`id` ASC LIMIT 1
    => #<Player:0x00007fcea7e69718 id: 1, name: "SS2ゴハン", created_at: Mon, 15 Jun 2020 18:13:45 JST +09:00, updated_at: Mon, 15 Jun 2020 18:13:45 JST +09:00, spike_id: 1>
    [2] pry(main)> player.position_tags
      PositionTag Load (1.6ms)  SELECT `tags`.* FROM `tags` INNER JOIN `player_tags` ON `tags`.`id` = `player_tags`.`tag_id` WHERE `tags`.`type` IN ('PositionTag') AND `player_tags`.`player_id` = 1
    => [#<PositionTag:0x00007fcea8f3a498 id: 1, type: "PositionTag", name: "FW", created_at: Mon, 15 Jun 2020 18:13:45 JST +09:00, updated_at: Mon, 15 Jun 2020 18:13:45 JST +09:00>,
     #<PositionTag:0x00007fcea8f3a2e0 id: 2, type: "PositionTag", name: "MF", created_at: Mon, 15 Jun 2020 18:13:45 JST +09:00, updated_at: Mon, 15 Jun 2020 18:13:45 JST +09:00>]
    
    player.position_tags와 그 유저 관련position_tags.
    그리고 each로 회전해서 하나씩 표시하면 마음대로 할 수 있습니다.

    최후


    STI는 반모드에 대한 기사를 많이 봤지만 이번에는 인터페이스가 똑같아서 사용했다.
    상쾌하다.

    좋은 웹페이지 즐겨찾기