3

各ユーザーには多くの役割があります。ユーザーが「管理者」ロールを持っているかどうかを確認するには、次のhas_role?メソッドを使用できます。

some_user.has_role?('admin')

これは次のように定義されています。

def has_role?(role_in_question)
  roles.map(&:name).include?(role_in_question.to_s)
end

some_user.has_role?('admin')のように書けるようにしたいsome_user.is_admin?ので、次のようにしました。

  def method_missing(method, *args)
    if method.to_s.match(/^is_(\w+)[?]$/)
      has_role? $1
    else
      super
    end
  end

このsome_user.is_admin?場合は問題なく動作しますが、別の関連付けで参照されているユーザーで呼び出そうとすると失敗します。

>> Annotation.first.created_by.is_admin?
NoMethodError: undefined method `is_admin?' for "KKadue":User
    from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/associations/association_proxy.rb:215:in `method_missing'
    from (irb):345
    from :0

何を与える?

4

2 に答える 2

3

Rails はrespond_to? "is_admin?"send.

respond_to?したがって、次のようにも専門化する必要があります。

def respond_to?(method, include_private=false)
  super || method.to_s.match(/^is_(\w+)[?]$/)
end

:なぜrespond_to?Rails がそこを実行するのではなく、なぜチェックするのかを私に聞かsendないでください。正当な理由はわかりません。

また: 最善の方法 (Ruby 1.9.2+) は、respond_to_missing?代わりに定義することです。次のような少し手の込んだものを使用して、すべてのバージョンと互換性を持たせることができます。

def respond_to_missing?(method, include_private=false)
  method.to_s.match(/^is_(\w+)[?]$/)
end

unless 42.respond_to?(:respond_to_missing?) # needed for Ruby before 1.9.2:
  def respond_to?(method, include_private=false)
    super || respond_to_missing?(method, include_private)
  end
end
于 2010-07-21T19:26:20.500 に答える
2

クラスは、モデルに到達する前に、探している呼び出しをActiveRecord::Associations::AssociationProxyオーバーライドしてインターセプトします。method_missing

これは、モデルがメソッドであるかどうかを AP がチェックするために発生respond_to?しますが、あなたの場合はそうではありません。

Rails のソースを編集する以外に、いくつかの解決策があります。

まず、メタプログラミングを使用して、ユーザー オブジェクトの各 is_* メソッドを手動で定義します。何かのようなもの:

class User
  Role.all.each do |role|
    define_method "is_#{role.name}?" do
      has_role?(role.name)
    end
  end
end

もう 1 つは、次のような他の方法で User オブジェクトをロードすることです。

User.find(Annotation.first.user_id).is_admin?

または、リストされている他の回答のいずれかを使用してください。

于 2010-07-21T19:33:09.667 に答える