Custom class name for relation that's not using Rails convention
vtno opened this issue · 2 comments
I have this Course model which has has_many: quality_badges relation but the actual class is named CharacterQualityBadge
class Course < ApplicationRecord
...
has_many :course_quality_badges
has_many :quality_badges, class_name: 'CharacterQualityBadge',
foreign_key: :character_quality_badge_id,
through: :course_quality_badges,
dependent: :destroy
...
end
In the controller I cannot do
# courses_controller.rb
render jsonapi: @course,
include: [
:course_locales, :course_schedules, :competency,
:quality_badges, :competency_badges
]
# serializable_course.rb
attributes :name, ....
...
has_many :quality_badges
It'll throw undefined method new' for nil:NilClass because there is no QualityBadge model class.
I need to add an alias method in the Model and use it in the serializable class in order to make it work. ( so: quality_badge -> character_quality_badge)
# course.rb
class Course < ApplicationRecord
...
has_many :course_quality_badges
has_many :quality_badges, class_name: 'CharacterQualityBadge',
foreign_key: :character_quality_badge_id,
through: :course_quality_badges,
dependent: :destroy
# This does not look so good to me.
def character_quality_badges
quality_badges
end
...
end
# course_controller.rb
render jsonapi: @course,
include: [
:course_locales, :course_schedules, :competency,
:character_quality_badges, :competency_badges
]
# serializable_course.rb
attributes :name, ....
...
has_many :character_quality_badges
It'd be great if I can specify the mapping of the class name inside linkage method or any other proper place like what you guys did for mapping resource with it serializer class.
render jsonapi: post, class: { Post: SerializableCustomPost }
Adding a custom name resolver seems to solve the problem but it'd still be nice if this could be config via render method as an extra attribute.
# initializer/jsonapi.rb
# Set a default serializable class mapping.
config.jsonapi_class = Hash.new { |h, k|
names = k.to_s.split('::')
klass = names.pop
h[k] = [*names, "Serializable#{klass}"].join('::').safe_constantize
}.tap { |h|
h[:CharacterQualityBadge] = SerializableQualityBadge
}
You can override it by:
render jsonapi: post, class: jsonapi_class.merge(CharacterQualityBadge: SerializableQualityBadge)