如何使用自动完成function将标记添加到Rails中的现有模型?

我正在尝试将“标签”添加到Rails 3应用程序中的Article模型中。

我想知道是否有一个gem或插件添加了模型中的“标记”function以及视图的自动完成帮助程序。

我发现了acts_as_taggable但我不确定这是不是我应该使用的。 有更新的东西吗? 我从2007年google acts_as_taggable获得了结果

acts_as_taggable_on和rails3-jquery-autocomplete可以很好地协同工作,制作类似SO的标记系统,请参见下面的示例。 对于rails来说,我认为还没有合适的all in one选项。

请按照以下步骤安装全部:

1。 备份你的rails应用程序!

2。 安装jquery-rails

注意:您可以使用jquery-rails安装jQuery UI,但我选择不这样做。

3。 下载并安装jQuery UI

选择一个与您的网页设计相称的主题(请务必使用您选择的主题测试自动完成演示,默认主题对我不起作用)。 下载自定义zip并将[zipfile]/js/jquery-ui-#.#.#.custom.min.js文件放入应用程序的/public/javascripts/文件夹中。 将[zipfile]/css/custom-theme/文件夹和所有文件放入应用程序的public/stylesheets/custom-theme/文件夹中。

4。 将以下内容添加到Gemfile中,然后运行“bundle install”

gem’行为 – 可标记 – 在’
gem’rail3-jquery-autocomplete’

5。 从控制台运行以下命令:

rails生成acts_as_taggable_on:迁移
rake db:migrate
rails生成自动完成:安装

在您的应用中进行这些更改

在您的应用程序布局中包含必要的javascript和css文件:

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

控制器示例

编辑:根据Seth Pellegrino的评论做出改变。

 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 %> 

注意:此示例假定您仅在整个应用程序中标记一个模型,并且您只使用默认标记类型:标记。 基本上上面的代码将搜索所有标签,而不是将它们限制为“Article”标签。

acts_as_taggable_on_steroids gem可能是你最好的选择。 我发现许多标记gem更像是一个“开始的好地方”,但后来需要大量的自定义来获得你想要的结果。

我最近写了一篇关于这个的博客文章 ; 为了简洁起见,我的方法允许你有(可选的) context -filtered标签(例如模型和模型上的属性),而@Tim Santeford的解决方案将为你获取模型的所有标签(不按字段过滤) 。 以下是逐字帖。


我尝试了Tim Santeford的解决方案 ,但问题在于标签结果。 在他的解决方案中,您将获得通过自动完成返回的所有现有标签,而不是作用于您的模型和可标记字段 ! 所以,我想出了一个解决方案,在我看来要好得多; 它可以自动扩展到你想要标记的任何模型,它是高效的,最重要的是它非常简单。 它使用acts-as-taggable-on gem和select2 JavaScript库。

安装Acts-As-Taggable-On gem

  1. 在你的Gemfile中添加act-as-taggable-on:gem’atject gem 'acts-as-taggable-on', '~> 3.5'
  2. 运行bundle install以安装它
  3. 生成必要的迁移: rake acts_as_taggable_on_engine:install:migrations
  4. 使用rake db:migrate运行rake db:migrate

完成!

在MVC中设置正常标记

假设我们有一个Film模型(因为我这样做)。 只需在模型中添加以下两行:

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

这就是模型。 现在进入控制器。 您需要接受参数中的标记列表。 所以我在FilmsController有以下FilmsController

 class FilmsController < ApplicationController def index ... end ... private def films_params params[:film].permit(..., :genre_list) end end 

请注意,该参数不是我们在模型中指定的genres 。 不要问我为什么,但是act-as-taggable-on需要单数+ _list ,这就是视图中所需要的。

在视图层上! 我使用SimpleForm gem和Slim模板引擎来查看视图,因此如果你不使用gem,我的表单可能看起来与你的不同。 但是,它只是一个普通的文本输入字段:

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

您需要具有该值集的input_html属性,以便将其呈现为逗号分隔的字符串(这是控制器中期望的作为标签的行为)。 提交表单时,标签现在可以正常工作! 如果它不起作用,我建议观看(惊人的) Ryan Bates的Railscast关于标记的情节 。

将select2集成到表单中

首先,我们需要包含select2库; 你可以手动包含它,或者使用(我的偏好) select2-rails gem,它将select2包装为Rails资产管道。

将gem添加到您的Gemfile:gem'select2 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表单输入在其值更改时转换为该字符串,并设置为隐藏字段。 我们很快就会到达那里。

f.inputidname属性实际上并不重要。 它们只是不能与您hidden输入重叠。 data哈希在这里非常重要。 可taggable字段允许我们使用JavaScript一次性初始化所有select2输入,而不是通过id为每个输入手动初始化。 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']")选择器只获取我们有taggable: true每个HTML元素taggable: true在数据中设置taggable: true 。 我们刚刚将其添加到表单中,这就是为什么 - 我们希望能够为所有可标记字段初始化select2。

其余的只是与AJAX相关的代码。 基本上,我们使用参数nametaggable_typecontext/tags进行AJAX调用。 听起来有点熟? 这些是我们在表单输入中设置的数据属性。 返回结果时,我们只需给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 (标记的字段 )。 如果我们有“喜剧”和“阴谋”的流派标签,那么在我们的表单中键入co ,呈现的JSON应该如下所示:

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

现在在select2输入中,你应该看到“喜剧”和“阴谋”作为自动完成的标签选项!

我的标签不会保存!

还有最后一步。 我们需要将select2值设置为我们之前创建的hidden字段。

根据您构建表单的方式,此代码可能会有所不同,但您基本上想要获取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"

这就是使用act-as-taggable-on和select2在Rails中执行自动完成标记所需的全部内容!

Interesting Posts