रेल प्रवास में दूसरे के मान के लिए एक कॉलम अपडेट करें


80

मेरे पास सैकड़ों-हजारों रिकॉर्ड के साथ एक रेल एप्लिकेशन में एक टेबल है, और उनके पास केवल created_atटाइमस्टैम्प है। मैं इन रिकॉर्ड्स को संपादित करने की क्षमता जोड़ रहा हूं, इसलिए मैं updated_atटेबल पर टाइमस्टैम्प जोड़ना चाहता हूं । कॉलम जोड़ने के लिए अपने माइग्रेशन में, मैं नए updated_atमैच के लिए सभी पंक्तियों को पुराने से अपडेट करना चाहता हूं created_at, क्योंकि यह रेल में नई बनाई गई पंक्तियों के लिए डिफ़ॉल्ट है। मैं find(:all)रिकॉर्ड के माध्यम से एक और पुनरावृति कर सकता था , लेकिन उस तालिका के आकार के कारण घंटों लगेंगे। मैं वास्तव में क्या करना चाहता हूं:

UPDATE table_name SET updated_at = created_at;

वहाँ एक अच्छा तरीका है कि कच्चे SQL निष्पादित करने के बजाय ActiveRecord का उपयोग कर एक रेल प्रवास में है?

जवाबों:


136

मैं एक प्रवास बनाऊंगा

rails g migration set_updated_at_values

और इसके अंदर कुछ इस तरह लिखें:

class SetUpdatedAt < ActiveRecord::Migration
  def self.up
    Yourmodel.update_all("updated_at=created_at")
  end

  def self.down
  end
end

इस तरह आप दो चीजें हासिल करते हैं

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

ध्यान दें: आप माइग्रेशन के अंदर भी कच्चे sql चला सकते हैं, अगर क्वेरी को activerecord का उपयोग करके लिखना बहुत कठिन हो जाता है। बस निम्नलिखित लिखें:

Yourmodel.connection.execute("update your_models set ... <complicated query> ...")

+1 - मुझे हाल ही में ऐसा करना था और SQL को एक ActiveRecord में इस्तेमाल किया। यह जितनी तेजी से मिल सकता है।
पीटर ब्राउन

40
Yourmodel.update_all 'update_at=created_at'अच्छा है, नहीं? यह एक दायरे पर भी काम करता है।
मार्क-एंड्रे लाफ्यून

रेल गाइड के अनुसार : "डेटाबेस स्कीमा अपरिवर्तित होना चाहिए यदि आप एक के upबाद करते हैं down" । इसलिए def changeइसके बजाय केवल विचार करें ।
एलियाडल

1
@ एलियाडल कुछ टिप्पणी: 1) हम स्कीमा को नहीं बदल रहे हैं, बस डेटाबेस की सामग्री। और 2) जिस समय यह उत्तर लिखा गया था, वह changeविधि अभी तक मौजूद नहीं थी, लेकिन इस मामले में मैं अभी भी स्पष्ट upऔर downअधिक स्पष्ट (यदि आप क्या करना downचाहिए नियंत्रित करना चाहते हैं) का उपयोग करना पसंद करते हैं।
नथ्नवाड़ा

20

आप अपडेट SQL का उपयोग कर सकते हैं, जो कच्चे SQL के समान है। आपके पास सभी विकल्प हैं।

BTW व्यक्तिगत रूप से मैं पलायन पर उतना ध्यान नहीं देता। कभी-कभी कच्चा एसक्यूएल वास्तव में सबसे अच्छा समाधान होता है। आमतौर पर माइग्रेशन कोड का पुन: उपयोग नहीं किया जाता है। यह एक बार की कार्रवाई है इसलिए मैं कोड शुद्धता के बारे में परेशान नहीं करता हूं।


2
यह आपकी तैनाती की जरूरतों पर निर्भर करता है। मैं वास्तव में माइग्रेशन का उपयोग करना पसंद करता हूं, क्योंकि वे मौजूदा प्लेटफार्मों पर दोहराए जाने की अनुमति देते हैं और समान परिणाम प्राप्त करते हैं। हमारे पास तैनाती के कई चरण हैं: देव, परीक्षण, क्यूए / स्वीकृति, अवधारणा मंच का प्रमाण (ग्राहकों का परीक्षण करने के लिए), एक उत्पादन मंच: हमें मौजूदा डेटा को एक गलती के बिना नव तैनात संस्करण में स्थानांतरित करने में सक्षम होने की आवश्यकता है। कॉलम जोड़ना और यह सुनिश्चित करना कि डेटा ठीक है, हमारे मामले में एक बार की कार्रवाई नहीं है।
नथनवदा

