プラグインでの tag-chooser の使用

新しいトピックを作成する際に、カテゴリにデフォルトのタグを割り当てるプラグインを作成しています。

以下のコードは、タグ名を「|」で区切って入力すれば「動作します」。例えば「tag1|tag2」と入力すると動作します。(信じられないのですが、話をそれます。)

<h3>{{i18n 'topic_default_tag.title'}}</h3>
<section class='field default-tag'>
  <div class="default-tag">
  <label>
    {{input type="list" value=category.custom_fields.default_tag }}
    {{popup-input-tip validation=tagValidation}}
    {{i18n 'topic_default_tag.default_tag'}}
  </label>
  </div>
</section>

今、未検証の文字列ではなく、適切なタグセレクターを使いたいと考えています。以下のコードが動作するはずだと思うのですが:

<h3>{{i18n 'topic_default_tag.title'}}</h3>
<section class='field default-tag'>
  <div class="default-tag">
  <label>
    {{tag-chooser tags=category.custom_fields.default_tag tabindex="4" categoryId=category.id}}
    {{popup-input-tip validation=tagValidation}}
    {{i18n 'topic_default_tag.default_tag'}}
  </label>
  </div>
</section>

しかし、動作しません。私の問題の本質は、それらのハンドルバーの「魔法」がどのように機能するかについて、ほとんど知識がないことです。例えば、最初のセクションが動作するのは、内のdefault-tagからフィールド名を「魔法のように」取得しているからだろうと思いますが、それは運が良かっただけかもしれません。:slight_smile:

tag-chooserを使用すると、タグが配列としてRailsに渡されますが、それを|区切りの文字列に変換してCategoryCustomFieldに格納する前に、Railsがそれを捨ててしまいます。{{input type=list...}}を使用すると、自分で|区切りの文字列を入力でき、それがうまく機能します。配列を文字列に変換するために、Ember側で何か「Emberの魔法」が必要なのでしょうか?

もしかすると、What's the best approach to access category specific settings? のようなことをする必要があるかもしれません。

編集:Webhookが呼び出される前にタグを追加するには、DiscourseEvent.on(:post_created)ではなくafter_createを使用してください。Railsについてはほぼ理解できるようになりましたが、Ember、JavaScript、CSSについてはまだよくわかりません。

使用している変数に必要な値が含まれているか確認するには、{{log variable_name}} を使用してコンソールを確認してください。正しい値がコンポーネントに渡されていない場合、正しい出力が表示されません。

コアコードでも同様の操作を行って、値が正しく渡されているか確認できます。

もしこれが幼稚に聞こえるようでしたら、お許しください。

いいえ!私はただの原始人ですから。

それは非常に役立ちました。その方法がわからなかったのです。実は、そのフィールドにはデータが存在しますさらに、タグ名データは category.custom_fields.default_tag にあり、mini-tag-chooser に渡されています。category.id にはカテゴリの ID が含まれていますが、選択器はタグを提示していません。

そのデータがあればフィールドに反映されるかどうかは判断できません。

編集:おおっ!mini-tag-chooser ではなく tag-chooser を使えば、期待通りに動作します(上記のコード accordingly に修正します)。唯一の問題は、保存ボタンをクリックしてもデータが保存されないことです。

この行が気になります。タグが配列を受け取っている可能性があり、あなたのコードを見ると単一の値を渡しているように見えます(確認が必要です)。もし単一の値が渡されているなら、それを配列にして試してみてください。

Rails 側では、これは | で区切られた文字列ですが、送信後に確認すると、入力した内容は以下のように送信されているようです。
"custom_fields"=>{"default_tag"=>["error", "high-availability", "best-practices"]}, および "custom_fields"=>{"default_tag"=>["health-checks"]},

全体は以下の通りです。

Started PUT "/categories/2" for 127.0.0.1 at 2019-08-01 13:56:13 -0700
Processing by CategoriesController#update as */*
  Parameters: {"name"=>"Lounge", "slug"=>"lounge", "color"=>"EEEEEE", "text_color"=>"652D90", "permissions"=>{"trust_level_3"=>"1"}, "auto_close_hours"=>"", "auto_close_based_on_last_post"=>"false", "position"=>"3", "email_in"=>"", "email_in_allow_strangers"=>"false", "mailinglist_mirror"=>"false", "allow_badges"=>"true", "custom_fields"=>{"default_tag"=>["error", "high-availability", "best-practices"]}, "topic_template"=>"", "suppress_from_latest"=>"false", "all_topics_wiki"=>"false", "allow_global_tags"=>"false", "sort_order"=>"", "sort_ascending"=>"", "topic_featured_link_allowed"=>"true", "show_subcategory_list"=>"false", "num_featured_topics"=>"3", "default_view"=>"", "subcategory_list_style"=>"rows_with_featured_topics", "default_top_period"=>"all", "minimum_required_tags"=>"0", "navigate_to_first_post_after_read"=>"false", "search_priority"=>"0", "id"=>"2"}

つまり、謎の側では正しい処理が行われているようですが、Rails がカテゴリのカスタムフィールドを更新できていないようです。CategoryCustomField を扱う他のプラグインと比較し直してみます。

@fzngagan、本当にありがとうございます!

追記:うーん。問題はこれではないでしょうか。

Unpermitted parameter: :default_tag

