блокировать создание нескольких объектов класса

Как ограничить объект любого класса одним. Мой класс выглядит так:

class Speaker
  include Mongoid::Document
  field :name, :type => String
end

Я просто хочу, чтобы один экземпляр динамика. Одним из способов было бы добавить проверку, которая будет проверять количество объектов, уже присутствующих в классе Speaker. Есть ли рубиновый способ сделать это?


person Prabesh Shrestha    schedule 19.08.2011    source источник
comment
Если вам нужен только один динамик, имеет ли смысл хранить его в db. Я бы извлек его в файл конфигурации.   -  person rubish    schedule 19.08.2011
comment
@rubish Мне нужно разрешить администратору изменить значение. Как бы я сделал это эффективно, если бы я не сохранял его в базе данных?   -  person Prabesh Shrestha    schedule 20.08.2011
comment
как насчет валидации, как я писал ниже?   -  person Sławosz    schedule 22.08.2011
comment
@Slawosz Я думаю, что это лучшее, что я могу сделать прямо сейчас. Просто жду, если я смогу найти лучшее решение.   -  person Prabesh Shrestha    schedule 22.08.2011


Ответы (6)


Как насчет использования модуля Singleton?

person Frank Schmitt    schedule 19.08.2011
comment
как изменить значение. Я также хочу, чтобы значение сохранялось. - person Prabesh Shrestha; 19.08.2011
comment
Если значение меняет ПОЛЬЗОВАТЕЛЬ-администратор, то этот ответ имеет запах кода. В противном случае см. stackoverflow.com/questions/137975/ для длительных дебатов. - person Alec Wenzowski; 01.09.2011

В этом случае я бы написал правильную проверку:

validate :only_one

def only_one
   errors.add(:base, "Only one Speaker can exist") if self.count > 0 
end
person Sławosz    schedule 19.08.2011
comment
Это не удастся, если запись уже существует и вы ее обновляете. - person Steven Soroka; 26.08.2011
comment
Хорошая мысль, но вы можете написать: validate :only_one, :on =› :create - person Sławosz; 26.08.2011
comment
NoMethodError: undefined method `count` for #<Speaker:0x28f18e1d> - self в контексте метода проверки является экземпляром, поэтому self.count необходимо изменить на Speaker.count или self.class.count. - person Abe Voelker; 03.04.2013

Я рекомендую использовать класс/модуль, предназначенный для хранения значений конфигурации, а не накладывать свои собственные поверх ванильной модели ActiveRecord.

Я использую старую копию плагина rails-settings с некоторыми пользовательскими модификациями (он до сих пор отлично работает в Рельс 3). На Github также есть несколько вариантов предложений, так что не стесняйтесь смотреть и выбирать.

person Jeremy Weathers    schedule 24.08.2011

Почему бы не предоставить объект Speaker по умолчанию и просто не предоставить действия контроллера для создания или удаления?

Кажется, самое простое решение на сегодняшний день.

person Steven Soroka    schedule 26.08.2011

Я вижу, вы используете Mongoid.

Запрошенная вами функциональность недоступна при использовании монгоидных проверок.

Поэтому вам нужно будет написать свой собственный. before_validation — это поддерживаемый обратный вызов и связанные Speaker.all.count методы доступны для вашей модели.

class Speaker
  include Mongoid::Document
  field :name, :type => String
  before_validation(:ensure_has_only_one_record, :on => :create)
  def ensure_has_only_one_record
    self.errors.add :base, "There can only be one Speaker." if Speaker.all.count > 0
  end
end

Однако рекомендуется поместить все параметры ключа/значения в одну таблицу< /а>.

person Alec Wenzowski    schedule 27.08.2011

Используя модуль Singleton и небольшое переопределение его методов, я считаю, что это работает и является потокобезопасным (на ruby ​​1.8):

class Speaker 

  include Singleton
  include Mongoid::Document
  field :name, :type => String

  @@singleton__instance__ = nil
  @@singleton__mutex__ = Mutex.new

  def self.instance
    return @@singleton__instance__ if @@singleton__instance__
    @@singleton__mutex__.synchronize {
      return @@singleton__instance__ if @@singleton__instance__
      @@singleton__instance__ = self.first
      @@singleton__instance__ ||= new()
    }
    @@singleton__instance__
  end

  def destroy
    @@singleton__mutex__.synchronize {
      super
      @@singleton__instance__ = nil
    }
  end

end
person andersonvom    schedule 27.08.2011
comment
Спасибо что подметил это. В Ruby 1.8 это было не так. - person andersonvom; 08.04.2013