Если вы работаете с унаследованными базами данных, у вас не всегда есть возможность менять имена полей, когда поля начинают конфликтовать с Ruby on Rails. Самый простой пример, это поле с именем ‘class’ в одной из ваших таблиц. Рельсам это действительно не нравится. Это как теща, которой не нравится твоя новая прическа, и она обращает на это внимание при любой возможности.
В виду отсутствия драматургического таланта, переводчик не смог, породить более яркую метафору, создающую общую ассоциацию, в противоположность частной
# попробуем использовать плохо-обозванный атрибут ruby-1.9.2-p0 > u = User.new :class => '1995' NoMethodError: undefined method `columns_hash' for nil:NilClass
#пытаемся присвоить другому атрибуту, виновному только в том, что он родился не в том месте. ruby-1.9.2-p0 > u = User.new :name NoMethodError: undefined method `has_key?' for nil:NilClass
# пробуем присвоить атрибут последовательно ruby-1.9.2-p0 > u = User.new => #<User id: nil, name: nil, class: nil, created_at: nil, updated_at: nil> ruby-1.9.2-p0 > u.class = '1995' NoMethodError: undefined method `private_method_defined?' for nil:NilClass
Как и вышеупомянутая теща, ваши проблемы неизбежны, пока прическа не будет исправлена.
К счастью, Брайан Джонс решил эту проблему для нас с его gem safe_attributes. Rails автоматически создает ацессоры ( геттеры и сеттеры ) для каждого атрибута в таблице модели ActiveRecord. Попытка переопределения Рельсами важных методов таких, как «class» это то, что доставляет нам проблемы. Safe_attributes исключает создание любых атрибутов с опасными именами.
Достаточно сделать следующее:
# app/models/user.rb class User < ActiveRecord::Base bad_attribute_names :class end
После добавления gem-а в bundle, передайте в bad_attribute_names список имен полей нарушителей, и это освободить Rails от попытка генерировать методы-ацессоры для них. Теперь все работает, но без этих ацессоров. Давайте попробуем получить/присвоить наш атрибут :class:
ruby-1.9.2-p0 > u = User.new => #<User id: nil, name: nil, class: nil, created_at: nil, updated_at: nil> ruby-1.9.2-p0 > u.class = '1995' => "1995" ruby-1.9.2-p0 > u => #<User id: nil, name: nil, class: "1995", created_at: nil, updated_at: nil> ruby-1.9.2-p0 > u.class => User(id: integer, name: string, class: string, created_at: datetime, updated_at: datetime)
Сеттер работает (я предполагаю, что он был создан еще и потому, что не было ранее существовавшего метода ‘class’=), и мы можем убедиться, что значение атрибута присвоено верно. Но вызов геттера по умолчанию вызывает… ну, поведение по умолчанию.
Дело в том, что можно всегда использовать атрибут в контексте hash (ассоциированный массив, далее хэш, прим. переводчика). Вы можете передать в объект хэш атрибутов ключ/значение, и это будет работать. Это означает, что ваш контроллер при создании и обновлении не придется менять.
Такие методы как new, create, update_attribute, update_attributes и т.д. будут нормально работать.
Если вы хотите только присвоить значение (чтобы избежать немедленного сохранение, для примера), сделайте следующим образом.
ruby-1.9.2-p0 > u[:class] = '1996' => "1996" ruby-1.9.2-p0 > u => #<User id: nil, name: nil, class: "1996", created_at: nil, updated_at: nil>
Вообще, вы все еще можете устанавливать значение атрибутов напрямую, вместо использования генерированных рельсами ацессоров. Но мы все еще в одном шаге от окончательного решения. Мы хотим обращаться к этому атрибуту, как к остальным, а это требует от нас организации нормального набора методов доступа (геттеров и сеттеров). Одна из причин сделать это в том, что нам будут доступны стандартные валидации этого атрибута.
Можно добавить ацессоры, как в этом примере:
# add to app/models/user.rb def class_name= value self[:class] = value end def class_name self[:class] end
Мы объявляем ацессор ‘class_name’, и теперь мы можем использовать его ге угодно вместо оригинального имени атрибута. Мы можем использовать его в формах:
<%= f.text_field :class_name %>
Или в валидаторах:
validates_presence_of :class_name
Или когда создаем новый объект:
User.create :class_name => 'class of 1995'
Если вы скачали код, то эти дополнения test-driven, имеется в виду то, что я писал тесты для этих методов перед написанием самих методов, чтобы убедиться в том, что эти методы работают подобающим образом. Призываю вас делать тоже самое.
Удачи!
ссылка на оригинал статьи http://habrahabr.ru/post/155215/
Добавить комментарий