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.
1 Answer 1
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.