У Rails есть_многие принадлежит_к с внешним_ключом и именем класса

Я пытаюсь смоделировать систему Users и Messages. Message имеют addresser и addressee. User есть sent_message и received_messages.

Прямо сейчас тесты терпят неудачу, так как не могут найти addressee_id и addresser_id. Я хотел бы знать, правильно ли я смоделировал это и как мне создавать сообщения через пользователей.

Изменить: вывод из тестов

ActiveRecord::UnknownAttributeError:неизвестный атрибут: addressee_id

Появляется в операторе before в спецификации сообщения.

Модель пользователя

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" 

Модель сообщения

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

Миграция

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

схема

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

person chankonabe    schedule 22.07.2014    source источник
comment
Что значит не работают тесты? Что значит не может найти addressee_id и addresser_id? Не просто давайте таблицы, дайте остальную часть кода, ввод и вывод. PS FK не принадлежат User.   -  person philipxy    schedule 23.07.2014
comment
Я добавил вывод к вопросу. Что касается ввода, я не могу придумать, что еще можно включить. Я тоже подумал, что странно, что в User будут FK, но согласно spacevatican.org/2008/5/6/ это решение. @филипи   -  person chankonabe    schedule 23.07.2014
comment
Добавленная информация помогает. Например, объявления таблиц, которым он должен соответствовать. (См. ответ.) Также: если он скомпилирован и запущен, введите и выведите данные. Вы не объяснили сбой и не можете найти или дать сообщение об ошибке, поэтому мы не знали, что было сделано для чего, когда это не удалось. (Где-то между компиляцией и запуском.) Включите все, относящееся к минимальному примеру. Как задать хороший вопрос?.   -  person philipxy    schedule 24.07.2014
comment
Понял, спасибо за подсказку.   -  person chankonabe    schedule 24.07.2014


Ответы (2)


Попробуйте заменить это:

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

С этим:

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

Также убедитесь, что миграции выполняются в тестовой среде.

Изменить: ActiveRecord::UnknownAttributeError означает, что столбец отсутствует в базе данных. Миграция выглядит нормально, но схема и вывод Message.column_names — нет.

Кажется, что ваш addressee_id/addresser_id на самом деле назван адресатом/addresser в базе данных. Вы редактировали файл миграции после запуска db: migrate?

Попробуйте запустить rake db:migrate:redo STEP=1 (если это была не последняя миграция, измените шаг)

person NorOddSto    schedule 22.07.2014
comment
Спасибо за предложение, к сожалению, это просто изменение ошибки на другую: NoMethodError: неопределенный метод 'addresser =' для nil: NilClass - person chankonabe; 24.07.2014
comment
Вы также должны изменить оба вхождения before { @message.addresser = nil } на before { message.addresser = nil } Все ли тесты не пройдены? Работает ли модель в консоли? - person NorOddSto; 24.07.2014
comment
Точно, совсем забыл эту часть. Я изменил его, но теперь он вернулся к тому же старому ActiveRecord::UnknownAttributeError:unknown attribute: addressee_id. Я пробовал создавать сообщения в консоли. Интересно, что Message.create выдает мне NoMethodError: undefined method 'addresser_id' - person chankonabe; 24.07.2014
comment
Вы выполняли миграции? rake db:migrate - person NorOddSto; 24.07.2014
comment
Да, я запустил db:migrate и test:prepare. - person chankonabe; 24.07.2014
comment
Попробуйте изменить проверки на validates_presence_of :addresser_id и validates_presence_of :addressee_id. - person dav1dhunt; 24.07.2014
comment
Что выводит, когда вы запускаете Message.column_names в консоли? - person NorOddSto; 24.07.2014
comment
2.0.0-p481 :001 > Message.column_names => ["id", "content", "addresser", "addressee", "created_at", "updated_at"] похоже, addressee_id и addresser_id не создаются? - person chankonabe; 24.07.2014
comment
ActiveRecord::UnknownAttributeError означает, что в столбце базы данных чего-то не хватает. Миграция выглядит нормально, но схема и вывод Message.column_names — нет. Кажется, что ваш addressee_id/addresser_id на самом деле назван адресатом/addresser в базе данных. Вы редактировали файл миграции после запуска db: migrate? Попробуйте запустить rake db:migrate:redo STEP=1 (если это была не последняя миграция, измените шаг) - person NorOddSto; 24.07.2014
comment
Я переделал миграцию, и Message.column_names отображает 2.0.0-p481 :001 > Message.column_names => ["id", "content", "addresser_id", "addressee_id", "created_at", "updated_at"] Однако те же ошибки, что и раньше, все еще появляются, хотя я могу правильно создавать сообщения в консоли. Я буду продолжать возиться. Спасибо! - person chankonabe; 24.07.2014
comment
Вероятно, вам также потребуется выполнить rake db:test:prepare для обновления тестовой базы данных. - person NorOddSto; 24.07.2014

Я предпочитаю делать это так

class User < ActiveRecord::Base
  has_many :sent_messages, class_name: "Message", as: :addressor
  has_many :received_messages, class_name: "Message", as: :addressee

а также

class Message < ActiveRecord::Base
  belongs_to :addressor, class_name: "User", foreign_key: :addressor_id
  belongs_to :addressee, class_name: "User", foreign_key: :addressee_id
person dav1dhunt    schedule 22.07.2014
comment
Хм, попробовал это, но он не распознает класс. Неизвестный ключ: класс (ArgumentError) - person chankonabe; 24.07.2014
comment
Извините, я отредактировал свой ответ, он должен был быть class_name, а не class. - person dav1dhunt; 24.07.2014
comment
Кроме того, чтобы заставить его работать, вы можете просто дать пользователю много сообщений, а затем использовать области или методы для извлечения сообщений, где их идентификатор является либо адресантом, либо адресатом. - person dav1dhunt; 24.07.2014
comment
Больше нет ArgumentError, но он вернулся к исходному ActiveRecord::UnknownAttributeError:unknown attribute: addressee_id - person chankonabe; 24.07.2014
comment
это хорошая идея, я думаю, я мог бы просто пойти дальше и сделать это. Эти ассоциации слишком болезненны, чтобы с ними справляться. - person chankonabe; 24.07.2014