Использование attr_accessible в модели соединения с отношением has_many:through

У меня есть ПОЛЬЗОВАТЕЛЬ, который создает КОМПАНИЮ и становится СОТРУДНИКОМ в этом процессе. Стол сотрудников имеет :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 ответа

Здесь много работы вместе.

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

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

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

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

Наконец, фактические идентификаторы для внешних ключей создаются базой данных, а не 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

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

Если вы делаете:

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

или же

@user.companies << Company.first

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

@user.companies.create(..)

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

@user.companies.build(..) 

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

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

Другие вопросы по тегам