12

質問: Ruby (および/または Rails) で 2 つのオブジェクトをマージする簡潔な方法はありますか?

具体的には、jQuery のメソッドに似たものを見つけようとしてい$.extend()ますが、最初に渡すオブジェクトのプロパティは 2 番目のオブジェクトによってオーバーライドされます。

Rails 3.2+ でテーブルレス モデルを使用しています。フォーム送信が発生すると、送信からのパラメーターを使用してユーザー オブジェクトが動的に入力されます。そのユーザー オブジェクトは、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 の save メソッドではなく、PStore 経由で永続化するために私が書いたメソッドです。

ユーザー オブジェクトが読み込まれており、フォームが送信されている場合は、次のようにします。

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

mergedフォームの送信で変更されたプロパティのみが更新されるユーザー オブジェクトになります。

一般的にこれを行うためのより良い方法について誰かがアイデアを持っているなら、私はすべて耳にします。

4

3 に答える 3

14

Hash#mergeあなたが探しているものではありませんか?http://www.ruby-doc.org/core-1.9.3/Hash.html#method-i-merge . あなたはただ行くことができるようです

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

Userおそらくそれが existingUserObject であり、いくつかのプロパティを上書きしたいだけなので、まったく新しいオブジェクトを作成する必要はないと思います。

于 2012-08-07T23:50:16.767 に答える
5

ハッシュの動作に便乗してそれを行います。メソッドのパラメーターのハッシュを受け取るクラスを作成し、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
>
于 2012-08-07T21:51:56.700 に答える
0

これは、私のモデルの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
于 2016-03-04T23:57:11.643 に答える