Основано на реальных событиях, произошедших(происходящих) с реальными людьми.
Если вы работаете с унаследованными базами данных, у вас не всегда есть возможность менять имена полей, когда поля начинают конфликтовать с Ruby on Rails. Самый простой пример, это поле с именем 'class' в одной из ваших таблиц. Рельсам это действительно не нравится. Это как теща, которой не нравится твоя новая прическа, и она обращает на это внимание при любой возможности.
Как и вышеупомянутая теща, ваши проблемы неизбежны, пока прическа не будет исправлена.
К счастью, Брайан Джонс решил эту проблему для нас с его gem safe_attributes. Rails автоматически создает ацессоры ( геттеры и сеттеры ) для каждого атрибута в таблице модели ActiveRecord. Попытка переопределения Рельсами важных методов таких, как «class» это то, что доставляет нам проблемы. Safe_attributes исключает создание любых атрибутов с опасными именами.
Достаточно сделать следующее:
После добавления gem-а в bundle, передайте в bad_attribute_names список имен полей нарушителей, и это освободить Rails от попытка генерировать методы-ацессоры для них. Теперь все работает, но без этих ацессоров. Давайте попробуем получить/присвоить наш атрибут :class:
Сеттер работает (я предполагаю, что он был создан еще и потому, что не было ранее существовавшего метода 'class'=), и мы можем убедиться, что значение атрибута присвоено верно. Но вызов геттера по умолчанию вызывает… ну, поведение по умолчанию.
Дело в том, что можно всегда использовать атрибут в контексте hash (ассоциированный массив, далее хэш, прим. переводчика). Вы можете передать в объект хэш атрибутов ключ/значение, и это будет работать. Это означает, что ваш контроллер при создании и обновлении не придется менять.
Такие методы как new, create, update_attribute, update_attributes и т.д. будут нормально работать.
Если вы хотите только присвоить значение (чтобы избежать немедленного сохранение, для примера), сделайте следующим образом.
Вообще, вы все еще можете устанавливать значение атрибутов напрямую, вместо использования генерированных рельсами ацессоров. Но мы все еще в одном шаге от окончательного решения. Мы хотим обращаться к этому атрибуту, как к остальным, а это требует от нас организации нормального набора методов доступа (геттеров и сеттеров). Одна из причин сделать это в том, что нам будут доступны стандартные валидации этого атрибута.
Можно добавить ацессоры, как в этом примере:
Мы объявляем ацессор 'class_name', и теперь мы можем использовать его ге угодно вместо оригинального имени атрибута. Мы можем использовать его в формах:
Или в валидаторах:
Или когда создаем новый объект:
Если вы скачали код, то эти дополнения test-driven, имеется в виду то, что я писал тесты для этих методов перед написанием самих методов, чтобы убедиться в том, что эти методы работают подобающим образом. Призываю вас делать тоже самое.
Удачи!
Оригинал доступен
Если вы работаете с унаследованными базами данных, у вас не всегда есть возможность менять имена полей, когда поля начинают конфликтовать с 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, имеется в виду то, что я писал тесты для этих методов перед написанием самих методов, чтобы убедиться в том, что эти методы работают подобающим образом. Призываю вас делать тоже самое.
Удачи!
Оригинал доступен