29

ArticleRails3アプリケーションのモデルに「タグ」を追加しようとしています。

モデルに「タグ付け」機能とビューのオートコンプリートヘルパーの両方を追加したgemまたはプラグインがあるかどうか疑問に思います。

私は見つけましacts_as_taggableたが、それが私が使用すべきものであるかどうかはわかりません。新しいものはありますか?私がacts_as_taggableをグーグルで検索した2007年から結果を得ています

4

3 に答える 3

54

Acts_as_taggable_onrails3-jquery-autocompleteはうまく連携して、SOのようなタグ付けシステムを作成します。以下の例を参照してください。レールに適したオールインワンオプションはまだ存在しないと思います。

これをすべてインストールするには、次の手順に従います。

1。Railsアプリをバックアップしてください!

2。jquery-railsをインストールします

注:jQuery UIはでインストールできますが、インストールしjquery-railsないことを選択しました。

3。jQueryUIをダウンロードしてインストールします

Webデザインを補完するテーマを選択してください(オートコンプリートデモを選択したテーマでテストしてください。デフォルトのテーマは機能しませんでした)。カスタムzipをダウンロードし、[zipfile]/js/jquery-ui-#.#.#.custom.min.jsファイルをアプリの/public/javascripts/フォルダーに配置します。[zipfile]/css/custom-theme/フォルダとすべてのファイルをアプリのフォルダに配置しpublic/stylesheets/custom-theme/ます。

4。以下をGemfileに追加してから、「バンドルインストール」を実行します

gem'acts-as-taggable-on'
gem'rails3-jquery-autocomplete'

5。コンソールから次のコマンドを実行します。

rails generateacts_as_taggable_on:migration
rake db:migrate
rails generate autocomplete:install

アプリでこれらの変更を行います

アプリケーションのレイアウトに必要なjavascriptファイルとcssファイルを含めます。

<%= stylesheet_link_tag "application", "custom-theme/jquery-ui-1.8.9.custom" %>  
<%= javascript_include_tag :defaults, "jquery-ui-#.#.#.custom.min", "autocomplete-rails" %>

コントローラの例

編集:SethPellegrinoのコメントに基づいて変更を加えました。

class ArticlesController < Admin::BaseController  
  #autocomplete :tag, :name  <- Old   
  autocomplete :tag, :name, :class_name => 'ActsAsTaggableOn::Tag' # <- New
end

モデル例

class Article < ActiveRecord::Base
   acts_as_taggable_on :tags
end

Route.rb

resources :articles do
  get :autocomplete_tag_name, :on => :collection    
end

例を見る

<%= form_for(@article) do |f| %>
  <%= f.autocomplete_field :tag_list, autocomplete_tag_name_articles_path, :"data-delimiter" => ', ' %> 
  # note tag_list above is a virtual column created by acts_as_taggable_on
<% end %> 

注:この例では、アプリ全体で1つのモデルのみにタグを付け、デフォルトのタグタイプ:tagsのみを使用していることを前提としています。基本的に、上記のコードはすべてのタグを検索し、それらを「Article」タグに限定しません。

于 2011-02-15T19:02:44.173 に答える
6

Acts_as_taggable_on_steroidsgemはおそらくあなたの最善の策ですタグ付けの宝石の多くは「開始するのに適した場所」であることがわかりましたが、希望する結果を得るにはかなりの量のカスタマイズが必要です。

于 2011-02-08T19:46:30.547 に答える
0

最近、これについてブログに投稿しました。簡潔にするために、私のメソッドでは(オプションの)コンテキストフィルター処理されたタグ(たとえば、モデル別およびモデルの属性別)を使用できますが、@ Tim Santefordのソリューションでは、モデルのすべてのタグを取得できます(フィールドでフィルター処理されません)。 。以下は逐語的な投稿です。


Tim Santefordのソリューションを試しましたが、問題はタグの結果にありました。彼のソリューションでは、既存のすべてのタグがオートコンプリートによって返され、モデルやタグ付け可能なフィールドにスコープされません。それで、私は私の意見でははるかに優れた解決策を思いつきました。タグ付けしたいモデルに自動的に拡張可能で、効率的で、何よりも非常にシンプルです。これは、acts-as-taggable-ongemselect2JavaScriptライブラリを使用します。

Acts-As-Taggable-Ongemをインストールします

  1. タグ付け可能な行為をGemfileに追加します。gem 'acts-as-taggable-on', '~> 3.5'
  2. 実行bundle installしてインストールします
  3. 必要な移行を生成します。rake acts_as_taggable_on_engine:install:migrations
  4. で移行を実行しますrake db:migrate

