You can still create relationships on keys that are not called id
(although I wouldn't recommend it. I would recommend using id
, at some point someone will want to change an abbreviation and it will not be easy. Joins on integers are also faster than joins on strings). I also suggest you name your join fields on DeviceVendor
as device_abbr
and vendor_abbr
so that you can add logical relationships called device
and vendor
without causing a conflict.
If you want to join on abbreviation you can do something like:
class Device < ApplicationRecord validates :abbr, uniqueness: { case_sensitive: false }, presence: true validates :name, presence: true has_many :device_vendors, foreign_key: :vendor_abbr, primary_key: :abbr # You can do something similar with has_and_belongs_to_many def abbr=(value) self[:abbr] = value.to_s.strip endendclass DeviceVendor < ApplicationRecord validates :device_abbr, presence:true validates :vendor_abbr, presence:true, uniqueness: {scope: :device_abbr} belongs_to :vendor, foreign_key: :vendor_abbr, primary_key: :abbr belongs_to :device, foreign_key: :device_abbr, primary_key: :abbrend# controller codedef index @device_vendors = DeviceVendor.order(:device, :vendor).include(:device, :vendor) # You could also simplify the above with a `scope` on DeviceVendorend# view code<% @device_vendors.each do |device_vendor| %><tr><td><%= device_vendor.device.name if device_vendor.device %></td><td><%= device_vendor.vendor.name if device_vendor.vendor %></td><td><%= link_to 'Show', device_vendor %></td><td><%= link_to 'Edit', edit_device_vendor_path(device_vendor) %></td></tr><% end %>