2011-08-19 14 views
40

मैं अपने आवेदन में after_commit का उपयोग कर रहा हूं।एक विशेषता के लिए बाद_commit

मैं इसे तभी ट्रिगर करना चाहता हूं जब मेरे मॉडल में कोई विशेष फ़ील्ड अपडेट हो। कोई जानता है कि उसे कैसे करना है?

उत्तर

3

ऐसा लगता है जैसे आप conditional callback की तरह कुछ चाहते हैं। आप कुछ कोड मैं सही दिशा तथापि में आप इशारा किया जा सकता था तैनात किया था, तो मुझे लगता है कि आप कुछ इस तरह का उपयोग करना चाहते हैं: after_commit

का इन

after_commit :callback, 
    :if => Proc.new { |record| record.field_modified? } 
+0

field_modified है? एक पूर्व-निर्मित विधि या क्या यह एक तरीका है जिसे मुझे फ़ील्ड मान की जांच करने के लिए लिखना होगा? मूल रूप से मैं अपनी सभी नियुक्ति रेटिंग के आधार पर उपयोगकर्ता की रेटिंग को पुन: गणना और सहेजने का प्रयास कर रहा हूं। एक अपॉइंटमेंट के लिए रेटिंग को बनाया जाने के बाद जोड़ा जा सकता है, इसलिए मैं जानना चाहता हूं कि रेटिंग फ़ील्ड को अपडेट किया गया था यहां कुछ कोड है जो मैं क्लास अपॉइंटमेंट alik

+0

नहीं फ़ील्ड मान की जाँच करें। –

4

मुझे नहीं लगता कि आप यह कर सकते हैं के बाद लेन-देन मेरी रेल कंसोल में Rails Transactions

प्रतिबद्ध है उदाहरण के लिए

> record = MyModel.find(1) 
=> #<MyModel id: 1, label: "test", created_at: "2011-08-19 22:57:54", updated_at: "2011-08-19 22:57:54"> 
> record.label = "Changing text" 
=> "Changing text" 
> record.label_changed? 
=> true 
> record.save 
=> true 
> record.label_changed? 
=> false 

आप इसलिए after_commit कहा जाता है पर :if स्थिति का उपयोग करने में सक्षम नहीं होंगे क्योंकि विशेषता को सहेजे जाने के रूप में अब और परिवर्तित नहीं किया जाएगा। रिकॉर्ड को सहेजने से पहले आपको यह ट्रैक करने की आवश्यकता हो सकती है कि आप जिस क्षेत्र के बाद हैं, changed? किसी अन्य कॉलबैक में है?

19

इस पुराने प्रश्न का उत्तर देना है क्योंकि यह अभी भी खोज परिणामों में पॉप अप होता है

आप previous_changes विधि है जो प्रारूप के हैश returnes उपयोग कर सकते हैं:

{ "changed_attribute" => [ "पुराने मूल्य "," नया मान "]}

यह क्या changes था, जब तक रिकॉर्ड वास्तव में सहेजा जाता है (active_record/attribute_methods/dirty.rb से) है:

def save(*) #:nodoc: 
    if status = super 
     @previously_changed = changes 
     @changed_attributes.clear 
     # .... whatever goes here 

तो आपके मामले में आप previous_changes.key? "your_attribute" या कि

63

