Указание контекста тега при использовании act_as_taggable_on и автозаполнения jQuery

Я использую драгоценные камни https://github.com/mbleigh/acts-as-taggable-on и https://github.com/crowdint/rails3-jquery-autocomplete для реализации тегов в приложении Rails 4.

У меня есть модель с именем Question с двумя отдельными категориями (контекстами) тегов: :topics и :courses. Проблема, которую я не могу решить, заключается в том, чтобы отфильтровать теги для автозаполнения, чтобы пользователю предлагались только теги из соответствующего контекста. В противном случае основные функции тегов и автозаполнения работают нормально, а это означает, что пользователь может ввести первые три буквы данного тега, и ему будет предложен список тегов для выбора (только без фильтрации по контексту).

вопрос.rb

acts_as_taggable_on   :topics, :courses

questions_controller.rb

autocomplete :topic, :name, :class_name => 'ActsAsTaggableOn::Tag'
autocomplete :course, :name, :class_name => 'ActsAsTaggableOn::Tag'

Примечание. Я попытался изменить :class_name на ActsAsTaggableOn::Course или ActsAsTaggableOn::Topic, но получил (несколько ожидаемую) ошибку: NameError (uninitialized constant ActsAsTaggableOn::Topic):

вопросы/_form.html.erb

<%= f.autocomplete_field :course_list, autocomplete_course_name_questions_path, :"data-delimiter" => ', ' %>
<%= f.autocomplete_field :topic_list, autocomplete_topic_name_questions_path, :"data-delimiter" => ', ' %>

config/routes.rb

resources :questions do
  get :autocomplete_topic_name, :on => :collection
  get :autocomplete_course_name, :on => :collection
end

Gemfile

gem 'acts-as-taggable-on', '~> 3.4.1'
gem 'rails3-jquery-autocomplete', '~> 1.0.14'

Стоит ли отказаться от rails3-jquery-autocomplete и напрямую использовать виджет пользовательского интерфейса jQuery? Возможно, есть способ использовать опцию :scopes из rails3-jquery-autocomplete для достижения желаемого результата? Я просто неправильно подхожу к проблеме, используя разные контексты тегов в одной и той же модели? Возможно, переопределить методы autocomplete_... в контроллере Questions, чтобы отфильтровать правильные теги? Любые мысли приветствуются. Заранее спасибо.


person Jacques    schedule 25.09.2014    source источник


Ответы (1)


В надежде, что это поможет кому-то еще, вот как я решил эту проблему.

Прежде всего, я заменил автозаполнение jQuery на jQuery Tokeninput, который можно найти по адресу: http://loopj.com/jquery-tokeninput. /. В основном я следовал рецепту, найденному на этом веб-сайте: http://bloginius.com/blog/2013/12/31/how-integrate-acts-as-taggable-on-with-jquery-token-input-with-rails-3/. Подозреваю, что мое решение не такое эффективное и элегантное, как у автора, но мне пришлось адаптировать его для работы с Rails 4 и использования двух «контекстов» (:topics и :courses) вместо :tags.

Вот код:

активы/javascripts/questions.js.coffee

jQuery ->
  $('#question_topic_list_tokens').tokenInput '/questions/topics.json',
    theme: 'facebook'
    minChars: 3
    allowCustomEntry: false
    preventDuplicates: true
    prePopulate: $('#question_topic_list_tokens').data('load')

jQuery ->
  $('#question_course_list_tokens').tokenInput '/questions/courses.json',
  theme: 'facebook'
  minChars: 3
  allowCustomEntry: false
  preventDuplicates: true
  prePopulate: $('#question_course_list_tokens').data('load')

controllers/questions_controller.rb

before_filter :find_topic_tags, only: [:new, :create, :edit, :update]
before_filter :find_course_tags, only: [:new, :create, :edit, :update]

def topics
  topics = Question.topic_counts.by_tag_name(params[:q]).map{|t| {id: t.name, name: t.name }}
  respond_to do |format|
    format.json { render json: topics }
  end
end

def courses
  courses = Question.course_counts.by_tag_name(params[:q]).map{|t| {id: t.name, name: t.name }}
  respond_to do |format|
    format.json { render json: courses }
  end
end

def question_params
  params.require(:question).permit(..., :topic_list_tokens, :course_list_tokens, ...)
end

def find_topic_tags
  @question_topics = params[:id].present? ? Question.find(params[:id]).topics.map{|t| {id: t.name, name: t.name }} : []
end

def find_course_tags
  @question_courses = params[:id].present? ? Question.find(params[:id]).courses.map{|t| {id: t.name, name: t.name }} : []
end

qmodels/question.rb

acts_as_taggable_on   :topics, :courses

attr_reader   :course_list_tokens, :topic_list_tokens

def topic_list_tokens=(tokens)
  self.topic_list = tokens.gsub("'", "")
end

def course_list_tokens=(tokens)
  self.course_list = tokens.gsub("'", "")
end

представления/вопросы/_form.html.erb

    <div class="form-group">
        <div class="col-md-3 control-label">
          <%= f.label :course_list_tokens, "course tags (separated by commas)" %><br/>
        </div>
        <div class="controls col-md-4">
          <%= f.text_field :course_list_tokens, data: {load: @question_courses} %>
        </div>
        <div class="col-md-3 text-muted">(optional)</div>
    </div>

    <div class="form-group">
        <div class="col-md-3 control-label">
              <%= f.label :topic_list_tokens, "topic tags (separated by commas)" %><br/>
        </div>
        <div class="controls col-md-4">
          <%= f.text_field :topic_list_tokens, data: {load: @question_topics} %>
        </div>
        <div class="col-md-3 text-muted">(optional)</div>
    </div>

config/initializers/acts_as_taggable_on.rb

ActsAsTaggableOn::Tag.send(:include, <YOUR APP>::TagExtend)

config/routes.rb

resources :questions do
  collection do
    get :topics, as: :topics
    get :courses, as: :courses
  end
end

lib/tag_extend.rb

module TagExtend
  extend ActiveSupport::Concern

  included do
    scope :by_tag_name, -> name { where("name like ?", "%#{name}%") }
  end
end
person Jacques    schedule 30.09.2014