通过表单更新所有者标签

我想在我的应用中唯一使用所有者标签。 我的问题是,当我通过表单创建/更新post时,我只有f.text_field :tag_list ,它只更新post的标签,但没有所有者。 如果我使用f.text_field :all_tags_list它不知道create / update上的属性。 我可以添加我的控制器:

 User.find(:first).tag( @post, :with => params[:post][:tag_list], :on => :tags ) 

但后来我有重复的标签,用于post和所有者标签。 如何使用所有者标签?

客户提出的答案(tsdbrown on SO) https://github.com/mbleigh/acts-as-taggable-on/issues/111对我有用

 # In a taggable model: before_save :set_tag_owner def set_tag_owner # Set the owner of some tags based on the current tag_list set_owner_tag_list_on(account, :tags, self.tag_list) # Clear the list so we don't get duplicate taggings self.tag_list = nil end # In the view: <%= f.text_field :tag_list, :value => @obj.all_tags_list %> 

我用一个观察者来解决这个问题。 就像是:

在/app/models/tagging_observer.rb中

 class TaggingObserver < ActiveRecord::Observer observe ActsAsTaggableOn::Tagging def before_save(tagging) tagging.tagger = tagging.taggable.user if (tagging.taggable.respond_to?(:user) and tagging.tagger != tagging.taggable.user) end end 

不要忘记在application.rb中声明您的观察者

 config.active_record.observers = :tagging_observer 

晚了,但我发现guillaume06的解决方案运行良好,我添加了一些额外的function:

这将启用:您将能够通过标记模型和标记所有者模型之间的关系名称指定标记所有者。

如何:编写一个模块并在初始化时包含在你的lib中( require 'lib/path/to/tagger' ):

  module Giga::Tagger extend ActiveSupport::Concern included do def self.tagger owner before_save :set_tag_owner def set_tag_owner self.tag_types.each do |tag| tag_type = tag.to_s # Set the owner of some tags based on the current tag_list set_owner_tag_list_on(owner, :"#{tag_type}", self.send(:"#{tag_type.chop}_list")) # Clear the list so we don't get duplicate taggings self.send(:"#{tag_type.chop}_list=",nil) end end end end end 

使用说明:

  Given: A model, Post, that is taggable A model, User, that is the tag owner A post is owned by the user through a relationship called :owner Then add to Post.rb: include Tagger acts_as_taggable_on :skills, :interests, :tags tagger :owner Make sure Post.rb already has called acts_as_taggable_on, and that User.rb has acts_as_tagger Note: This supports multiple tag contexts, not just tags (eg skills, interests).. 

set_tag_owner before_save为我工作。 但正如bcb所提到的,我必须添加一个条件(tag_list_changed?)来防止标记在更新时被删除:

 def set_tag_owner if tag_list_changed? set_owner_tag_list_on(account, :tags, tag_list) self.tag_list = nil end end 

尝试使用委托:

 class User < ActiveRecord::Base acts_as_taggable_on end class Post < ActiveRecord::Base delegate :tag_list, :tag_list=, :to => :user end 

因此,当您保存post时,它会直接在用户对象上设置标记。

我最终创建了一个运行User.tag语句的虚拟属性:

在我的thing.rb模型中:

 attr_accessible :tags belongs_to :user acts_as_taggable def tags self.all_tags_list end def tags=(tags) user = User.find(self.user_id) user.tag(self, :with => tags, :on => :tags, :skip_save => true) end 

您唯一需要做的就是更改视图和控制器以将tag_list更新为tags ,并确保在thingtags之前设置thinguser_id

使用所有权时,可标记模型会使其标记略有不同。 没有所有权,它可以得到它的标签:

 @photo.tag_list << 'a tag' # adds a tag to the existing list @photo.tag_list = 'a tag' # sets 'a tag' to be the tag of the @post 

但是,这两个操作都会创建taggins ,其tagger_idtagger_typenil

为了设置这些字段,您必须使用此方法:

 @user.tag(@photo, on: :tags, with: 'a tag') 

假设您将此行添加到PhotosControllercreate/update操作:

 @user.tag(@photo, on: :tags, with: params[:photo][:tag_list]) 

这将创建两个标记(一个带有一个没有tagger_id/_type ),因为params[:photo][:tag_list]已经包含在photo_params 。 所以为了避免这种情况,请不要白名单:tag_list

对于Rails 3 - 从attr_accessible删除:tag_list attr_accessible

对于Rails 4 - 从params.require(:photo).permit(:tag_list)删除:tag_list

最后,您的create操作可能如下所示:

 def create @photo = Photo.new(photo_params) # at this point @photo will not have any tags, because :tag_list is not whitelisted current_user.tag(@photo, on: :tags, with: params[:photo][:tag_list]) if @photo.save redirect_to @photo else render :new end end 

另请注意,以这种方式标记对象时,您无法使用通常的tag_list方法来检索照片的标记,因为它会搜索taggings ,其中tagger_id IS NULL 。 你必须改用

 @photo.tags_from(@user) 

如果您的可标记对象belongs_to单个用户,您也可以使用all_tags_list