#ruby-on-rails #ruby #rspec
#ruby-on-rails #ruby #rspec
Вопрос:
Я создал приложение на основе курса Hartl — вплоть до раздела 9.2 (аутентификация) включительно. Оттуда я попытался расширить функциональность, добавив организационную модель. Сначала я попытался использовать функцию командной строки scaffold generate, решил, что она слишком много построила, откатила ее, а затем построила вручную. Я считаю, что в этом беспорядке я, возможно, испортил свои миграции (см. Ниже). Я использую Rails версии 4.1.1, Rspec 3.0.0 и Capybara 2.2.0 — все базы данных являются postgres.
В организации может быть много пользователей, тогда как каждый пользователь принадлежит только одной организации.
Я должен отметить, что, используя среду разработки на моем собственном компьютере, у меня есть поле для организации, работающее корректно во время регистрации пользователя — оно создает нового пользователя, я могу правильно просматривать страницы организации и пользователя, и в производительности приложения нет ошибок. Мои проблемы начинаются, когда я тестирую с использованием тестов Rspec — выдает ряд ошибок, подобных этому:
ActiveModel::MissingAttributeError:
can't write unknown attribute 'organization_id'
Мои модели:
class Organization < ActiveRecord::Base
validates :organization_name, presence: true, length: { maximum: 50 }
has_many :users
end
class User < ActiveRecord::Base
belongs_to :organization
accepts_nested_attributes_for :organization
before_save { self.email = email.downcase }
before_create :create_remember_token, :create_organization
validates :name, presence: true, length: {maximum: 50}
VALID_EMAIL_REGEX = /A[w -.] @[a-zd-] (?:.[a-zd-] )*.[a-z] z/i
validates :email, presence: true, format: {with: VALID_EMAIL_REGEX}, uniqueness: {case_sensitive: false}
has_secure_password
validates :password, length: {minimum: 6}
def create_organization
self.organization = Organization.create(:organization_name => Organization.organization_name) unless self.organization.present?
end
Мои фабрики:
FactoryGirl.define do
factory :organization do
organization_name "Orgname"
end
factory :user do
association :organization
name "A Name"
email "name@example.com"
password "foobar"
password_confirmation "foobar"
end
end
Пример набора тестов Rspec:
describe "edit" do
let(:organization) { FactoryGirl.create(:organization) }
let(:login) { FactoryGirl.create(:login,
:organization => organization,
:user => FactoryGirl.create(:user)) }
before do
sign_in login
visit edit_user_path (user)
end
Мой файл schema.rb:
ActiveRecord::Schema.define(version: 20140619041326) do
create_table "organizations", force: true do |t|
t.datetime "created_at"
t.datetime "updated_at"
t.string "organization_name"
end
create_table "users", force: true do |t|
t.string "name"
t.string "email"
t.datetime "created_at"
t.datetime "updated_at"
t.string "password_digest"
t.integer "organization_id"
t.string "remember_token"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
add_index "users", ["organization_id"], name: "index_users_on_organization_id", using: :btree
add_index "users", ["remember_token"], name: "index_users_on_remember_token", using: :btree
end
Здесь, возможно, стоит отметить, что, когда я впервые начал запускать тесты, я использовал версию Rspec, рекомендованную в книге Хартла, что означает, что мне пришлось принудительно вносить изменения из базы данных разработки в тестовую базу данных с помощью функции командной строки bin / rake dg:migrate RAILS_ENV=test . Каждый раз, когда я запускал это, мой файл schema.rb (как указано выше) терял строку
t.integer "organization_id"
и мне пришлось бы разгребать базу данных, чтобы она снова заработала.
Я понимаю, что здесь много информации, и что мои вопросы, вероятно, довольно глупые (я новичок в языке и фреймворке, и это мое первое приложение), но это сводит меня с ума. Я провел прошлую неделю, пытаясь выяснить, почему тесты прерываются, когда само приложение работает.
Любая помощь будет высоко оценена.
Комментарии:
1. Я обнаружил проблему — по-видимому, Rails 4 не обновляет схему автоматически с помощью
ActiveRecord::Migration.maintain_test_schema!
spec_helper — вместо этого вам все равно нужно использовать «rake db: test: prepare». Однако, хотя это избавило меня от некоторых ошибок, я по-прежнему получаю 3 основные ошибки: 1.) Ему не нравится мой заводской «логин» (я копировал другой код, который, казалось, предполагал, что это сработает) 2.) На пользовательских страницах rspec тесты не могут найти поле «Имя организации» 3.) В нем говорится, что метод «organization_name» не определен для функции «create_organization», указанной выше, какие-либо идеи?
Ответ №1:
Я думаю, что нет фабрики для :login
… и я думаю, что метод sign_in хочет передать пользовательский объект.
Поэтому измените свое let(:login)
утверждение на…
let(:login) { FactoryGirl.create(:user, :organization => organization) }
Комментарии:
1. Спасибо. На самом деле я решил это, добавив признак в фабрику пользователей и передав как нового пользователя, так и признак. Будет ли ваш метод лучше или я должен просто оставить свой код как есть?
Ответ №2:
Ваш before_create
метод create_organization
в следующей строке…
self.organization = Organization.create(:organization_name => Organization.organization_name) unless self.organization.present?
При этом вы ссылаетесь на метод класса (не объекта) Organization.organization_name
, а такого метода класса не существует.
Вы могли бы создать его в Organization
модели … это может быть какое-то значение по умолчанию…
def self.organization_name
"Default Organization Name"
end
Комментарии:
1. Спасибо. Мое намерение с этим кодом create_organization состояло в том, чтобы гарантировать, что любой, кто подписывается на учетную запись, в которой существует существующая организация, будет принадлежать этой организации (а не дублировать ее). Будет ли установка значения по умолчанию иметь какие-либо негативные последствия? Или есть лучший способ достичь моей цели без этого кода create_organization?
2. Как бы то ни было, если организация уже была назначена пользователю перед вызовом create , она будет вести себя так, как ожидалось. Вы хотите сказать, что если организация не была назначена, но в таблице организаций уже есть хотя бы одна организация, вы хотите использовать любую первую запись в таблице организаций?
3. Нет, я просто был обеспокоен тем, что это позволит людям регистрироваться без указания названия организации, а затем застрять как часть группы, используя вместо этого «Имя организации по умолчанию». На данный момент это не окажет никакого влияния, но в конечном итоге я хочу, чтобы первый пользователь, зарегистрировавшийся в любой организации, был администратором и мог запускать отчеты по всей базе пользователей. Если люди, которые опускают название организации, все еще могут зарегистрироваться, это создаст проблему.
4. Хорошо, код
Organization.organization_name
неправильный, поскольку такого метода класса нет. Похоже, что в рамках процесса регистрации пользователь может ввести название организации? И вы хотите использовать это для создания записи организации?5. Да, это правильно. (Совершенно новый) пользователь, заходящий на сайт, регистрирует как свое имя пользователя, так и название организации, к которой он будет принадлежать. Последующие пользователи, пытающиеся зарегистрироваться в той же организации, будут отправлены в очередь для утверждения первым пользователем (первым пользователем в конечном итоге будет администратор). Смысл этого кода состоял в том, чтобы попытаться предотвратить появление нескольких организаций с одинаковым именем.