如何在rails中扩展belongs_to功能

时间:2013-08-21 15:45:24

标签: ruby-on-rails ruby-on-rails-3 activerecord

我正在构建一个gem,我希望它的部分功能扩展ActiveRecord::Associations::Builder::BelongsTo,但我无法弄清楚如何做到这一点

所以基本上用户应该能够指定:

class Event < ActiveRecord::Base
  belongs_to :users, foo: true
end
谁知道怎么做?

这不起作用:

module Mygem
  module BelongsToFoo

    def valid_options
      super + [:foo]
    end

    #... other functionality
  end
end

class ActiveRecord::Associations::Builder::BelongsTo
  extend MyGem::BelongsToFoo
end

控制台

ActiveRecord::Associations::Builder::BelongsTo.valid_options.include? :foo
#=> false   ... :(

Event
ArgumentError: Unknown key: foo

belongs_to source code

=============================================== ============================== 的更新

流动delwyns answer我试图再次查看我的代码,他说对了,但是ActiveRecord::Associations::Builder::BelongsTo也有变量valid_options

所以我可以做到

ActiveRecord::Associations::Builder::BelongsTo.new(:a, :b, :c).valid_options.include? :foo
# => true

但也

ActiveRecord::Associations::Builder::BelongsTo.valid_options.include? :foo
# => true

所以它应该看起来像这样

module MyGem
  module BelongsToFoo
    extend ActiveSupport::Concern

    included do
      self.valid_options += [:foo]
    end

    def valid_options
      super + [:foo]
    end

    def define_callbacks(model, reflection)
      # this wont get executed
      add_foo_callbacks(model, reflection)# if options[:foo]
      super
    end

    def add_foo_callbacks(model, reflection)
      # therefore this wont either 
    end
  end
end

即使我试试这个

module MyGem
  module BelongsToFoo

    def define_callbacks(model, reflection)
      raise "dobugging"
    end
  end
end

什么都不会发生,Rails完全忽略我的方法覆盖

所以是的,我可以定义自己的选项,但是他们什么都不做:(任何建议?

2 个答案:

答案 0 :(得分:4)

有一种用于扩展关联代理的内置方法,请参阅http://guides.rubyonrails.org/association_basics.html#association-extensions

class Event < ActiveRecord::Base
  belongs_to :users, :extend => MyGem::SpecialTouch
end

module MyGem
  module SpecialTouch
    def touch
      # do the magic
    end
  end
end

然后您当然可以覆盖或别名链belongs_to,以便它从选项哈希中弹出:foo选项,将其转换为正确的:extend => ...和(实际或有效)调用{{ 1}}。

答案 1 :(得分:2)

valid_options是一种实例方法,因此您需要使用include而不是extend。

module MyGem
  def valid_options
    super + [:foo]
  end
end

class ActiveRecord::Associations::Builder::BelongsTo
  include ::MyGem
end

relation = ActiveRecord::Associations::Builder::BelongsTo.new(:a, :b, :c)
relation.valid_options.include? :foo
#=> true 

希望有所帮助。