React, Rails 및 전체 패키지를 결합하여 SPA 웹 어플리케이션 구축

Flatiron School에서 소프트웨어 공학을 배운 지 1년 만에 드디어 제 마지막 프로젝트가 왔습니다.이 프로젝트는 Rails 백엔드와 React 백엔드를 통해 우리가 전체 과정에서 배운 모든 것을 돋보이게 하기 위한 것이다.그리고 이 프로젝트는 제 훈련소의 최고봉이기 때문에 제가 한 사람으로서의 신분을 보여줄 뿐만 아니라 현실 세계의 문제를 해결할 수 있는 것들을 만들고 싶습니다.
나는 내가 어떤 프로젝트를 하고 싶은지, 그리고 내 투자조합이 이해하기 쉬운지 알아보는 데 많은 시간을 들였다.나는 이 프로그램과 운동 프로그램 사이를 왔다 갔다 하며 이 프로그램을 사용하기로 결정했다. 왜냐하면 나는 이미 여러 번 해 놓은 프로젝트를 다시 처리하는 것이 아니라 문제를 해결하기 시작할 수 있기 때문이다.내가 걱정하는 것은 전자음악이 너무 복잡해서 사람들이 빨리 이해하기 어려우므로 이 방향으로 발전하는 것은 일종의 위험이다.그러나 나는 내가 이런 복잡한 문제들을 간소화해서 쉽게 이해하고 사용할 수 있을 것이라고 믿는다.
나는 전자 음악을 좋아한다.House, Techno, Progressive, 그리고'EDM'우산 아래의 모든 소형 하위 유형.나는 매일 인터넷에서 많은 DJ를 주목하고 그들의 믹스를 틀어 놓는다.나는 내가 가장 좋아하는 DJ 플레이어를 찾아내려고 노력해 왔다는 것을 알게 되었다.보통 저는 Shazam과 Soundhound 등 도구를 사용해 보려고 하지만 가정 음악을 식별하는 데 엉망으로 유명하다(특히 DJ가 한 곡을 다른 곡에 섞거나 곡의 관건을 바꾸기 때문이다).인터넷에서 노래 추천과 아티스트 차트를 검색해서 이 노래를 찾을 수 있었으면 좋겠어요.더 복잡한 것은 많은 DJ들이 아직 발표되지 않은 곡을 재생하기 때문에 그들은 인터넷에서 거의 찾을 수 없다.
이 문제를 해결하기 위해 저는 On Rotation - SPA 인터넷 앱을 만들었습니다. 전자 음악의 팬들은 그 중에서 전자 음악을 협동하여 식별하고 그들이 가장 좋아하는 곡을 식별한 후에 알림을 받을 수 있습니다.

