4
module HasUrl
  extend ActiveSupport::Concern

  included do
    attr_accessor :bar
  end

  def bar
    0
  end
end

class Foo < ActiveRecord::Base
  include HasUrl
end

bar 属性はデータベースに保存されませんが、フォームで使用されます (SimpleForm の を使用f.input)。barこのメソッドのゲッターをオーバーライドして、他の属性に基づいて設定し、フォームに値を適切に事前入力できるようにしたいと思います。

問題は、このようなインクルード ブロックで使用すると、クラスattr_accessorにゲッターがセットアップされることです。FooモジュールはFoo祖先チェーンの上位に含まれているため、 bar0 を返すカスタム メソッドには触れられません。

これを解決する1つの方法は、

class Foo < ActiveRecord::Base
  include HasUrl

  def bar
    super
  end
end

しかし、私はこの余分なステップを避けたいと思っています。モジュールを含めて、それを「機能」させたいだけです。もう 1 つのオプションは、フォーム (f.input_field など) で別のヘルパーを使用することですが、SimpleForm のラッパーを利用することはできません。

Module#prepend も私の問題を解決しませんHasUrl。他のもの (特に ActiveRecord コールバック) も定義しているためです。先頭に追加すると、これらのコールバックでエラーが発生します。

NoMethodError: undefined method `_run_...__find__...__callbacks`

prepend が機能するように、このエラーを回避する方法はありますか? または、これを完全に行う別の方法はありますか?

4

1 に答える 1

9

本当に が必要ですattr_accessorか? attr_writer十分ではないでしょうか?

require 'active_support/all'

module HasUrl
  extend ActiveSupport::Concern

  included do
    attr_writer :bar
  end

  def bar
    0
  end
end

class Foo
  include HasUrl
end

p Foo.new.bar

とにかく、本当に を使用したい場合はattr_accessor、これでうまくいくはずです:

require 'active_support/all'

module HasUrl
  extend ActiveSupport::Concern

  included do
    attr_accessor :bar
    define_method :bar do
      0
    end
  end
end

class Foo
  include HasUrl
end

p Foo.new.bar
于 2013-07-03T16:26:43.390 に答える