ActiveRecord实例设置

时间:2011-11-10 19:47:56

标签: ruby-on-rails activerecord

我很好奇是否有宝石或每个模型设置的方式。例如,用户首选项。

我希望每个模型都有默认值(比如一个类属性),但是可以定义(在另一个表上!我不希望我的模型上有可序列化的字段)。

例如:

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

UserSetting会有一个模型,其模式为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

2 个答案:

答案 0 :(得分:1)

我将使用User has_many UserSettings实现此功能,UserSetting是user_id,key和value。 也许有一种方便的方法来访问它们,如下:

class User < ActiveRecord::Base
  has_many :user_settings
  def setting(key)
    user_settings.where(:key => key).first.try(&: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 :(得分:0)

has_settings宝石似乎是这样做的,但似乎没有保持唉。 This fork至少支持Rails 3。

如果找不到适合自己需要的宝石,可以通过简单的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) &&
          @settings[key] = new_val                && # 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

显然这可以完成工作,但显然不是很强大,所以你可能会遇到陷阱。