2014-02-11 33 views
28

我有一個模型對象是不是從ActiveRecord :: Base的後代,並沒有存儲在數據庫中。我爲它創建了一個序列化器(使用相同的名稱+「Serializer」),並在我的控制器中調用render json: object_instance使用active_model_serializer與非ActiveRecord對象

結果是從render的深處發生的例外。

我實現了一個as_json方法來實例化序列化器並調用它,但結果是對象read_attribute_for_serialization中缺少的方法。

我希望我的對象像ActiveModel兼容的對象一樣至少與Active Model Serializer一樣,但我在他們的文檔中沒有看到任何對此的引用。

回答

50

幾小時後,我終於找到了解決辦法。該模型對象需要正是如此它包含:

class ModelName 
    include ActiveModel::SerializerSupport 
end 

這實現了對象中需要的方法,同時還可以自動發現串行匹配的對象名稱,因此它可以透明地使用,就像一個ActiveRecord對象。

這適用於active_model_serializers版本0.8.1到0.9.3。

+3

你應該接受你自己的答案,因爲它看起來是正確的。 :) –

+0

嘿羅賓你可以包括你的對象的例子,誰想從頭開始類似的人嗎? (這是一個包含序列化器支持的非活動記錄對象) – Will

+0

您是否可以在模型中序列化嵌套的序列化對象數組? – Chris

7

我在升級到Rails 4.2時遇到了這個問題。已經移除了0.10-穩定的ActiveModel::SerializerSupport。我最終只是增加一個別名我波羅斯這似乎這樣的伎倆:

alias :read_attribute_for_serialization :send 

(active_model_serializers 0.10.0.rc2)

您還需要添加包括ActiveModel::Model在您的類。

3

我的帳戶是太新的卡爾·威爾伯的回答發表評論,但繼承人我加入這樣的代碼,我可以傳遞一個哈希對象序列化:

class SerializableHash < Hash 
    alias :read_attribute_for_serialization :[] 
end 

用法:

o = SerializableHash.new(user: current_user, account: current_account) 
    respond_with(o, serializer: SettingsSerializer) 
0

擴大在@ ratbeard的回答下面,任何active_model_serializer版本0.9.x及以上版本都適用。我包含了獲取PORO可序列化散列對象與rails之外的activemodel序列化器一起工作所需的最少量的active_support和active_model類。對於我作爲優化的目的,我傳遞了一個預先計算的序列化對象數組,這些對象在應用程序中的其他位置計算。如果可用,則可以重載ActiveModel :: Serializer子類中的初始化程序以將其傳遞,而不是重新計算。

的lib/serializable_hash.rb

class SerializableHash < Hash 
    alias :read_attribute_for_serialization :[] 
end 

應用程序/串行器/電子郵件/ foo_serializer。RB

require 'active_model/serializer' 
require 'active_support/core_ext/object' 
require 'active_support/inflector' 
require 'active_support/notifications' 
class Email::FooSerializer < ActiveModel::Serializer 
    attributes :id, :bars, :created_at, :updated_at 

    def initialize(foo, precomputed_serialized_array_of_bars =nil) 
    unless serialized_bars 
     serialized_bars = {} 
     foo.bar.each do | bar | 
     serialized_searches[bar.baz] ||= [] 
     serialized_searches[bar.baz] << Email::BarSerializer.new(bar).attributes 
     end 
    end 

    super(SerializableHash[ 
     id: foo.id, 
     bars: serialized_bars, 
     created_at: foo.created_at 
     updated_at: foo.updated_at 
    ]) 
    end 
end 

爲了完整性我還包括使用一個實例變量,而不是串行化散列此替代版本:

應用程序/串行器/電子郵件/ foo_serializer.rb

require 'active_model/serializer' 
require 'active_support/core_ext/object' 
require 'active_support/inflector' 
require 'active_support/notifications' 
class Email::FooSerializer < ActiveModel::Serializer 
    attributes :id, :bars, :created_at, :updated_at 

    def initialize(foo, precomputed_serialized_array_of_bars=nil) 
    @bars = precomputed_serialized_array_of_bars 
    super(foo) 
    end 

    def bars 
    if @bars 
     return @bars 
    else 
     serialized_bars = {} 
     object.bars.each do | bar | 
     serialized_bars[bar.baz] ||= [] 
     serialized_bars[bar.baz] << Email::BarSerializer.new(bar).attributes 
     end 
     return serialized_bars 
    end 
    end 
end 

然後要使用序列化頂級對象,您只需執行

require 'app/serializers/email/foo_serializer' 
require 'app/serializers/email/bar_serializer' 
Email::FooSerializer.new(Foo.first).as_json 

或者如果你想用酒吧的預先計算的序列化數組:

# pre-compute array_of_serialized_bars somewhere up here 

require 'app/serializers/email/foo_serializer' 
require 'app/serializers/email/bar_serializer' 
Email::FooSerializer.new(Foo.first, array_of_pre_serialized_bars).as_json 
+1

'class SerializableHash BF4

3

爲active_model_serializers 0.10.x的和Rails 4.2,這裏就是我們的要求採用主動型串行普通的老式Ruby對象:

普通老式Ruby對象:

class SearchResult 
    extend ActiveModel::Naming 
    include ActiveModel::Serialization 
    attr_accessor :stories, :users, :friends 

    def id 
    hash 
    end 

    def initialize(search:) 
    @stories = search.stories 
    @users = search.users 
    @friends = search.friends 
    end 

    def attributes 
    { stories: stories, 
     users: users, 
     friends: friends 
    } 
    end 
end 

串行:

class SearchResultSerializer < ActiveModel::Serializer 
    attributes :stories, :users, :friends 
end 
+0

with'active_model_serializers 0.10.0.rc4:我發現很多這個設置不必要,請參閱下面的答案。我已經添加了一個單獨的答案,因爲註釋不能很好地處理代碼塊: – b73

10

從mutexkid答案繼與active_model_serializers 0.10.0.rc4,需要做一個普通的老式Ruby對象發揮好與串行如下:

PORO:

class SearchResult 
    include ActiveModel::Serialization 

    attr_reader :stories, :users, :friends 

    def initialize(search:) 
    @stories = search.stories 
    @users = search.users 
    @friends = search.friends 
    end 
end 

串行:

class SearchResultSerializer < ActiveModel::Serializer 
    attributes :stories, :users, :friends 
end 
+0

這是使用Rails 4.0.13 – b73

+0

這也記錄了(可能更明顯)並在0.10中創建。系列:https://github.com/rails-api/active_model_serializers/blob/e1d1a3dbf969cfa48d91e978c8c7fd7e2f098e7c/docs/general/rendering.md#serializing-non-activerecord-objects https://github.com/rails-api/active_model_serializers/blob /e1d1a3dbf969cfa48d91e978c8c7fd7e2f098e7c/docs/ARCHITECTURE.md#what-does-a-serializable-resource-look-like – BF4

+0

與Rails 5.0.1和AMS 0.10.4很好地配合 –