Rails: обновление атрибута модели без вызова обратных вызовов - PullRequest
66 голосов
/ 28 декабря 2011

У меня есть модель User, которая имеет атрибут: credits. Мне нужна простая кнопка, которая добавит 5 к кредитам пользователя по маршруту, называемому «добавить», чтобы / users / 3 / add добавила 5 к кредитам пользователя id = 3.

def add
    @user = User.find(params[:id])
    @user.credits += 5
    redirect_to root_path
end

Это важная часть моего контроллера. Проблема в том, что я не хочу звонить @ user.save, потому что у меня есть обратный вызов before_save, который повторно шифрует пароль пользователя на основе текущего времени UTC. Я просто хочу добавить 5 к атрибуту и ​​избежать обратного вызова, я никогда не думал, что такая простая вещь может быть такой сложной.

EDIT:

Я изменил обратный вызов на: before_create, вот мой новый код контроллера (соответствующая часть):

  def add
    @user = User.find(params[:id])
    @user.add_credits(5)
    @user.save
    flash[:success] = "Credits added!"
    redirect_to root_path
  end

и вот мой код в модели:

 def add_credits(num)
    self.credits = num
 end

РЕДАКТИРОВАТЬ 2:

Хорошо, это была проблема проверки, из-за которой изменения в «РЕДАКТИРОВАНИИ» не работали, но я все равно хотел бы получить ответ на первоначальный вопрос обновления без обратных вызовов!

Ответы [ 10 ]

129 голосов
/ 29 декабря 2011

В Rails 3.1 введено update_column, что совпадает с update_attribute, но без запуска проверок или обратных вызовов:

http://apidock.com/rails/ActiveRecord/Persistence/update_column

7 голосов
/ 07 сентября 2012

Чтобы обновить несколько атрибутов без обратных вызовов, вы можете использовать update_all в вашей модели следующим образом:

self.class.update_all({name: value, name: value}, self.class.primary_key => id)

Если вы действительно хотите, вы можете даже попробовать метод update_columns и смешать его с вашим базовым классом активной записи.

Для обновления одного атрибута вы можете использовать update_column. Кроме того, есть некоторые конкретные методы, которые можно найти в направляющих рельсов http://guides.rubyonrails.org/active_record_callbacks.html#skipping-callbacks

4 голосов
/ 22 февраля 2017

Как общий ответ, в Rails 4 это простой способ обновить атрибуты без запуска обратных вызовов:

@user.update_column 'credits', 5

Если вам нужно обновить несколько атрибутов без обратных вызовов триггеров:

@user.update_columns credits: 5, bankrupt: false  

Есть и другие варианты здесь, в Руководстве по Rails , если хотите, но я нашел этот способ наиболее простым.

3 голосов
/ 28 декабря 2011

Я думаю, что вы должны использовать метод update_counters в этом случае. Используйте это в своем действии контроллера:

def add
  User.update_counters params[:id], :credits => 5
  redirect_to root_path
end
2 голосов
/ 19 июня 2015

Для mongoid я использовал http://mongoid.org/en/mongoid/docs/persistence.html В частности, вы можете использовать:

person.set(name:"Robert Pulson")

, и обратный вызов не будет выполнен.Так круто.

2 голосов
/ 10 декабря 2013

Несколько вариантов, как это сделать в rails4 http://edgeguides.rubyonrails.org/active_record_callbacks.html#skipping-callbacks

2 голосов
/ 28 декабря 2011

Вы должны иметь возможность использовать update_all , чтобы избежать инициирования обратных вызовов.

def add
 @user = User.find(params[:id])
 User.where(:id=>@user.id).update_all(:credits => @user.credits+5)
 redirect_to root_path
end

Я бы предпочел поместить эту логику в модель, но это должно сработать, чтобы решить вашу оригинальнуюпроблема, как указано в контроллере.

1 голос
/ 28 декабря 2011

У вас есть несколько вариантов, включая изменение используемого вами обратного вызова, например, after_create.

Вы можете обновить столбцы без запуска обратных вызовов, см. Пропуск обратных вызовов в руководстве по AR. Например, update_column не вызывает обратные вызовы. Предыдущая ссылка содержит список не запускающих функций.

Вы также можете использовать любую из форм Условный обратный вызов (или даже наблюдателя) для изменения пароля. См. ActiveModel :: Dirty , например, @user.password_changed?.

1 голос
/ 28 декабря 2011

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

0 голосов
/ 11 июля 2019

Вы можете обновить столбец, выполнив это

User.where (имя: 'lily') .update_all (возраст: '10')

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...