Ошибка для отношения один-к-одному: ActiveModel :: MissingAttributeError: невозможно записать неизвестный атрибут - PullRequest
2 голосов
/ 16 марта 2012

Я разрабатываю тестовое приложение для изучения Rails. Во время игры с ассоциациями я получаю ActiveModel::MissingAttributeError: can't write unknown attribute 'linked_section_id' ошибку.

Позвольте мне сначала объяснить требования. Пользователь выбирает раздел книги для просмотра. В конце каждого раздела будет несколько вопросов, связанных с другими разделами. Если пользователь нажимает на ссылку с любым вопросом, он будет перенаправлен в соответствующий раздел.

Таким образом, отношение сущностей такое, как описано ниже:

  • В разделе может быть несколько вопросов (один ко многим)
  • Вопрос относится только к одному разделу (многие к одному - обратная сторона одного ко многим)
  • Вопрос может быть связан с другим разделом (один к одному)

Окружающая среда: Руби 1.9.3, Rails 3.2.2 со всеми необходимыми драгоценными камнями

вот классы моделей:

class Section < ActiveRecord::Base

  # Associations
  has_many :questions

end

class Question < ActiveRecord::Base
  belongs_to  :section, :foreign_key => :section_id
  has_one :linked_section, :class_name => "Section", :foreign_key => "linked_section_id"
end

db/schema.rb
.
.
create_table "sections", :force => true do |t|
    t.string   "name"
    t.string   "content"
    t.datetime "created_at", :null => false
    t.datetime "updated_at", :null => false
  end
create_table "questions", :force => true do |t|
    t.string   "description"
    t.integer  "section_id"
    t.integer  "linked_section_id"
    t.datetime "created_at",        :null => false
    t.datetime "updated_at",        :null => false
  end
.
.

Вот спецификации.

question_spec.rb
require 'spec_helper'

describe Question do
  before do
      @question = Question.new(description:'Test')
    end

        subject { @question }

        # Check for attribute accessor methods
        it { should respond_to(:description) }
        it { should respond_to(:section) }
        it { should respond_to(:linked_section) }
        it { should respond_to(:linked_section_id) }
end

section_spec.rb
require 'spec_helper'

describe Section do
    before do
      @section = Section.new(name:'Test')
    end

        subject { @section }

        # Check for attribute accessor methods
        it { should respond_to(:name) }
        it { should respond_to(:questions) }

        # Sanity check, verifying that the @section object is initially valid
        it { should be_valid }

    describe "Question should have one action item while persisted" do
            pending "This is broken after changing entity relationship"
      before {
        @section = Section.new(name: 'Section 2')

        linked_section = Section.new(name: 'Action Section')
        linked_section.save

        question = Question.new(description: 'What next?')
        question.linked_section = linked_section
        @section.questions << question
        @section.save
        .
                .
        .

      }
      .
            .
            .
    end

end

Теперь question_spec.rb проходит без ошибок, но получает ActiveModel::MissingAttributeError: can't write unknown attribute 'linked_section_id' ошибку в строке question.linked_section = linked_section.

но если вы заметили, следующие примеры question_spec.rb

it { should respond_to(:linked_section) }
it { should respond_to(:linked_section_id) }

проходит без ошибок. Это означает, что у Вопроса есть 'connected_section_id'. Так почему же rspec паникует?

У меня есть сомнения относительно отношения, определенного для связи вопроса с другим разделом. Кто-нибудь может подсказать, пожалуйста, как правильно проектировать модели?

Спасибо, Амит Патель

1 Ответ

1 голос
/ 16 марта 2012

Ваши спецификации проверяют, отвечает или нет вопрос на: connected_section_id (метод чтения), а не отвечает или нет на него: connected_section_id = (метод записи). Все поля в таблице будут иметь методы чтения, связанные с ними, и, поскольку вы добавили в таблицу поле connected_section_id, метод чтения есть.

Всякий раз, когда вы добавляете внешние ключи в таблицу, она должна быть * принадлежащей к * стороне ассоциации. Здесь вы использовали has_one. Переключите это на assign_to, и в модели Section укажите

has_one :linked_section, :class_name => 'Question'

Надеюсь, это поможет,

...