How to implement a singleton model

后端 未结 13 1320
余生分开走
余生分开走 2020-12-24 12:36

I have a site in rails and want to have site-wide settings. One part of my app can notify the admin by SMS if a specific event happens. This is an example of a feature that

相关标签:
13条回答
  • 2020-12-24 12:38

    I will put a few remarks to the previous answers:

    • no need for a separate field for uniq index, we can put the constraint on the id field. Since we should have id field in a Rails app anyway, it's a good tradeoff
    • no need special validations on the model and explicit ID assignment, it's enough to put default value on the column

    If we apply these modifications, the solution becomes very easy:

    # migration
    create_table :settings, id: false do |t|
      t.integer :id, null: false, primary_key: true, default: 1, index: {unique: true}
      t.integer :setting1
      t.integer :setting2
      ...
    end
    
    # model
    class Settings < ApplicationRecord
      def self.instance
        first_or_create!(...)
      end  
    end
    
    0 讨论(0)
  • 2020-12-24 12:39

    I assume to use inheriting column type with uniq constraint.

    # miragtion
    class CreateSingletonRecords < ActiveRecord::Migration[5.2]
      create_table :balance_holders do |t|
        t.string :type
        t.index :type, unique: true
    
        t.timestamps
      end
    end
    

    several methods in you parent class:

    class SingletonRecord < ApplicationRecord
      class << self
        def instance
          @singleton__instance__
        end
    
        def load_record(params = {})
          @singleton__instance__ = find_or_create_by!(params)
        end
      end
    
      load_record
    
      validates :type, uniqueness: true
    end
    

    After it you can forever use single record for singleton model class. Your instance will be loaded or created one time durring model class loaded.

    0 讨论(0)
  • 2020-12-24 12:41

    I am not sure I'd waste the database/ActiveRecord/Model overhead for such a basic need. This data is relatively static (I am assuming) and on the fly calculations aren't necessary (including database lookups).

    Having said that, I'd recommend you define a YAML file with your site-wide settings and define an initializer file that loads the settings into a constant. You won't have nearly as many of the unnecessary moving parts.

    There is no reason that data couldn't just sit in memory and save you a ton of complexity. Constants are available everywhere, and they don't need to be initialized or instantiated. If its absolutely critical that you utilize a class as a singleton, I'd recommend doing these two things:

    1. undef the initialize/new method
    2. define only self.* methods that way it is not possible for you to maintain a state
    0 讨论(0)
  • 2020-12-24 12:42

    I know this is an old thread, but I just needed the same thing and found out that there's a gem for this: acts_as_singleton.

    Installation instructions are for Rails 2, but it works great with Rails 3 too.

    0 讨论(0)
  • 2020-12-24 12:43

    Using has_many :contacts doesn't mean you need a model. has_many does some magic, but in the end it's just adds some method with a specified contract. There's no reason why you can't implement those methods (or some subset that you need) to make your model behave like it has_many :contacts yet not actually use an ActiveRecord model (or model at all) for Contact.

    0 讨论(0)
  • 2020-12-24 12:44

    You can do it like this:

     class Config < ApplicationRecord
      def self.instance
        Config.first || Config.create!
      end
     end
    
    0 讨论(0)
提交回复
热议问题