Настройки экземпляра ActiveRecord

#ruby-on-rails #activerecord

#ruby-on-rails #activerecord

Вопрос:

Мне любопытно, есть ли драгоценный камень или способ выполнения настроек для каждой модели. Например, пользовательские настройки.

Я хотел бы иметь значения по умолчанию для каждой модели (скажем, атрибут класса), но определяемые (в другой таблице! Мне не нужно сериализуемое поле в моей модели).

Например:

 user = User.find(1)
user.settings.newsletter # => true
  

Была бы модель для настройки пользователя, которая имела бы схему key => string, value => string, type => string (логическое значение, дата, строка и т.д.)

Обновить:

Вот мое решение этого в конце. Поддерживает типы значений для настроек (логическое значение, время и т.д.)

     def setting(key, whiny=true)
      s = user_settings.where(:key => key).first

      if s
        case s.value_type
        when 'Boolean'
          s.value.to_i == 1
        when 'Time'
          Time.parse(s.value)
        else
          s.value
        end
      else
        if whiny
          raise NameError, "Setting key #{key} does not exist for #{name}."
        else
          nil
        end
      end
    end
  

Ответ №1:

Я бы реализовал это с помощью пользовательских настроек пользователя has_many, а пользовательский параметр — это идентификатор пользователя, ключ и значение. Может быть, есть удобный способ доступа к ним, например:

 class User < ActiveRecord::Base
  has_many :user_settings
  def setting(key)
    user_settings.where(:key => key).first.try(amp;:value)
  end
end

class UserSetting < ActiveRecord::Base
  belongs_to :user
end
  

Затем вы можете перейти

 user = User.find(1)
user.setting('newsletter') # => true/false (or nil if that setting doesn't exist)
  

Комментарии:

1. Выглядит великолепно, просто должно быть .try(:value)

2. @RobertRoss Упс, да. Исправлено. Спасибо.

3. Обновленный исходный пост, если вас интересует конечный результат.

Ответ №2:

has_settings Кажется, что gem делает это, но, увы, похоже, что он не поддерживается. Этот форк поддерживает Rails 3, по крайней мере.

Если вы не можете найти gem, который соответствует вашим потребностям, его довольно просто реализовать самостоятельно с помощью простого отношения has_many и небольшой магии расширения ассоциации, например (непроверенный):

 class User < ActiveRecord::Base
  has_many :settings do
    # association extension
    def method_missing name, *args
      key = name.to_s

      # setter
      if key.ends_with? '='
        key.chop!
        new_val = args.first

        setting = find_or_create_by_key key

        setting.update_attribute(:value, new_val) amp;amp;
          @settings[key] = new_val                amp;amp; # KISS cache
          true  # to mirror the semantics of update_attribute

      # getter
      elsif @settings.has_key? name # is it cached?
        @settings[name]

      elsif setting = where(:key => name).select(:value).first
        @settings[name] = setting.value # KISS cache again

      else
        super
      end

    end
  end

end

class Setting < ActiveRecord::Base
  belongs_to :user

  serialize :value # so we don't have to bother with an extra :type attribute
end

class CreateSettings < ActiveRecord::Migration
  def up
    create_table :settings do |t|
      t.references :user
      t.string :key
      t.string :value
    end
  end

  def down
    remove_table :settings
  end
end
  

Очевидно, что это позволяет выполнить работу, но, очевидно, не очень надежно, поэтому вы можете столкнуться с ошибками.