У меня есть приложение Rails 3 с Cancan 1.6.9 для авторизации. Я хочу преобразовать класс 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>]}
Любая идея?
1 ответ
TL; DR: реализуйте метод self.as_json
в своих моделях и явно укажите, какие поля преобразовывать в JSON. После этого вы сможете запускать Ability.for(User.last).to_json
без ошибок.
Полное объяснение: давайте посмотрим на структуру Ability
, как видно из источник:
- Экземпляр
Ability
имеет поле с именем@rules
. - У каждого правила есть поле с именем
@subject
, которое представляет собой плоский класс ActiveRecord (User
,ExchangeRate
и т. Д.). Да, класс , а не экземпляр класса. @subject
преобразуется в JSON, и появляетсяCircularReferenceError
. Почему?
Проблема в том, что преобразование класса User
или ExchangeRate
в JSON - не лучшая идея, поскольку их структура может быть очень сложной. Например, если вы попытаетесь запустить User.as_json
, результат может быть примерно таким, как this. Возможно, одно из полей User
ссылается на User
, и вы получите CircularReferenceError
. Чтобы этого избежать, укажите, какие поля должны быть включены в JSON-представление User
(то же самое применяется для ExchangeRate
):
class User < ActiveRecord::Base
#...
def self.as_json(options = {})
{ "class" => "User" }
end
end
Похожие вопросы
Новые вопросы
ruby-on-rails
Ruby on Rails - это полнофункциональная платформа веб-приложений с открытым исходным кодом, написанная на Ruby. Он следует популярной модели фреймворка MVC и известен своим подходом «соглашение поверх конфигурации» при разработке приложений.