Как связать родительскую модель с глубоко вложенной при создании / обновлении

#ruby-on-rails #ruby #activerecord

#ruby-on-rails #ruby #activerecord

Вопрос:

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

Рассмотрим эти модели

 class Group < ApplicationRecord
  belongs_to :owner, class_name: 'User'
  has_many :profiles
  has_many :users, through: :profiles

  validates :name, :owner, presence: true

  accepts_nested_attributes_for :owner
end
 
 class User < ApplicationRecord
  has_many :profiles
  has_many :groups, through: :profiles
  has_many :owned_groups, class_name: 'Group', foreign_key: :owner_id, optional: true

  validates :name, presence: true

  accepts_nested_attributes_for :profiles
end
 
 class Profile < ApplicationRecord
  belongs_to :user
  belongs_to :group

  enum role: [:admin, :moderator, :user]

  validates :user, :group, :role, presence: true
end
 

Есть ли какой-либо способ shape или form, где я могу иметь глубоко вложенную форму для создания всего этого, чтобы могло произойти следующее? Или действительно будет необходимо вручную создать профиль после создания группы / администратора?

 deeply_nested_params = params.require(:group).permit(
  :name,
  owner_attributes: [
    :id, # nil on create
    :name,
    profiles_attributes: [
      :id, # nil on create
      :role
    ]
  ]
)
group = Group.new(deeply_nested_params) #=> #<Group>
group.owner.profiles.first.group == group #=> true
# last but not least
group.valid? #=> true
 

Я спрашиваю в основном из любопытства, а также потому, что я нашел бы это более «элегантным» способом по-настоящему создать group (в моем примере) в одной строке.

PS: проблема с текущим способом, которым я пытаюсь, заключается в том, что group.owner.profiles.first.group значение равно нулю, поэтому проверки завершаются неудачно

PS2: у меня есть 3 строки (если вместо них вы используете {} блоки) 1 сохранить решение (вроде), которое работает. Но опять же, мне интересно узнать о решении, в котором требуется это обходное решение.

 group = Group.new(deeply_nested_params) #=> #<Group>
group.owner.profiles.select do |profile| # select because nothing is saved yet so find won't work
  profile.id.nil? # new records only
end.each do |profile|
  profile.group = group
end
group.save!
 

Комментарии:

1. accepts_nested_attributes_for хорошо работает только для ассоциаций «один к одному» и «один ко многим», но ваша групповая пользовательская ассоциация — это «многие ко многим»

2. По логике вещей, вы не можете сохранить запись в таблице profiles, не зная идентификаторов пользователя и группы, поэтому перед созданием профиля необходимо сохранить как пользователя, так и группу.

3. Я хотел бы увидеть дизайн пользовательского интерфейса для создания пользователя, группы и профиля, все вместе, одновременно, за один шаг..

4. @DavidAldridge не обязательно, я добавил редактирование, которое показывает, что вы можете «технически» сделать это в одном save , но вам нужно манипулировать несохраненными моделями между new и save . Это, конечно, означает, что ее нельзя сократить до одного create! , например (что является своего рода целью вопроса)

5. Ваши модели и остальная часть вопроса не имеют смысла вместе. Нет объяснения, откуда взялся этот group.admin метод. Также нет объяснения того, каким должен быть желаемый результат.