終わり!

MVCで通常のタグ付けを設定する

Filmモデルがあるとしましょう(私が持っているからです)。モデルに次の2行を追加するだけです。

class Film < ActiveRecord::Base
    acts_as_taggable
    acts_as_taggable_on :genres
end

モデルは以上です。今度はコントローラーに移ります。パラメータでタグリストを受け入れる必要があります。だから私は私の中に次のものを持っていますFilmsController

class FilmsController < ApplicationController
    def index
        ...
    end
    ...

    private

    def films_params
        params[:film].permit(..., :genre_list)
    end
end

パラメータがgenresモデルで指定したものとは異なることに注意してください。理由は聞かないでください。ただし、タグ付け可能として機能する場合は、単数形の+ _listが必要です。これは、ビューで必要なものです。

ビューレイヤーに!ビューにはSimpleFormgemSlimテンプレートエンジンを使用しているため、gemを使用しない場合、フォームは実際のフォームとは少し異なる場合があります。ただし、これは通常のテキスト入力フィールドです。

= f.input :genre_list, input_html: {value: @film.genre_list.to_s}

カンマ区切りの文字列としてレンダリングするには、この属性にその値を設定する必要がありinput_htmlます(これは、コントローラーでタグ付け可能として機能するものです)。フォームを送信するときにタグ付けが機能するようになりました。それが機能しない場合は、タグ付けに関する(驚くべき)ライアンベイツのRailscastエピソードを視聴することをお勧めします。

select2をフォームに統合する

まず、select2ライブラリを含める必要があります。手動で含めるか、(私の好みで)Railsアセットパイプライン用にselect2をパッケージ化するselect2-railsgemを使用できます。

gemをGemfile:に追加してからgem 'select2-rails', '~> 4.0'、を実行しbundle installます。

アセットパイプラインにJavaScriptとCSSを含めます。

application.js//= require select2-fullの場合:。application.css*= require select2内:。

次に、フォームを少し変更して、select2がタグ付けに期待するものを含める必要があります。これは少し紛らわしいように思えるかもしれませんが、すべてを説明します。以前のフォーム入力を変更します。

= f.input :genre_list, input_html: {value: @film.genre_list.to_s}

に:

= f.hidden_field :genre_list, value: @film.genre_list.to_s
= f.input :genre_list,
    input_html: { id: "genre_list_select2",
                name: "genre_list_select2",
                multiple: true,
                data: { taggable: true, taggable_type: "Film", context: "genres" } },
    collection: @film.genre_list

コントローラに送信される実際の値として機能する非表示の入力を追加します。Select2は配列を返します。ここで、acts-as-taggable-onは、コンマ区切りの文字列を想定しています。select2フォーム入力は、値が変更されるとその文字列に変換され、非表示フィールドに設定されます。すぐにそれを取得します。

実際の属性idname属性f.inputは重要ではありません。それらはあなたのhidden入力とオーバーラップすることはできません。ここdataではハッシュが非常に重要です。このtaggableフィールドでは、JavaScriptを使用して、各入力をIDで手動で初期化する代わりに、すべてのselect2入力を一度に初期化できます。このtaggable_typeフィールドは、特定のモデルのタグをフィルタリングするために使用され、このcontextフィールドは、そのフィールドで以前に使用されたタグをフィルタリングするために使用されます。最後に、collectionフィールドは入力に値を適切に設定するだけです。

次の部分はJavaScriptです。アプリケーション全体ですべてのselect2要素を初期化する必要があります。これを行うには、次の関数をapplication.jsファイルに追加するだけで、すべてのルートで機能するようになります。

// Initialize all acts-as-taggable-on + select2 tag inputs
$("*[data-taggable='true']").each(function() {
    console.log("Taggable: " + $(this).attr('id') + "; initializing select2");
    $(this).select2({
        tags: true,
        theme: "bootstrap",
        width: "100%",
        tokenSeparators: [','],
        minimumInputLength: 2,
        ajax: {
            url: "/tags",
            dataType: 'json',
            delay: 100,
            data: function (params) {
                console.log("Using AJAX to get tags...");
                console.log("Tag name: " + params.term);
                console.log("Existing tags: " + $(this).val());
                console.log("Taggable type: " + $(this).data("taggable-type"));
                console.log("Tag context: " + $(this).data("context"));
                return {
                    name: params.term,
                    tags_chosen: $(this).val(),
                    taggable_type: $(this).data("taggable-type"),
                    context: $(this).data("context"),
                    page: params.page
                }
            },
            processResults: function (data, params) {
                console.log("Got tags from AJAX: " + JSON.stringify(data, null, '\t'));
                params.page = params.page || 1;

                return {
                    results: $.map(data, function (item) {
                        return {
                            text: item.name,
                            // id has to be the tag name, because acts_as_taggable expects it!
                            id: item.name
                        }
                    })
                };
            },
            cache: true
        }
    });
});

