ActiveRecord 콜백 실행을 방지하려면 어떻게 해야 합니까?
after_save 콜백이 있는 모델이 있습니다.보통은 괜찮지만, 개발 데이터를 만들 때와 같은 경우에는 콜백을 실행하지 않고 모델을 저장하고 싶습니다.그렇게 하는 간단한 방법이 있습니까?뭔가 비슷한...
Person#save( :run_callbacks => false )
또는
Person#save_without_callbacks
레일즈 문서를 찾아봤지만 아무것도 발견하지 못했습니다.하지만 제 경험상 레일즈 문서가 항상 모든 것을 말해주지는 않습니다.
갱신하다
다음과 같은 모델에서 콜백을 제거하는 방법을 설명하는 블로그 게시물을 찾았습니다.
Foo.after_save.clear
저는 그 방법이 어디에 기록되어 있는지 찾을 수 없었지만 효과가 있는 것 같습니다.
사용하다update_column
= (레일 > = v3.1) 또update_columns
(Rails > = 4.0): 콜백 및 유효성 검사를 건너뜁니다.방법들을 도, 또한이방사용면하을들,updated_at
업데이트되지 않았습니다.
#Rails >= v3.1 only
@person.update_column(:some_attribute, 'value')
#Rails >= v4.0 only
@person.update_columns(attributes)
http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-update_column
#2: 객체를 생성하는 동안에도 작동하는 콜백 건너뛰기
class Person < ActiveRecord::Base
attr_accessor :skip_some_callbacks
before_validation :do_something
after_validation :do_something_else
skip_callback :validation, :before, :do_something, if: :skip_some_callbacks
skip_callback :validation, :after, :do_something_else, if: :skip_some_callbacks
end
person = Person.new(person_params)
person.skip_some_callbacks = true
person.save
업데이트(2020)
레일즈는 항상 지원 및 옵션을 제공하므로 위의 코드는 다음과 같이 단순화할 수 있습니다.
class Person < ActiveRecord::Base
attr_accessor :skip_some_callbacks
before_validation :do_something, unless: :skip_some_callbacks
after_validation :do_something_else, unless: :skip_some_callbacks
end
person = Person.new(person_params)
person.skip_some_callbacks = true
person.save
이 솔루션은 레일 2 전용입니다.
저는 방금 이것을 조사했고 저는 해결책이 있다고 생각합니다.다음 두 가지 ActiveRecord 개인 방법을 사용할 수 있습니다.
update_without_callbacks
create_without_callbacks
이러한 메서드를 호출하려면 send를 사용해야 합니다.예:
p = Person.new(:name => 'foo')
p.send(:create_without_callbacks)
p = Person.find(1)
p.send(:update_without_callbacks)
이것은 확실히 콘솔이나 몇 가지 무작위 테스트를 수행할 때만 사용하기를 원하는 것입니다.이것이 도움이 되길 바랍니다!
업데이트됨:
@Vikant Chaudhary의 솔루션이 더 나은 것 같습니다.
#Rails >= v3.1 only
@person.update_column(:some_attribute, 'value')
#Rails >= v4.0 only
@person.update_columns(attributes)
나의 원래 대답은:
다음 링크 참조:ActiveRecord 콜백을 건너뛸 수 있는 방법은 무엇입니까?
레일 3에서,
클래스 정의가 있다고 가정합니다.
class User < ActiveRecord::Base
after_save :generate_nick_name
end
접근법 1:
User.send(:create_without_callbacks)
User.send(:update_without_callbacks)
접근법 2:rspec 파일 등에서 이러한 파일을 건너뛰려면 다음을 수행합니다.
User.skip_callback(:save, :after, :generate_nick_name)
User.create!()
참고: 이 작업이 완료되면 rspec 환경이 아닌 경우 콜백을 재설정해야 합니다.
User.set_callback(:save, :after, :generate_nick_name)
레일 3.0.5에서 잘 작동합니다.
콜백이나 유효성 검사 없이 레코드를 삽입하는 것이 목표이며 추가 보석에 의존하거나 조건부 검사를 추가하거나 RAW SQL을 사용하거나 기존 코드를 사용하지 않고 레코드를 삽입하려면 기존 데이터베이스 테이블을 가리키는 "그림자 개체"를 사용하는 것이 좋습니다.이와 같은 경우:
class ImportedPerson < ActiveRecord::Base
self.table_name = 'people'
end
이 기능은 모든 Rails 버전에서 작동하며 스레드 세이프이며 기존 코드를 수정하지 않고도 모든 유효성 검사와 콜백을 완전히 제거합니다.실제 가져오기 직전에 클래스 선언서를 제출하면 됩니다. 바로 제출해 주시면 됩니다.새 클래스를 사용하여 다음과 같이 개체를 삽입하십시오.
ImportedPerson.new( person_attributes )
레일 3:
MyModel.send("_#{symbol}_callbacks") # list
MyModel.reset_callbacks symbol # reset
사용자 모델에서 다음과 같은 작업을 수행할 수 있습니다.
after_save :something_cool, :unless => :skip_callbacks
def skip_callbacks
ENV[RAILS_ENV] == 'development' # or something more complicated
end
EDIT: after_save는 기호가 아니지만, 제가 기호로 만들기 위해 시도한 것은 적어도 1,000번째입니다.
사용할 수 있습니다.update_columns
:
User.first.update_columns({:name => "sebastian", :age => 25})
저장을 호출하지 않고 개체의 지정된 특성을 업데이트하므로 유효성 검사 및 콜백을 건너뜁니다.
모든 after_save 콜백을 방지하는 유일한 방법은 첫 번째 콜백이 false를 반환하도록 하는 것입니다.
다음과 같은 방법을 시도할 수 있습니다(테스트되지 않음).
class MyModel < ActiveRecord::Base
attr_accessor :skip_after_save
def after_save
return false if @skip_after_save
... blah blah ...
end
end
...
m = MyModel.new # ... etc etc
m.skip_after_save = true
m.save
레일즈 2.3(예: update_without_callbacks가 사라졌기 때문에)에서 이를 처리하는 한 가지 방법은 레일즈 가이드의 섹션 12에 따라 콜백을 검증 및 콜백으로 건너뛸 수 있는 방법 중 하나인 update_all을 사용하는 것입니다.
또한 after_callback에서 많은 연관성(즉, a has_manyassoc, accept_nested_attributes_for)을 기반으로 계산하는 작업을 수행하는 경우에는 저장의 일부로 해당 구성원 중 하나가 삭제된 경우를 대비하여 연결을 다시 로드해야 합니다.
많은 장가.up-voted
경우에 따라 답변이 혼동될 수 있습니다.
간단한 것만 사용할 수 있습니다.if
다음과 같은 콜백을 건너뛸지 확인합니다.
after_save :set_title, if: -> { !new_record? && self.name_changed? }
레일 6을 사용하여 이제 삽입 방법을 사용할 수 있습니다.
설명서에서:
단일 SQL INSERT 문에 여러 레코드를 데이터베이스에 삽입합니다.모델을 인스턴스화하거나 활성 레코드 콜백 또는 유효성 검사를 트리거하지 않습니다.통과된 값은 Active Record의 유형 캐스팅 및 직렬화를 거칩니다.
https://gist.github.com/576546
이 monkey-backs를 config/initializers/sys_callbacks로 덤프하기만 하면 됩니다.
그리고나서
Project.skip_callbacks { @project.save }
뭐 그런 것들
전적으로 저자의 공이다.
보석이나 플러그인을 사용하지 않고 모든 버전의 레일에서 작동해야 하는 해결책은 단순히 업데이트 문을 직접 발행하는 것입니다.예를 들어
ActiveRecord::Base.connection.execute "update table set foo = bar where id = #{self.id}"
업데이트의 복잡성에 따라 이 옵션이 선택사항이 될 수도 있고 그렇지 않을 수도 있습니다.이는 예를 들어 after_save 콜백 내에서 레코드의 플래그를 업데이트할 때 잘 작동합니다(콜백을 다시 트리거하지 않고).
저는 Rails 4에 대한 해결책이 필요했기 때문에 다음과 같이 생각해냈습니다.
app/syslog/sessage/save_without_callbacks.message
module SaveWithoutCallbacks
def self.included(base)
base.const_set(:WithoutCallbacks,
Class.new(ActiveRecord::Base) do
self.table_name = base.table_name
end
)
end
def save_without_callbacks
new_record? ? create_without_callbacks : update_without_callbacks
end
def create_without_callbacks
plain_model = self.class.const_get(:WithoutCallbacks)
plain_record = plain_model.create(self.attributes)
self.id = plain_record.id
self.created_at = Time.zone.now
self.updated_at = Time.zone.now
@new_record = false
true
end
def update_without_callbacks
update_attributes = attributes.except(self.class.primary_key)
update_attributes['created_at'] = Time.zone.now
update_attributes['updated_at'] = Time.zone.now
update_columns update_attributes
end
end
모든 모델에서:
include SaveWithoutCallbacks
그러면 다음을 수행할 수 있습니다.
record.save_without_callbacks
또는
Model::WithoutCallbacks.create(attributes)
콜백을 완전히 제어해야 하는 경우 스위치로 사용되는 다른 특성을 만듭니다.간편하고 효과적:
모델:
class MyModel < ActiveRecord::Base
before_save :do_stuff, unless: :skip_do_stuff_callback
attr_accessor :skip_do_stuff_callback
def do_stuff
puts 'do stuff callback'
end
end
테스트:
m = MyModel.new()
# Fire callbacks
m.save
# Without firing callbacks
m.skip_do_stuff_callback = true
m.save
# Fire callbacks again
m.skip_do_stuff_callback = false
m.save
# for rails 3
if !ActiveRecord::Base.private_method_defined? :update_without_callbacks
def update_without_callbacks
attributes_with_values = arel_attributes_values(false, false, attribute_names)
return false if attributes_with_values.empty?
self.class.unscoped.where(self.class.arel_table[self.class.primary_key].eq(id)).arel.update(attributes_with_values)
end
end
이 중 어느 것도 다음을 가리키지 않습니다.without_callbacks
필요한 작업을 수행하는 플러그인...
class MyModel < ActiveRecord::Base
before_save :do_something_before_save
def after_save
raise RuntimeError, "after_save called"
end
def do_something_before_save
raise RuntimeError, "do_something_before_save called"
end
end
o = MyModel.new
MyModel.without_callbacks(:before_save, :after_save) do
o.save # no exceptions raised
end
http://github.com/cjbottaro/without_callbacks 은 Rails 2.x와 함께 작동합니다.
저는 레일즈 3에서 update_without_callback을 구현하는 플러그인을 작성했습니다.
http://github.com/dball/skip_activerecord_callbacks
제 생각에 올바른 해결책은 애초에 콜백을 피하기 위해 모델을 다시 작성하는 것입니다. 하지만 단기간에 실용적이지 않다면 이 플러그인이 도움이 될 수도 있습니다.
레일 2를 사용하는 경우.콜백 및 유효성 검사를 실행하지 않고 SQL 쿼리를 사용하여 열을 업데이트할 수 있습니다.
YourModel.connection.execute("UPDATE your_models SET your_models.column_name=#{value} WHERE your_models.id=#{ym.id}")
모든 레일 버전에서 작동해야 한다고 생각합니다.
Rails에서 테스트 데이터를 생성하려면 다음 해킹을 사용합니다.
record = Something.new(attrs)
ActiveRecord::Persistence.instance_method(:create_record).bind(record).call
https://coderwall.com/p/y3yp2q/edit
당신은 snicky-save gem: https://rubygems.org/gems/sneaky-save 를 사용할 수 있습니다.
이는 유효성 검사 없이 연결을 저장하는 데 도움이 되지 않습니다.모델과 달리 sql 쿼리를 직접 삽입하기 때문에 'created_at cannot be null' 오류가 발생합니다.이를 구현하기 위해서는 DB의 모든 자동 생성 열을 업데이트해야 합니다.
사용자 지정 콜백의 경우attr_accessor
그리고unless
콜백으로
다음과 같이 모델을 정의합니다.
class Person << ActiveRecord::Base
attr_accessor :skip_after_save_callbacks
after_save :do_something, unless: :skip_after_save_callbacks
end
그리고 만약 당신이 기록을 치지 않고 저장할 필요가 있다면.after_save
정의한 콜백, 설정skip_after_save_callbacks
가상 속성true
.
person.skip_after_save_callbacks #=> nil
person.save # By default, this *will* call `do_something` after saving.
person.skip_after_save_callbacks = true
person.save # This *will not* call `do_something` after saving.
person.skip_after_save_callbacks = nil # Always good to return this value back to its default so you don't accidentally skip callbacks.
개발 과정에서 이러한 작업을 수행할 수 있는 이유는 무엇입니까?이것은 분명 잘못된 데이터로 애플리케이션을 구축하고 있다는 것을 의미하며, 따라서 프로덕션에서 예상하는 것이 아니라 이상하게 동작한다는 것을 의미합니다.
만약 당신이 당신의 devdb에 데이터를 채우고 싶다면, 더 나은 접근법은 가짜 보석을 사용하여 유효한 데이터를 구축하고 원하는 만큼 또는 적은 수의 레코드를 만드는 것을 DB로 가져오는 것이지만, 만약 당신이 그것에 열중하고 있다면, 만약 당신이_callback 없이 update_without_create_without_callback,하지만 여러분이 여러분의 의지에 따라 레일을 구부리려고 할 때, 여러분이 하고 있는 것이 정말 좋은 생각인지 스스로에게 물어보십시오.
한 가지 옵션은 동일한 테이블을 사용하여 이러한 조작을 위한 별도의 모델을 갖는 것입니다.
class NoCallbacksModel < ActiveRecord::Base
set_table_name 'table_name_of_model_that_has_callbacks'
include CommonModelMethods # if there are
:
:
end
(동일한 접근 방식으로 검증을 쉽게 우회할 수 있음)
스테판
또 다른 방법은 콜백 대신 유효성 검사 후크를 사용하는 것입니다.예:
class Person < ActiveRecord::Base
validate_on_create :do_something
def do_something
"something clever goes here"
end
end
이렇게 하면 기본적으로 do_something을 가져올 수 있지만 다음을 사용하여 쉽게 재정의할 수 있습니다.
@person = Person.new
@person.save(false)
의 모든 버전에서 작동해야 하는 기능ActiveRecord
존재할 수도 있고 없을 수도 있는 옵션 또는 활성 레코드 방법에 의존하지 않습니다.
module PlainModel
def self.included(base)
plainclass = Class.new(ActiveRecord::Base) do
self.table_name = base.table_name
end
base.const_set(:Plain, plainclass)
end
end
# usage
class User < ActiveRecord::Base
include PlainModel
validates_presence_of :email
end
User.create(email: "") # fail due to validation
User::Plain.create(email: "") # success. no validation, no callbacks
user = User::Plain.find(1)
user.email = ""
user.save
TLDR: 동일한 테이블에 "다른 활성 레코드 모델" 사용
저장 중인 모든 레코드에 대해 콜백을 실행하지 않고 레이크 태스크를 실행하려고 할 때도 동일한 문제에 직면했습니다.이것은 저에게 효과가 있었고(레일 5), 거의 모든 버전의 레일에서 효과가 있어야 합니다.
class MyModel < ApplicationRecord
attr_accessor :skip_callbacks
before_create :callback1
before_update :callback2
before_destroy :callback3
private
def callback1
return true if @skip_callbacks
puts "Runs callback1"
# Your code
end
def callback2
return true if @skip_callbacks
puts "Runs callback2"
# Your code
end
# Same for callback3 and so on....
end
작동 방식은 skip_callbacks가 true인 메서드의 첫 번째 줄에서 true를 반환하므로 메서드의 나머지 코드는 실행되지 않습니다.콜백을 건너뛰려면 다음을 저장, 생성, 삭제하기 전에 skip_callbacks를 true로 설정하기만 하면 됩니다.
rec = MyModel.new() # Or Mymodel.find()
rec.skip_callbacks = true
rec.save
가장 깨끗한 방법은 아니지만, 레일 환경을 확인하는 조건으로 콜백 코드를 감쌀 수 있습니다.
if Rails.env == 'production'
...
언급URL : https://stackoverflow.com/questions/632742/how-can-i-avoid-running-activerecord-callbacks
'programing' 카테고리의 다른 글
SQL: 첫 글자만 대문자로 표시 (0) | 2023.06.04 |
---|---|
활성 레코드를 복제하는 가장 쉬운 방법은 무엇입니까? (0) | 2023.06.04 |
npm이 make not found 오류와 함께 시간을 설치하지 못했습니다. (0) | 2023.06.04 |
Android Studio에 장치가 표시되지 않습니다. (0) | 2023.06.04 |
선의 개별 점에 대한 마커 설정 (0) | 2023.06.04 |