Как сделать, чтобы имя атрибута перечисляло все имена атрибутов в документе с динамическими атрибутами
У меня есть приложение 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]