#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
Очевидно, что это позволяет выполнить работу, но, очевидно, не очень надежно, поэтому вы можете столкнуться с ошибками.