У меня есть объект Foo, и я хочу назначить ему сразу несколько атрибутов, аналогично assign_attributes в Rails:

class Foo
    attr_accessor :a, :b, :c
end

f = Foo.new
my_hash = {a: "foo", b: "bar", c: "baz"}
f.assign_attributes(my_hash)

Вышеупомянутое не работает, за исключением случаев, когда класс является моделью ActiveRecord в Rails. Есть ли способ сделать это в Ruby?

1
max 24 Ноя 2021 в 20:20
Кстати, большая часть Rails реализована на Ruby, поэтому вы всегда можете взглянуть на его исходный код. (хотя некоторые из них довольно сложны и их трудно понять)
 – 
Stefan
24 Ноя 2021 в 20:38

2 ответа

Лучший ответ

Вы можете реализовать метод массового присвоения самостоятельно.

Один из вариантов - установить соответствующие переменные экземпляра через instance_variable_set:

class Foo
  attr_accessor :a, :b, :c

  def assign_attributes(attrs)
    attrs.each_pair do |attr, value|
      instance_variable_set("@#{attr}", value)
    end
  end
end

Другой способ - динамически вызывать сеттеры через public_send:

  def assign_attributes(attrs)
    attrs.each_pair do |attr, value|
      public_send("#{attr}=", value)
    end
  end

Кроме того, вы можете убедиться, что переданный аргумент является хешем, а его ключи являются действительными / известными атрибутами.

Использование последнего подхода дает преимущество в том, что, если установщик был определен для включения ограничений и элементов управления для устанавливаемого значения, последний подход учитывает это.

6
Chris 24 Ноя 2021 в 23:06
1
Я бы сказал, что более поздняя реализация намного лучше, потому что в параметре присвоения переменной экземпляра отсутствует структурированный контроль, предоставляемый attr_accessor, например. f.assign_attributes(('a'..'zzz').then {|a| a.zip(a)}.to_h)
 – 
engineersmnky
24 Ноя 2021 в 20:48

assign_attributes - это метод экземпляра ActiveRecord

Вы должны определить свой метод assign_attributes, если не используете ActiveRecord

def assign_attributes(attrs_hash)
  attrs_hash.each do |k, v|
    self.instance_variable_set("@#{k}", v)
  end
end
0
Nitin Srivastava 24 Ноя 2021 в 20:41