Вы можете использовать транзакцию в контроллере, если хотите. Как вы отметили, это плохая практика, но если вы хотите это сделать, просто позвоните Product.transaction do
вместо transaction do
. transaction
- метод класса на ActiveRecord::Base
, поэтому вам нужно вызвать его в классе, основанном на ActiveRecord. Любой класс модели в вашем приложении будет делать (nit-picking caveat: если вы подключаетесь к различным базам данных для разных моделей, это может быть неверно ... но вы, вероятно, этого не делаете).
Причина, по которой это плохая практика, заключается в том, что она не разделяет озабоченность в соответствии с парадигмой MVC. Ваш контроллер не должен быть так озабочен реализацией ваших данных. Лучшим подходом было бы добавить метод к Product
. Может быть, что-то вроде этого:
def save_and_update_create_time
transaction do
if save
client.update_attribute(:product_create, Time.now)
end
end
end
Тогда вместо вызова product.save
в контроллере, вызовите product.save_and_update_client_create_time
. Возможно, вам придется пройти client
; это неясно из вашего кода, откуда приходит client
. Если это атрибут на product
, то метод выше должен работать.
Есть более, более Railsy способы сделать это, особенно если product
знает о его client
без каких-либо данных контроллера. Тогда вы можете просто использовать after_save
обратный вызов, как это (добавить в Product
класс):
after_save :update_client
private
def update_client(product)
product.client.update_attribute(:product_create, Time.now)
end
Тогда каждый раз, когда Product
сохраняется, поле на соответствующем клиенте будет обновляться. Возможно, вам придется ввести код для проверки наличия client
.
Преимущество использования обратных вызовов, помимо чистого кода, заключается в том, что вся цепочка обратного вызова работает в одной транзакции вместе с сохранением; вам не нужно создавать транзакцию вручную. Вы можете узнать больше о обратных вызовах в Rails documentation.
Большое спасибо Джим, вы действительно поможете мне с вашим объяснением! – user1364684
Если транзакционная логика помещается в Модель, не будут ли транзакции не ограничиваться одной моделью, чтобы не нарушать отдельные правила? Обычно существует высокая вероятность того, что транзакции охватывают несколько моделей, которые не обязательно связаны друг с другом на уровне БД. – xSNRG
Да, у меня была смущение в этом аспекте моего комментария. Мне нравится идея держать его вне контроллера, но многомодельные взаимодействия должны быть где-то обернуты.Возможно, еще один класс, но в некоторых ситуациях контроллер, возможно, будет правильным местом. –