레일: active_model_serializer와의 깊이 중첩된 연관성을 직렬화하는 중
하고 Rails 4.2.1
★★★★★★★★★★★★★★★★★」active_model_serializers 0.10.0.rc2
를 선택했습니다.active_model_serializers
이 되고 것 것은 ).RABL
another serializer ( 시리얼라이저)
제가 안고 있는 문제는 다단계 관계에서 다양한 속성을 포함할 수 없다는 것입니다.예를 들어 다음과 같습니다.
프로젝트
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
가 내 the를 때/projects/1
다음 중 하나:
{
"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,
"project_code_id": 8,
"tax_type_id": 1
}
]
}
다만, 제작하고 싶은 것은 다음과 같습니다.
{
"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의 문제를 조사해 본 결과, 이 문제에 대한 대응 방법(또는 이러한 기능이 실제로 지원되고 있는지 여부)에 대해서는 몇 가지 의견이 엇갈리고 있는 것 같습니다만, 현재 상태를 정확하게 파악하는데 어려움을 겪고 있습니다.
- https://github.com/rails-api/active_model_serializers/issues/835
- https://github.com/rails-api/active_model_serializers/issues/968
- https://github.com/rails-api/active_model_serializers/issues/414
- https://github.com/rails-api/active_model_serializers/issues/444
제안된 솔루션 중 하나는 네스트된 속성을 호출하는 메서드로 속성을 덮어쓰는 것이었는데, 해킹으로 간주되는 것 같아서 가능하면 피하고 싶었습니다.
어쨌든 이 방법이나 일반적인 API 조언의 예를 들어 주시면 감사하겠습니다.
Commit 1426: https://github.com/rails-api/active_model_serializers/pull/1426 및 관련 설명에 따라 기본 네스팅이 설정되어 있는 것을 확인할 수 있습니다.json
★★★★★★★★★★★★★★★★★」attributes
시리얼라이제이션
디폴트로 딥네스트 할 경우 active_model_serializer initializer로 설정 속성을 설정할 수 있습니다.
ActiveModelSerializers.config.default_includes = '**'
v0.10.6의 상세한 것에 대하여는, https://github.com/rails-api/active_model_serializers/blob/v0.10.6/docs/general/adapters.md#include-option 를 참조해 주세요.
JSONAPI 어댑터를 사용하는 경우 다음을 수행하여 중첩된 관계를 렌더링할 수 있습니다.
render json: @project, include: ['estimates', 'estimates.project_code', 'estimates.tax_type', 'estimates.proposals']
자세한 내용은 jsonapi 문서를 참조하십시오.http://jsonapi.org/format/ #fetching-buffer
그래서 이게 최선도 아니고 좋은 대답도 아니지만, 이게 내가 필요한 방식이야.
네스트된 Atribute와 사이드 로드된 Atribute를 포함하는 것은 를 사용하는 경우는 서포트되고 있는 것처럼 보입니다.json_api
AMS 탑재 어댑터, 플랫 json 지원이 필요했습니다.또한 이 방법은 각 시리얼라이저가 컨트롤러에서 아무것도 할 필요 없이 다른 시리얼라이저에 의존하지 않고 필요한 것을 정확하게 생성하기 때문에 잘 작동했습니다.
코멘트 / 대체 방법은 언제든지 환영입니다.
프로젝트 모델
class Project < ActiveRecord::Base
has_many :estimates, autosave: true, dependent: :destroy
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
결과
[
{
"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",
"created_at": "2015-08-12T04:23:38.183Z",
"updated_at": "2015-08-12T04:23:38.183Z",
"project": {
"id": 1,
"name": "123 Park Ave."
},
"project_code": {
"id": 8,
"valuation": 30,
"created_at": "2015-08-09T18:02:42.079Z",
"updated_at": "2015-08-09T18:02:42.079Z"
},
"tax_type": {
"id": 1,
"name": "No Tax",
"created_at": "2015-08-09T18:02:42.079Z",
"updated_at": "2015-08-09T18:02:42.079Z"
},
"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"
}
]
}
]
}
]
저는 기본적으로 모든 것을 구현하려는 시도를 무시했습니다.has_many
또는belongs_to
시리얼라이저에 관련지어 동작을 커스터마이즈 했을 뿐입니다.나는 사용했다slice
특정 애트리뷰트를 선택합니다.좀 더 우아한 해결책이 나오길 바란다.
변경할 수 있습니다.default_includes
를 위해ActiveModel::Serializer
:
# 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
결과:
{
"user":{
"id":1,
"phone_number":"79202700000",
"links":{
"self":"/users/1",
"api":"/api/v1/users/1.json"
},
"current_team_id":1,
"profile":{
"id":1,
"name":"Alexander Kalinichev",
"username":"Blackchestnut",
"birthday_on":"1982-11-19",
"avatar_url":null
},
"teams":[
{
"id":1,
"name":"Agile Season",
"image_url":null,
"user_id":1,
"games":[
{
"id":13,
"kind":"training",
"address":"",
"date_at":"2016-12-21T10:05:00.000Z",
"gamers":[
{
"id":17,
"user_id":1,
"game_id":13,
"line":1,
"created_at":"2016-11-21T10:05:54.653Z",
"updated_at":"2016-11-21T10:05:54.653Z"
}
]
}
]
}
]
}
}
내 경우 'MyApp/config/initializers'에 있는 'active_model_serializer.rb'라는 파일을 만들었습니다.이 파일은 다음과 같습니다.
ActiveModelSerializers.config.default_includes = '**'
서버를 재기동하는 것을 잊지 말아 주세요.
$ rails s
이게 네가 원하는 걸 할 수 있을 거야.
@project.to_json( include: { estimates: { include: {:project, :project_code, :tax_type, :proposals } } } )
최상위 네스팅은 자동으로 포함되지만 그 이상의 깊이는 show 액션 또는 호출 위치에 포함되어야 합니다.
에릭 노크로스의 답변을 뒷받침하기 위해 다음과 같은 답변을 덧붙였습니다.
레일 어플리케이션의 serilization에 jsonapi-serializer gem을 사용하고 있었습니다.컨트롤러에 네스트되어 있는 것과 사이드 로딩된 Atribute를 사용하는 것이 편리하지 않았습니다.나는 단지 더 나은 관심사 분리를 원했을 뿐이다.따라서 시리얼라이제이션과 관련된 것은 시리얼라이제이션파일 내부에만 있어야 하며 컨트롤러 파일과는 관계가 없습니다.
제 경우엔 다음과 같은 연관성이 있었습니다.
학교 모델
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
시리얼라이저 파일의 구성은 다음과 같습니다.
학교 시리얼라이저
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
그게 다예요.
이게 도움이 됐으면 좋겠다
언급URL : https://stackoverflow.com/questions/32079897/rails-serializing-deeply-nested-associations-with-active-model-serializers
'programing' 카테고리의 다른 글
서블릿과 웹 서비스의 차이점 (0) | 2023.03.23 |
---|---|
MySQL 데이터베이스 연결 IIS10을 설정하는 동안 WordPress 오류 발생 (0) | 2023.03.23 |
Mongoose에서 Enum을 생성하여 사용하는 방법 (0) | 2023.03.23 |
Select2 Ajax 메서드가 선택되지 않음 (0) | 2023.03.23 |
구성 요소 정의에 forwardRef의 표시 이름이 없습니다. (0) | 2023.03.18 |