首页 文章

Rails:覆盖ActiveRecord关联方法

提问于
浏览
33

有没有办法覆盖ActiveRecord关联提供的方法之一?

比方说,我有以下典型的多态has_many:通过关联:

class Story < ActiveRecord::Base
    has_many :taggings, :as => :taggable
    has_many :tags, :through => :taggings, :order => :name
end


class Tag < ActiveRecord::Base
    has_many :taggings, :dependent => :destroy
    has_many :stories, :through => :taggings, :source => :taggable, :source_type => "Story"
end

您可能知道这会为Story模型添加一大堆相关方法,如标签,标签<<,tags =,tags.empty?等 .

我如何重写这些方法之一?特别是标签<<方法 . 覆盖普通的类方法很容易,但我似乎无法找到有关如何覆盖关联方法的任何信息 . 做点什么

def tags<< *new_tags
    #do stuff
end

调用它时会产生语法错误,所以显然不那么简单 .

7 回答

  • 54

    您可以使用 has_many 块来扩展与方法的关联 . 见评论"Use a block to extend your associations" here .
    覆盖现有方法也有效,但不知道这是否是一个好主意 .

    has_many :tags, :through => :taggings, :order => :name do
        def << (value)
          "overriden" #your code here
          super value
        end     
      end
    
  • 0

    如果要在Rails 3.2中访问模型本身,则应使用 proxy_association.owner

    例:

    class Author < ActiveRecord::Base
      has_many :books do
        def << (book)
          proxy_association.owner.add_book(book)
        end
      end
    
      def add_book (book)
        # do your thing here.
      end
    end
    

    documentation

  • 0

    我认为您需要 def tags.<<(*new_tags) 用于签名,这应该可以使用,或者以下是等效的,如果您需要覆盖多个方法则更清洁一点 .

    class << tags
      def <<(*new_tags)
        # rawr!
      end
    end
    
  • 18

    您必须定义tags方法以返回具有 << 方法的对象 .

    你可以这样做,但我真的不推荐它 . 除了尝试替换ActiveRecord使用的东西之外,只需向模型添加一个方法就可以做得更好 .

    这基本上运行默认的 tags 方法将<<方法添加到结果对象并返回该对象 . 这可能有点资源,因为每次运行它都会创建一个新方法

    def tags_with_append
      collection = tags_without_append
      def collection.<< (*arguments)
        ...
      end
      collection
    end
    # defines the method 'tags' by aliasing 'tags_with_append'
    alias_method_chain :tags, :append
    
  • 0

    我使用的方法是扩展关联 . 你可以在这里看到我处理'quantity'属性的方式:https://gist.github.com/1399762

    它基本上允许你这样做

    has_many : tags, :through => : taggings, extend => QuantityAssociation
    

    如果不能确切地知道你希望通过覆盖方法实现什么,那么很难知道你是否可以做同样的事情 .

  • 0

    这可能对您的情况没有帮助,但可能对其他人有用 .

    协会回调:http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

    来自文档的示例:

    class Project
      has_and_belongs_to_many :developers, :after_add => :evaluate_velocity
    
      def evaluate_velocity(developer)
        ...
      end
    end
    

    另请参阅Association Extensions:

    class Account < ActiveRecord::Base
      has_many :people do
        def find_or_create_by_name(name)
          first_name, last_name = name.split(" ", 2)
          find_or_create_by_first_name_and_last_name(first_name, last_name)
        end
      end
    end
    
    person = Account.first.people.find_or_create_by_name("David Heinemeier Hansson")
    person.first_name # => "David"
    person.last_name  # => "Heinemeier Hansson"
    
  • 0

    Rails guides有关直接覆盖添加方法的文档 .

    OP覆盖 << 的问题可能是唯一的例外,因为the top answer . 但它不适用于 has_one= 赋值方法或getter方法 .

相关问题