पुराने सवाल की तरह कुछ के लिए जाँच कर सकते हैं, लेकिन यह एक तरीका है कि मैं मिल गया है (बंद paukul's answer काम) कि after_commit कॉलबैक के साथ काम हो सकता है। कम से कम, मूल्य आईआरबी में पोस्ट-प्रतिबद्ध बने रहते हैं।

after_commit :callback, 
    if: proc { |record| 
    record.previous_changes.key?(:attribute) && 
     record.previous_changes[:attribute].first != record.previous_changes[:attribute].last 
    } 
+1

[प्रलेखन] (http://apidock.com/rails/ActiveModel/Dirty/previous_changes) के आधार पर, मुझे लगता है कि 'कुंजी' को कॉल किया जाना चाहिए: 'record.previous_changes.keys.include? (: विशेषता)'। इस बदलाव के साथ, यह मेरे लिए काम करता है। – milkfarm

+13

'record.previous_changes.key? (: विशेषता)' पर्याप्त शर्त है, क्योंकि पहले और अंतिम मान हमेशा बराबर नहीं होते हैं। –

+2

@jamesdevar सही है, लेकिन यह समाधान विफल हो सकता है यदि आपका मॉडल लेनदेन के दौरान एक से अधिक बार सहेजा जाता है। यहां समस्या का प्रदर्शन करने के लिए एक नमूना रेल परियोजना https://github.com/ccmcbeck/after-commit है और इसे ठीक करने का मेरा समाधान यहां दिया गया है। –

0

मणि ArTransactionChanges का उपयोग करें। previous_changes रेल 4.0.x में मेरे लिए काम नहीं कर रहा

उपयोग:

class User < ActiveRecord::Base 
    include ArTransactionChanges 

    after_commit :print_transaction_changes 

    def print_transaction_changes 
    transaction_changed_attributes.each do |name, old_value| 
     puts "attribute #{name}: #{old_value.inspect} -> #{send(name).inspect}" 
    end 
    end 
end 
1

यह एक बहुत ही पुरानी समस्या है, लेकिन उसे स्वीकार previous_changes समाधान सिर्फ पर्याप्त मजबूत नहीं है। ActiveRecord लेन-देन में, कई कारण हैं कि आप मॉडल को दो बार क्यों बचा सकते हैं। previous_changes केवल अंतिम save के परिणाम को दर्शाता है।इस उदाहरण

class Test < ActiveRecord::Base 
    after_commit: :after_commit_test 

    def :after_commit_test 
    puts previous_changes.inspect 
    end 
end 

test = Test.create(number: 1, title: "1") 
test = Test.find(test.id) # to initialize a fresh object 

test.transaction do 
    test.update(number: 2) 
    test.update(title: "2") 
end 

जो आउटपुट पर विचार करें:

{"title"=>["1", "2"], "updated_at"=>[...]} 

लेकिन, क्या आप की जरूरत है:

{"title"=>["1", "2"], "number"=>[1, 2], "updated_at"=>[...]} 

तो, मेरे समाधान यह है:

module TrackSavedChanges 
    extend ActiveSupport::Concern 

    included do 
    # expose the details if consumer wants to do more 
    attr_reader :saved_changes_history, :saved_changes_unfiltered 
    after_initialize :reset_saved_changes 
    after_save :track_saved_changes 
    end 

    # on initalize, but useful for fine grain control 
    def reset_saved_changes 
    @saved_changes_unfiltered = {} 
    @saved_changes_history = [] 
    end 

    # filter out any changes that result in the original value 
    def saved_changes 
    @saved_changes_unfiltered.reject { |k,v| v[0] == v[1] } 
    end 

    private 

    # on save 
    def track_saved_changes 
    # maintain an array of ActiveModel::Dirty.changes 
    @saved_changes_history << changes.dup 
    # accumulate the most recent changes 
    @saved_changes_history.last.each_pair { |k, v| track_saved_change k, v } 
    end 

    # v is an an array of [prev, current] 
    def track_saved_change(k, v) 
    if @saved_changes_unfiltered.key? k 
     @saved_changes_unfiltered[k][1] = track_saved_value v[1] 
    else 
     @saved_changes_unfiltered[k] = v.dup 
    end 
    end 

    # type safe dup inspred by http://stackoverflow.com/a/20955038 
    def track_saved_value(v) 
    begin 
     v.dup 
    rescue TypeError 
     v 
    end 
    end 
end 

आप जो यहां आज़मा सकते हैं: https://github.com/ccmcbeck/after-commit

संबंधित मुद्दे