Rails: обновление атрибута модели без вызова обратных вызовов
у меня есть модель пользователя, которая имеет атрибут :credits. Я хочу простую кнопку, которая будет добавлять 5 в кредит пользователя, по пути, под названием "добавить" так, что /пользователи/3/Добавить добавить 5 к кредитов идентификатор пользователя = 3.
def add
@user = User.find(params[:id])
@user.credits += 5
redirect_to root_path
end
это соответствующая часть моего контроллера. Проблема в том, что я не хочу звонить @user.сохранить, потому что у меня есть обратный вызов 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
EDIT 2:
хорошо, это была проблема проверки, которая сделала изменения в "EDIT" не работают, но я все равно хотел бы получить ответ на исходный вопрос об обновлении без обратных вызовов!
9 ответов:
рельсы 3.1 введен
update_column
, что то же самое, чтоupdate_attribute
, но без запуска проверок или обратных вызовов:http://apidock.com/rails/ActiveRecord/Persistence/update_column
чтобы обновить несколько атрибутов без обратных вызовов, вы можете использовать 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
Я думаю, что вы должны использовать метод update_counters в этом случае. Используйте его так в действии контроллера:
def add User.update_counters params[:id], :credits => 5 redirect_to root_path end
как общий ответ, в Rails 4 это простой способ обновить атрибуты без запуска обратных вызовов:
@user.update_column 'credits', 5
Если вам нужно обновить несколько атрибутов, не вызывает обратные вызовы:
@user.update_columns credits: 5, bankrupt: false
есть и другие варианты здесь в направляющих рельсов если вы предпочитаете, но я нашел этот способ самый простой.
вы должны быть в состоянии использовать 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
Я бы предпочел поместить эту логику в модель, но это должно работать, чтобы решить вашу оригинальную проблему, как указано в контроллере.
несколько вариантов, как это сделать в rails4 http://edgeguides.rubyonrails.org/active_record_callbacks.html#skipping-callbacks
для mongoid, я в конечном итоге с помощью http://mongoid.org/en/mongoid/docs/persistence.html В частности, вы можете использовать:
person.set(name:"Robert Pulson")
и обратный вызов не будет выдан. Так круто.
возможно, ваш другой крючок before_save должен проверить, действительно ли пароль пользователя изменился, прежде чем шифровать его снова.
у вас есть несколько вариантов, в том числе изменение обратного вызова, которые вы используете, например,
after_create
.вы можете обновить столбцы без запуска обратных вызовов, см. Пропуск Вызовов в руководстве AR. Например,
update_column
не вызывает обратные вызовы. В предыдущей ссылке перечислены не вызывающие функции.вы также можете использовать любой из Условный Обратный Вызов формы (или даже наблюдатель)для изменения пароля. Видеть ActiveModel:: Dirty, например,
@user.password_changed?
.