2011-06-22 1 views
2

У меня есть ПОЛЬЗОВАТЕЛЬ, который создает КОМПАНИЮ и становится СОТРУДНИКОМ в этом процессе. Таблица сотрудников имеет :user_id и :company_id.Использование attr_accessible в модели соединения с has_many: через отношения

class User 
has_many :employees 
has_many :companies, :through => :employees 

class Employee 
belongs_to :user 
belongs_to :company 
attr_accessible :active 

class Company 
has_many :employees 
has_many :users, :through => employees 

Pretty basic. Но вот что, ресурс EMPLOYEE имеет другие атрибуты, чем его внешние ключи, такие как boolean :active. Я хотел бы использовать attr_accessible, но это вызывает некоторые проблемы. Атрибут :user_id установлен вправо, но :company_id - это нуль.

@user.companies << Company.new(...) 
Employee id:1 user_id:1 company_id:nil 

Так что мой вопрос: если :user_id установлен правильно, несмотря на это не attr_accessible, почему :company_id не установлен прямо так же? Это не должно быть attr_accessible.

Я использую Rails 3.0.8, а также протестировал его с помощью 3.0.7.

ответ

0

Компания_ид отсутствует, потому что компания еще не была сохранена в базе данных. Компания.new просто создает объект в памяти, не сохраняя его.

Если вы:

@user.companies << Company.create(..) 

или

@user.companies << Company.first 

Они должны оба работают. Там даже более короткий метод, который я думаю, должен работать тоже:

@user.companies.create(..) 

Все зависит в какой момент вы хотите сохранить ассоциацию. В некоторых случаях, возможно, лучше не сохранять модели сотрудников и компаний сразу, а вместо этого ждать, когда будет сохранена родительская модель (Пользователь). В этом случае вы можете использовать:

@user.companies.build(..) 

(что похоже на код в вашем примере).

С точки зрения вашего active атрибута boolean на модели Employee, если это столбец в базе данных, вам не нужно явно объявлять attr_accessible для него - он будет доступен по умолчанию.

+0

Frankie, спасибо, что нашли время, чтобы помочь мне. Я использовал: @ user.companies.create() и ошибка была такой же. Экземпляр компании сохраняется в базе данных, но когда дело касается сотрудника, ActiveRecord жалуется, что компания не должна быть пустой. Я не пробовал, что бы вы ни делали: @ user.companies << Компания.create() В модели Employee я могу использовать валидации на company_id, например, наличие. Но мне было совершенно ясно, что это должно быть приемлемым. Когда я использую его на company_id, работают как create, так и << (с Company.new). Оба не работают, когда я этого не делаю. –

+0

Я также попробовал @ user.companies << Company.create(), а: company_id не attr_accessible. Ошибка такая же. Компания не может быть пустым, поэтому компания-экземпляр сохраняется, но не сотрудник. Когда: company_id настроен на доступ, три способа работы: create, << Company.new и << Company.create. –

+0

Привет. Во-первых, вам не нужно объявлять какие-либо атрибуты как attr_accessible - все они доступны по умолчанию. –

2

Здесь много бит, работающих вместе.

Вы определенно хотите использовать attr_accessible для всех моделей. (Google «хак рельсы массового присвоения» и читать Rails Guide on mass assignment.)

После добавления attr_accessible к модели, всех задания из хэш (массовых заданий) отключены, за исключением тех, кого вы явно разрешить. Тем не менее, вы все равно можете назначать значения напрямую, по одному за раз.

Внешние ключи кажутся хорошими, чтобы исключить из массового назначения, поэтому не указывайте их в attr_accessible.

Способы .create и .build не используют массовое присвоение, поэтому они могут установить значение ассоциация внешних ключей. Если есть несколько ассоциаций, насколько я могу судить, вам придется устанавливать все, кроме первого отдельно.

И, наконец, фактические идентификаторы для внешних ключей создаются базой данных, а не ActiveRecord. Таким образом, вам нужно будет одновременно создавать родительские и дочерние записи, иначе вам придется сначала сохранить дочерний элемент, прежде чем вы сможете назначить внешний ключ в родительском элементе. В противном случае идентификатор недоступен для назначения.

Мне непонятно, из вашего примера, как создается экземпляр Employee. Но поскольку Employee принадлежит как пользователю, так и компании, я думаю, что что-то вроде этого может работать, если @user уже существует:

company = @user.companies.create(..) # fills in company.user_id and saves to DB 
employee = @user.employees.build(..) # fills in employee.user_id but does NOT save yet 
employee.company = company   # fills in employee.company_id 
employee.save       # now save to DB 
+0

как проверить что-то подобное в RSpec? рассмотрите 'User' с' has_many: role' и 'has_many: accounts, через:: role'. Скажем, вы отключили 'attr_accessible' на' role.user_id' и 'role.account_id' и' role.role'. Я не могу представить, как вы будете тестировать Rspec для роли. Как вы создадите роль и присоедините ее к учетной записи и пользователю? – Mohamad

+0

Mohamad, это зависит от того, что вы хотите проверить. Если вы хотите подтвердить, что роль не может быть назначена массой, вы можете использовать модельный тест, например, пример Майкла Хартла (http://ruby.railstutorial.org/book/ruby-on-rails-tutorial#code:attr_accessible_user_id_test) (требуется Rails 3.2) и/или тест интеграции, такой как тот, который я предлагаю [здесь] (http://stackoverflow.com/questions/10262993/rails-integration-test-against-page-modification-hack/10342951#10342951). Чтобы «создать роль и прикрепить ее к учетной записи и пользователю», вы будете использовать стандартные тесты ActiveRecord в тесте или, что более вероятно, FactoryGirl. –