我有一个允许用户标记其馆藏中的项目的RoR应用程序。我使用tag-it.js Jquery插件并使用Ajax调用来添加和删除ItemsController中的标签。我的问题是每个标记都被添加两次,这样当我执行@ item.tags.each时,所有标记都会显示两次。
ItemsController:
def add_tag
@collection = current_user.collections.find(params[:collection_id])
@item = @collection.items.find(params[:id])
@item.tag_list.add(params[:tag])
current_user.tag(@item, :with => @item.tag_list.to_s, :on => :tags)
@item.save
render nothing: true
end
def remove_tag
@item = current_user.items.find_by_id(params[:id])
@item.tag_list.remove(params[:tag])
current_user.tag(@item, :with => @item.tag_list.to_s, :on => :tags)
@item.save
render nothing: true
end
使用Tag-it.js处理AJAX标记的Javascript:
$('#item_tags').tagit({
onTagAdded: function(event, tag) {
var add_url = $('#item_tags').attr("data-add-url");
$.ajax({
url: add_url,
data: {tag: tag.text().substring(0, tag.text().length-1)},
})
},
onTagRemoved: function(event, tag) {
var remove_url = $('#item_tags').attr("data-remove-url");
$.ajax({
url: remove_url,
type: 'DELETE',
data: {tag: tag.text().substring(0, tag.text().length-1)},
})
},
tagSource: function(search, showChoices) {
var autocomplete_url = $('#item_tags').attr("data-auctocomplete-url");
$.ajax({
url: autocomplete_url,
data: {term: search.term},
success: function(choices) {
showChoices(choices);
}
})
}
});
项目#_form查看用户添加/删除标记的位置:
<ul id='item_tags' class='tagit' data-remove-url="<%= remove_tag_collection_item_path %>" data-add-url="<%= add_tag_collection_item_path %>" data-auctocomplete-url="/collections/<%=@collection.id %>/items/autocomplete_tag_name">
<% @item.tags.each do |tag| %>
<li><%= tag.name %></li>
<% end %>
</ul>
我必须注意,必须拥有标签所有权(通过current_user),以便Jquery自动完成仅基于当前用户以前的标签而不是所有用户完成。我认为问题是我必须将标记添加到tag_list,然后将tag_list添加到用户项标记。我无法找到解决方法,因为当调用current_user.tag()时,current_user.tag()方法似乎会覆盖先前的项目标记,因此我必须将新标记添加到以前的标记以保留它们。
此外,当我提交项目#_form时,我需要以某种方式让更新方法忽略tags属性,因为它试图将它们保存到项目中,但它们已经通过AJAX调用保存,因此我收到此错误:< / p>
ActiveRecord::AssociationTypeMismatch in ItemsController#update
ActsAsTaggableOn::Tag(#82082080) expected, got String(#72294010)
提前致谢。
PS。以下是我在ItemsController中完成自动完成工作的方法:
def get_autocomplete_items(parameters)
tags = current_user.owned_tags.named_like(parameters[:term])
end
答案 0 :(得分:0)
你是对的:
我认为问题是我必须将标签添加到tag_list和 然后将tag_list添加到用户项标记。我无法找到方法 因为current_user.tag()方法似乎覆盖了 调用current_user.tag()时的前一项标签,所以我必须这样做 将新标记添加到以前的标记以保留它们。
.tag
方法使用给定列表覆盖现有标记。因此,如果您想添加新标签,您似乎需要将新标签附加到现有标签,然后传入新列表。但是,.tag_list.add
实际上也会创建标记。
所以,当你这样做时:
@item.tag_list.add(params[:tag])
current_user.tag(@item, :with => @item.tag_list.to_s, :on => :tags)
你确实两次添加新标签。
当我这样做的时候:
tag_list = profile.tag_list // oops!
tag_list.add(tags)
self.tag(profile, with: tag_list, on: :tags)
我正在创建对tag_list的引用,然后在其上调用add。我们需要做的是:
tag_list = profile.tags.map(&:name)
为我们标记的对象创建一个标记名称数组。然后我们可以在列表的副本上调用add,没问题!没有更多重复的标签。
我很高兴遇到了你的问题,因为它让我得到了一个对我有用的答案。但是,如果图书馆提供这样做的好方法,我会更高兴。通过阅读文档,我无法找到一个好方法。
答案 1 :(得分:0)
你做得很好,但是,只是一个小错误。
此处tag_list
获取重复标记,其中一个包含所有者,其他包含所有者
您的@item.tag_list.add(params[:tag])
行正在添加标签没有所有者
并且current_user.tag(@item, :with => @item.tag_list.to_s, :on => :tags)
行正在添加相同的标记与所有者
之后,当您保存对象时,由于tag_list
表现为对象的 un ownered 标记的引用,因此都会保存
以下代码可以正常工作。
def add_tag
@collection = current_user.collections.find(params[:collection_id])
@item = @collection.items.find(params[:id])
tag_list = @item.all_tag_list.dup # Reference to original tag_list avoided
# Also instead of "tag_list", use "all_tag_list" method, as "tag_list" only return tags without owner
# Link(go to last line og Tag Ownership topic) : "https://github.com/mbleigh/acts-as-taggable-on#tag-ownership"
tag_list.add(params[:tag])
current_user.tag(@item, :with => tag_list.to_s, :on => :tags)
@item.save
render nothing: true
end
def remove_tag
@item = current_user.items.find_by_id(params[:id])
tag_list = @item.all_tag_list.dup # Reference to original tag_list avoided
tag_list.remove(params[:tag])
current_user.tag(@item, :with => tag_list.to_s, :on => :tags)
@item.save
render nothing: true
end
改进版本
def add_owned_tag
@some_item = Item.find(params[:id])
owned_tag_list = @some_item.all_tag_list - @some_item.tag_list
owned_tag_list += [(params[:tag])]
@tag_owner.tag(@some_item, :with => stringify(owned_tag_list), :on => :tags)
@some_item.save
end
def stringify(tag_list)
tag_list.inject('') { |memo, tag| memo += (tag + ',') }[0..-1]
end
def remove_owned_tag
@some_item = Item.find(params[:id])
owned_tag_list = @some_item.all_tag_list - @some_item.tag_list
owned_tag_list -= [(params[:tag])]
@tag_owner.tag(@some_item, :with => stringify(owned_tag_list), :on => :tags)
@some_item.save
end
答案 2 :(得分:-1)
注意在页面加载时触发的onTagAdded事件。请参阅此处的事件示例http://aehlke.github.com/tag-it/examples.html
//-------------------------------
// Tag events
//-------------------------------
var eventTags = $('#eventTags');
eventTags.tagit({
availableTags: sampleTags,
onTagRemoved: function(evt, tag) {
console.log(evt);
alert('This tag is being removed: ' + eventTags.tagit('tagLabel', tag));
},
onTagClicked: function(evt, tag) {
console.log(tag);
alert('This tag was clicked: ' + eventTags.tagit('tagLabel', tag));
}
}).tagit('option', 'onTagAdded', function(evt, tag) {
// Add this callbackafter we initialize the widget,
// so that onTagAdded doesn't get called on page load.
alert('This tag is being added: ' + eventTags.tagit('tagLabel', tag));
});