किसी माइग्रेशन में निर्माण समय रिकॉर्ड करने के लिए डेटाइम कॉलम के लिए डिफ़ॉल्ट मान कैसे सेट करें?


114

नीचे दी गई तालिका निर्माण स्क्रिप्ट पर विचार करें:

create_table :foo do |t|
  t.datetime :starts_at, :null => false
end

क्या वर्तमान समय में डिफ़ॉल्ट मान सेट करना संभव है?

मैं नीचे दिए गए SQL स्तंभ परिभाषाओं के लिए रेल में एक DB स्वतंत्र समकक्ष खोजने की कोशिश कर रहा हूँ:

ओरेकल सिंटेक्स

start_at DATE DEFAULT SYSDATE() 

MySQL सिंटेक्स

start_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP

या

start_at DATETIME DEFAULT NOW()

जवाबों:


174

यह अब रेल 5 में समर्थित है।

यहाँ एक नमूना प्रवासन है:

class CreatePosts < ActiveRecord::Migration[5.0]
  def change
    create_table :posts do |t|
      t.datetime :modified_at, default: -> { 'CURRENT_TIMESTAMP' }
      t.timestamps
    end
  end 
end

Https://github.com/rails/rails/issues/27077 पर चर्चा देखें और प्रतिमाश-सोनीपतकी द्वारा उत्तर दें


14
बहुत बढ़िया जवाब। विशुद्ध रूप से एक तरफ के रूप में, ध्यान रखें कि पोस्टग्रेज CURRENT_TIMESTAMPमें वर्तमान लेनदेन की शुरुआत का समय होगा, इसलिए एक ही लेनदेन में बनाए गए कई रिकॉर्डों को समान मूल्य मिलेगा। यदि आप वास्तविक वर्तमान समय चाहते हैं तो स्टेटमेंट निष्पादित होता है (लेन-देन के संदर्भ की अनदेखी), जाँच करें CLOCK_TIMESTAMP
अबे वोल्कर

मैंने कुछ इस तरह से जोड़ा: add_column :table_name, :start_date, :datetime, default: -> { 'CURRENT_TIMESTAMP' }और यह है कि यह स्कीमा में पसंद है ।rb t.datetime "start_date", default: -> { "now()" }लेकिन जब मैंने नया रिकॉर्ड बनाया है, तो यह आबाद नहीं हो रहा है। कोई विचार क्यों?
संदीप सूबेदार

मेरे लिए @SandipSubedi वही। रेल पर 5.2.3।
अदालतों

1
@courtsimas आपको post.reloadउन मूल्यों को प्राप्त करने के लिए करने की आवश्यकता है । इसे यहाँ समझाया गया है: stackoverflow.com/questions/53804787/…
Sandip Subedi

1
@SandipSubedi मुझे अपनी टिप्पणी के 5 मिनट बाद एहसास हुआ। बस uuid पीढ़ी के साथ की तरह। धन्यवाद!
कोर्टमैस

119

आप इस तरह एक मॉडल में एक समारोह जोड़ सकते हैं:

  before_create :set_foo_to_now
  def set_foo_to_now
    self.foo = Time.now
  end

ताकि मॉडल वर्तमान समय मॉडल में सेट हो जाए।

आप डेटाबेस स्तर पर डिफ़ॉल्ट मान सेट करने के लिए माइग्रेशन में कुछ sql कोड भी डाल सकते हैं, जैसे:

execute 'alter table foo alter column starts_at set default now()'

कुछ इस तरह से सेट करना:

create_table :foo do |t|
  t.datetime :starts_at, :null => false, :default => Time.now
end

माइग्रेट करने के दौरान Time.now फ़ंक्शन को निष्पादित करने का कारण बनता है तो डेटाबेस में तालिका इस तरह बनाई जाती है:

create table foo ( starts_at timestamp not null default '2009-01-01 00:00:00');

लेकिन मुझे लगता है कि यह वह नहीं है जो आप चाहते हैं।