मैं update_allमाइग्रेशन फ़ाइल के अंदर उपयोग के बारे में लिखता हूं :-) आप कच्चे एसक्यूएल को माइग्रेशन फ़ाइल के अंदर भी निष्पादित कर सकते हैं। हालाँकि update_allथोड़ा अधिक सुरुचिपूर्ण है। दोनों बिल्कुल एक जैसा प्रदर्शन करेंगे।
ग्रेग डैन

आमतौर पर माइग्रेशन को मॉडल घोषित करना एक स्मार्ट विचार है, क्योंकि इससे समस्याओं को रोका जा सकेगा यदि मूल मॉडल को बाद में फिर से परिभाषित किया जाए। : बस इस लेख जो सब कुछ काफी अच्छी तरह से बताते हैं पाया complicated-simplicity.com/2010/05/...
फ़्राँस्वा Beausoleil

साथ update_allमैं कैसे के रूप में ओ पी का अनुरोध किया, एक और की है कि स्तंभ का मान सेट करने के लिए कोई विचार है। कृपया प्रदर्शित करें।
नथनवद

14

जैसा कि ग्रिगेडन ने लिखा है, आप उपयोग कर सकते हैं update_all। आप ऐसा कुछ कर सकते हैं:

Model.where(...).update_all('updated_at = created_at')

पहला भाग आपकी विशिष्ट परिस्थितियों का सेट है। अंतिम भाग कहता है कि असाइनमेंट कैसे करें। यह UPDATEकम से कम रेल 4 में एक बयान देगा ।


यह 4.2 में उत्पन्न होता है SET'posts'.'email' = 'options', विकल्प एक शाब्दिक स्ट्रिंग है
lulalala

इस टिप की पुष्टि करना मेरे लिए भी काम नहीं करता है। अनिश्चित है कि यह पूरी तरह से गलत समाधान है। Donmartvote @martin का जवाब न दें
woto

यहाँ रेल कंसोल से आउटपुट है:User.update_all('updated_at = created_at') SQL (0.4ms) UPDATE "users" SET updated_at = created_at
मार्टिन स्ट्रीचर

2

आप सीधे अपने आदेश को चला सकते हैं rails console ActiveRecord::Base.connection.execute("UPDATE TABLE_NAME SET COL2 = COL1")

उदाहरण के लिए: मैं अपने आइटम तालिका के sku को अद्यतन करना चाहता हूं जिसमें आइटम टेबल के रिमोट_ड के साथ हैं। कमांड निम्नानुसार होगी:
ActiveRecord::Base.connection.execute("UPDATE items SET sku = remote_id")


वास्तव में यह सबसे अधिक "इतिहास" सुरक्षित तरीका है, क्योंकि भविष्य में (जब कुछ माइग्रेशन चलाएंगे, मॉडल Yourmodelको पहले ही हटा दिया जा सकता है। माइग्रेशन में मॉडल का उपयोग करने से बचने की कोशिश करें।
फोटॉन

0

यह क्वेरी लिखने की आवश्यकता के बिना हल करने का एक सामान्य तरीका है, क्योंकि प्रश्न जोखिम के अधीन हैं।

  class Demo < ActiveRecord::Migration
    def change
     add_column :events, :time_zone, :string
     Test.all.each do |p|
       p.update_attributes(time_zone: p.check.last.time_zone)
     end
     remove_column :sessions, :time_zone
    end
  end

-4

एक बार के ऑपरेशन के रूप में, मैं इसे अभी करूँगा rails console। क्या सच में घंटे लगेंगे? हो सकता है अगर लाखों रिकॉर्ड हों ...

records = ModelName.all; records do |r|; r.update_attributes(:updated_at => r.created_at); r.save!; end;`

यह अनिवार्य रूप से मैंने पहले प्रयास किया था, लेकिन क्योंकि सैकड़ों हजारों रिकॉर्ड हैं जिन्हें बदलने की आवश्यकता है, जिसमें घंटे (दिन) लगेंगे।
जरीदीको

जब मैंने इसका परीक्षण किया तो यह मेरे डेवलपर मशीन (सर्वर नहीं) पर लगभग 50 रिकॉर्ड सेकंड में चल रहा था।
जर्दोको

4
यदि संभव हो तो हमेशा पुनरावृत्ति से बचें, 'सभी' का उपयोग करने से बचें जो हर रिकॉर्ड को एक ही बार में रैम में लोड करता है, और चूंकि अपडेट_एट्यूएंट पहले से ही स्वचालित रूप से एक बचत करता है, बचाने के लिए अतिरिक्त कॉल! पूरे ऑपरेशन को दो बार लंबे समय तक ले जाएगा।
ryan0
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.