특징.

  • 사용자 로그인
  • 트랙 리스트, 트랙 리스트\트랙, 아티스트 및 레이블 추가
  • 알림 시간
  • 을 사용하여 유튜브 동영상을 입력하여 추적
  • 알 수 없는 궤도에 대한 식별 제안
  • 입력
  • 다른 사용자가 제출한 궤도 표지에 대해 투표
  • 책갈피 추적을 통해 정확한 표지가 승인된 후에 통지를 받을 수 있도록 한다
  • 프로젝트 방법


    코드를 한 줄 작성하기 전에, 나는 최종 제품을 구상하려고 했다.나는 나 자신에게 물었다.
  • 어플리케이션의 모양과 동작은 무엇입니까?
  • 나는 어떻게 이해할 수 있는 방식으로 사용자에게 데이터를 보여 줍니까?
  • 전자 음악의 성질을 감안하여 나는 어떻게 부족한 데이터를 처리하고 검증해야 합니까?
  • 로그인한 사용자에 비해 일반인은 어떤 기능을 사용할 수 있습니까?
  • MVP에 포함되지 않는 기능은 무엇입니까?
  • 나는 노트에 프로젝트 도면을 디자인하여 내가 원하는 기능의 작업 방식과 외관을 개선하기 시작했다.나는 아이콘과 재사용 가능한 구성 요소에 대해 필기를 하고 아이디어를 냈다.그런 다음 Adobe XD의 모양과 기능을 보여주는 와이어프레임을 만들었습니다.나는 며칠 동안 응용 프로그램의 테두리를 기초하고 다양한 데이터를 보여주는 방법을 집중적으로 토론했다.이것은 나로 하여금 데이터가 어떻게 서로 교류하는지 알게 했다. 특히 응용 프로그램의 일부 핵심 기능은 부족한 데이터를 채우는 것이기 때문이다.나는 백엔드를 만들 때 단추 작업 방식의 전용 이름을 가지게 하기 위해 내가 사용하고 싶은 아이콘을 다시 설계했다.예를 들어, 나는 책갈피 대신 '눈' 아이콘으로 이 노래를 보았지만, 그것은 자극적이지 않아서 사용할 수 없을 것 같다.그리고 나서 나는 별이나 마음을 생각했지만, 이것은 누군가가 이 노래가 무엇인지 알 때 나에게 알려주는 것이 아니라, '좋아' 를 의미하는 것 같았다.나는 위에 별이 있는 책갈피를 선택했다. 왜냐하면 이것은 '가장 좋아하는 것' 을 암시하고, '나중에 이것을 다시 보자' 를 의미하기 때문이다.

    백엔드


    데이터베이스 모드


    그리고,drawio에서 제 모델을 그렸고, 데이터 형식, 검증, 요구 사항을 작성했습니다.이것은 정말 내가 사물 간의 관계를 사고하는 데 도움을 준다.그리고 저는 모델 구축과 이동, 모델, 관계 구축과 데이터베이스 제약을 시작한 다음에 모델 검증을 했습니다.나는 seed 파일을 작성하는 동시에 rails 컨트롤러에서 검증/제약과 관계를 정확하게 처리할 수 있도록 노력한다.나는 모든 것이 정상임을 확보하기 위해 이 단계에 한동안 머물렀다.

    나는 더 쉽게 이해할 수 있는 코드를 작성하기 위해 모델과db 제약에 대해 열을 사용하여 별명을 인용하기로 결정했다.나는 {foreign_key: } 산열과 {references: } 산열의 이전을 통해 시작했다.
    # /db/migrate/create_tracklists.rb
    
    class CreateTracklists < ActiveRecord::Migration[6.1]
      def change
        create_table :tracklists do |t|
          t.string :name, :null => false
          t.date :date_played, :null => false
          t.references :artist, :null => false, :foreign_key => true
          t.string :youtube_url
          t.references :creator, :references => :users, :null => false, :foreign_key => { :to_table => :users}
          t.timestamps
      end
    end
    
    Active Record::Base가 belongs_to 방법으로 유사한 산열을 통해 별명 관계 데이터를 전달하는 방법을 알아야 합니다.
    # /app/models/tracklsit.rb
    class Tracklist < ApplicationRecord
      belongs_to :creator, class_name: 'User'
    
      ...
    
    end
    
    또 다른 문제는 Tracklist Tracks가 특정한 순서로 Tracklist에서 되돌아와야 하는데, SQL의 구조는 연결표를 만들지 않고 관계 데이터를 질서정연하게 저장하는 것을 허용하지 않는다.이 문제의 해결 방안 중 하나는 Tracklist Tracks를 하나의 체인 테이블로 구성하여 그 전신을 인용하는 열을 만드는 것이다.앞에 있는 트랙리스트 트랙을 가리키는 predessor_id 열을 만들었습니다.
    class CreateTracklistTracks < ActiveRecord::Migration[6.1]
      def change
        create_table :tracklist_tracks do |t|
          t.references :tracklist, :null => false, foreign_key: true
          t.references :track, :null => false, foreign_key: true
          t.time :cue_time
          t.integer :predessor_id, :unique => true
          t.references :identifier, references: :users, :null => false, foreign_key: { to_table: :users }
          t.timestamps
        end
      end
    end
    
    Tracklist 모델에서 기본값id을 순환하고 덮어쓰는 방법을 사용하고 pull Tracklist tracks out을 질서정연하게 호출합니다.
    # /app/models/tracklist.rb
    
    class Tracklist < ApplicationRecord
      ...
    
      def tracks
        tracklist_tracks = self.tracklist_tracks.includes(:track)
        current_tracklist_track = tracklist_tracks.find { |tracklist_track| tracklist_track.predessor_id == nil}
    
        array_of_tracks = []
        order = 1
    
        loop do
          current_track = current_tracklist_track.track
          current_track.order = order
          order += 1
          array_of_tracks << current_track
          current_tracklist_track = tracklist_tracks.find { |tracklist_track| tracklist_track.predessor_id == current_tracklist_track.id}
    
          break if current_tracklist_track == nil
        end
    
        array_of_tracks
      end
    
    end
    

    시리얼화된 데이터


    넷플릭스가 belongs_to 에 대한 지원을 중단했기 때문에 데이터를 전방으로 서열화하기 위해서 active_model_serializers 사용하기로 결정했습니다.Gemfile에 추가한 후에 컨트롤러에서 fast_jsonapi 새로운 서열화 프로그램을 신속하게 구축할 수 있습니다.rails g serializer <model_name>의 좋은 특징은 컨트롤러가 자동으로 active_model_serializers 디렉터리에서 같은 이름의 일치하는 서열화 프로그램을 찾고 rails의 마력 응용을 서열화하는 것이다./serializers의 또 다른 중요한 특징은 서열화 프로그램에서 active_model_serializersbelongs_to 관계를 작성하여 모델의 구조와 일치하도록 하는 것이다.
    사용자가 두 가지 종류의 알림 (BookmarkedTracklist와 BookmarkedTracklistTrack) 을 받아야 하기 때문에, 나는 알림 서열화 프로그램에서 사용자 정의 데이터 서열화를 구축했다.이렇게 하면 서열화 프로그램은 has_many 클래스 호출의 track 속성만 표시하고 BookmarkedTrack 클래스 호출의 tracklist 속성만 표시합니다.우리는 BookmarkedTracklistTrack 산열을 속성이나 관계에 전달해서 조건 속성을 작성할 수 있으며, 이 방법이truthy 값으로 되돌아오기만 하면 된다.
    # /app/serializers/notification_serializer.rb
    
    class NotificationSerializer < ActiveModel::Serializer
      attributes :id, :updated_at, :has_unseen_updates
    
      belongs_to :track, serializer: TrackSerializer, if: :is_track?
      belongs_to :tracklist, if: :is_tracklist?
    
      def is_track?
        object.class == BookmarkedTrack
      end
    
      def is_tracklist?
        object.class == BookmarkedTracklist
      end
    
    end
    

    프런트엔드


    구성 요소를 구축하기 시작했을 때, 구성 요소, 용기, 축소기, 조작, 페이지 보기를 분리하는 파일 구조를 찾기가 매우 어려웠다.몇 가지 연구를 한 후에 나는 모든 Reduxjs를 {if: <instance_method>} 디렉터리에 저장하고 모든 페이지 보기를 store 디렉터리에 저장하기로 결정했다.레이아웃 구성 요소를 views 디렉터리에 저장하고 전체 응용 프로그램에서 사용하는 소형 기능 구성 요소에 layout 하위 디렉터리를 제공하기로 결정했습니다.
    # .
    
    ├── README.md
    ├── public
    └── src
        ├── App.js
        ├── components
        ├── containers
        ├── index.js
        ├── layout
        │   ├── NavBar
        │   └── global
        ├── store
        │   ├── actions
        │   └── reducers
        └── views
            ├── Artist
            ├── Home.js
            ├── NotFound.js
            ├── Track
            └── Tracklist
    

    React 공유기의 실현


    React는 계속해서 하나의 페이지 응용 프로그램에서 모든 구성 요소를 추가하고 삭제하기 때문에 사용자는 React UI를 사용하지 않고 특정 페이지로 수동으로 이동할 수 없습니다.REST-ful URL의 가상을 만들기 위해서 셸 실행 global 을 통해 React Router라는 패키지를 추가했습니다.그리고 나는 npm i react-router-dom<App> 부품을 쌌다.그곳에서 나는 <Router><Switch> 구성 요소를 사용하여 경로를 구축했다.<Route> 도구를 사용하면 공유기를 통해 제공되는 도구를 사용할 수 있습니다.이렇게 하면 모든 하위 구성 요소가 현재 경로를 쉽게 알고 특정 자원을 식별할 수 있다render.
    // /src/App.js
    
    ...
    
      <Switch>
        <Route exact path="/" render={() => <Home />} />
        <Route exact path="/tracklists" render={(routerProps) => <TracklistIndex {...routerProps} />}/>
    
        ...
    
        <Redirect to="/404" />
      </Switch>
    
    ...
    
    
    id 구성 요소 끝에 있는 <Redirect> 구성 요소를 사용하면 404페이지로 사용자를 안내하여 그들이 요청한 루트가 존재하지 않는다는 것을 알 수 있습니다.

    Redux 및 Thunk 추가


    내가 응용 프로그램을 개발함에 따라 상태 관리가 문제가 되기 시작했다.구성 요소는 사용자가 로그인했는지, 사용자 ID가 무엇인지, 특정 구성 요소에 대해 투표했는지, 표지를 만들었는지, 페이지에 표시된 다른 정보를 알아야 합니다.Redux를 입력합니다.
    Redux는 구축된react 패키지입니다. 모든 구성 요소의 상태를 하나의 중심 상태로 이동할 수 있고, 모든 하위 구성 요소가 전체 프로그램의 상태를 자유롭게 수정할 수 있습니다.
    <Switch>를 사용하면 다양한 감속기를 중앙 저장소로 이동할 수 있습니다.게다가 combine-reducers의 강력한 기능으로 우리는 thunk 작업에서 비동기적으로fetch를 호출할 수 있다.
    // src/store/reducers/index.js
    
    export default combineReducers({
      indexReducer,
      tracklistShowReducer,
      notificationReducer,
      sessionReducer,
    });
    
    // src/index.js
    
    import reducer from "./store/reducers/index";
    let store = createStore(reducer, composeWithDevTools(applyMiddleware(thunk)));
    
    

    OnRotation 캡처


    /



    / 경로 목록



    / 트랙 목록 / 신규



    /tracklist/:id



    알림 드롭다운 목록



    제안된 항적 식별



    날짜 선택기


    좋은 웹페이지 즐겨찾기