2009-11-19 10 views
10

यदि कोई प्लगइन या ActiveRecord क्लास स्थापित करने का सबसे अच्छा तरीका है तो आश्चर्य की बात है, उदाहरण के लिए, जब कोई रिकॉर्ड "प्रकाशित" स्थिति दर्ज करता है, तो कुछ विशेषताओं को जमे हुए होते हैं कि वे छेड़छाड़ नहीं किया जा सका।Rails ActiveRecord: रिकॉर्ड किसी विशेष स्थिति में प्रवेश करते समय गुणों को लॉक करना

उत्तर

8

आप @readonly को सही (विधि में) सेट करके एक संपूर्ण AR :: B ऑब्जेक्ट को फ्रीज कर सकते हैं, लेकिन यह सभी विशेषताओं को लॉक कर देगा।

तरह से मैं सिफारिश करेंगे विशेषता सेटर तरीकों कि सुपर को पार करने से पहले वर्तमान स्थिति के लिए जाँच को परिभाषित करते हुए है:

class Post < ActiveRecord::Base 
    def author=(author) 
    super unless self.published? 
    end 

    def content=(content) 
    super unless self.published? 
    end 
end 

[संपादित करें] या विशेषताओं की एक बड़ी राशि के लिए:

class Post < ActiveRecord::Base 
    %w(author content comments others).each do |method| 
    class_eval <<-"end_eval", binding, __FILE__, __LINE__ 
     def #{method}=(val) 
     super unless self.published? 
     end 
    end_eval 
    end 
end 

मैं निश्चित रूप से दूसरों के साथ साझा करने के लिए एक प्लगइन में खींचने की वकालत करता हूं, और disable_attributes :author, :content, :comments, :when => :published?

+0

प्रतिक्रिया कॉलिन के लिए धन्यवाद। बड़ी संख्या में गुणों के लिए मुझे लगता है कि मैं लॉक होने की आवश्यकता वाले गुणों की एक सरणी में गुजरकर इन सेटर्स को ओवरराइट करने के लिए कक्षा उत्तीर्ण कर सकता हूं, आह? –

+0

सटीक रूप से। मैंने बहस की कि क्या मुझे इसे कक्षा_वृत्त के रूप में लिखना चाहिए, लेकिन इसके खिलाफ पठनीयता के लिए फैसला किया। हालांकि मैं दूसरों के लिए इसका सामना करूंगा। –

3

आप एसी जोड़ सकते हैं यदि आप किसी निश्चित स्थिति में हैं तो गुणों में परिवर्तनों को अवरुद्ध करने के लिए कस्टम सत्यापन। आप सीधे कोड प्रमाणीकरण में हार्ड कोड चीजें कर सकते हैं। लेकिन मैं एक श्वेतसूची (एक राज्य में बदलने की अनुमति देने वाले गुणों की सूची) या एक ब्लैकलिस्ट परिभाषित करने वाले स्थिरांक का उपयोग करके थोड़ा अधिक मजबूत दृष्टिकोण पसंद करता हूं (गुणों की सूची किसी राज्य में बदलने की अनुमति नहीं है)।

यहां दोनों दृष्टिकोणों का एक उदाहरण दिया गया है। प्रत्येक दृष्टिकोण मानता है कि आपके मॉडल में एक राज्य विधि है जो वर्तमान/नए राज्य को स्ट्रिंग के रूप में लौटाती है।

श्वेत सूची दृष्टिकोण

WhiteListStateLockMap = { 
    "state_1" => [ 
    "first_attribute_allowed_to_change_in_state_1", 
    "second_attribute_allowed_to_change_in_state_1", 
    ... 
    ], 
    "state_2" => [ 
    "first_attribute_allowed_to_change_in_state_2", 
    "second_attribute_allowed_to_change_in_state_2", 
    ... 
    ], 
    ... 
} 

validates :state_lock 

def state_lock 
    # ensure that all changed elements are on the white list for this state. 
    unless changed & WhiteListStateLockMap[state] == changed 
    # add an error for each changed attribute absent from the white list for this state. 
    (changed - WhiteListStateLockMap[state]).each do |attr| 
     errors.add attr, "Locked while #{state}" 
    end 
    end 
