При создании записи скопируйте атрибут из связанной записи

В моем приложении для работы на 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 отношений.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
32
1

Ответы 1

Чтобы обратиться к текущей записи, которая должна быть создана, попробуйте запустить обратный вызов before_create.

 before_create :inherit_user

и self.blocked_by теперь должно иметь значение.

Когда я меняю :inherit_user с before_validate на before_create, модель не проходит проверку, и обратный вызов вообще не выполняется.

DawnPaladin 28.03.2019 14:24

Мне нужно взглянуть на ваши проверки, а также как вы получаете значение block_by (если вы не запрашиваете его у пользователя, то оно должно быть пустым, и вам нужно определить его, прежде чем вы сможете использовать его внутри если заявление). Если это не так, покажите мне файл вашей модели и метод создания.

Rishabh Aggarwal 31.03.2019 06:52

Я отредактировал свой файл модели в вопросе. Выяснение того, как определить значение block_by, — это именно то, что я пытаюсь сделать. У меня нет специального метода создания.

DawnPaladin 01.04.2019 18:52

Чтобы получить имя пользователя задачи, вы можете использовать Task.includes(:user).first.user.name Он берет первую задачу в базе данных и включает пользователя, которому она принадлежит, и возвращает его имя, измените синтаксис в соответствии с задачей, которая вам нужна. Надеюсь, это то, что вы ищете.

Rishabh Aggarwal 05.04.2019 15:39

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