0

I have a Rails API that communicates with an Ember app. I need to be able to serialize a model that has two primary keys instead of the default id.

This is what it looks like right now:

Models

# This is the problem model:
class Value < ActiveRecord::Base
  self.primary_keys = :foreign_id, :type_id
  belongs_to :type, foreign_key: :type_id
end

class Type < ActiveRecord::Base
  has_many :codes, foreign_key: :code_type_id
  has_many :values, foreign_key: :type_id
end

class Code < ActiveRecord::Base
  belongs_to :type, foreign_key: :code_type_id
end

class Activity < ActiveRecord::Base
  has_many :values, -> (object){ where("type_subject_area = ?", "Activity") }, foreign_key: :foreign_id
end

Schema

create_table "values", id: false, force: :cascade do |t|
  t.integer  "foreign_id"
  t.string   "type_subject_area"
  t.integer  "code_id"
  t.integer  "type_id"
  t.string   "type_title"
  t.text     "text"
  t.datetime "created_at"
  t.datetime "updated_at"
end

add_index "values", ["foreign_id", "type_id"], name: "index_values_on_foreign_id_and_type_id", unique: true, using: :btree

create_table "types", force: :cascade do |t|
  t.integer  "id"
  t.string   "title"
  t.string   "subject_area"
  t.datetime "created_at"
  t.datetime "updated_at"
end

add_index "types", ["id"], name: "index_types_on_id", unique: true, using: :btree

create_table "activities", force: :cascade do |t|
  t.integer  "id"
  t.datetime "created_at"
  t.string   "name"
end

add_index "activities", ["activity_type"], name: "index_activities_on_activity_type", using: :btree
add_index "activities", ["id"], name: "index_activities_on_id", unique: true, using: :btree

create_table "codes", force: :cascade do |t|
  t.integer  "id"
  t.string   "description"
  t.string   "code_value"
  t.integer  "code_type_id"
  t.datetime "created_at"
  t.datetime "updated_at"
end

add_index "codes", ["id"], name: "index_codes_on_id", unique: true, using: :btree

Serializers

class ActivitySerializer < ActiveModel::Serializer
  attributes  :id, :name
  has_many :values
end

class UDFValuesSerializer < ActiveModel::Serializer
  attributes :foreign_id, :type_subject_area, :type_id, :text, :type_title
end

As you can see, a type has many values and codes. An activity has many values, though it's only related to the values that have a subject area of "Activity". Since values don't have an individual primary key, I'm not sure how to format it in such a way that works in Ember. From what I understand, Ember needs to have an id available in order to receive the values.

Thoughts? Ideas? I'm afraid this needs to be in this format because the Rails API is communicating and syncing with another, larger API.

NJP
  • 815
  • 1
  • 7
  • 20

1 Answers1

0

You can only have one primary key on a table. You can create a composite primary key, but since ActiveRecord doesn't support this, you'll need to find a way to do this. There's a composite_primary_keys gem that claims to add this support, but I haven't used it.

However, I don't think that's what you want to do here. If foreign_id is supposed to reference an ID in an API, then it would be a foreign key not a primary key because it refers to a primary key on another table. If you want to ensure the uniqueness of foreign_id at the SQL level (in addition to using validates_uniqueness_of), you add an index in a migration like so:

add_index :values, :foreign_id, unique: true

If the API uses both foreign_id and type_id in a composite primary key, perhaps you want to index both as unique:

add_index :values, [:foreign_id, :type_id], unique: true

Again, you would want to add a validation at the Rails level as well:

validates_uniqueness_of :foreign_id, scope: :type_id

This would ensure that all foreign_id, type_id pairs on your table are unique.

Community
  • 1
  • 1
eirikir
  • 3,802
  • 3
  • 21
  • 39