초보자용 주제 커스텀 필드 추가 방법

토픽에 커스텀 필드를 추가하는 방법을 이해하려고 하고 있으며, 매우 기본적인 예제를 다루고 있습니다. 목표: 생성되는 각 토픽에 "sample_field"라는 이름의 커스텀 필드를 추가하고, 간단한 문자열 값을 부여하는 것입니다.

투표 플러그인, 해결됨 플러그인, 그리고 이 토론 등 다양한 예제를 살펴봤지만, 이 플러그인들은 커스텀 필드를 이용해 훨씬 더 많은 일을 수행하고 있어 아직 필요한 기본 코드를 파악하지 못했습니다.

그래서 아직 목표에 도달하지 못했는데, plugin.rb 파일에 뭔가 빠져 있는 것 같고(제 생각에는), 토픽이 생성될 시점에 문자열 값을 custom_field에 바인딩하는 방법도 아직 찾지 못했습니다.

이것이 작동하려면 무엇이 필요할까요?

도움 주시면 감사하겠습니다. 감사합니다!

현재까지 작성한 내용은 다음과 같습니다.

plugin.rb:
// 커스텀 필드 생성:

  after_initialize do
     Topic.register_custom_field_type('sample_field', :string)
     add_to_serializer(:topic_view, :custom_fields) { object.custom_fields } // 클라이언트 측에서 커스텀 필드를 표시하려면
  end

assets/javascripts/initializers/topic-custom-field.js.es6:
// 커스텀 필드 객체를 초기화하고 서버로 전송할 수 있도록 설정:

import { withPluginApi } from 'discourse/lib/plugin-api';

export default {
  name: 'topic-custom-field',
  initialize() {
    withPluginApi('0.8.31', api => {
      api.modifyClass('model:topic', {
        custom_fields: {},
        asJSON() {
          return Object.assign(this._super(), {
            custom_fields: this.custom_fields
          });
        }
      })
    })
  }
}

그렇다면, 토픽이 저장될 시점에 커스텀 필드의 값을 토픽에 추가하는 방법은 무엇일까요?

토픽의 핵심 “저장” 동작은 코드베이스의 다음 위치에 있다고 생각합니다:

