Ruby on rails Rails 3中的标记

Ruby on rails Rails 3中的标记,ruby-on-rails,Ruby On Rails,在Rails 3中添加标签的最佳解决方案是什么?在类固醇上扮演标签角色 我研究了两种解决方案,但更喜欢 结束 更好的文档,对我来说更灵活。 是我昨天刚创建的一个新图书馆。它是使用Ernie Miller的squeel gem实现的 在可能的情况下,所有可怕的SQL都需要正确实现标记库 它很干净 比较作为标记的行为 def tagged_with(tags, options = {}) tag_list = ActsAsTaggableOn::TagList.from(tags)

在Rails 3中添加标签的最佳解决方案是什么?

在类固醇上扮演标签角色


我研究了两种解决方案,但更喜欢 结束

更好的文档,对我来说更灵活。

是我昨天刚创建的一个新图书馆。它是使用Ernie Miller的squeel gem实现的 在可能的情况下,所有可怕的SQL都需要正确实现标记库 它很干净

比较作为标记的行为

  def tagged_with(tags, options = {})
    tag_list = ActsAsTaggableOn::TagList.from(tags)
    empty_result = scoped(:conditions => "1 = 0")

    return empty_result if tag_list.empty?

    joins = []
    conditions = []

    context = options.delete(:on)
    alias_base_name = undecorated_table_name.gsub('.','_')

    if options.delete(:exclude)
      tags_conditions = tag_list.map { |t| sanitize_sql(["#{ActsAsTaggableOn::Tag.table_name}.name #{like_operator} ?", t]) }.join(" OR ")
      conditions << "#{table_name}.#{primary_key} NOT IN (SELECT #{ActsAsTaggableOn::Tagging.table_name}.taggable_id FROM #{ActsAsTaggableOn::Tagging.table_name} JOIN #{ActsAsTaggableOn::Tag.table_name} ON #{ActsAsTaggableOn::Tagging.table_name}.tag_id = #{ActsAsTaggableOn::Tag.table_name}.#{ActsAsTaggableOn::Tag.primary_key} AND (#{tags_conditions}) WHERE #{ActsAsTaggableOn::Tagging.table_name}.taggable_type = #{quote_value(base_class.name)})"

    elsif options.delete(:any)
      # get tags, drop out if nothing returned (we need at least one)
      tags = ActsAsTaggableOn::Tag.named_any(tag_list)
      return scoped(:conditions => "1 = 0") unless tags.length > 0

      # setup taggings alias so we can chain, ex: items_locations_taggings_awesome_cool_123
      # avoid ambiguous column name
      taggings_context = context ? "_#{context}" : ''

      #TODO: fix alias to be smaller
      taggings_alias   = "#{alias_base_name}#{taggings_context}_taggings_#{tags.map(&:safe_name).join('_')}_#{rand(1024)}"

      tagging_join  = "JOIN #{ActsAsTaggableOn::Tagging.table_name} #{taggings_alias}" +
                      "  ON #{taggings_alias}.taggable_id = #{table_name}.#{primary_key}" +
                      " AND #{taggings_alias}.taggable_type = #{quote_value(base_class.name)}"
      tagging_join << " AND " + sanitize_sql(["#{taggings_alias}.context = ?", context.to_s]) if context

      # don't need to sanitize sql, map all ids and join with OR logic
      conditions << tags.map { |t| "#{taggings_alias}.tag_id = #{t.id}" }.join(" OR ")
      select_clause = "DISTINCT #{table_name}.*" unless context and tag_types.one?

      joins << tagging_join

    else
      tags = ActsAsTaggableOn::Tag.named_any(tag_list)
      return empty_result unless tags.length == tag_list.length

      tags.each do |tag|
        prefix   = "#{tag.safe_name}_#{rand(1024)}"

        taggings_alias = "#{alias_base_name}_taggings_#{prefix}"

        tagging_join  = "JOIN #{ActsAsTaggableOn::Tagging.table_name} #{taggings_alias}" +
                        "  ON #{taggings_alias}.taggable_id = #{table_name}.#{primary_key}" +
                        " AND #{taggings_alias}.taggable_type = #{quote_value(base_class.name)}" +
                        " AND #{taggings_alias}.tag_id = #{tag.id}"
        tagging_join << " AND " + sanitize_sql(["#{taggings_alias}.context = ?", context.to_s]) if context

        joins << tagging_join
      end
    end

    taggings_alias, tags_alias = "#{alias_base_name}_taggings_group", "#{alias_base_name}_tags_group"

    if options.delete(:match_all)
      joins << "LEFT OUTER JOIN #{ActsAsTaggableOn::Tagging.table_name} #{taggings_alias}" +
               "  ON #{taggings_alias}.taggable_id = #{table_name}.#{primary_key}" +
               " AND #{taggings_alias}.taggable_type = #{quote_value(base_class.name)}"


      group_columns = ActsAsTaggableOn::Tag.using_postgresql? ? grouped_column_names_for(self) : "#{table_name}.#{primary_key}"
      group = "#{group_columns} HAVING COUNT(#{taggings_alias}.taggable_id) = #{tags.size}"
    end

    scoped(:select     => select_clause,
           :joins      => joins.join(" "),
           :group      => group,
           :conditions => conditions.join(" AND "),
           :order      => options[:order],
           :readonly   => false)
  end
这要干净得多,尽管我并没有声称已经处理了acts_as_taggable_所实现的所有功能。总有明天:)

所以,如果你想要一个标签库,你可以潜入其中并为它添加一些功能,因为标签可能就是你想要的

在加载相关标签时,它还注意性能,避免了N+1问题。它值得一看,但目前是非常阿尔法,我将添加功能,因为我的项目需要它们

顺便说一句,多亏了充当标签的角色。我决不会放火烧图书馆。我从中借用了模式和想法,但当我想修复自己的功能时,我觉得代码中的SQL风格很难理解,在使用AR查询需求后,我觉得我可以在干净的板岩上更好地工作

RocketTag还有一套全面的rspec测试套件

  def with_tag_context context
    if context
      where{taggings.context == my{context} }
    else
      where{}
    end
  end

  def tagged_with tags_list, options = {}

    on = options.delete :on
    all = options.delete :all

    q = if all
          joins{tags}.where{
            id.in( 
                my{self}.
                  select{id}.
                  joins{tags}.
                  where{tags.name.in(my{tags_list})}.
                  group{~id}.
                  having{count(~id)==my{tags_list.length}}.
                  with_tag_context(my{on})
            )
          }
    else
      joins{tags}.where{tags.name.in(my{tags_list})}.with_tag_context(on)
    end

    q.select{"distinct #{my{table_name}}.*"}

  end