ruby-on-rails - Cancan:json的能力类

标签 ruby-on-rails ruby-on-rails-3 cancan

我有带有 Cancan 1.6.9 的 Rails 3 应用程序进行授权。我想将能力类转换为 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>]}

有什么想法吗?

最佳答案

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


完整解释:让我们看看从source看到的Ability的结构:

  • Ability 实例有一个名为 @rules 的字段。
  • 每个规则都有一个名为 @subject 的字段,它是一个扁平化的 ActiveRecord 类(UserExchangeRate 等)。是的,,不是类实例。
  • @subject 被转换为 JSON 并出现 CircularReferenceError。为什么?

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

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

关于ruby-on-rails - Cancan:json的能力类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15629181/

相关文章:

ruby-on-rails-3 - 如何在控制台中测试 CanCan?

ruby-on-rails - 在 Rails 4 中的实时服务器上安装私有(private)酒吧时出错

ruby-on-rails - Rails 使用键数组缓存 read_multi

ruby-on-rails - Rails Active Record,如何在查询结果中添加附加字段参数?

ruby-on-rails - 如何在 Nokogiri 中创建具有属性和值的 xml 元素

jquery - 使用 Kaminari gem 进行 Ajax 分页

java - 分段上传不适用于 android + rails

ruby-on-rails - acts_as_follower 无法与我的 Rails3.2 应用程序正常工作

ruby - 在引擎中使用 CanCan。 Ability.rb 例子

ruby-on-rails-4 - 使用 ActiveAdmin 更新 rolify 中的角色