Ruby on rails Rails自定义元模型?

Ruby on rails Rails自定义元模型?,ruby-on-rails,ruby-on-rails-3,metamodel,Ruby On Rails,Ruby On Rails 3,Metamodel,我希望能够将“元”信息添加到模型中,基本上是用户定义的字段。例如,让我们设想一个用户模型: 我为名字、姓氏、年龄、性别定义字段 我希望用户能够定义一些“元信息”,基本上进入他们的个人资料页面并共享其他信息。因此,一个用户可能想添加“嗜好”、“职业”和“家乡”,另一个用户可能想添加“嗜好”和“教育” 因此,我希望能够为这类东西提供一个标准视图,例如,在视图中,我可以做一些类似(在HAML中)的事情: 通过这种方式,我可以确保信息始终显示,而不仅仅是向用户提供一个标记文本框,用户可以使用所有不同的格

我希望能够将“元”信息添加到模型中,基本上是用户定义的字段。例如,让我们设想一个用户模型:

我为名字、姓氏、年龄、性别定义字段

我希望用户能够定义一些“元信息”,基本上进入他们的个人资料页面并共享其他信息。因此,一个用户可能想添加“嗜好”、“职业”和“家乡”,另一个用户可能想添加“嗜好”和“教育”

因此,我希望能够为这类东西提供一个标准视图,例如,在视图中,我可以做一些类似(在HAML中)的事情:

通过这种方式,我可以确保信息始终显示,而不仅仅是向用户提供一个标记文本框,用户可以使用所有不同的格式

我还希望能够点击meta并看到其他用户给出了相同的东西,因此在上面的示例中,两个用户都定义了“嗜好”,如果能够说我想看到有共同爱好的用户,那就更好了,或者我想看到嗜好为\uuuuuu的用户

所以,由于我不知道用户需要预先定义哪些字段,那么提供这种功能有哪些选项呢

有没有一个gem可以处理像这样的模型上的自定义元信息,或者至少类似的?有人遇到过这种问题吗?如果是,你是如何解决的


谢谢

如果允许每个用户定义自己的属性,一个选项可能是有一个包含三列的表:user\u id、attribute\u name、attribute\u value。它可能看起来像:

| user_id | attribute_name | attribute_value |
| 2       | hobbies        | skiing          |
| 2       | hobbies        | running         |
| 2       | pets           | dog             |
| 3       | hobbies        | skiing          |
| 3       | colours        | green           |
此表将用于查找具有相同爱好/宠物等的其他用户

出于性能原因(此表将变得越来越大),您可能希望维护信息存储的多个位置——不同目的的不同信息源。我不认为在多个表中存储相同的信息是不好的,如果这对性能是绝对必要的

这完全取决于您需要什么功能。也许每个用户都将其键/值对序列化为users表上的字符串列(Rails为这种类型的序列化提供了很好的支持),因此当您显示特定用户的信息时,您甚至不需要触摸庞大的表。或者,您可能会得到另一张如下所示的桌子:

| user_id | keys             | values               |
| 2       | hobbies, pets    | skiing, running, dog |
| 3       | hobbies, colours | skiing, green        |
如果您需要查找所有有兴趣爱好的用户(针对“键”列运行类似sql),或所有与狗有关的用户(针对“值”列运行类似sql),则此表将非常有用


根据你提出的要求,这是我能给出的最好答案。也许有第三方解决方案,但我对此表示怀疑。这不是一个“弹出宝石”类型的问题。

在这种情况下,我至少会考虑像Mango或CouCh这样的文档数据库,它可以比RDMS更容易处理这种情况。
如果不是这样的话,我可能会按照Mike A.描述的思路做一些事情。

动态字段的实现取决于以下因素:

  • 动态添加属性的能力
  • 支持新数据类型的能力
  • 无需额外查询即可检索动态属性
  • 能够访问动态属性,如常规属性
  • 能够基于动态属性查询对象。(例如:找到具有 滑雪(爱好)
  • 通常,解决方案不能满足所有需求。Mike的解决方案优雅地解决了1和5。如果1和5对你很重要,你应该使用他的解决方案

    这里有一个解决1、2、3、4和5的长解决方案

    更新
    用户

    将名为
    meta
    text
    字段添加到用户表中

    更新您的
    用户
    型号

    class User < ActiveRecord::Base  
      serialize :meta, Hash  
    
      def after_initialize
        self.meta ||= {} if new_record?
      end
    
    end
    
    访问元字段

    u = User.first
    u.meta[:hobbies] = "skiing"
    u.save
    
    puts "hobbies=#{u.meta[:hobbies]}"
    
    迭代元字段

    u.meta.each do |k, v|
      puts "#{k}=#{v}"
    end
    
    u = User.first
    u.similar_users # matching any one of the meta fields
    u.similar_users :hobbies # with matching hobbies
    u.similar_users :hobbies, :city # with matching hobbies or the same city
    
    为了满足第五个要求,您需要使用Solr或Sphinx全文搜索引擎。它们比依赖数据库进行
    之类的
    查询更有效

    这里有一种方法,如果你通过太阳黑子宝石使用Solr

    class User    
      searchable do
        integer(:user_id, :using => :id)
        meta.each do |key, value|
          t = solr_type(value)
          send(t, key.to_sym) {value} if t
        end
      end
    
      def solr_type(value)
        return nil      if value.nil?
        return :integer if value.is_a?(Fixnum)
        return :float   if value.is_a?(Float)
        return :string  if value.is_a?(String)
        return :date    if value.is_a?(Date)
        return :time    if value.is_a?(Time)
      end    
    
      def similar_users(*args)
        keys = args.empty? ? meta.keys : [args].flatten.compact
        User.search do
          without(:user_id, id)
          any_of do
            keys.each do |key|
              value = meta[key]
              with(key, value) if value
            end
          and
        end
      end
    end
    
    查找类似用户

    u.meta.each do |k, v|
      puts "#{k}=#{v}"
    end
    
    u = User.first
    u.similar_users # matching any one of the meta fields
    u.similar_users :hobbies # with matching hobbies
    u.similar_users :hobbies, :city # with matching hobbies or the same city
    

    这里的性能提升非常显著。

    这是一个非常好的方法,我非常感谢您的分享!