Rails: Overriding ActiveRecord association method

后端 未结 7 1359
忘了有多久
忘了有多久 2020-12-05 02:21

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 ass

相关标签:
7条回答
  • 2020-12-05 02:47

    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

    0 讨论(0)
  • 2020-12-05 02:54

    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.

    0 讨论(0)
  • 2020-12-05 02:55

    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"
    
    0 讨论(0)
  • 2020-12-05 02:57

    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
    
    0 讨论(0)
  • 2020-12-05 02:58

    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 讨论(0)
  • 2020-12-05 03:05

    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  
    
    0 讨论(0)
提交回复
热议问题