【问题标题】:Update owner tags via form通过表单更新所有者标签
【发布时间】:2010-09-01 14:52:31
【问题描述】:

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

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

但是我有重复的标签,用于发布和所有者标签。我怎样才能只使用所有者标签?

【问题讨论】:

  • 我正在尝试实现同样的目标。你有什么收获吗?
  • 你有没有想过拥有一个属于 Owner 和 Post 的 owner_tags 模型?这将需要更多的跑腿工作,但是您将知道谁拥有这些标签以及它们属于哪个帖子。您可能需要 attr_accessor :tag_list 以便表单视图仍然有效,然后让模型在创建/更新时将它们拆分到 owner_tags 模型。
  • 在acts_as_taggable_on 的自述文件中,它向您展示了如何声明所有权标签。我不“明白”你想要做什么。一个标签怎么可能有帖子但没有所有者?

标签: ruby-on-rails tagging acts-as-taggable-on


【解决方案1】:

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

【讨论】:

  • 在这个例子中这似乎对我不起作用stackoverflow.com/questions/6933659/…
  • 这对我很有用。但是,请务必在 before_save 上设置条件,除非您真的希望在每次保存之前执行此代码(例如,在表单之外保存)。例如,如果您在代码中的其他地方更新了一个属性并且这些属性不包含“tag_list”,您将被烧毁(所有者的标签列表将被意外设置为 nil)。我是第一手发现的:)
【解决方案2】:

我使用了一个观察者来解决这个问题。比如:

在 /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

【讨论】:

    【解决方案3】:

    聚会迟到了,但我发现 guillaume06 的解决方案效果很好,我为其添加了一些额外的功能:

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

    如何:编写一个模块并在初始化时包含在您的库中 (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)..
    

    【讨论】:

      【解决方案4】:

      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
      

      【讨论】:

      • 请分享您的代码,我认为这不是一个有效的答案。
      【解决方案5】:

      使用所有权时,可标记模型的标记会有所不同。没有所有权,它可以像这样获得它的标签:

      @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,一个没有tagger_id/_type),因为params[:photo][:tag_list] 已经包含在photo_params 中。因此,为了避免这种情况,请不要将:tag_list 列入白名单。

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

      对于 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

      【讨论】:

        【解决方案6】:

        尝试使用委托:

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

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

        【讨论】:

          【解决方案7】:

          我最终创建了一个运行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,并确保将thinguser_id 设置在@987654329 的tags 之前@。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-04-04
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-03-16
            相关资源
            最近更新 更多