简体   繁体   English

Rails:覆盖ActiveRecord关联方法

[英]Rails: Overriding ActiveRecord association method

Is there a way to override one of the methods provided by an ActiveRecord association? 有没有办法覆盖ActiveRecord关联提供的方法之一?

Say for example I have the following typical polymorphic has_many :through association: 比如说我有以下典型的多态has_many:through关联:

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

As you probably know this adds a whole slew of associated methods to the Story model like tags, tags<<, tags=, tags.empty?, etc. 您可能知道,这会将整个关联方法添加到Story模型中,例如标签,标签<<,标签=,tags.empty?等。

How do I go about overriding one of these methods? 我该如何覆盖这些方法之一? Specifically the tags<< method. 特别是tags <<方法。 It's pretty easy to override a normal class methods but I can't seem to find any information on how to override association methods. 重写普通的类方法很容易,但是我似乎找不到有关如何重写关联方法的任何信息。 Doing something like 做类似的事情

def tags<< *new_tags
    #do stuff
end

produces a syntax error when it's called so it's obviously not that simple. 调用时会产生语法错误,因此显然不是那么简单。

You can use block with has_many to extend your association with methods. 您可以在has_many使用block来扩展与方法的关联。 See comment "Use a block to extend your associations" here . 请参见此处的注释“使用块扩展您的关联”。
Overriding existing methods also works, don't know whether it is a good idea however. 覆盖现有方法也可以,但是不知道这是否是一个好主意。

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

If you want to access the model itself in Rails 3.2 you should use proxy_association.owner 如果要在Rails 3.2中访问模型本身,则应使用proxy_association.owner

Example: 例:

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

See documentation 参阅文件

This may not be helpful in your case but could be useful for others looking into this. 这可能对您的情况没有帮助,但可能对其他调查此问题的人有用。

Association Callbacks: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html 关联回调: http : //api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

Example from the docs: 来自文档的示例:

class Project
  has_and_belongs_to_many :developers, :after_add => :evaluate_velocity

  def evaluate_velocity(developer)
    ...
  end
end

Also see 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"

I think you wanted def tags.<<(*new_tags) for the signature, which should work, or the following which is equivalent and a bit cleaner if you need to override multiple methods. 我认为您需要def tags.<<(*new_tags)作为签名,应该可以工作,或者以下等价的工作,如果您需要覆盖多个方法,则可以更干净一些。

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

You would have to define the tags method to return an object which has a << method. 您将必须定义标签方法以返回具有<<方法的对象。

You could do it like this, but I really wouldn't recommend it. 您可以这样做,但是我真的不建议这样做。 You'd be much better off just adding a method to your model that does what you want than trying to replace something ActiveRecord uses. 与向模型中添加ActiveRecord所使用的方法相比,向模型中添加一种可以执行所需操作的方法要好得多。

This essentially runs the default tags method adds a << method to the resulting object and returns that object. 这实际上是运行默认的tags方法,将<<方法添加到结果对象,然后返回该对象。 This may be a bit resource intensive because it creates a new method every time you run it 这可能会占用一些资源,因为每次运行它都会创建一个新方法

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  

Rails guides documents about overriding the added methods directly. Rails指导有关直接覆盖添加的方法的文档。

OP's issue with overriding << probably is the only exception to this, for which follow the top answer . OP的优先级<<可能是唯一的例外,为此,遵循最高答案 But it wouldn't work for has_one 's = assignment method or getter methods. 但是对于has_one=赋值方法或getter方法不起作用。

The method I use is to extend the association. 我使用的方法是扩展关联。 You can see the way I handle 'quantity' attributes here: https://gist.github.com/1399762 您可以在此处查看我处理“数量”属性的方式: https : //gist.github.com/1399762

It basically allows you to just do 它基本上可以让你做

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

Without knowing exactly what your hoping to achieve by overriding the methods its difficult to know if you could do the same. 如果不确切地知道您希望通过覆盖这些方法实现什么,那么很难知道您是否可以这样做。

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

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