简体   繁体   English

Cancan:json的能力等级

[英]Cancan: Ability class to json

I have Rails 3 application with Cancan 1.6.9 for authorization. 我有使用Cancan 1.6.9的Rails 3应用程序进行授权。 I want to convert Ability class to JSON. 我想将Ability类转换为JSON。 Here is the my Ability class. 这是我的能力课程。

# 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

When I run Ability.for(User.last).to_json I get following errors: 当我运行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

And when I run Ability.for(User.last).as_json I get result. 当我运行Ability.for(User.last).as_json我得到了结果。 But it's not valid JSON result. 但它不是有效的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>]}

Any idea? 任何想法?

TL;DR: Implement self.as_json method in your models and explicitly specify which fields to convert to JSON. TL; DR:在模型中实现self.as_json方法,并明确指定要转换为JSON的字段。 After this you will be able to run Ability.for(User.last).to_json without errors. 在此之后,您将能够Ability.for(User.last).to_json地运行Ability.for(User.last).to_json


Complete explanation: let's look at the structure of Ability as seen from source : 完整的解释:让我们看一下从源头看到的Ability结构:

  • Ability instance has a field named @rules . Ability实例有一个名为@rules的字段。
  • Each rule has a field named @subject which is a flattened ActiveRecord class ( User , ExchangeRate etc). 每个规则都有一个名为@subject的字段,它是一个展平的ActiveRecord类( UserExchangeRate等)。 Yes, class , not class instance. 是的, ,而不是类实例。
  • @subject gets converted to JSON and CircularReferenceError appears. @subject转换为JSON并出现CircularReferenceError Why? 为什么?

The problem is, converting User or ExchangeRate class to JSON is not a good idea because their structure may be very complicated. 问题是,将UserExchangeRate类转换为JSON并不是一个好主意,因为它们的结构可能非常复杂。 For instance, if you try running User.as_json , the result might be like this . 举例来说,如果你尝试运行User.as_json ,结果可能会像这样 Probably one of User 's fields references back to User and you get CircularReferenceError . User的某个字段可能会引用回User并且您会收到CircularReferenceError To avoid this, specify which fields should be included into JSON representation of User (the same is applied for ExchangeRate ): 要避免这种情况,请指定哪些字段应包含在User JSON表示中(同样适用于ExchangeRate ):

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM