Почему атрибуты модели Rails не доступны с использованием символов вместо строк? - PullRequest
5 голосов
/ 12 октября 2011

Мне нужно сравнить некоторые значения атрибутов модели Rails (2.3.11) до и после обновления базы данных, поэтому я начну с поиска своей записи и сохранения существующих значений атрибутов в хэш-памяти следующим образом:

id = params[:id]
work_effort = WorkEffort.find(id)

ancestor_rollup_fields = {
    :scheduled_completion_date => work_effort.scheduled_completion_date
}

work_effort.update_attributes(params.except(:controller, :action))
#etcetera

Примечание. Я придерживаюсь "наилучшей практики" использования символа для хеш-ключа.

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

def rollup_ancestor_updates(work_effort, ancestor_rollup_fields)
    ancestor_rollup_fields.each do |key, value|
        model_val = work_effort.attributes[key] #nil
        #etcetera

При отладке вышеизложенного я заметил, что жесткое кодирование строки как ключа:

work_effort.attribute['scheduled_completion_date']

Возвращает желаемое значение.Итак, в каждом блоке я пробовал следующее, и это работало:

model_val = work_effort.attributes[key.to_s]

Есть ли другой способ сделать это?Для меня, имея всего 3 месяца опыта работы с Ruby / Rails, использование символов в качестве ключей хеша сбивает с толку, как это рекомендовано в качестве лучшей практики, но затем приходится вызывать .to_s для символа, чтобы получить атрибут модели.Кто-нибудь еще испытывал это, работал вокруг этого, был также смущен этим?Заранее спасибо

Ответы [ 4 ]

11 голосов
/ 12 октября 2011

Хэш, возвращаемый при вызове #attributes в экземпляре AR, имеет строковые ключи, поэтому символ в качестве индекса в хэше не работает в вашем случае.Существует подкласс Hash, называемый HashWithIndifferentAccess, который автоматически преобразует индексы символов в строки.

Довольно часто в Rails вы встречаете HashWithIndifferentAccess экземпляров.Прекрасным примером является переменная params, к которой вы обращаетесь в вашем контроллере и просматриваете код.

Попробуйте использовать work_effort.attributes.with_indifferent_access[key]

На самом деле это просто то же, что и вы, но это происходит засцены.

5 голосов
/ 19 февраля 2013

Вы можете перезаписать метод атрибутов своим собственным.

Откройте свой класс WorkEffort

class WorkEffort
  def attributes
    super.symbolize_keys
  end
end

тогда, когда вы вызовете work_effort.attributes, у вас будут символизированные ключи в хэше.

1 голос
/ 08 июля 2019

Все ваши модели Rails могут иметь символизированные имена атрибутов:

class ApplicationRecord < ActiveRecord::Base
  # ...

  class << self
    def attribute_names(symbols = false)
      return self.attribute_names.map(&:to_sym) if symbols

      super()
    end
  end
end

Затем вы можете позвонить MyModel.attribute_names(symbols = true) и получить обратно [:id, :my_attribute, :updated_at, :created_at, ...], все еще позволяя attribute_names возвращать строки.

Обратите внимание, что вам нужны скобки после super, чтобы избежать ошибки аргумента в первоначально определенной функции.

0 голосов
/ 12 октября 2011

Вы можете использовать: stringify_keys! который широко используется во всем коде Rails.

def rollup_ancestor_updates(work_effort, ancestor_rollup_fields)
  ancestor_rollup_fields.stringify_keys!.each do |key, value|
    model_val = work_effort.attributes[key]
  end
  #....
end
...