问题:在Ruby(和/或Rails)中是否有一种简洁的方法将两个对象合并在一起?
具体来说,我正在尝试找出类似于jQuery的$.extend()
方法的东西,而传入的第一个对象将使其属性被第二个对象覆盖。
我正在使用Rails 3.2+中的无表格模型。发生表单提交时,提交中的参数用于动态填充User对象。该用户对象在使用Ruby的PStore类的页面请求之间保持不变,将对象编组为平面文件,以后可以轻松检索。
相关代码:
module Itc
class User
include ActiveModel::Validations
include ActiveModel::Conversion
include ActionView::Helpers
extend ActiveModel::Naming
def set_properties( properties = {} )
properties.each { |k, v|
class_eval("attr_reader :#{k.to_sym}")
self.instance_variable_set("@#{k}", v)
} unless properties.nil?
end
end
end
创建用户对象的方式如下:
user = Itc.User.new( params[:user] )
user.save()
上面的save()
方法不是ActiveRecord的保存方法,而是我写的一个通过PStore执行持久化的方法。
如果我加载了用户对象,并且我有表单提交,我想做这样的事情:
merged = existingUserObject.merge(User.new(params[:user])
并且merged
的结果是用户对象,只更新表单提交中更改的属性。
如果有人对一般的更好的方法有任何想法,我会全力以赴。
答案 0 :(得分:6)
Hash#merge
不是您想要的吗? http://www.ruby-doc.org/core-1.9.3/Hash.html#method-i-merge。好像你可以去
merged = existingUserObject.merge(params[:user])
我认为你不需要创建一个全新的User
对象,因为大概是现有的UserObject是什么,你只想覆盖一些属性。
答案 1 :(得分:3)
通过搭载哈希的行为来做到这一点。创建一个类,该类为new()
方法的参数提供哈希,然后创建一个to_h
方法,该方法接受一个对象并从该实例的当前状态生成一个哈希:
class Foo
def initialize(params={})
@a = params[:a]
@b = params[:b]
end
def to_h
{
a: @a,
b: @b
}
end
end
instance_a = Foo.new(a: 1, b:2)
instance_b = Foo.new(a: 1, b:3)
instance_c = Foo.new(instance_a.to_h.merge(instance_b.to_h))
将其转入IRB:
irb(main):001:0> class Foo
irb(main):002:1> def initialize(params={})
irb(main):003:2> @a = params[:a]
irb(main):004:2> @b = params[:b]
irb(main):005:2> end
irb(main):006:1>
irb(main):007:1* def to_h
irb(main):008:2> {
irb(main):009:3* a: @a,
irb(main):010:3* b: @b
irb(main):011:3> }
irb(main):012:2> end
irb(main):013:1> end
nil
irb(main):014:0>
irb(main):015:0* instance_a = Foo.new(a: 1, b:2)
#<Foo:0x1009cfd00
@a = 1,
@b = 2
>
irb(main):016:0> instance_b = Foo.new(a: 1, b:3)
#<Foo:0x1009ead08
@a = 1,
@b = 3
>
irb(main):017:0>
irb(main):018:0* instance_c = Foo.new(instance_a.to_h.merge(instance_b.to_h))
#<Foo:0x100a06c60
@a = 1,
@b = 3
>
答案 2 :(得分:0)
这就是我用我的模型
取得类似的东西 # merge other_config.attrs into self.attrs, only for nil attrs
def merge!(other_object)
return if other_object.nil? || other_object.class != self.class
self.assign_attributes(self.attributes.slice ('id').merge(other_object.attributes.slice!('id')){|key, oldval, newval|
oldval.nil? ? newval: oldval
})
end