В моем приложении для работы на Rails у меня есть модель Tasks. Задачи могут быть blocked_by друг друга. У каждой задачи есть Пользователь. Когда я выполняю taskA.blocked_by.create(name: "Task B"), я хочу, чтобы задача Б получила того же пользователя, что и задача А.
Проблема в том, что я не могу понять, как ссылаться на запись, создающую текущую запись. Мне нужно научиться получать taskA.user, чтобы я мог автоматически назначать его taskB. Я бы предпочел не делать это вручную каждый раз, когда я создаю задачу block_by.
Я пытался установить self.user в методе before_validation.
before_validation :inherit_user, on: :create
private
def inherit_user
if self.user == nil
p "Task #{self.name} missing user"
if self.blocked_by.count > 0
self.user = self.blocked_by.first.user
p "Inheriting user from first blocked_by task #{self.blocked_by.first.name}"
end
end
end
Это не работает, потому что self.blocked_by пусто, потому что запись еще не сохранена.
Документация Rails по методам класса ассоциации заставляет меня поверить, что я должен сделать что-то вроде этого:
has_many :blocked_by do |owner|
def create(attributes)
p owner # access properties from association owner here
attributes.push(user: owner.user)
super
end
end
Когда я пробую это, я получаю:
NoMethodError (undefined method `owner' for #<ActiveRecord::Associations::CollectionProxy []>)
Редактировать: Вот мой файл модели:
class Task < ApplicationRecord
validates :name, :presence => true
belongs_to :user
has_many :children, class_name: "Task", foreign_key: "parent_id"
belongs_to :parent, class_name: "Task", optional: true
has_ancestry
# thanks to https://medium.com/@jbmilgrom/active-record-many-to-many-self-join-table-e0992c27c1e
has_many :blocked_blocks, foreign_key: :blocker_id, class_name: "BlockingTask"
has_many :blocked_by, through: :blocked_blocks, source: :blocking, dependent: :destroy
has_many :blocker_blocks, foreign_key: :blocked_id, class_name: "BlockingTask"
has_many :blocking, through: :blocker_blocks, source: :blocker, dependent: :destroy
has_many_attached :attachments
before_validation :inherit_user, on: :create
def completed_descendants
self.descendants.where(completed: true)
end
def attachment_count
self.attachments.count
end
private
def inherit_user
if self.user == nil and self.parent
self.user = self.parent.user
end
end
end
Я могу inherit_user из родительской задачи, вот так: taskA.children.create(name: "Task B"). Я хотел бы сделать то же самое для blocked_by отношений.





Чтобы обратиться к текущей записи, которая должна быть создана, попробуйте запустить обратный вызов before_create.
before_create :inherit_user
и self.blocked_by теперь должно иметь значение.
Мне нужно взглянуть на ваши проверки, а также как вы получаете значение block_by (если вы не запрашиваете его у пользователя, то оно должно быть пустым, и вам нужно определить его, прежде чем вы сможете использовать его внутри если заявление). Если это не так, покажите мне файл вашей модели и метод создания.
Я отредактировал свой файл модели в вопросе. Выяснение того, как определить значение block_by, — это именно то, что я пытаюсь сделать. У меня нет специального метода создания.
Чтобы получить имя пользователя задачи, вы можете использовать Task.includes(:user).first.user.name Он берет первую задачу в базе данных и включает пользователя, которому она принадлежит, и возвращает его имя, измените синтаксис в соответствии с задачей, которая вам нужна. Надеюсь, это то, что вы ищете.
Когда я меняю :inherit_user с before_validate на before_create, модель не проходит проверку, и обратный вызов вообще не выполняется.