Cancan:json的能力等级

Zec*_*eck 3 ruby-on-rails cancan ruby-on-rails-3

我有使用Cancan 1.6.9的Rails 3应用程序进行授权.我想将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
Run Code Online (Sandbox Code Playgroud)

当我跑步时,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
Run Code Online (Sandbox Code Playgroud)

当我跑步时,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>]}
Run Code Online (Sandbox Code Playgroud)

任何的想法?

Ily*_*kov 9

TL; DR:self.as_json在模型中实现方法并明确指定要转换为JSON的字段.在此之后,您将能够Ability.for(User.last).to_json无错误地运行.


完整的解释:让我们看一下Ability源头看到的结构:

  • Abilityinstance有一个名为的字段@rules.
  • 每个规则有一个名为字段@subject是一个扁平的ActiveRecord类(User,ExchangeRate等).是的,,而不是类实例.
  • @subject转换为JSON并CircularReferenceError出现.为什么?

问题是,转换UserExchangeRate类转换为JSON不是一个好主意,因为它们的结构可能非常复杂.举例来说,如果你尝试运行User.as_json,结果可能会像这样.可能其中一个User字段引用回来User,你得到CircularReferenceError.要避免这种情况,请指定哪些字段应包含在JSON表示中User(同样适用ExchangeRate):

class User < ActiveRecord::Base
  #...
  def self.as_json(options = {})
    { "class" => "User" }
  end
end
Run Code Online (Sandbox Code Playgroud)