1
वर्तमान में मैं इसमें मान सेट कर रहा हूं: इससे पहले कि कॉलबैक करें। <br> मैं यहां कुछ प्रकार के एआर मैजिक की तलाश कर रहा था। मैंने कुछ समय रेल कोड को देखने में बिताया, लेकिन मुझे कोई हल नहीं मिला। मैंने सोचा कि मैं चारों ओर से पूछूंगा कि क्या कोई विकल्प है।
हरीश शेट्टी

मैं पहले call_create पर कॉलबैक के साथ इसे करने का सुझाव दूंगा।
जौनी

1
मैं DB तालिका को बदलना नहीं चाहता क्योंकि मैं अपने कोड DB को तटस्थ रखना चाहता हूं। मैं उम्मीद कर रहा था कि AR के पास dat_ क्षेत्र के लिए डिफ़ॉल्ट मान सेट करने के लिए कुछ तंत्र है जो create_at फ़ील्ड के समान है।
हरीश शेट्टी

9
ध्यान रखें कि डेटाबेस में डालने से पहले पहले_क्रीट कॉलबैक चलता है लेकिन आपके द्वारा अपनी वस्तु (जैसे new()) के तुरंत बाद । तो self.foo = Time.nowआपके द्वारा दिए जा सकने वाले मूल्य को ओवरराइड कर देगा new()। मैं self.foo = Time.current unless self.foo.present?इसके बजाय सुझाव देता हूं ।
फतह

2
ऐसा नहीं है कि, निष्पादन का उपयोग करते समय, यह :starts_at, :default => 'now()'स्कीमा.आरबी में एक पंक्ति डाल देगा। हालांकि यह तब काम नहीं करेगा जब उपयोग rake db:schema:dumpकरने से स्कीमा ओवरब्राइड हो जाएगा :starts_at, :default => '2015-05-29 09:46:33'(या जब भी आप स्क्रिप्ट लॉन्च करेंगे, तो तारीख) ... दुखद ....
astreal

13

यदि तालिका में created_at/ created_onया updated_at/ वाले फ़ील्ड में सक्रिय रिकॉर्ड स्वचालित रूप से टाइमस्टैम्प बनाते हैं और संचालन को अद्यतन करते हैं updated_onस्रोत - api.rubyonrails.org

आपको उस कॉलम के अलावा कुछ और करने की आवश्यकता नहीं है।


मेरे पास पहले से ही मेरी तालिका में वे फ़ील्ड हैं। मुझे अपने शेड्यूलर के लिए प्रारंभ दिनांक रखने के लिए एक अतिरिक्त फ़ील्ड की आवश्यकता है। वर्तमान में, मैं वर्तमान दिनांक को सेट करने के लिए call_create कॉलबैक से पहले उपयोग कर रहा हूं। यदि मैं इस परिदृश्य का अक्सर सामना करता हूं, तो मुझे ColumnDefinition वर्ग की 'to_sql' पद्धति में डिफ़ॉल्ट मान हैंडलिंग को बदलने के लिए एक प्लगइन लिखने का सहारा लेना होगा।
हरीश शेट्टी

9

मैं एक समान समाधान खोज रहा था लेकिन मैंने https://github.com/FooBarWidget/default_value_for का उपयोग कर समाप्त कर दिया ।

default_value_forप्लगइन एक एक कथात्मक ढंग से ActiveRecord मॉडल के लिए डिफ़ॉल्ट मान परिभाषित करने की अनुमति देता है। उदाहरण के लिए:

class User < ActiveRecord::Base
  default_value_for :name, "(no name)"
  default_value_for :last_seen do
    Time.now
  end
end

u = User.new
u.name       # => "(no name)"
u.last_seen  # => Mon Sep 22 17:28:38 +0200 2008

9

मैं आमतौर पर करता हूं:

