4
\$\begingroup\$

I have a Character model that has a CharClass and ClassPerks child.

Currently I am duplicating my logic a lot by manually assigning data.

My Character index and create:

def index

    @campaign = Campaign.find_by_id(params[:campaign_id])
    @characters = @campaign.characters
    render json: {
        characters: @characters
    }
end

def create
    @campaign = Campaign.find_by_id(params[:campaign_id])
    @charClass = CharClass.find_by_id(params[:character_char_class_id])
    @character = @campaign.characters.new(character_params)
    @character.char_class_id = params[:character_char_class_id]

    if @character.save!
        render status: 201, json: {

            message: "Successfull added this character to the campaign!",
            character_name: @character.character_name + ' the ' + @charClass.class_name,
            character_class: @charClass.class_name,
            character_level: @character.character_level,
            character_experience: @character.character_experience,
            character_gold: @character.character_gold,
            character_perks: get_names(@character.character_perks),
            character_image: @character.character_image

        }
    else
        render status: 404, json: {
            message: "Something went wrong: Check line 24 of the Character Controller"
        }
    end
end

I am manually assigning character_class and character_image despite both of these ALWAYS being the same based on their character_class.

Inside of the character.rb I am doing this to assign them post-create:

    after_create :add_perks, :save_class

    def add_perks
        self.class_perks.each do |perk|
            self.character_perks.create(class_perk_id: perk.id)
        end
    end


    def save_class()
        case self.char_class_id
            when 1 # Mindthief
                self.character_image = "https://gloomhavenil.files.wordpress.com/2017/12/11849117_616974988445216_217288420_n.jpg?w=480"
                self.character_class = "Mindthief"
                self.save
            when 2 # Tinkerer
                self.character_image = "http://www.cephalofair.com/wp-content/uploads/2015/04/Quatryl-Tinkerer.jpg"
                self.character_class = "Tinkerer"
                self.save
            # when 'Sawbones'
            # else
        end
    end
end

It is working, but I am unsure how to do this better/appropriately. I removed useless fields but you'll see below I have the relations set up appropriately.

  create_table "char_classes", force: :cascade do |t|
    t.string "class_name"
    t.string "class_image"
    t.string "class_perks"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

 create_table "characters", force: :cascade do |t|
    t.string "character_class"
    t.string "character_image"
    t.integer "char_class_id"
    t.index ["campaign_id"], name: "index_characters_on_campaign_id"
    t.index ["char_class_id"], name: "index_characters_on_char_class_id"
  end

I can do Character.first.char_class.class_name and I will get the appropriate result; so I am back to assuming this method I'm following is very incorrect.

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

You need to use ActiveModelSerializers (AMS) to serialize your json responses based upon the instances of your class.

class CampaignsController < ApplicationController
  def index
    render json: { characters: campaign.characters }
  end

  def create
    @character = campaign.characters.new(character_params.merge(char_class_id: char_class.id))

    if @character.save!
        render json: @character, serializer: CharacterSerializer, status: 201 # This should automatically be formatted by AMS
    else
        not_found('Something went wrong: Check line 24 of the Character Controller')
    end
  end

  private

  def campaign
    @campaign ||= Campaign.find_by_id(params[:campaign_id])
  end

  def char_class
    @charClass ||= CharClass.find_by_id(params[:character_char_class_id])
  end
end

This is how you AMS class for Character class should look like

class CharacterSerializer < ActiveModel::Serializer
  attributes :message, :character_name, :character_class, :character_level, :character_experience, :character_gold, :character_perks, :character_image

  def message
    'Successfull added this character to the campaign!'
  end

  def character_name
    return object.character_name + ' the ' + character_class # check the associations
  end

  def character_class
    object.charClass.class_name
  end

  def character_perks
    # Unsure what this get names methods does so im leaving it for you to refactor
    get_names(object.character_perks),
  end

end

Also add this to your ApplicationController

class ApplicationController < ActionController::Base

  # Add this to your application controller

  def not_found(message = nil)
    render json: { message }, status: 404
  end

end

I'll update the refactored model class based upon your info soon. Hope this helps for now.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.