Как сделать, чтобы имя атрибута перечисляло все имена атрибутов в документе с динамическими атрибутами

У меня есть приложение Rails 4.2 с mongoid, в которое я импортирую файлы csv с результатами теста. Я не могу определить все поля в модели, потому что они меняются от теста к тесту, а их всегда около 700. Я использую динамические атрибуты, и импорт и отображение работает нормально.

Я пытаюсь использовать метод attribute_names, чтобы получить все имена атрибутов, но все, что я получаю, это те, которые определены в модели. Если я ничего не определяю в модели, то возвращается только "_id". Метод атрибутов, с другой стороны, может видеть атрибуты в реальном документе, с другой стороны.

>> @results.first.attributes.count
=> 763
>> @results.first.attribute_names
=> ["_id"]

Я также пробовал fields.keys, та же проблема

>> @results.first.fields.keys
=> ["_id"]

Моя модель на данный момент выглядит так

class Result
  include Mongoid::Document
  include Mongoid::Attributes::Dynamic

  def self.import(file)
    CSV.foreach(file.path, headers: true) do |row|
        Result.create! row.to_hash
    end
  end
end

Может кто-нибудь объяснить, как заставить это работать?

Любая помощь с благодарностью.

1 ответ

Эта часть не очень понятна в документации. и этот ответ не касается того, как вы можете заставить ваше дело работать (я действительно не знаю)... но у него есть один патч обезьяны в конце...

все, что я знаю, это то, почему этот случай не работает...

как говорится в документации

При работе с динамическими атрибутами применяются следующие правила:

Если атрибут существует в документе, Mongoid предоставит вам ваши стандартные методы получения и установки.

Например, рассмотрим человека с атрибутом "пол", установленным в документе:

# Set the person's gender to male.
person[:gender] = "Male"
person.gender = "Male"

# Get the person's gender.
person.gender

это не ваш случай... потому что, как кажется, вы не определяете какие-либо атрибуты в вашей модели...

что применимо в вашем случае (из кода, который вы показали, и проблемы, которую вы описали)

Если атрибут еще не существует в документе,

Mongoid не предоставит вам методы получения и установки и обеспечит нормальное выполнение method_missing поведение.

В этом случае вы должны использовать другие методы доступа: ([] а также []=) или же (read_attribute а также write_attribute).

# Raise a NoMethodError if value isn't set.
person.gender
person.gender = "Male"

# Retrieve a dynamic field safely.
person[:gender]
person.read_attribute(:gender)

# Write a dynamic field safely.
person[:gender] = "Male"
person.write_attribute(:gender, "Male")

как вы можете видеть... у mongoid нет способа добавить методы setter и getter во время выполнения...

Monkey Patch

  • Вы можете добавить поле (возможно, строку, массив, хеш, что вам подходит) в документ (атрибут существует в документе)
  • при заполнении документа из строки CSV... просто сохраните поля CSV в этом поле... (удерживайте в нем ключи CSV)
  • используйте ваше предопределенное поле (которое содержит ключи) вместо использования .keys,

Пример кода в вашем случае.

class Result
  include Mongoid::Document
  include Mongoid::Attributes::Dynamic

  field :the_field_that_holds_the_keys, type: Array
  # ...
end

и в вашем контроллере:

@results.first.some_attribute
#=> method missing error
@results.first[:some_attribute]
#=> some_value
@results.first.the_field_that_holds_the_keys
#=> [:some_attribute, :some_other_attribute, :yada]
Другие вопросы по тегам