रूबी ऑन रेल्स: वैश्विक स्थिरांक कहां परिभाषित करें?


213

मैं अभी रेल्स वेब पर अपनी पहली रूबी के साथ शुरुआत कर रहा हूं। मुझे विभिन्न मॉडलों, विचारों, नियंत्रकों और इसी तरह का एक गुच्छा मिला है।

मैं वास्तव में वैश्विक स्थिरांक की परिभाषाओं को छड़ी करने के लिए एक अच्छी जगह ढूंढना चाहता हूं, जो मेरे पूरे ऐप पर लागू होती है। विशेष रूप से, वे मेरे मॉडल के तर्क में, और मेरे विचारों में लिए गए निर्णयों में दोनों को लागू करते हैं। मुझे इन परिभाषाओं को रखने के लिए कोई भी DRY जगह नहीं मिल रही है जहाँ वे मेरे सभी मॉडलों के लिए उपलब्ध हैं और मेरे सभी विचारों में भी।

एक विशिष्ट उदाहरण लेने के लिए, मुझे एक निरंतरता चाहिए COLOURS = ['white', 'blue', 'black', 'red', 'green']। यह सभी जगह पर, मॉडल और दृश्य दोनों में उपयोग किया जाता है। मैं इसे केवल एक जगह पर कैसे परिभाषित कर सकता हूं ताकि यह सुलभ हो?

मैंने क्या कोशिश की है:

  • Model.rb फ़ाइल में लगातार वर्ग चर जो वे सबसे अधिक संबंधित हैं, जैसे कि @@COLOURS = [...]। लेकिन मुझे इसे परिभाषित करने के लिए एक समझदार तरीका नहीं मिल रहा है ताकि मैं अपने विचारों को लिख Card.COLOURSपाऊं जैसे कुछ कीचड़ भरे Card.first.COLOURS
  • मॉडल पर एक विधि, कुछ ऐसी def colours ['white',...] endही समस्या।
  • Application_helper.rb में एक विधि - यह वही है जो मैं अभी तक कर रहा हूं, लेकिन सहायक केवल मॉडल में नहीं, विचारों में सुलभ हैं
  • मुझे लगता है कि मैंने application.rb या environment.rb में कुछ आज़माया होगा, लेकिन वे वास्तव में सही नहीं लगते हैं (और वे काम नहीं करते हैं)

क्या मॉडल और विचारों दोनों से सुलभ होने के लिए कुछ भी परिभाषित करने का कोई तरीका नहीं है? मेरा मतलब है, मुझे पता है कि मॉडल और विचार अलग-अलग होने चाहिए, लेकिन निश्चित रूप से कुछ डोमेन में कई बार समान डोमेन-विशिष्ट ज्ञान को संदर्भित करने की आवश्यकता होगी?



मैं सराहना करता हूं कि यह वास्तव में देर हो चुकी है, लेकिन अन्य पाठकों के लिए मुझे आश्चर्य है कि आपने उन्हें केवल अपने मॉडल में परिभाषित क्यों नहीं किया और अपने नियंत्रकों का उपयोग करके उन्हें अपने विचारों के पास भेज दिया। इस तरह, आपको नियंत्रक / दृश्य और मॉडल / दृश्य के बीच निर्भरता बनाने के बजाय चिंताओं का एक अलग अलगाव होगा।
टॉम टॉम

2
@TomTom: इन स्थिरांक को प्रत्येक दृश्य में पास करें और सहायक की आवश्यकता है? दूसरे शब्दों में, नियंत्रक को इस बात से अवगत कराएं कि किन विचारों को किस स्थिरांक की आवश्यकता है? ऐसा लगता है कि एमवीसी का उल्लंघन अधिक है।
एलेक्सा

जवाबों:


229

यदि आपका मॉडल वास्तव में स्थिरांक के लिए "ज़िम्मेदार" है, तो आपको उन्हें वहाँ रहना चाहिए। आप एक नई वस्तु उदाहरण बनाए बिना उन्हें एक्सेस करने के लिए क्लास मेथड बना सकते हैं:

class Card < ActiveRecord::Base
  def self.colours
    ['white', 'blue']
  end
end

# accessible like this
Card.colours

वैकल्पिक रूप से, आप वर्ग चर और एक सहायक बना सकते हैं। हालाँकि यह हतोत्साहित किया जाता है क्योंकि वर्ग चर, वंशानुक्रम और बहु-थ्रेड वातावरण में आश्चर्यचकित कर सकते हैं।

class Card < ActiveRecord::Base
  @@colours = ['white', 'blue']
  cattr_reader :colours
end

# accessible the same as above

उपरोक्त दो विकल्प आपको आवश्यक होने पर एक्सेसर विधि के प्रत्येक आह्वान पर दिए गए सरणी को बदलने की अनुमति देते हैं। यदि आपके पास वास्तव में अपरिवर्तनीय स्थिरांक है, तो आप इसे मॉडल वर्ग पर भी परिभाषित कर सकते हैं:

class Card < ActiveRecord::Base
  COLOURS = ['white', 'blue'].freeze
end

# accessible as
Card::COLOURS

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

# put this into config/initializers/my_constants.rb
COLOURS = ['white', 'blue'].freeze

नोट: जब हम ऊपर स्थिरांक को परिभाषित करते हैं, तो अक्सर हम freezeसरणी के लिए चाहते हैं । अन्य कोड को बाद में (अनजाने में) जैसे नए तत्व को जोड़कर सरणी को संशोधित करने से रोकता है। एक बार जब कोई वस्तु जमी होती है, तो उसे अब और नहीं बदला जा सकता है।


1
आपका बहुत बहुत धन्यवाद। ऐसा लगता है कि मैं कक्षा के तरीकों को परिभाषित करने के लिए रूबी वर्ग-फू को याद कर रहा था। लेकिन मुझे वास्तव में इस मामले में शुरुआती विकल्प पसंद है, क्योंकि रंगों का उपयोग कई मॉडल और विचारों में किया जाता है। बहुत धन्यवाद!
एलेक्सा

21
यदि config/initializers/my_constants.rbमार्ग जा रहा है , तो सर्वर को पुनः आरंभ करने के लिए याद रखें:touch tmp/restart.txt
user664833

4
def self.coloursउदाहरण के आदर्श नहीं है। हर बार जब आप कॉल करते हैं def self.colours, तो सरणी का एक नया उदाहरण वापस आ जाएगा#freezeइस मामले में मदद नहीं करेगा। सर्वोत्तम अभ्यास यह है कि इसे रूबी स्थिरांक घोषित करें, जिस स्थिति में आप हमेशा उसी वस्तु को वापस प्राप्त करेंगे।
ज़ब्बा

@ ज़ब्बा यदि किसी एकल सरणी का आवंटन आपके ऐप के लिए ध्यान देने योग्य अंतर बनाता है, तो आपको शायद रूबी का उपयोग पहली जगह में नहीं करना चाहिए ... उन्होंने कहा, एक विधि का उपयोग करके और हर बार पूरी तरह से नई सरणी वापस करने पर एक युगल हो सकता है फायदे के: (1) यह निकटतम चीज है जिसे आप रूबी में अपनी कक्षा की सीमा पर अपरिवर्तनीय वस्तुओं की ओर ले जा सकते हैं और (2) आप अंतर्निहित स्थिति के आधार पर बाद में वापसी मूल्य को अनुकूलित करने की संभावना के साथ अपनी कक्षा में एक समान इंटरफ़ेस रखते हैं (उदाहरण के लिए) इंटरफेस को बदले बिना डीबी से रंग पढ़ना)।
होल्गर बस २

@ होलगर बस, आपके कम से कम एक लक्ष्य को अभी भी एक स्थिर का उपयोग करके प्राप्त किया जा सकता है: class Card; COLOURS = ['white', 'blue'].freeze; def self.colours; COLOURS; end; endयह कहा गया है, किसी भी भाषा में एक सरणी का आवंटन संभावित समस्याग्रस्त हो सकता है; एक के लिए, यह बिना किसी (अच्छे) कारण के मेमोरी का उपयोग कर रहा है। यदि एक DB से लोड हो रहा है, और मूल्य को कैश करना चाहते हैं, तो एक वर्ग उदाहरण चर का उपयोग भी कर सकता है, जिसे def self.coloursविधि का उपयोग करके आलसी लोड किया जा सकता है । हालांकि अपरिवर्तनीय पहलू के बारे में सहमत हैं।
ज़ब्बा

70

कुछ विकल्प:

एक स्थिरांक का उपयोग करना:

class Card
  COLOURS = ['white', 'blue', 'black', 'red', 'green', 'yellow'].freeze
end

कक्षा उदाहरण चर का उपयोग करके आलसी लोड:

class Card
  def self.colours
    @colours ||= ['white', 'blue', 'black', 'red', 'green', 'yellow'].freeze
  end
end

यदि यह वास्तव में वैश्विक स्थिरांक है ( हालांकि, इस प्रकृति के वैश्विक स्थिरांक से बचें ), तो आप config/initializers/my_constants.rbउदाहरण के लिए एक शीर्ष-स्तरीय स्थिरांक लगाने पर भी विचार कर सकते हैं ।


1
हे। निष्पक्ष टिप्पणी - टाइपिंग-से-मेमोरी में त्रुटि जब मेरा उदाहरण :) टिप के लिए धन्यवाद!
एलेक्सा

2
तब extendवर्ग में मॉड्यूल तो यह साथ उपलब्ध होगा Card.COLOURS
अपरिभाषित

जब extendइसका उपयोग मेरे लिए काम नहीं कर रहा है। जब includeमैं का उपयोग कर सकते हैं जैसे:Card::COLOURS
Abhi

आपको निश्चित रूप से इसके तहत जगह नहीं देनी चाहिए /models। यदि आप एक इनिशियलाइज़र बनाते हैं तो यह बहुत बेहतर है।
linkyndy

@linkyndy मैं कहूंगा कि इसे नीचे रखना ठीक है /models, लेकिन केवल अगर इसके मॉड्यूल के अंदर, जैसे module Constants; COLOURS = ...; endकि एक फ़ाइल में models/constants.rb
केल्विन

57

रेल 4.2 के रूप में, आप config.xसंपत्ति का उपयोग कर सकते हैं:

# config/application.rb (or config/custom.rb if you prefer)
config.x.colours.options = %w[white blue black red green]
config.x.colours.default = 'white'

जो इस प्रकार उपलब्ध होगा:

Rails.configuration.x.colours.options
# => ["white", "blue", "black", "red", "green"]
Rails.configuration.x.colours.default
# => "white"

कस्टम कॉन्फ़िगरेशन लोड करने का एक और तरीका:

# config/colours.yml
default: &default
  options:
    - white
    - blue
    - black
    - red
    - green
  default: white
development:
  *default
production:
  *default
# config/application.rb
config.colours = config_for(:colours)
Rails.configuration.colours
# => {"options"=>["white", "blue", "black", "red", "green"], "default"=>"white"}
Rails.configuration.colours['default']
# => "white"

रेल 5 और 6 में , आप configurationकस्टम कॉन्फ़िगरेशन के लिए सीधे ऑब्जेक्ट का उपयोग कर सकते हैं , इसके अलावा config.x। हालाँकि, इसका उपयोग केवल गैर-नेस्टेड कॉन्फ़िगरेशन के लिए किया जा सकता है:

# config/application.rb
config.colours = %w[white blue black red green]

यह इस प्रकार उपलब्ध होगा:

Rails.configuration.colours
# => ["white", "blue", "black", "red", "green"]

2
मुझे Rails.configuration.coloursसबसे अच्छा लगता है (हालांकि मेरी इच्छा है कि यह इतना लंबा न हो)
टॉम रॉसी

@TomRossi मैं सहमत हूँ, जैसे configके रूप में अच्छा है configuration। हम कुछ बिंदु पर एक शॉर्टकट प्राप्त करने की उम्मीद कर सकते हैं :)
हैल ürzgür

यह अभी भी 6 में सबसे अच्छा तरीका है कि 6 को लगातार कई नियंत्रकों में साझा किया जा सकता है? जवाब के लिए धन्यवाद!
क्रैशलॉट

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

@ HalilÖzgür उत्तर के लिए धन्यवाद। आप एक सामान्य पूर्वज में स्थिरांक कैसे परिभाषित करते हैं?
Crashalot

18

यदि एक से अधिक वर्ग में एक स्थिरांक की आवश्यकता होती है, तो मैं इसे सभी कैप्‍स में हमेशा कॉन्‍फ़िगरेशन / इनिशियलाइज़र / कंटेंट.बीआर में डाल देता हूं (नीचे राज्यों की सूची छंटनी होती है)।

STATES = ['AK', 'AL', ... 'WI', 'WV', 'WY']

वे इस तरह से मॉडल कोड को छोड़कर आवेदन के माध्यम से उपलब्ध हैं:

    <%= form.label :states, %>
    <%= form.select :states, STATES, {} %>

किसी मॉडल में निरंतर का उपयोग करने के लिए, निरंतर उपलब्ध करने के लिए attr_accessor का उपयोग करें।

class Customer < ActiveRecord::Base
    attr_accessor :STATES

    validates :state, inclusion: {in: STATES, message: "-- choose a State from the drop down list."}
end

1
अच्छा, config/initializers/constants.rbशायद एक बेहतर विकल्प होगा
आदित सक्सेना

मैं भी इसका उपयोग करता हूं, लेकिन हाल ही में इस मुद्दे पर आया कि ये स्थिरांक अनुप्रयोग में सुलभ नहीं हैं।
आरबी

मेरे स्थिरांक काम कर रहे थे, लेकिन किसी कारण से बंद हो गया (जैसा कि किसी तरह मेरी फ़ाइल इनिशियलाइज़र से बाहर चली गई)। इस उत्तर की जाँच करने के बाद मैंने बारीकी से देखा और उन्हें वापस ले लिया और अब काम कर रहा था। साभार
मुहम्मद नासिर शमशाद

मुझे नहीं लगता कि attr_accessor की जरूरत है। क्या आप किसी विशेष रेल संस्करण के बारे में बात कर रहे हैं?
मयूरेश श्रीवास्तव

16

एप्लिकेशन-वाइड सेटिंग के लिए और वैश्विक स्थिरांक के लिए मैं Settingslogic का उपयोग करने की सलाह देता हूं । यह सेटिंग YML फ़ाइल में संग्रहीत की जाती है और इसे मॉडल, दृश्य और नियंत्रक से एक्सेस किया जा सकता है। इसके अलावा, आप अपने सभी वातावरणों के लिए अलग-अलग सेटिंग्स बना सकते हैं:

  # app/config/application.yml
  defaults: &defaults
    cool:
      sweet: nested settings
    neat_setting: 24
    awesome_setting: <%= "Did you know 5 + 5 = #{5 + 5}?" %>

    colors: "white blue black red green"

  development:
    <<: *defaults
    neat_setting: 800

  test:
    <<: *defaults

  production:
    <<: *defaults

कहीं न कहीं देखने के लिए (मैं इस तरह के सामान के लिए सहायक तरीके पसंद करता हूं) या एक मॉडल में, उदाहरण के लिए, रंगों की सरणी Settings.colors.split(/\s/)। यह बहुत लचीला है। और आपको बाइक का आविष्कार करने की आवश्यकता नहीं है।


7

एक वर्ग विधि का उपयोग करें:

def self.colours
  ['white', 'red', 'black']
end

फिर Model.coloursउस सरणी को वापस करेगा। वैकल्पिक रूप से, एक इनिशलाइज़र बनाएं और नामपट्स संघर्षों से बचने के लिए स्थिरांक को एक मॉड्यूल में लपेटें।


4

एक स्थान पर सभी को स्थिर रखने की कोशिश करें, अपने आवेदन में मैंने शुरुआती के अंदर स्थिरांक फ़ोल्डर बनाया है जो निम्नानुसार है:

यहां छवि विवरण दर्ज करें

और मैं आमतौर पर इन फ़ाइलों में सभी को स्थिर रखता हूं।

आपके मामले में आप स्थिरांक फ़ोल्डर के तहत फ़ाइल बना सकते हैं colors_constant.rb

colors_constant.rb

यहां छवि विवरण दर्ज करें

सर्वर को पुनरारंभ करने के लिए मत भूलना


1
यह सबसे अच्छा जवाब है जो मुझे यहां मिला है। धन्यवाद।
प्रॉमिस

3

एक अन्य विकल्प, यदि आप अपने स्थिरांक को एक स्थान पर परिभाषित करना चाहते हैं:

module DSL
  module Constants
    MY_CONSTANT = 1
  end
end

लेकिन फिर भी उन्हें पूरी तरह से योग्य तरीके से उपयोग किए बिना विश्व स्तर पर दिखाई देते हैं:

DSL::Constants::MY_CONSTANT # => 1
MY_CONSTANT # => NameError: uninitialized constant MY_CONSTANT
Object.instance_eval { include DSL::Constants }
MY_CONSTANT # => 1

3

अनुप्रयोग-व्यापी वैश्विक स्थिरांक रखने का एक सामान्य स्थान अंदर है config/application

module MyApp
  FOO ||= ENV.fetch('FOO', nil)
  BAR ||= %w(one two three)

  class Application < Rails::Application
    config.foo_bar = :baz
  end
end

2

मेरे रेल कार्यक्रम में आम तौर पर एक 'लुकअप' मॉडल / टेबल होता है और इसे स्थिरांक के लिए उपयोग करते हैं। यदि विभिन्न वातावरण के लिए स्थिरांक अलग होने जा रहे हैं तो यह बहुत उपयोगी है। इसके अलावा, यदि आपके पास उन्हें विस्तारित करने की योजना है, तो आप बाद की तारीख में 'पीला' जोड़ना चाहते हैं, आप बस लुकअप टेबल में एक नई पंक्ति जोड़ सकते हैं और इसके साथ किया जा सकता है।

यदि आप व्यवस्थापक को इस तालिका को संशोधित करने की अनुमति देते हैं, तो वे रखरखाव के लिए आपके पास नहीं आएंगे। :) DRY।

मेरा माइग्रेशन कोड इस प्रकार है:

class CreateLookups < ActiveRecord::Migration
  def change
    create_table :lookups do |t|
      t.string :group_key
      t.string :lookup_key
      t.string :lookup_value
      t.timestamps
    end
  end
end

मैं इसे पूर्व-आबाद करने के लिए सीड्रेस्ब का उपयोग करता हूं।

Lookup.find_or_create_by_group_key_and_lookup_key_and_lookup_value!(group_key: 'development_COLORS', lookup_key: 'color1', lookup_value: 'red');

1

वैश्विक चर को config/initializersनिर्देशिका में घोषित किया जाना चाहिए

COLOURS = %w(white blue black red green)

धन्यवाद! दूसरों ने इसका उल्लेख पहले ही कर दिया है। यह होल्गर के उत्तर की अंतिम पंक्ति है, और ज़ब्बा ने इस तकनीक का भी उल्लेख किया है, हालांकि ज़ब्बा ने इसके खिलाफ चेतावनी दी है।
एलेक्सजेंट

0

अपनी स्थिति के अनुसार, आप कुछ पर्यावरण चर भी परिभाषित कर सकते हैं, और इसे ENV['some-var']माणिक कोड के माध्यम से प्राप्त कर सकते हैं, यह समाधान आपके लिए उपयुक्त नहीं हो सकता है, लेकिन मुझे आशा है कि यह दूसरों की मदद कर सकता है।

उदाहरण: यदि आप अलग अलग फ़ाइलें बना सकते हैं .development_env, .production_env, .test_envजाँच इस पीढ़ी है, और अपने आवेदन के वातावरण के अनुसार इसे लोड dotenv-रेल जो आपके लिए इस को स्वचालित।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.