【问题标题】:as_json not calling as_json on associationsas_json 没有在关联上调用 as_json
【发布时间】:2011-06-17 23:29:05
【问题描述】:

我有一个模型,其数据在呈现为 json 时不应包含在内。所以我实现了类的 as_json 方法以使其行为适当。问题是当与此模型关联的其他模型渲染 json 时,我的自定义 as_json 没有被调用。

class Owner < ActiveRecord::Base
  has_one :dog

  def as_json(options={})
    puts "Owner::as_json"
    super(options)
  end  
end

class Dog < ActiveRecord::Base
  belongs_to :owner

  def as_json(options={})
    puts "Dog::as_json"
    options[:except] = :secret
    super(options)
  end  
end

加载开发环境(Rails 3.0.3)
ruby-1.9.2-p136 :001 > d = Dog.first
=> #&lt;Dog id: 1, owner_id: 1, name: "Scooby", secret: "I enjoy crapping everwhere">
ruby-1.9.2-p136:002 > d.as_json
狗::as_json
=> {"dog"=>{"id"=>1, "name"=>"Scooby", "owner_id"=>1}}
ruby-1.9.2-p136 :004 > d.owner.as_json(:include => :dog)
所有者::as_json
=> {"owner"=>{"id"=>1, "name"=>"Shaggy", :dog=>{"id"=>1, "name"=>"Scooby", "owner_id"= >1, "secret"=>"我喜欢到处拉屎"}}}

感谢您的帮助

【问题讨论】:

  • 我也有这个问题,在 Rails 3.0.9 上使用 Mongoid。

标签: ruby-on-rails json ruby-on-rails-3


【解决方案1】:

【讨论】:

  • 这实际上是一个不同的错误(它不是专门针对关联模型的),并且在 3.0.2 中已修复。
【解决方案2】:

我遇到了同样的问题。我想让这个工作:

render :json => @favorites.as_json(:include => :location)

但事实并非如此,所以我最终添加了一个带有以下内容的 index.json.erb:

<% favs = @favorites.as_json.each do |fav| %>
    <% fav["location"] = Location.find(fav["location_id"]).as_json %>
<% end %>
<%= favs.to_json.html_safe %>

不是修复 - 只是一种解决方法。我想你也做了同样的事情。

【讨论】:

    【解决方案3】:

    这是 Rails 中的known bug。 (由于从以前的错误跟踪器迁移到 Github 问题,该问题被标记为已关闭,但在 Rails 3.1 中仍然存在问题。)

    【讨论】:

    • 是的,迁移到 Github 问题破坏了所有现有链接。 :( 固定。
    • 对于那些寻找快速解决方法的人来说,它隐藏在 cmets 中,但基本上,您可以通过将自定义 as_json 重命名为 serializable_hash github.com/rails/rails/pull/2200#issuecomment-3131652 来解决
    【解决方案4】:

    更新 @John 指出这是 Rails 中的一个已知错误。修复它的补丁似乎是:https://github.com/rails/rails/pull/2200。不过,你可以试试 RABL,因为它很甜。

    我一直对传递一组复杂的选项感到沮丧来创建我想要的 JSON 视图。我在 Rails 3.0.9 中使用 Mongoid 遇到的问题促使我编写 JSON 模板。但实际上,如果您正在处理关系或自定义 api 属性,那么 模板会更好。

    此外,处理不同的输出在我看来就像是 View 层,所以 我决定使用 API 模板语言 RABL 它使构建有效 JSON 并包含任何关联或字段。

    不是问题的解决方案,而是用例的更好解决方案。

    【讨论】:

      【解决方案5】:

      如上所述,这是 Rails 基础的问题。 rails 补丁here 还没有应用,至少看起来有点争议,所以我很犹豫是否在本地应用它。即使作为猴子补丁应用,它也可能使未来的 Rails 升级复杂化。

      我还在考虑上面建议的RABL,它看起来很有用。目前,我不想在我的应用程序中添加另一种视图模板语言。我目前的需求很小。

      所以这里有一个解决方法,它不需要补丁并且适用于大多数简单的情况。这适用于您希望调用的关联 as_json 方法看起来像

      def as_json(options={})
        super( <... custom options ...> )
      end
      

      就我而言,我有 Schedule 模型,其中有很多 Events

      class Event < ActiveRecord::Base
      
        # define json options as constant, or you could return them from a method
        EVENT_JSON_OPTS = { :include => { :locations => { :only => [:id], :methods => [:name] } } }
      
        def as_json(options={})
          super(EVENT_JSON_OPTS)
        end
      end
      
      class Schedule < ActiveRecord::Base
        has_many :events
      
        def as_json(options={})
          super(:include => { :events => { Event::EVENT_JSON_OPTS } })
        end
      end
      

      如果您遵循以下准则,即无论何时在您的 as_json() 方法中 :include 关联,您将需要的任何选项定义为要引用的模型中的常量,这将适用于任意级别的关联。 注意我只需要上面示例中自定义的第一级关联。

      【讨论】:

        【解决方案6】:

        我发现 serializable_hash 的工作方式与您期望的 as_json 一样,并且总是被调用:

          def serializable_hash(options = {})
            result = super(options)
            result[:url] = "http://.."
            result
          end
        

        【讨论】:

        • 这是问题的实际解决方案。 Rails 5.1 中仍然存在错误/“功能”,而且看起来不会修复。
        • 我在 rails 5.1.4 上的测试表明这不再正确。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-12-02
        • 1970-01-01
        • 1970-01-01
        • 2015-10-14
        • 2012-11-15
        • 2014-10-26
        相关资源
        最近更新 更多