3

承認のためにCancan1.6.9を使用したRails3アプリケーションがあります。AbilityクラスをJSONに変換したい。これが私の能力クラスです。

# encoding: utf-8

module Ability

  def self.for(guest)
    guest ||= User.new # guest user (not logged in)

    if guest.admin?
      AdminAbility.new(guest)
    elsif guest.assurer?
      AssurerAbility.new(guest)
    end
  end

  ##
  # Assurer
  class AssurerAbility
    include CanCan::Ability

    def initialize(user)
      cannot :manage, User
      can :read, ExchangeRate
    end
  end

  ##
  # Admin
  class AdminAbility
    include CanCan::Ability

    def initialize(user)
      can :manage, User
      can :manage, ExchangeRate
    end

  end

end

実行するAbility.for(User.last).to_jsonと、次のエラーが発生します。

ActiveSupport::JSON::Encoding::CircularReferenceError: object references itself
    from /home/user/.rvm/gems/ruby-1.9.3-p392@rails-3.2.13/gems/activesupport-3.2.13/lib/active_support/json/encoding.rb:75:in `check_for_circular_references'
    from /home/user/.rvm/gems/ruby-1.9.3-p392@rails-3.2.13/gems/activesupport-3.2.13/lib/active_support/json/encoding.rb:46:in `encode'
    from /home/user/.rvm/gems/ruby-1.9.3-p392@rails-3.2.13/gems/activesupport-3.2.13/lib/active_support/json/encoding.rb:246:in `block in encode_json'
    from /home/user/.rvm/gems/ruby-1.9.3-p392@rails-3.2.13/gems/activesupport-3.2.13/lib/active_support/json/encoding.rb:246:in `each'
    from /home/user/.rvm/gems/ruby-1.9.3-p392@rails-3.2.13/gems/activesupport-3.2.13/lib/active_support/json/encoding.rb:246:in `map'
    from /home/user/.rvm/gems/ruby-1.9.3-p392@rails-3.2.13/gems/activesupport-3.2.13/lib/active_support/json/encoding.rb:246:in `encode_json'
    from /home/user/.rvm/gems/ruby-1.9.3-p392@rails-3.2.13/gems/activesupport-3.2.13/lib/active_support/json/encoding.rb:48:in `block in encode'
    from /home/user/.rvm/gems/ruby-1.9.3-p392@rails-3.2.13/gems/activesupport-3.2.13/lib/active_support/json/encoding.rb:77:in `check_for_circular_references'
    from /home/user/.rvm/gems/ruby-1.9.3-p392@rails-3.2.13/gems/activesupport-3.2.13/lib/active_support/json/encoding.rb:46:in `encode'
    from /home/user/.rvm/gems/ruby-1.9.3-p392@rails-3.2.13/gems/activesupport-3.2.13/lib/active_support/json/encoding.rb:246:in `block in encode_json'
    from /home/user/.rvm/gems/ruby-1.9.3-p392@rails-3.2.13/gems/activesupport-3.2.13/lib/active_support/json/encoding.rb:246:in `each'
    from /home/user/.rvm/gems/ruby-1.9.3-p392@rails-3.2.13/gems/activesupport-3.2.13/lib/active_support/json/encoding.rb:246:in `map'
    from /home/user/.rvm/gems/ruby-1.9.3-p392@rails-3.2.13/gems/activesupport-3.2.13/lib/active_support/json/encoding.rb:246:in `encode_json'
    from /home/user/.rvm/gems/ruby-1.9.3-p392@rails-3.2.13/gems/activesupport-3.2.13/lib/active_support/json/encoding.rb:48:in `block in encode'
    from /home/user/.rvm/gems/ruby-1.9.3-p392@rails-3.2.13/gems/activesupport-3.2.13/lib/active_support/json/encoding.rb:77:in `check_for_circular_references'
    from /home/user/.rvm/gems/ruby-1.9.3-p392@rails-3.2.13/gems/activesupport-3.2.13/lib/active_support/json/encoding.rb:46:in `encode'