これは複雑に見えるかもしれませんが、それほど難しくはありません。基本的に、セレクターは、データ$("*[data-taggable='true']")に設定したすべてのHTML要素を取得するだけです。これをフォームに追加したところです。これが理由です。タグ付け可能なすべてのフィールドに対してselect2taggable: trueを初期化できるようにする必要があります。

残りはAJAX関連のコードです。/tags基本的に、パラメータとを使用してnameAJAX呼び出しをtaggable_type行いますcontext。おなじみですか?これらは、フォーム入力で設定したデータ属性です。結果が返されるとき、select2にタグの名前を付けるだけです。

今、あなたはおそらく考えているでしょう:私には/tagsルートがありません!。あなたが正しい!しかし、あなたはもうすぐです:)

/tagsルートを追加する

ファイルに移動しroutes.rb、以下を追加しますresources :tagsタグのすべてのルートを追加する必要はありませんが、タグをCRUDする簡単な方法を用意するために追加しました。簡単に行うこともできます。get '/tags' => 'tags#index'

現時点で必要なルートはこれだけです。ルートができたので、次のコントローラーを作成する必要がありますTagsController

class TagsController < ApplicationController
    def index
        @tags = ActsAsTaggableOn::Tag
                .where("name ILIKE ?", "%#{params[:name]}%")
                .where.not(name: params[:tags_chosen])
                .includes(:taggings)
                .where(taggings: {taggable_type: params[:taggable_type]})
        @tags = @tags.where(taggings: {context: params[:context] }) if params[:context]
        @tags.order!(name: :asc)
        render json: @tags
    end
end

これはかなり簡単です。/tagsパラメータname(タグテキスト)、tags_chosen(既存の選択されたタグ)、taggable_type(タグ付けされたモデル)、およびオプションcontext(タグ付けされたフィールド)を使用して、にリクエストを送信できます。「comedy」と「conspiracy」のジャンルタグがある場合、フォームにcoと入力すると、レンダリングされるJSONは次のようになります。

[
    {
        "id": 12,
        "name": "comedy",
        "taggings_count": 1
    },
    {
        "id": 11,
        "name": "conspiracy",
        "taggings_count": 1
    }
]

select2入力では、自動入力されたタグオプションとして「コメディ」と「陰謀」が表示されます。

私のタグは保存されません!

最後のステップが1つあります。hidden以前に作成したフィールドにselect2値を設定する必要があります。

このコードは、フォームの構造によって異なる場合がありますが、基本的にはselect2入力を取得し、文字列の配列をCSV文字列に変換して(例:["comedy", "conspiracy"]-> "comedy, conspiracy")、そのCSV文字列を非表示フィールドに設定する必要があります。 。幸いなことに、それはそれほど難しいことではありません。

select2入力変更イベント、またはその他の適切なイベントをキャッチできます。これはあなたの選択ですが、Railsコントローラーが値を正しく受け取るようにするには、この手順を実行する必要があります。繰り返しますが、application.jsでは:

/*
* When any taggable input changes, get the value from the select2 input and
* convert it to a comma-separated string. Assign this value to the nearest hidden
* input, which is the input for the acts-on-taggable field. Select2 submits an array,
* but acts-as-taggable-on expects a CSV string; it is why this conversion exists.
*/
$(document).on('select2:select select2:unselect', "*[data-taggable='true']", function() {

    var taggable_id = $(this).attr('id')
    // genre_list_select2 --> genre_list
    var hidden_id = taggable_id.replace("_select2", "");
    // film_*genre_list* ($= jQuery selectors ends with)
    var hidden = $("[id$=" + hidden_id + "]")
    // Select2 either has elements selected or it doesn't, in which case use []
    var joined = ($(this).val() || []).join(",");
    hidden.val(joined);
});

値を正常に変換すると、コントローラーのアクションに次のように表示されます。"genre_list"=>"comedy,conspiracy"

そして、acts-as-taggable-onとselect2を使用してRailsでオートコンプリートタグを実行するために必要なのはこれだけです。

于 2017-02-06T20:56:45.810 に答える