可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
This is how you use autocomplete with jQuery Tokeninput and ActsAsTaggableOn.
In my situation i am using a nested form but it shouldnt matter. Everything below is code that works.
Code
Product Model:
attr_accessible :tag_list # i am using the regular :tag_list
acts_as_taggable_on :tags # Tagging products
Products Controller:
#1. Define the tags path
#2. Searches ActsAsTaggable::Tag Model look for :name in the created table.
#3. it finds the tags.json path and whats on my form.
#4. it is detecting the attribute which is :name for your tags.
def tags
@tags = ActsAsTaggableOn::Tag.where("tags.name LIKE ?", "%#{params[:q]}%")
respond_to do |format|
format.json { render :json => @tags.map{|t| {:id => t.name, :name => t.name }}}
end
end
Routes:
# It has to find the tags.json or in my case /products/tags.json
get "products/tags" => "products#tags", :as => :tags
Application.js:
$(function() {
$("#product_tags").tokenInput("/products/tags.json", {
prePopulate: $("#product_tags").data("pre"),
preventDuplicates: true,
noResultsText: "No results, needs to be created.",
animateDropdown: false
});
});
Form:
<%= p.text_field :tag_list,
:id => "product_tags",
"data-pre" => @product.tags.map(&:attributes).to_json %>
Issue 1(SOLVED)
Must have the line:
format.json { render :json => @tags.collect{|t| {:id => t.name, :name => t.name }}}
Note - You can use @tags.map
here as well and you dont have to change the form either.
Below are the 2 issues on why you needed to do this:
I have the following Tag
: {"id":1,"name":"Food"}
. When I save a Product
, tagged "Food"
, it should save as ID: 1
when it searches and finds the name "Food"
. Currently, it saves a new Tag
with a new ID that references the "Food"
ID, i.e. {"id":19,"name":"1"}
. Instead, it should be finding the ID, showing the name, and doing a find_or_create_by
so it doesn't create a new Tag
.
Issue 2(SOLVED)
When I go to products/show
to see the tags by doing <%= @product.tag_list %>
. The name appears as "Tags: 1", when it really should be "Tags: Food".
How can I fix these issues?
回答1:
You should define a route in your routes.rb
which should handle products/tags
path. You can define it like:
get "products/tags" => "products#tags", :as => :tags
Thus should give you a tags_path
helper which should evaluate to /products/tags
. This should get rid of the errors you mentioned in the question. Be sure to add this route before defining resources :product
in your routes.rb
Now onto acts-as-taggable-on, I haven't used this gem, but you should look at method all_tag_counts
documentation. Your ProductsController#tags
method will need some changes on the following lines. I am not sure if its exactly what would be required, as I use Mongoid and can't test it out.
def tags
@tags = Product.all_tag_counts.(:conditions => ["#{ActsAsTaggableOn::Tag.table_name}.name LIKE ?", "%#{params[:q]}%"])
respond_to do |format|
format.json { render :json => @tags.collect{|t| {:id => t.name, :name => t.name } }
end
end
回答2:
little add-on:
If you want to create the tags on the fly, you could do this in your controller:
def tags
query = params[:q]
if query[-1,1] == " "
query = query.gsub(" ", "")
Tag.find_or_create_by_name(query)
end
#Do the search in memory for better performance
@tags = ActsAsTaggableOn::Tag.all
@tags = @tags.select { |v| v.name =~ /#{query}/i }
respond_to do |format|
format.json{ render :json => @tags.map(&:attributes) }
end
end
This will create the tag, whenever the space bar is hit.
You could then add this search setting in the jquery script:
noResultsText: 'No result, hit space to create a new tag',
It's a little dirty but it works for me.
回答3:
There is a bug in Application.js code. There is an extra ) after "/products/tags.json". Remove the extra ). The code should be:
$("#product_tags").tokenInput("/products/tags.json", {
prePopulate: $("#product_tags").data("pre"),
preventDuplicates: true,
noResultsText: "No results, needs to be created.",
animateDropdown: false
});
回答4:
I don't know if this is the entirety of your error, but you are not hitting the proper URL with the tokenInput plugin.
This
$("#product_tag_list").tokenInput("/products/tags.json"), {
should be
$("#product_tag_list").tokenInput("/products.json"), {
As I said, I don't know if this is the only problem you are having, but if you change this, does it work?
EDIT:
I have never used ActsAsTaggableOn
. Does it create a Tag
model for you to use?
From the looks of it on github, if you wanted to query all tags, you might have to use its namespace as opposed to just Tag
, meaning ActsAsTaggableOn::Tag
. For example, you can see how they access Tag
s directly in some of the specs.
回答5:
I had problems with editing the tags if for example the model failed to validate,
I changed
<%= p.text_field :tag_list,
:id => "product_tags",
"data-pre" => @product.tags.map(&:attributes).to_json %>
to
<%= p.text_field :tag_list,
:id => "product_tags",
"data-pre" => @product.tag_list.map {|tag| {:id => tag, :name => tag } }.to_json %>
If the form failed to validate on first submission, it was creating tags as the ID's of the tags it had created on subsequent submissions.
回答6:
Two notes: if you're getting the tags changed by numbers on the POST request, use:
tokenValue: "name"
And if you're trying to add non-existent tags, use (undocumented):
allowFreeTagging: true