jsonapi-rb / jsonapi-rails

Rails gem for fast jsonapi-compliant APIs.
http://jsonapi-rb.org
MIT License
319 stars 63 forks source link

Custom class name for relation that's not using Rails convention #95

Closed vtno closed 5 years ago

vtno commented 6 years ago

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 }

vtno commented 5 years ago

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
  }
beauby commented 5 years ago

You can override it by:

render jsonapi: post, class: jsonapi_class.merge(CharacterQualityBadge: SerializableQualityBadge)