Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails Rails:使用活动的\u模型\u序列化程序序列化深度嵌套的关联_Ruby On Rails_Json_Active Model Serializers - Fatal编程技术网

Ruby on rails Rails:使用活动的\u模型\u序列化程序序列化深度嵌套的关联

Ruby on rails Rails:使用活动的\u模型\u序列化程序序列化深度嵌套的关联,ruby-on-rails,json,active-model-serializers,Ruby On Rails,Json,Active Model Serializers,我使用的是rails4.2.1和active\u model\u序列化程序0.10.0.rc2 我是API新手,选择了active\u model\u序列化程序,因为它似乎正在成为rails的标准(尽管我并不反对使用RABL或其他序列化程序) 我遇到的问题是,我似乎无法在多级关系中包含各种属性。例如,我有: 项目 class ProjectSerializer < ActiveModel::Serializer attributes :id,

我使用的是
rails4.2.1
active\u model\u序列化程序0.10.0.rc2

我是API新手,选择了
active\u model\u序列化程序
,因为它似乎正在成为rails的标准(尽管我并不反对使用
RABL
或其他序列化程序)

我遇到的问题是,我似乎无法在多级关系中包含各种属性。例如,我有:

项目

class ProjectSerializer < ActiveModel::Serializer
  attributes                      :id, 
                                  :name,
                                  :updated_at

  has_many                        :estimates, include_nested_associations: true

end
class EstimateSerializer < ActiveModel::Serializer
  attributes                      :id, 
                                  :name, 
                                  :release_version, 
                                  :exchange_rate, 
                                  :updated_at,

                                  :project_id, 
                                  :project_code_id, 
                                  :tax_type_id 

  belongs_to                      :project
  belongs_to                      :project_code
  belongs_to                      :tax_type

  has_many                        :proposals

end
class ProposalSerializer < ActiveModel::Serializer
  attributes                      :id, 
                                  :name, 
                                  :updated_at,

                                  :estimate_id

  belongs_to                      :estimate
end
然而,我想让它产生的是:

{
  "id": 1,
  "name": "123 Park Ave.",
  "updated_at": "2015-08-09T02:36:23.950Z",
  "estimates": [
    {
      "id": 1,
      "name": "E1",
      "release_version": "v1.0",
      "exchange_rate": "0.0",
      "updated_at": "2015-08-12T04:23:38.183Z",
      "project": { 
        "id": 1,
        "name": "123 Park Ave."
      },
      "project_code": {
        "id": 8,
        "valuation": 30
      },
      "tax_type": {
        "id": 1,
        "name": "no-tax"
      },
      "proposals": [
        {
          "id": 1,
          "name": "P1",
          "updated_at": "2015-08-12T04:23:38.183Z"
        },
        {
          "id": 2,
          "name": "P2",
          "updated_at": "2015-10-12T04:23:38.183Z"
        }
      ]
    }
  ]
}
理想情况下,我还希望能够指定每个序列化程序中包括哪些属性、关联以及这些关联的属性

我一直在研究AMS的问题,似乎在如何处理这一问题上有一些反复(或者如果这种功能实际上得到了支持),但我很难准确地确定当前的状态

建议的解决方案之一是使用调用嵌套属性的方法覆盖属性,但这似乎被视为一种攻击,因此我希望尽可能避免这种情况


无论如何,如果您能举一个关于如何处理此问题或一般API建议的示例,我们将不胜感激。

这将满足您的需求

@project.to_json(包括:{估计:{
包括:{:项目,:项目\代码,:税务\类型,:建议书}}})


顶级嵌套将自动包括在内,但任何比它更深的内容都需要包括在您的show action中或您称之为的任何地方。

因此,这不是最好的答案,甚至不是一个好答案,但这正是我所需要的

在AMS中使用
json\u api
适配器时,似乎支持包含嵌套和侧加载属性,但我需要对平面json的支持。此外,该方法工作得很好,因为每个序列化程序都专门生成我所需要的内容,以独立于任何其他序列化程序,而无需在控制器中执行任何操作