app/templates/composer.hbs:

  <div class="save-or-cancel">
            {{#unless model.viewFullscreen}}
              {{composer-save-button action=(action "save")
                                     icon=saveIcon
                                     label=saveLabel
                                     disableSubmit=disableSubmit}}
...

그 “저장” 동작이 발생할 때 무언가(이 경우 커스텀 필드에 값을 추가하는 것)를 수행하는 방법은 무엇일까요?

initializers 아래에 js 파일을 만들어서 다음과 같은 작업을 수행할 수 있을 것 같다고 시도해 봤습니다:

api.modifyClass('component:composer-save-button', {
   actions: {
       topic.set('custom_fields.sample_field', 'here's a value for the sample_field')
   }
}

하지만 composer.hbs의 “저장” 동작과 해당 "topic.set"을 연결하는 방법을 모릅니다.


더 간단한 방법이 있다면 기꺼이 듣고 싶습니다!

완벽한 예시는 떠오르지 않지만, 나중에 하나 만들어볼 수도 있겠네요.

다른 플러그인들을 살펴보면 예시를 찾을 수 있을 겁니다. 딱 떠오르는 건 없지만, all-the-plugins라는 이름의 Discourse 저장소가 있는데, 거기서 필요한 걸 찾을 때 grep을 자주 씁니다.

지금은 테스트 중인 리액션 플러그인이 좋은 예시가 될 것 같네요. 배너를 확인하고 해당 플러그인을 한번 살펴보세요.

네, 항상 기존 플러그인을 확인해 보세요.

다음은 예시입니다:

이것은 다음 커넥터와 컴포넌트에 의존합니다:

다들 감사합니다–이것들을 살펴볼게요. 원래 글에서 이미 다른 예제들을 많이 검토했었다고 언급했었는데요. 제가 제공한 코드에 대해 어떤 의견이 있으신가요?

죄송합니다. 제 눈에는 명확한 문제가 보이지 않았습니다. 플러그인 개발은 점점 더 잘하게 되긴 했지만, 위험할 만큼 아는 정도에 머물러 있는 것 같다는 느낌이 자주 듭니다.

'Discourse 방식’으로 처리할 수 있다면, 즉 Topic Meta 영역에서 데이터를 편집하고 나중에 연필 아이콘이 클릭될 때만 처리하는 방식이라면, 현재 코드는 과도하게 복잡할 수 있습니다.

올바르게 연결된 입력 상자를 렌더링하고, 값을 Topic View에 직렬화(Serialize)했는지 확인하기만 하면 됩니다.

PostRevisor 코드가 커스텀 필드를 업데이트하는 마법을 대신 수행해 줍니다.

Locations 플러그인 예시를 참고해 보세요. 그 예시조차도 필요한 것보다 더 많습니다.

어떤 모습인지 확인하기 위해 Locations 플러그인도 실행해 보세요.

다음은 입력 시나리오가 약간 다르지만 동일한 메커니즘과 훅을 활용하는 또 다른 예시입니다:

https://github.com/paviliondev/discourse-topic-previews/blob/master/assets/javascripts/discourse/connectors/edit-topic/select-thumbnail-connector.hbs

https://github.com/paviliondev/discourse-topic-previews/blob/6064a5940a80e69ed56a7cbe67f8ded8e33e5d67/plugin.rb#L82

감사합니다. PostRevisor는 잘 모르겠습니다. 지금 확인해 보고 있습니다.

Topic Meta 영역이 무엇을 의미하는지 잘 모르겠습니다. 특정 파일을 말씀하시는 건가요? (UI 측면에서는 생성을 위한 컴포저와 그 안에 있는 d-editor, 그리고 토픽 뷰 자체는 알고 있습니다. 그런데 “Meta” 영역이 어디에 있는지 잘 모르겠습니다.)

저는 카테고리 및 태그 정보를 메타데이터로 간주합니다.

아래는 현재 작동하는 기본 예시입니다. 토픽 커스텀 필드를 생성한 후 값을 설정하는 방법입니다. 이 예시에서는 사용자가 토픽 보기 페이지의 특정 버튼을 클릭할 때 필드가 설정됩니다.

토픽 커스텀 필드를 가진 플러그인들을 살펴보면, plugin.rb에서 PostRevisor(예: PostRevisor.track_topic_field)와 DiscourseEvent.on(:topic_created) do |topic|...가 공통적으로 사용되고 있음을 알 수 있습니다. 이를 통해 버튼을 클릭하지 않고도 커스텀 필드를 설정할 수 있을 것입니다. 예를 들어, 토픽이 생성될 때 커스텀 필드를 설정하는 식입니다. 다만 아직 이를 완전히 파악하지는 못했습니다.

[편집: plugin.rb에서 토픽 생성 시점에 커스텀 필드 값을 토픽에 추가하는 코드(별도의 버튼을 클릭해야 하는 대신)를 제안해 주실 분이 있다면, 꼭 제안해 주세요! :slight_smile: ]

따라서 아래는 그 복잡한 기능 없이 작동하는 기본 예시입니다:

plugin.rb

Topic.register_custom_field_type('sample_field', :string)
add_to_class(:topic, :sample_field) { self.custom_fields['sample_field'] } ##아마도 불필요할 수 있음. discourse-locations 플러그인의 plugin.rb 83행에 기반
	
add_to_serializer(:topic_view, :sample_field, false) { object.topic.sample_field } ##사용자에게 커스텀 필드 결과를 표시하려는 경우에만 필요할 수 있음

connector/[add-button].hbs

//여기서 예시: connector는 topic-above-post-stream이며, 플러그인 아웃렛에 모델(topic)을 전달합니다

<button {{action "setThatTopic" model}}>여기를 클릭하세요</button>

connector/[add-button].js.es6

import Topic from 'discourse/models/topic';  //아마도 불필요할 수 있음

export default {			
    actions: {
       setThatTopic(model){
           model.set('custom_fields.sample_field', 'newValue123')
           console.log('커스텀 필드가 있는지 테스트 = ' + JSON.stringify(model.custom_fields))
        }
     }
}

assets/javascripts/initializers/topic-custom-field.js.es6

//이것도 아마 불필요할 수 있습니다. 그러나 아이디어는 커스텀 필드 객체를 초기화하여 서버로 전송할 수 있도록 만드는 것입니다:

import { withPluginApi } from 'discourse/lib/plugin-api';

export default {
    name: 'topic-custom-field',
     initialize() {
	   withPluginApi('0.8.31', api => {
		 api.modifyClass('model:topic', {
			custom_fields: {},
			asJSON() {
			    return Object.assign(this._super(), {
				custom_fields: this.custom_fields
			   });
			}
	     })
	   })
    }
}

방금 이 방법을 보여주는 "교육용 플러그인"을 게시했습니다

@angus님, 감사합니다. 정말 큰 도움이 되네요. 디스코스를 활용한 코딩을 훨씬 쉽게 만들어 주는 바로 그런 자료입니다. 개인적으로 이런 종류의 자료를 다양한 디스코스 작업에 대해 보고 싶습니다. 즉, 한 번에 하나의 기능만 구현하는, 핵심만 짚은 최소한의 코드 예시 말이죠. 예를 들어 카테고리나 그룹에 대한 사용자 정의 필드도 포함하면 좋겠습니다. 이런 자료는 시간을 크게 절약해 줍니다.