その答えを見つけるのはきっと楽しいでしょう。それでも、お手伝いが必要であれば、喜んでサポートいたします。:slight_smile:

はい、その通りです。Rails はまだこの新しいフィールドをどのように扱えばよいか認識していません。新しいフィールドを add_to_serializer に追加する必要があります。カスタムフィールドを追加するプラグインで、その例を確認できます。

さて、plugin.rb には以下が含まれています:

  Category.register_custom_field_type('default_tag', :list)
  Site.preloaded_category_custom_fields << 'default_tag' if Site.respond_to? :preloaded_category_custom_fields
  add_to_serializer(:basic_category, :default_tag) { object.custom_fields["default_tag"] }

詳しくは GitHub - pfaffman/discourse-topic-default-tag: Allow topics to include default tags · GitHub をご覧ください。

私は混乱しています。なぜなら、

   {{input type="list" value=category.custom_fields.default_tag }}

は動作するのですが、

{{tag-chooser tags=category.custom_fields.default_tag tabindex="4" categoryId=category.id}}

は動作しないからです。

編集:tag-chooser を使用すると、カスタムフィールドが配列として Rails に送信され、処理される前に破棄されてしまうようです。一方、| で区切られた文字列を作成する text field を使用すると、問題なく動作します。(Rails 側で before_validation を追加して修正できるかと思ったのですが、うまくいきませんでした。)

つまり、Ember 側で何らかの魔法を使って、送信前に配列を文字列に変換する必要があるようです。

私もパラメータなしで tag-chooser を使用し、利用可能なすべてのタグを取得しました。

さらに、rails 側で tag-chooser を使用した際に、なぜそれらが保存されない(あるいは届かない)のか、その理由が見つかったと思います。input type="list" を使用し value フィールドを追加すると、それが自動的にフォームの一部になります。

しかし、tag chooser が生成するマークアップは div です。そのため、フォームの送信に含まれないのです。

对此の回避策をまとめようとしています。動作確認が取れ次第、PR を提出します。

昨日、@j.jaffeux と話しました。彼は変更作業を進めています。

まさにその通りです。

それは素晴らしいですね。初心者として、より多くを学ぼうとしていますが、これは非常に助かります :slight_smile:

@pfaffman さん、こんにちは。

修正版を作成しました。Ember 側では tag-chooser があまりに素晴らしいため、それを削除することができませんでした。そのため、Rails 側で対応しました。

CategoriesController に簡単な関数を作成し、:before_action として登録しました。その中で default_tag 配列を | で区切られた文字列に変換しています。

さらに、custom_fields がその時点で設定されるため、before_updatebefore_commit に変更しました。

ふむ、それ試したつもりだったけど、オフィスに着いたら確認してみます。ありがとう!

なるほど!それが私にはどうすればいいかわかりませんでした。それは plugin.rb に記述するのですか?

はい、これで私の場合うまくいきました。

class ::ApplicationController
    def convert_default_tag
      return unless :topic_default_tag_enabled
      puts 'request'
     #エラーを避けるためにフィールドが存在するか確認するだけ
      request.params["custom_fields"]["default_tag"] = request.params["custom_fields"]["default_tag"].join('|')
      p request.params["custom_fields"]["default_tag"]
    end
  end
  require 'categories_controller'
  class ::CategoriesController
     before_action :convert_default_tag , only: [:create]
  end

コントローラー自体に default_tag メソッドを定義することも可能だとは思いますが、その方法ではうまくいきませんでした。ApplicationController はすべての Discourse コントローラーが継承するクラスであるため、このメソッドは ApplicationController からクラスを拡張した時点で読み込まれ、目的を果たします。

@merefield
コントローラー自体で :before_action として呼び出されるメソッドを定義することは可能でしょうか?

コードブロックの前後に3つのバッククォートをつけてください。

```
 ここにコードを記述
  ```

明日試すのが待ちきれません!ありがとうございます。

ありがとうございます。単一のバッククォートだと思っていたのですが、うまくいかず困っていました。そのため、動作するように従来の HTML の

 タグを使用しました。

はい、可能だと思います

それは大きな助けになりました。これで以下のような状態になりました:

  class ::CategoriesController
    before_action :default_tag_to_string, only: [:create, :update]

    def default_tag_to_string
      puts "CDT: #{params}"

      return unless :topic_default_tag_enabled
      # エラーを防ぐためにフィールドが存在するかだけを確認
      request.params["custom_fields"]["default_tag"] = request.params["custom_fields"]["default_tag"].join('|')
      p request.params["custom_fields"]["default_tag"]
    end

  end

これで、Rails がレコードの更新を試みる前に選択されたタグが文字列に変換され、期待通りに動作するようになりました。

さて、問題は、Rails サイト上のこの文字列を、JavaScript/Ember 側で必要な配列に変換する場所を特定することです。@j.jaffeux さん、あなたが解決しようとしていた問題は、JavaScript から Rails 側への値の書き換え(これは解決済み!)なのか、それとも Rails から JavaScript 側への値の変換(まだ混乱しています)なのか、覚えていません(あるいは、より可能性が高いのは、理解していなかったということです)。

私の場合、トピックにタグを割り当てる際、コード内の :before_update:before_commit に変更することで解決しました。

次に、カテゴリ編集ページを開く際、デフォルトのタグ設定フィールドでタグパラメータに配列を渡すことで、選択されたタグが表示されるようになります。