Объединение двух объектов ruby

вопрос: есть ли краткий способ в Ruby (и/или Rails) объединить два объекта вместе?

в частности, я пытаюсь выяснить что-то похожее на jQuery $.extend() метод, тогда как первый объект, который вы передаете, будет иметь свои свойства, переопределенные вторым объектом.

Я работаю с моделью бестабличные в Rails 3.2+. При отправке формы параметры из отправки используются для динамического заполнения объекта пользователя. Этот объект пользователя сохраняется между запросами страниц, используя класс Pstore Ruby, сортируя объекты на плоские файлы, которые можно легко получить в будущем.

соответствующий код:

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 быть объектом пользователя, только свойства, которые были изменены в представлении формы, будут обновлены.

если у кого-нибудь есть идеи о лучшем способе сделать это в целом, я все уши.

3 ответов


сделайте это, piggybacking на поведении хэша. Создайте класс, который принимает хэш для параметра 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
>

Is Hash#merge Не то, что вы ищете? http://www.ruby-doc.org/core-1.9.3/Hash.html#method-i-merge. Кажется, вы могли бы просто пойти

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

Я не думаю, что вам нужно создать совершенно новый User object так как предположительно это то, что existingUserObject и вы просто хотите перезаписать некоторые свойства.


вот как я достиг аналогичной вещи с 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