... 19 levels...
    from /home/user/.rvm/gems/ruby-1.9.3-p392@rails-3.2.13/gems/activesupport-3.2.13/lib/active_support/json/encoding.rb:46:in `encode'
    from /home/user/.rvm/gems/ruby-1.9.3-p392@rails-3.2.13/gems/activesupport-3.2.13/lib/active_support/json/encoding.rb:246:in `block in encode_json'
    from /home/user/.rvm/gems/ruby-1.9.3-p392@rails-3.2.13/gems/activesupport-3.2.13/lib/active_support/json/encoding.rb:246:in `each'
    from /home/user/.rvm/gems/ruby-1.9.3-p392@rails-3.2.13/gems/activesupport-3.2.13/lib/active_support/json/encoding.rb:246:in `map'
    from /home/user/.rvm/gems/ruby-1.9.3-p392@rails-3.2.13/gems/activesupport-3.2.13/lib/active_support/json/encoding.rb:246:in `encode_json'
    from /home/user/.rvm/gems/ruby-1.9.3-p392@rails-3.2.13/gems/activesupport-3.2.13/lib/active_support/json/encoding.rb:48:in `block in encode'
    from /home/user/.rvm/gems/ruby-1.9.3-p392@rails-3.2.13/gems/activesupport-3.2.13/lib/active_support/json/encoding.rb:77:in `check_for_circular_references'
    from /home/user/.rvm/gems/ruby-1.9.3-p392@rails-3.2.13/gems/activesupport-3.2.13/lib/active_support/json/encoding.rb:46:in `encode'
    from /home/user/.rvm/gems/ruby-1.9.3-p392@rails-3.2.13/gems/activesupport-3.2.13/lib/active_support/json/encoding.rb:31:in `encode'
    from /home/user/.rvm/gems/ruby-1.9.3-p392@rails-3.2.13/gems/activesupport-3.2.13/lib/active_support/core_ext/object/to_json.rb:16:in `to_json'
    enter code here

そして、実行するAbility.for(User.last).as_jsonと結果が得られます。しかし、それは有効なJSONの結果ではありません。

{"rules"=>[#<CanCan::Rule:0xaf5e81c @match_all=false, @base_behavior=false, @actions=[:manage], @subjects=[User(id: integer, password_digest: string, created_at: datetime, updated_at: datetime, uic: string, role: string, name: string, register_no: string)], @conditions={}, @block=nil>, #<CanCan::Rule:0xaf5e72c @match_all=false, @base_behavior=true, @actions=[:read], @subjects=[ExchangeRate(id: integer, data: float, date: date, created_at: datetime, updated_at: datetime)], @conditions={}, @block=nil>]}

何か案が?

4

1 に答える 1

9

TL; DR:モデルにメソッドを実装self.as_jsonし、JSONに変換するフィールドを明示的に指定します。Ability.for(User.last).to_jsonこの後、エラーなしで実行できるようになります。


完全な説明:ソースAbilityから見たときの構造を見てみましょう:

  • Abilityインスタンスには、という名前のフィールドがあります@rules
  • 各ルールに@subjectは、フラット化されたActiveRecordクラス(など)であるUserという名前のフィールドがありExchangeRateます。はい、クラスインスタンスではなく、クラスです。
  • @subjectJSONに変換されて表示されますCircularReferenceError。なんで?

問題は、JSONへの変換UserまたはExchangeRateクラス化は、その構造が非常に複雑になる可能性があるため、お勧めできません。たとえば、を実行しようとするUser.as_jsonと、結果は次のようになります。おそらく、Userのフィールドの1つがに戻って参照しUser、を取得しますCircularReferenceError。これを回避するには、次のJSON表現に含めるフィールドを指定しますUser(同じことが適用されExchangeRateます)。

class User < ActiveRecord::Base
  #...
  def self.as_json(options = {})
    { "class" => "User" }
  end
end
于 2013-03-28T17:15:14.477 に答える