문제

After_save 콜백이있는 모델이 있습니다. 일반적으로 괜찮지 만 개발 데이터를 작성할 때와 같이 콜백을 실행하지 않고도 모델을 저장하고 싶습니다. 그렇게하는 간단한 방법이 있습니까? 비슷한 것 ... ...

Person#save( :run_callbacks => false )

또는

Person#save_without_callbacks

나는 Rails 문서를보고 아무것도 찾지 못했습니다. 그러나 내 경험상 Rails Docs가 항상 전체 이야기를하는 것은 아닙니다.

업데이트

나는 찾았다 블로그 게시물 이는 다음과 같은 모델에서 콜백을 제거 할 수있는 방법을 설명합니다.

Foo.after_save.clear

그 방법이 문서화되는 위치를 찾을 수 없었지만 작동하는 것 같습니다.

도움이 되었습니까?

해결책

이 솔루션은 Rails 2입니다.

방금 이것을 조사했고 해결책이 있다고 생각합니다. 사용할 수있는 두 가지 ActiveRecord 개인 방법이 있습니다.

update_without_callbacks
create_without_callbacks

이 방법을 호출하기 위해 보내기 위해 보내야합니다. 예 :

p = Person.new(:name => 'foo')
p.send(:create_without_callbacks)

p = Person.find(1)
p.send(:update_without_callbacks)

이것은 콘솔에서 또는 임의의 테스트를 수행하는 동안 실제로 사용하고 싶은 것입니다. 도움이 되었기를 바랍니다!

다른 팁

사용 update_column (Rails> = 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

업데이트 :

@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

당신은 당신의 사람 모델에서 이와 같은 것을 시도 할 수 있습니다.

after_save :something_cool, :unless => :skip_callbacks

def skip_callbacks
  ENV[RAILS_ENV] == 'development' # or something more complicated
end

편집하다: After_save는 상징이 아니지만 적어도 1,000 번째 시간입니다.

콜백이나 검증없이 레코드를 삽입하는 것이 목표이며 추가 보석에 의지하거나 조건부 검사를 추가하거나, SQL을 사용하거나, 종료 코드를 습격하지 않고도 "섀도우를 사용하는 것을 고려하십시오. 오브젝트 "기존 DB 테이블을 가리키십시오. 그렇게 :

class ImportedPerson < ActiveRecord::Base
  self.table_name = 'people'
end

이것은 모든 버전의 레일과 함께 작동하며 스레드 사프이며 기존 코드를 수정하지 않고 모든 유효성 검사 및 콜백을 완전히 제거합니다. 실제 수입 직전에 해당 클래스 선언을 던질 수 있으며, 가면 좋을 것입니다. 새 클래스를 사용하여 다음과 같은 개체를 삽입하는 것을 잊지 마십시오.

ImportedPerson.new( person_attributes )

당신이 사용할 수있는 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

Rails 2.3에서 이것을 처리하는 한 가지 방법처럼 보입니다 (update_without_callbacks가 사라 졌기 때문에). update_all을 사용하는 것이며, 이는 콜백을 마르는 메소드 중 하나입니다. 유효성 검사 및 콜백에 대한 Rails 안내서 12 절.

또한 After_ Callback에서 무언가를하고 있다면 많은 협회 (예 : Has_many Assoc, 여기서 _nested_attributes_for)를 기반으로 한 계산을 수행하면 저장의 일부로 협회를 다시로드해야합니다. , 회원 중 한 명이 삭제되었습니다.

https://gist.github.com/576546

이 Monkey-Patch를 구성/초기화기/skip_callbacks.rb에 덤프합니다.

그 다음에

Project.skip_callbacks { @project.save }

또는 같은.

저자에게 모든 신용

보석이나 플러그인을 사용하지 않고 모든 버전의 레일에서 작동 해야하는 솔루션은 단순히 업데이트 문을 직접 발행하는 것입니다. 예를 들어

ActiveRecord::Base.connection.execute "update table set foo = bar where id = #{self.id}"

이것은 업데이트가 얼마나 복잡한 지에 따라 옵션이 될 수 있습니다. 이것은 예를 들어 레코드에서 플래그를 업데이트하는 데 적합합니다. 이내에 콜백을 재전거하지 않고 후 _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

올바른 솔루션은 콜백을 피하기 위해 모델을 다시 작성하는 것이지만, 단기적으로 비현실적이라면이 플러그인이 도움이 될 수 있습니다.

Rails 2를 사용하는 경우 콜백 및 유효성 검사를 실행하지 않고 열을 업데이트하기 위해 SQL 쿼리를 사용할 수 있습니다.

YourModel.connection.execute("UPDATE your_models SET your_models.column_name=#{value} WHERE your_models.id=#{ym.id}")

나는 그것이 모든 레일 버전에서 작동해야한다고 생각합니다.

콜백을 완전히 제어해야 할 때 스위치로 사용되는 다른 속성을 만듭니다. 간단하고 효과 :

모델:

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

레일에서 테스트 데이터를 작성하려면이 해킹을 사용합니다.

record = Something.new(attrs)
ActiveRecord::Persistence.instance_method(:create_record).bind(record).call

https://coderwall.com/p/y3yp2q/edit

당신은 snecty-save 보석을 사용할 수 있습니다 : https://rubygems.org/gems/sneaky-save.

이것은 검증없이 연결을 저장하는 데 도움이 될 수 없습니다. 모델과 달리 SQL 쿼리를 직접 삽입하므로 'created_at가 null이 될 수 없다'오류를 던지는 오류가 발생합니다. 이를 구현하려면 DB의 모든 자동 생성 된 열을 업데이트해야합니다.

Rails 4를위한 솔루션이 필요했기 때문에 다음을 생각해 냈습니다.

앱/모델/우려/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

모든 모델에서 :

include SaveWithoutCallbacks

그런 다음 할 수 있습니다.

record.save_without_callbacks

또는

Model::WithoutCallbacks.create(attributes)

개발 에서이 작업을 수행 할 수있는 이유는 무엇입니까? 반드시 이것은 유효하지 않은 데이터로 응용 프로그램을 구축한다는 것을 의미 할 것이며, 따라서 생산에서 예상되는 것처럼 이상하게 행동 할 것입니다.

Dev DB를 데이터로 채우려면 더 나은 접근 방식은 Faker Gem을 사용하여 유효한 데이터를 구축하고 원하는만큼 레코드를 작성하는 DB로 가져 오는 갈퀴 작업을 구축하는 것입니다. 그것에 구부러지고 정당한 이유가 있습니다. update_without_callbacks 및 create_without_callbacks는 잘 작동하지만, 당신의 의지에 레일을 구부리려고 할 때, 당신에게 좋은 이유가 있고, 당신이하고있는 일이 실제로 좋은 생각입니다.

한 가지 옵션은 동일한 테이블을 사용하여 이러한 조작에 대한 별도의 모델을 갖는 것입니다.

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 존재하거나 존재하지 않을 수도있는 옵션 또는 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 : 같은 테이블 위에 "다른 activerecord 모델"을 사용하십시오.

가장 깨끗한 방법은 아니지만 Rails 환경을 점검하는 조건으로 콜백 코드를 랩핑 할 수 있습니다.

if Rails.env == 'production'
  ...
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top