Rails 3动态添加虚拟属性

时间:2011-09-01 22:40:55

标签: ruby-on-rails ruby ruby-on-rails-3 activerecord

我的设置:Rails 3.0.9,Ruby 1.9.2

我有理由这样做,但我需要的是一种动态添加虚拟属性到activerecord结果集的方法。这意味着我没有在模型中使用attr_accessor,而是希望动态地将虚拟属性添加到结果集中。

例如,

users = User.all
#a user has following attributes: name, email, password

我喜欢说的是添加(不使用attr_accessor)虚拟属性statususers,这可能吗?

4 个答案:

答案 0 :(得分:15)

你应该这样做:

users.each do |user|
  user.instance_eval do
    def status
      instance_variable_get("@status")
    end        
    def status=(val) 
      instance_variable_set("@status",val)
    end
  end
end

答案 1 :(得分:2)

您可以执行以下操作:

添加一个属性“extras”,它将作为Hash访问,并将存储任何其他/动态属性 - 然后告诉Rails通过ActiveRecord或Mongo中的JSON或您使用的任何内容来持久化Hash

e.g:

class AddExtrasToUsers < ActiveRecord::Migration
  def self.up
    add_column :users, :extras, :text    # do not use a binary type here! (rails bug)
  end
  ...
end

然后在模型中添加一个语句来“序列化”该新属性 - 例如这意味着它被持久化为JSON

class User < ActiveRecord::Base
...
serialize :extras
...
end

您现在可以执行此操作:

   u = User.find 3

   u.extras[:status] = 'valid'
   u.save

你还可以为User模型添加一些魔法,如果它获得method_missing()调用,则查看额外的Hash

另见:   谷歌“Rails 3序列化”

答案 2 :(得分:1)

如果您的属性是只读的,您也可以通过在数据库查询中选择它们来添加它们。出现在SQL结果结果中的字段将自动添加为属性。

示例:

User.find_by_sql('users.*, (...) AS status')
User.select('users.*, joined_table.status').join(...)

通过这些示例,您将拥有所有User个属性和一个额外的status属性。

答案 3 :(得分:1)

你可以这样做:

users.each { |user| user.class_eval { attr_accessor :status } }

所有users都有user.statususer.status = :new_status可用。