欢迎提出意见/备选方法

项目模型

class Project < ActiveRecord::Base      
  has_many  :estimates, autosave: true, dependent: :destroy
end
module Baserecord
  class School < ApplicationRecord
    has_many :programs, class_name: Baserecord.program_class, dependent: :destroy
    has_many :faculties, class_name: Baserecord.faculty_class, through: :programs, dependent: :destroy
end
module Baserecord
  class Faculty < ApplicationRecord
    belongs_to :program, class_name: Baserecord.program_class
    has_many :departments, class_name: Baserecord.department_class, dependent: :destroy
    has_many :program_of_studies, class_name: Baserecord.program_of_study_class, through: :departments,
                                  dependent: :destroy
  end
end
项目序列化程序

def index
  @projects = Project.all
  render json: @projects
end
class ProjectSerializer < ActiveModel::Serializer
  attributes  :id, 
              :name,
              :updated_at,

              # has_many
              :estimates



  def estimates
    customized_estimates = []

    object.estimates.each do |estimate|
      # Assign object attributes (returns a hash)
      # ===========================================================
      custom_estimate = estimate.attributes


      # Custom nested and side-loaded attributes
      # ===========================================================
      # belongs_to
      custom_estimate[:project] = estimate.project.slice(:id, :name) # get only :id and :name for the project
      custom_estimate[:project_code] = estimate.project_code
      custom_estimate[:tax_type] = estimate.tax_type

      # has_many w/only specified attributes
      custom_estimate[:proposals] = estimate.proposals.collect{|proposal| proposal.slice(:id, :name, :updated_at)}

      # ===========================================================
      customized_estimates.push(custom_estimate)
    end

    return customized_estimates
  end
end
module Baserecord
  class SchoolSerializer
    include JSONAPI::Serializer
    attributes :id, :name, :code, :description, :school_logo, :motto, :address

    attribute :programs do |object|

      # Create an empty array
      customized_programs = []

      object.programs.each do |program|

        # Assign object attributes (returns a hash)
        custom_program = program.attributes

        # Create custom nested and side-loaded attributes
        custom_program[:faculties] = program.faculties

        # Push the created custom nested and side-loaded attributes into the empty array
        customized_programs.push(custom_program)
      end

      # Return the new array
      customized_programs
    end

    cache_options store: Rails.cache, namespace: 'jsonapi-serializer', expires_in: 1.hour
  end
end

我基本上忽略了在序列化程序中实现任何
有许多
属于
关联的尝试,只是定制了行为。我使用
slice
选择特定属性。希望会出现一个更优雅的解决方案。

如果使用JSONAPI适配器,可以执行以下操作来呈现嵌套关系:

render json: @project, include: ['estimates', 'estimates.project_code', 'estimates.tax_type', 'estimates.proposals']
您可以阅读jsonapi文档中的更多内容:

Per commit 1426:-和相关讨论,您可以看到
json
属性
序列化的默认嵌套是一个级别

如果默认情况下需要深度嵌套,可以在活动的\u model\u序列化程序初始值设定项中设置配置属性:

ActiveModelSerializers.config.default\u包含='**'


有关v0.10.6的详细参考信息:

您可以更改
ActiveModel::Serializer的
默认\u包含内容

# config/initializers/active_model_serializer.rb
ActiveModel::Serializer.config.default_includes = '**' # (default '*')
此外,为了避免无限递归,可以按如下方式控制嵌套序列化:

class UserSerializer < ActiveModel::Serializer
  include Rails.application.routes.url_helpers

  attributes :id, :phone_number, :links, :current_team_id

  # Using serializer from app/serializers/profile_serializer.rb
  has_one :profile
  # Using serializer described below:
  # UserSerializer::TeamSerializer
  has_many :teams

  def links
    {
      self: user_path(object.id),
      api: api_v1_user_path(id: object.id, format: :json)
    }
  end

  def current_team_id
    object.teams&.first&.id
  end

  class TeamSerializer < ActiveModel::Serializer
    attributes :id, :name, :image_url, :user_id

    # Using serializer described below:
    # UserSerializer::TeamSerializer::GameSerializer
    has_many :games

    class GameSerializer < ActiveModel::Serializer
      attributes :id, :kind, :address, :date_at

      # Using serializer from app/serializers/gamers_serializer.rb
      has_many :gamers
    end
  end
end

在我的例子中,我创建了一个名为“active_model_serializer.rb”的文件,该文件位于“MyApp/config/initializers”处,包含以下内容:

ActiveModelSerializers.config.default_includes = '**'

不要忘记重新启动服务器:

$ rails s
为了进一步说明,我补充了以下答案

我在rails应用程序中使用了用于序列化的。我没有发现在控制器中包含嵌套属性和侧加载属性对我来说很方便。我只是想更好地分离关注点。因此,任何与序列化有关的内容都应该只在序列化文件中,而与控制器文件无关

因此,在我的案例中,我有以下联系:

学校模式

class Project < ActiveRecord::Base      
  has_many  :estimates, autosave: true, dependent: :destroy
end
module Baserecord
  class School < ApplicationRecord
    has_many :programs, class_name: Baserecord.program_class, dependent: :destroy
    has_many :faculties, class_name: Baserecord.faculty_class, through: :programs, dependent: :destroy
end
module Baserecord
  class Faculty < ApplicationRecord
    belongs_to :program, class_name: Baserecord.program_class
    has_many :departments, class_name: Baserecord.department_class, dependent: :destroy
    has_many :program_of_studies, class_name: Baserecord.program_of_study_class, through: :departments,
                                  dependent: :destroy
  end
end
就这些


我希望这会有所帮助

这种方法是否真的利用了
活动的(model)序列化程序
,或者它只是rails输出
JSON
的默认方式?@greetification否,它使用了rails还原时留下的AMS痕迹。请参见Rails ActiveModel::Serializers::JSON和ActiveModel::Serialization,我想这个方法最大的问题是它需要在两个不同的文件中管理代码;控制器和序列化程序。这并不是说这不是正确的做法;只是我觉得更不方便。这是得到“筑巢”的最好方法。。虽然JSON:API实际上将其扁平化了。如果您不希望将深度嵌套作为默认值,但希望将其用于一个特定的模型,该怎么办?(如果特定模型需要2或3个嵌套级别怎么办?)您可以在每个操作中传入
'**'
。请注意,这是一个安全问题。最好是明确你想要包括什么。虽然这个问题的最上等答案肯定是正确的传统方式,但当遵循AMS惯例时,很难得到你想要的。我也只是编写自己的回调来显示嵌套的关联,并且发现AMS约定太笨拙了。我发现几乎所有关于Rails和嵌套关联的事情都是这样的——约定很难处理,请遵循普通的ol'ruby。与您的问题无关,但请在序列化程序文件中使用该间距!它只会降低可读性,所以你知道,我个人觉得它更可读,但我认为每个人都有自己的可读性。
class ProjectSerializer < ActiveModel::Serializer
  attributes                      :id, 
                                  :name,
                                  :updated_at

  has_many                        :estimates, include_nested_associations: true

end
class EstimateSerializer < ActiveModel::Serializer
  attributes                      :id, 
                                  :name, 
                                  :release_version, 
                                  :exchange_rate, 
                                  :updated_at,

                                  :project_id, 
                                  :project_code_id, 
                                  :tax_type_id 

  belongs_to                      :project
  belongs_to                      :project_code
  belongs_to                      :tax_type

  has_many                        :proposals

end
class ProposalSerializer < ActiveModel::Serializer
  attributes                      :id, 
                                  :name, 
                                  :updated_at,

                                  :estimate_id

  belongs_to                      :estimate
end