Использование attr_accessible в модели соединения с отношением has_many: through - PullRequest
2 голосов
/ 22 июня 2011

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

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

Довольно простой. Но в том-то и дело, что у ресурса EMPLOYEE есть другие атрибуты, кроме его внешних ключей, например, логическое значение :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.

Ответы [ 2 ]

2 голосов
/ 29 марта 2012

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

Вы определенно хотите использовать attr_accessible на всех моделях. (Google "взломайте массовое назначение рельсов" и прочитайте Руководство по рельсам массового назначения .)

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

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

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

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

Мне не понятно из вашего примера, как работает сотрудник. Но поскольку Сотрудник принадлежит как Пользователю, так и Компании, я думаю, что-то подобное может сработать, предполагая, что @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 голосов
/ 22 июня 2011

Company_id равен nil просто потому, что Company еще не была сохранена в базе данных - Company.new просто создает объект в памяти, не сохраняя его пока.*

или

@user.companies << Company.first

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

@user.companies.create(..)

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

@user.companies.build(..) 

(что аналогично коду в вашем примере).

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

...