end 

काला सूची दृष्टिकोण

BlackListStateLockMap = { 
    "state_1" => [ 
    "first_attribute_not_allowed_to_change_in_state_1, 
    "second_attribute_not_allowed_to_change_in_state_1, 
    ... 
    ], 
    "state_2" => [ 
    "first_attribute_not_allowed_to_change_in_state_2", 
    "second_attribute_not_allowed_to_change_in_state_2", 
    ... 
    ], 
    ... 
} 

validates :state_lock 

def state_lock 
    # ensure that no changed attributes are on the black list for this state. 
    unless (changed & BlackListStateLockMap[state]).empty? 
    # add an error for all changed attributes on the black list for this state. 
    (BlackListStateLockMap[state] & changed).each do |attr| 
     errors.add attr, "Locked while #{state}" 
    end 
    end 
end 
+0

पोस्ट करने के बाद, मुझे एहसास हुआ कि मेरा समाधान अनिवार्य रूप से लिखे गए सिवाय इसके अलावा, इस तरह के समान था। मेरा मानना ​​है कि मेरा अधिक स्पष्ट है, लेकिन यह भी अच्छा है, क्योंकि यह अधिक घोषणात्मक है। –

+0

एम्फी - प्रतिक्रिया के लिए धन्यवाद।यह मेरे रूबी ज्ञान के लिए थोड़ा उन्नत है, एक सिंगल एम्परसैंड से जुड़ी दो लाइनों की रेखाओं के संदर्भ में, यह सुनिश्चित नहीं है कि वास्तव में क्या हो रहा है, जब तक कि यह एक और नहीं है - मुझे वास्तव में इसका परीक्षण करने में त्रुटि हो रही है: अपरिभाषित विधि ' और 'के लिए {}: हैश –

+1

और सरणी के लिए चौराहे ऑपरेटर है। http://ruby-doc.org/core/classes/Array.html#M002212। ऐरे ए और ऐरे बी तत्वों को दोनों सरणी के लिए आम तौर पर लौटाता है। यदि ए और बी == ए तो ए के सभी तत्व बी में हैं। इसके अलावा आपको मेरी एक टाइपो की वजह से त्रुटि मिल रही है जिसकी प्रतिलिपि बनाई गई है और कई बार चिपकाया गया है। परिवर्तनों के सभी उदाहरण बदल गए होंगे। मैंने इस – EmFi

14

विशेषताएं संपादित करना जो संपादित नहीं किया जाना चाहिए एक प्रमाणीकरण त्रुटि है:

class Post < ActiveRecord::Base 
    validate :lock_down_attributes_when_published 

    private 

    def lock_down_attributes_when_published 
    return unless published? 

    message = "must not change when published" 
    errors.add(:title, message) if title_changed? 
    errors.add(:published_at, message) if published_at_changed? 
    end 
end 

थी एस 2.212 में पेश किए गए ActiveRecord::Dirty एक्सटेंशन का उपयोग करता है।

+0

को प्रतिबिंबित करने के लिए समाधान अद्यतन किया है फ्रैंकोइस प्रतिक्रिया के लिए धन्यवाद, यह ऐसा करने का एक और शानदार तरीका है। –

0

यदि विशेष स्थिति केवल persisted? है, तो attr_readonly सबसे अच्छा विकल्प है।

attr_readonly(*attributes)सार्वजनिक

Attributes listed as readonly will be used to create a new record but update operations will ignore these fields.

परीक्षण करने के लिए (THAiSi के सौजन्य से):

class MyModel < ActiveRecord::Base 
    attr_readonly :important_type_thingie 
end 

#RSpec 
describe MyModel do 
its('class.readonly_attributes') { should include "important_type_thingie" } 

it "should not update the thingie" do 
    m = create :my_model, :important_type_thingie => 'foo' 
    m.update_attributes :important_type_thingie => 'bar' 
    m.reload.important_type_thingie.should eql 'foo' 
end 
end 
संबंधित मुद्दे