def change
  execute("
    ALTER TABLE your_table
    ALTER COLUMN your_column
    SET DEFAULT CURRENT_TIMESTAMP
  ")
end

तो, आपके schema.rbपास कुछ ऐसा है:

create_table "your_table", force: :cascade do |t|
  t.datetime "your_column", default: "now()"
end

नकारात्मक पक्ष: यह समाधान केवल तब काम करता है जब आप चलाते हैं rake db:migrate, न कि जब आप अपनी स्कीमा फ़ाइल को कुछ इस तरह से लोड करते हैं rake db:schema:load
अल्टर लागोस

8

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

class MakeStartsAtDefaultDateForFoo < ActiveRecord::Migration[5.0]
  def change
    change_column :foos, :starts_at, :datetime, default: -> { 'CURRENT_TIMESTAMP' }
  end
end

कुछ को वोट करने के लिए खराब फॉर्म और यह नहीं बताएं कि उत्तर के साथ क्या मुद्दा लिया गया था। किसी को भी इस बात का अंदाजा है कि यह मतदान क्यों हुआ? यदि आप एक कॉलम बनाने के बजाय एक कॉलम को बदलना चाहते हैं तो यह सिंटैक्स प्रदर्शित कर रहा है।
मैट लॉन्ग

मैं वह नहीं हूं जिसने नीचा दिखाया है, लेकिन मुझे यह देखने में कठिनाई हो रही है कि यह जवाब किस तरह से विल के उत्तर से भिन्न होता है जो एक वर्ष से पहले आपका है। प्रश्न डिफ़ॉल्ट सेट करने के बारे में है, और आपके उत्तर में एक ही लैम्ब्डा क्लॉज है।
nurettin

2
@nurettin मुझे आपकी बात मिल गई है, लेकिन मेरे बचाव में, एक नया कॉलम बनाने के लिए वाक्यविन्यास एक मौजूदा कॉलम को बदलने से बिल्कुल अलग है । उन लोगों के लिए सिंटैक्स प्रदान करना जिन्होंने वेब खोज के माध्यम से यह प्रश्न पाया है कि एक नया मॉडल / तालिका बनाने के बजाय अपने वर्तमान डेटा मॉडल में डिफ़ॉल्ट रूप से जोड़ने की कोशिश करना संभवतः बहुत उपयोगी है। नहीं? आप मान रहे हैं कि हर कोई जानता है कि वे एक परिवर्तन के लिए एक ही लंबोदर का उपयोग कर सकते हैं। शायद उन्हें इस बात का एहसास होना चाहिए, लेकिन इसीलिए मैंने यहाँ जवाब दिया - ताकि उन्हें यह पता लगाने के लिए कहीं और न जाना पड़े। चीयर्स!
मैट लॉन्ग

4
FWIW मैं अभी इस वाक्यविन्यास का उपयोग करता था और मेरी गूगल खोज और विशेष समस्या के लिए सराहना करता था कि इस उत्तर ने मुझे सबसे अधिक मदद की।
जे किलेन

1
मुझे टिप्पणी के बजाय इसका उत्तर देने में कुछ भी गलत नहीं लगता। Upvoted। मुझे लगता है कि डाउनवोटर्स केवल लापरवाही से पढ़ रहे हैं (जैसे अधिकांश प्रश्न क्लोजर्स?; पी)।
इकोनॉस्टल

-1

@ Szymon-lipi (ski (सिजमन लिपिस्की) द्वारा दिए गए उत्तर में, निष्पादन विधि मेरे लिए काम नहीं करती थी। यह एक MySQL सिंटैक्स त्रुटि फेंक रहा था।

MySQL सिंटैक्स जो मेरे लिए काम करता है वह यह है।

execute "ALTER TABLE mytable CHANGE `column_name` `column_name` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP"

तो माइग्रेशन स्क्रिप्ट में डेटाइम कॉलम के लिए डिफ़ॉल्ट मान सेट करने के लिए निम्नानुसार किया जा सकता है:

def up
  create_table :foo do |t|
    t.datetime :starts_at, :null => false
  end

  execute "ALTER TABLE `foo` CHANGE `starts_at` `starts_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP"
end
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.