合并两个 ruby​​ 对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11853491/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 03:49:23  来源:igfitidea点击:

Merging two ruby objects

ruby-on-railsruby

提问by jiveTurkey

Question: Is there a concise way in Ruby (and/or Rails) to merge two objects together?

问题:在 Ruby(和/或 Rails)中是否有一种简洁的方法可以将两个对象合并在一起?

Specifically, I'm trying to figure out something akin to jQuery's $.extend()method, whereas the first object you pass in will have its properties overridden by the second object.

具体来说,我试图找出类似于 jQuery$.extend()方法的东西,而您传入​​的第一个对象的属性将被第二个对象覆盖。

I'm working with a tableless model in Rails 3.2+. When a form submission occurs, the parameters from the submission are used to dynamically populate a User object. That user object is persisted between page requests using Ruby's PStore class, marshalling objects to flat files which can be easily retrieved in the future.

我正在使用 Rails 3.2+ 中的无表模型。当表单提交发生时,来自提交的参数用于动态填充用户对象。该用户对象使用 Ruby 的 PStore 类在页面请求之间持久化,将对象编组为将来可以轻松检索的平面文件。

Relevant code:

相关代码:

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

Creation of a user object occurs like this:

用户对象的创建是这样发生的:

user = Itc.User.new( params[:user] )
user.save()

The save()method above is not ActiveRecord's save method, but a method I wrote to do persistence via PStore.

save()上面的方法不是ActiveRecord的save方法,而是我写的一个通过PStore做持久化的方法。

If I have a user object loaded, and I have a form submission, I'd like to do something like this:

如果我加载了一个用户对象,并且我有一个表单提交,我想做这样的事情:

merged = existingUserObject.merge(User.new(params[:user])

and have the outcome of mergedbe a user object, with only properties that were changed in the form submission be updated.

并且结果merged是一个用户对象,只有在表单提交中更改的属性才会更新。

If anyone has any ideas about a better way to do this in general, I'm all ears.

如果有人对一般情况下更好的方法有任何想法,我会全力以赴。

采纳答案by the Tin Man

Do it by piggybacking on hash's behaviors. Create a class that takes a hash for the parameter of the new()method, and then a to_hmethod that takes an object and generates a hash from the current state of the instance:

通过捎带散列的行为来做到这一点。创建一个类,该类接受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))

Dumping it into IRB:

将其转储到 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
>

回答by JGrubb

Is Hash#mergenot what you're looking for? http://www.ruby-doc.org/core-1.9.3/Hash.html#method-i-merge. Seems like you could just go

Hash#merge不是你想要的?http://www.ruby-doc.org/core-1.9.3/Hash.html#method-i-merge。看来你可以走了

merged = existingUserObject.merge(params[:user])

I don't think you need to create an entirely new Userobject since presumably that's what existingUserObject is and you just want to overwrite some properties.

我认为您不需要创建一个全新的User对象,因为这可能是 existingUserObject 的内容,而您只想覆盖一些属性。

回答by Sumit Maheshwari

This is how I achieved similar thing with 1 of my model

这就是我如何用我的模型 1 实现类似的事情

  # 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