ActiveRecord 콜백을 실행하지 않으려면 어떻게해야합니까?
after_save 콜백이있는 모델이 있습니다. 일반적으로 문제는 없지만 개발 데이터를 만들 때와 같은 일부 상황에서는 콜백을 실행하지 않고 모델을 저장하려고합니다. 그렇게하는 간단한 방법이 있습니까? 비슷한 것 ...
Person#save( :run_callbacks => false )
또는
Person#save_without_callbacks
Rails 문서를 보았는데 아무것도 찾지 못했습니다. 그러나 내 경험상 Rails 문서가 항상 전체 이야기를 말하는 것은 아닙니다.
최신 정보
다음 과 같은 모델에서 콜백을 제거하는 방법을 설명하는 블로그 게시물 을 찾았 습니다 .
Foo.after_save.clear
해당 방법이 문서화 된 곳을 찾을 수 없지만 작동하는 것 같습니다.
이 솔루션은 Rails 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)
이것은 확실히 콘솔에서만 또는 임의의 테스트를 수행하는 동안 사용하고 싶은 것입니다. 도움이 되었기를 바랍니다!
사용 update_column
(레일> = 3.1) 또는 update_columns
(레일> = 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
업데이트 :
@Vikrant Chaudhary의 솔루션이 더 좋아 보입니다.
#Rails >= v3.1 only
@person.update_column(:some_attribute, 'value')
#Rails >= v4.0 only
@person.update_columns(attributes)
내 원래 답변 :
이 링크 참조 : ActiveRecord 콜백을 건너 뛰는 방법?
Rails3에서
클래스 정의가 있다고 가정하십시오.
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에서 잘 작동합니다.
레일 3 :
MyModel.send("_#{symbol}_callbacks") # list
MyModel.reset_callbacks symbol # reset
Person 모델에서 다음과 같은 것을 시도해 볼 수 있습니다.
after_save :something_cool, :unless => :skip_callbacks
def skip_callbacks
ENV[RAILS_ENV] == 'development' # or something more complicated
end
편집 : after_save는 기호가 아니지만 적어도 1,000 번 시도했습니다.
콜백이나 유효성 검사없이 단순히 레코드를 삽입하는 것이 목표이며 추가 gem에 의존하지 않고 조건부 검사를 추가하거나 RAW SQL을 사용하거나 종료 코드를 사용하여 어떤 식 으로든 퍼팅하지 않고 수행하려는 경우 "그림자" 기존 DB 테이블을 가리키는 개체 " 이렇게 :
class ImportedPerson < ActiveRecord::Base
self.table_name = 'people'
end
이것은 모든 Rails 버전에서 작동하며 스레드 안전하며 기존 코드를 수정하지 않고도 모든 유효성 검사 및 콜백을 완전히 제거합니다. 실제로 가져 오기 직전에 해당 클래스 선언을 던질 수 있으며 잘 진행해야합니다. 다음과 같이 새 클래스를 사용하여 객체를 삽입하십시오.
ImportedPerson.new( person_attributes )
당신은 사용할 수 있습니다 update_columns
:
User.first.update_columns({:name => "sebastian", :age => 25})
save를 호출하지 않고 객체의 지정된 속성을 업데이트하므로 유효성 검사 및 콜백을 건너 뜁니다.
모든 after_save 콜백을 방지하는 유일한 방법은 첫 번째 콜백이 false를 반환하도록하는 것입니다.
아마도 (unested)와 같은 것을 시도 할 수 있습니다.
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
Rails 2.3에서 이것을 처리하는 한 가지 방법처럼 보입니다 (update_without_callbacks가 없어진 이후 등). update_all을 사용하는 것 입니다. 이것은 레일스 가이드의 섹션 12에 따라 콜백을 건너 뛰는 메소드 중 하나입니다 .
또한 after_ 콜백에서 무언가를 수행하는 경우 많은 연관 (예 : has_many assoc, accepts_nested_attributes_for도 수행)을 기반으로 계산을 수행하는 경우 저장의 일부로 연결을 다시로드해야합니다. , 회원 중 하나가 삭제되었습니다.
https://gist.github.com/576546
이 원숭이 패치를 config / initializers / skip_callbacks.rb에 덤프하십시오.
그때
Project.skip_callbacks { @project.save }
등.
저자에게 모든 신용
gem 또는 플러그인을 사용하지 않고 모든 버전의 Rails에서 작동해야하는 솔루션은 단순히 update 문을 직접 발행하는 것입니다. 예 :
ActiveRecord::Base.connection.execute "update table set foo = bar where id = #{self.id}"
업데이트가 얼마나 복잡한 지에 따라 옵션이 될 수도 있고 아닐 수도 있습니다. 예를 들어 after_save 콜백 내 에서 (콜백을 다시 트리거하지 않고) 레코드의 플래그를 업데이트하는 데 효과적 입니다.
경우에 따라 대부분의 up-voted
답변이 혼란스러워 보일 수 있습니다.
if
다음과 같이 콜백을 건너 뛰려면 간단한 확인 만하면 됩니다.
after_save :set_title, if: -> { !new_record? && self.name_changed? }
# 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에서 작동합니다
Rails 3에서 update_without_callbacks를 구현하는 플러그인을 작성했습니다.
http://github.com/dball/skip_activerecord_callbacks
The right solution, I think, is to rewrite your models to avoid callbacks in the first place, but if that's impractical in the near term, this plugin may help.
If you are using Rails 2. You could use SQL query for updating your column without running callbacks and validations.
YourModel.connection.execute("UPDATE your_models SET your_models.column_name=#{value} WHERE your_models.id=#{ym.id}")
I think it should work in any rails versions.
When I need full control over the callback, I create another attribute that is used as a switch. Simple and effective:
Model:
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
Test:
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 creating test data in Rails you use this hack:
record = Something.new(attrs)
ActiveRecord::Persistence.instance_method(:create_record).bind(record).call
https://coderwall.com/p/y3yp2q/edit
You can use sneaky-save gem: https://rubygems.org/gems/sneaky-save.
Note this cannot help in saving associations along without validations. It throws error 'created_at cannot be null' as it directly inserts the sql query unlike a model. To implement this, we need to update all auto generated columns of db.
I needed a solution for Rails 4, so I came up with this:
app/models/concerns/save_without_callbacks.rb
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
in any model:
include SaveWithoutCallbacks
then you can:
record.save_without_callbacks
or
Model::WithoutCallbacks.create(attributes)
Why would you want to be able to do this in development? Surely this will mean you are building your application with invalid data and as such it will behave strangely and not as you expect in production.
If you want to populate your dev db with data a better approach would be to build a rake task that used the faker gem to build valid data and import it into the db creating as many or few records as you desire, but if you are heel bent on it and have a good reason I guess that update_without_callbacks and create_without_callbacks will work fine, but when you are trying to bend rails to your will, ask yourself you have a good reason and if what you are doing is really a good idea.
One option is to have a separate model for such manipulations, using the same table:
class NoCallbacksModel < ActiveRecord::Base
set_table_name 'table_name_of_model_that_has_callbacks'
include CommonModelMethods # if there are
:
:
end
(Same approach might make things easier for bypassing validations)
Stephan
Another way would be to use validation hooks instead of callbacks. For example:
class Person < ActiveRecord::Base
validate_on_create :do_something
def do_something
"something clever goes here"
end
end
That way you can get the do_something by default, but you can easily override it with:
@person = Person.new
@person.save(false)
Something that should work with all versions of ActiveRecord
without depending on options or activerecord methods that may or may not exist.
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: use a "different activerecord model" over the same table
Not the cleanest way, but you could wrap the callback code in a condition that checks the Rails environment.
if Rails.env == 'production'
...
참고URL : https://stackoverflow.com/questions/632742/how-can-i-avoid-running-activerecord-callbacks
'development' 카테고리의 다른 글
.htaccess mod_rewrite-재 작성 규칙에서 디렉토리를 제외하는 방법 (0) | 2020.06.25 |
---|---|
모달 바디에만 스크롤 막대를 두는 방법은 무엇입니까? (0) | 2020.06.25 |
컨텐츠 요약 검색을위한 깨끗한 Wikipedia API가 있습니까? (0) | 2020.06.25 |
스 와이프하여 UITableViewCell을 삭제합니다. (0) | 2020.06.25 |
Xcode 단위 테스트에서 @testable을 사용할 때 "해당 모듈 없음" (0) | 2020.06.25 |