繁体   English   中英

如何烘干此代码

[英]How to DRY up this code

我已经为模型Unit,Group和Event实现了标记系统,当前,每个模型都有自己的方法add_tags和self.tagged_with的实例。

def add_tags(options=[])
    transaction do
      options.each do |tag|
        self.tags << Tag.find_by(name: tag)
      end
    end
end

def self.tagged_with(tags=[])
  units = Unit.all
    tags.each do |tag|
      units = units & Tag.find_by_name(tag).units
    end
    units
  end
end

我想将它们移动到模块中并将其包含在模型中,但是如您所见,tagd_with方法不是多态的,因为我不知道如何引用育儿类(单元,组等)并调用像“全部”这样的方法。 有什么建议吗?

标签型号:

Class Tag < ActiveRecord::Base
  has_and_belongs_to_many: units, :join_table => :unit_taggings
  has_and_belongs_to_many: groups, :join_table => :group_taggings
  has_and_belongs_to_many: events, :join_table => :event_taggings
end

您可以调用self.class来获取当前类,如下所示:

def self.tagged_with(tags=[])
  klass = self.class
  units = klass.all
    tags.each do |tag|
      units = units & Tag.find_by_name(tag).units
    end
    units
  end
end

self.class应该返回Unit或任何类,在类对象( self.class.tagged_with )上调用任何方法都与Unit.tagged_with相同

我建议您使用Concerns在这里看看

编辑您的评论的答案

使用关注点,您可以执行以下操作,每个类都具有您之前提到的方法,但是您不必在每个类(或文件)上重写所有代码:

# app/models/concerns/taggable.rb
module Taggable
  extend ActiveSupport::Concern

  module ClassMethods
    def self.tagged_with(tags=[])
      klass = self.class
      units = klass.all
        tags.each do |tag|
          units = units & Tag.find_by_name(tag).units
        end
        units
      end
    end
  end
end

# app/models/unit.rb
class Unit
  include Taggable

  ...
end

# app/models/group.rb
class Group
  include Taggable

  ...
end

# app/models/event.rb
class Event
  include Taggable

  ...
end

我会这样做:

#table: taggings, fields: tag_id, taggable type (string), taggable id
class Tagging
  belongs_to :tag
  belongs_to :taggable, :polymorphic => true

现在在lib中创建一个模块-我们称其为“ ActsAsTaggable” *

module ActsAsTaggable
  def self.included(base)
    base.extend(ClassMethods)
    base.class_eval do 
      #common associations, callbacks, validations etc go here
      has_many :taggings, :as => :taggable, :dependent => :destroy
      has_many :tags, :through => :taggings
    end
  end

  #instance methods can be defined in the normal way

  #class methods go in here
  module ClassMethods  

  end
end      

现在,您可以在要标记为任何标签的任何类中执行此操作

include ActsAsTaggable 
  • 已经有一个叫做ActsAsTaggable的宝石(也许是插件),它基本上可以这样工作。 但是,最好能看到解释,而不是仅仅被告知要使用该宝石。

编辑:这是您需要在Tag端建立关联的代码:注意source选项。

class Tag
  has_many :taggings
  has_many :taggables, :through => :taggings, :source => :taggable

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM