开发者

Rails: Overriding ActiveRecord association method

Is there a way to override one of the methods provided by an ActiveRecord association?

Say for example I have the following typical polymorphic has_many :through association:

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开发者_JAVA技巧, :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.

How do I go about overriding one of these methods? Specifically the tags<< method. 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. 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

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


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.

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.

This essentially runs the default tags method adds a << method to the resulting object and returns that object. 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  


The method I use is to extend the association. You can see the way I handle 'quantity' attributes here: 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.


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

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"


Rails guides documents about overriding the added methods directly.

OP's issue with overriding << probably is the only exception to this, for which follow the top answer. But it wouldn't work for has_one's = assignment method or getter methods.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