[Ruby-on-rails] ActiveRecord में बनाने पर आईडी ओवरराइड करना


Answers

प्रयत्न

a_post = Post.new do |p| 
  p.id = 10
  p.title = 'Test'
  p.save
end

जो आपको वह दिखाना चाहिए जो आप खोज रहे हैं।

Question

क्या मॉडल के आईडी मान को ओवरराइड करने का कोई तरीका है? कुछ इस तरह:

Post.create(:id => 10, :title => 'Test')

आदर्श होगा, लेकिन जाहिर है काम नहीं करेगा।




रेल के लिए 4:

Post.create(:title => 'Test').update_column(:id, 10)

अन्य रेल 4 उत्तरों मेरे लिए काम नहीं किया। रेल कंसोल का उपयोग करते समय उनमें से कई बदल गए, लेकिन जब मैंने MySQL डेटाबेस में मानों की जांच की, तो वे अपरिवर्तित बने रहे। अन्य उत्तरों केवल कभी-कभी काम करते थे।

कम से कम MySQL के लिए, ऑटो increment id संख्या के नीचे एक id असाइन नहीं करता है जब तक आप update_column उपयोग नहीं करते। उदाहरण के लिए,

p = Post.create(:title => 'Test')
p.id
=> 20 # 20 was the id the auto increment gave it

p2 = Post.create(:id => 40, :title => 'Test')
p2.id
=> 40 # 40 > the next auto increment id (21) so allow it

p3 = Post.create(:id => 10, :title => 'Test')
p3.id
=> 10 # Go check your database, it may say 41.
# Assigning an id to a number below the next auto generated id will not update the db

यदि आप new + save लिए create को बदलते create तो आपको अभी भी यह समस्या होगी। id मैन्युअल रूप से बदलना जैसे p.id = 10 भी इस समस्या का उत्पादन करता है।

आम तौर पर, मैं id को बदलने के लिए update_column का उपयोग करता हूं, भले ही यह अतिरिक्त डेटाबेस क्वेरी खर्च करे, क्योंकि यह हर समय काम करेगा। यह एक त्रुटि है जो आपके विकास वातावरण में दिखाई नहीं दे सकती है, लेकिन यह कहकर काम कर रही है कि चुपचाप अपने उत्पादन डेटाबेस को दूषित कर सकती है।




पोस्टग्रेस्क्ल 9.5.3 के साथ रेल 4.2.1 में, Post.create(:id => 10, :title => 'Test') तब तक काम करता है जब आईडी = 10 के साथ कोई पंक्ति नहीं है।




यह मामला एक समान मुद्दा है जिसे id को एक प्रकार की कस्टम तिथि के साथ ओवरराइट करना आवश्यक था:

# in app/models/calendar_block_group.rb
class CalendarBlockGroup < ActiveRecord::Base
...
 before_validation :parse_id

 def parse_id
    self.id = self.date.strftime('%d%m%Y')
 end
...
end

और तब :

CalendarBlockGroup.create!(:date => Date.today)
# => #<CalendarBlockGroup id: 27072014, date: "2014-07-27", created_at: "2014-07-27 20:41:49", updated_at: "2014-07-27 20:41:49">

कॉलबैक ठीक काम करता है।

शुभ लाभ!।




Post.create!(:title => "Test") { |t| t.id = 10 }

यह मुझे ऐसी चीज के रूप में नहीं रोकता है जो आप सामान्य रूप से करना चाहते हैं, लेकिन यदि आपको किसी निश्चित सेट के साथ तालिका को पॉप्युलेट करने की आवश्यकता है तो यह बहुत अच्छी तरह से काम करता है (उदाहरण के लिए जब रेक रेक का उपयोग करके डिफ़ॉल्ट बनाते हैं) और आप ऑटो-इंक्रिमेंटिंग को ओवरराइड करना चाहते हैं (ताकि जब भी आप कार्य को चलाते हैं तो टेबल एक ही आईडी के साथ पॉप्युलेट हो जाता है):

post_types.each_with_index do |post_type|
  PostType.create!(:name => post_type) { |t| t.id = i + 1 }
end



जैसा कि जेफ बताते हैं, आईडी व्यवहार करती है जैसे कि attr_protected है। इसे रोकने के लिए, आपको डिफ़ॉल्ट संरक्षित विशेषताओं की सूची को ओवरराइड करने की आवश्यकता है। कहीं भी ऐसा करने से सावधान रहें कि विशेषता जानकारी बाहर से आ सकती है। आईडी फ़ील्ड किसी कारण से डिफ़ॉल्ट रूप से संरक्षित है।

class Post < ActiveRecord::Base

  private

  def attributes_protected_by_default
    []
  end
end

(ActiveRecord 2.3.5 के साथ परीक्षण किया गया)