Search code examples
ruby-on-railsforeign-keysrails-activerecordhas-manybelongs-to

Rails has_many belongs_to with foreign_key and class_name


I'm trying to model a system of Users and Messages. Messages have addressers and addressees. Users have sent_messages and received_messages.

Right now the tests are failing as it can't seem to find addressee_id and addresser_id. I'd like to know if I have modeled this correctly and how I should go about creating messages through users.

Edit: The output from the tests

ActiveRecord::UnknownAttributeError:unknown attribute: addressee_id

Pops up in the before statement in the message spec.

User Model

class User < ActiveRecord::Base
  has_many :sent_messages, class_name: "Message", foreign_key: "addresser_id"
  has_many :received_messages, class_name: "Message", foreign_key: "addressee_id" 

Message Model

class Message < ActiveRecord::Base
  validates :addresser_id, presence: true
  validates :addressee_id, presence: true
  belongs_to :addresser, class_name: "User", foreign_key: "addresser_id"
  belongs_to :addressee, class_name: "User", foreign_key: "addressee_id"
end

Migration

class CreateMessages < ActiveRecord::Migration
  def change
    create_table :messages do |t|
      t.string :content     
      t.integer :addresser_id
      t.integer :addressee_id
      t.timestamps
    end
  add_index :messages, [:addressee_id, :addresser_id, :created_at]
  end
end

schema

create_table "messages", force: true do |t|
    t.string   "content"
    t.integer  "addresser"
    t.integer  "addressee"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  add_index "messages", ["addressee", "addresser", "created_at"], name: "index_messages_on_addressee_and_addresser_and_created_at"

message_spec

require 'spec_helper'

describe Message do
  let(:user1) { FactoryGirl.create(:user) }
  let(:user2) { FactoryGirl.create(:user) }
  before { @message = user1.sent_messages.build(content: "Lorem ipsum", addressee_id: user2.id) }

  subject { @message }

  it { should respond_to(:content) }
  it { should respond_to(:addresser_id) }
  it { should respond_to(:addressee_id) }
  its(:addresser) { should eq user1 }

  it { should be_valid }

  describe "when addresser is not present" do
    before { @message.addresser = nil }
    it { should_not be_valid }
  end

  describe "when addressee is not present" do
    before { @message.addressee = nil }
    it { should_not be_valid }
  end
end

Solution

  • Try replacing this:

    describe Message do
      ...
      before { @message = user1.sent_messages.build(content: "Lorem ipsum", addressee_id: user2.id) }
      subject { @message }
      ...
    end
    

    With this:

    describe Message do
      ...
      let(:message){ user1.sent_messages.build(content: "Lorem ipsup", addressee_id: user2.id) }
      subject { message }
      ...
    end
    

    Also check that migrations are run in test environment.

    Edit: ActiveRecord::UnknownAttributeError means that a column is missing from the database. The migration seems ok, but schema and the output of Message.column_names does not.

    Seems your addressee_id / addresser_id is actually named addressee / addresser in the database. Did you edit migration file after running db:migrate?

    Try running rake db:migrate:redo STEP=1 (if this was not your last migration, change step)