Подтвердить что ты не робот

Rails: обновить атрибут модели без вызова обратных вызовов

У меня есть модель 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:

Хорошо, это была проблема проверки, из-за которой изменения в "EDIT" не работали, но я все равно люблю отвечать на исходный вопрос об обновлении без обратных вызовов!

4b9b3361

Ответ 2

Чтобы обновить несколько атрибутов без обратных вызовов, вы можете использовать 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

Ответ 3

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

@user.update_column 'credits', 5

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

@user.update_columns credits: 5, bankrupt: false  

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

Ответ 4

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

def add
  User.update_counters params[:id], :credits => 5
  redirect_to root_path
end

Ответ 5

Вы можете использовать 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

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

Ответ 7

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

person.set(name:"Robert Pulson")

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

Ответ 8

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

Ответ 9

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

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

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

Ответ 10

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

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