Почему attr_accessor блокирует существующие переменные в этой модели в Ruby on Rails?
-
11-09-2019 - |
Вопрос
Недавно меня это задело, и было бы полезно точно знать, что происходит, чтобы это произошло, чтобы другие избежали этой ошибки.
У меня есть модель пользователя, со схемой, подобной такой:
create_table "users", :force => true do |t|
t.string "user_name"
t.string "first_name"
t.string "last_name"
t.string "email"
t.string "location"
t.string "town"
t.string "country"
t.string "postcode"
t.boolean "newsletter"
В классе user.rb у меня есть attr_accessor для трех методов:
class User < ActiveRecord::Base
# lots of code
attr_protected :admin, :active
# relevant accessor methods
attr_accessor :town, :postcode, :country
end
Теперь в моем пользовательском контроллере, если у меня есть следующий метод:
def create
@user = User.new params[:user]
end
Когда, когда я пытаюсь создать нового пользователя с содержимым в этом параметре hash:
--- !map:HashWithIndifferentAccess
# other values
country: United Kingdom
dob(1i): "1985"
dob(2i): "9"
dob(3i): "19"
town: london
Возвращаемый объект содержит пустые строки для country
, town
и почтовый индекс postcode
ценности, вот так.
(rdb:53) y user1
--- !ruby/object:User
attributes:
# lots of attributes that aren't relevant for this example, and are filled in okay
postcode:
country:
town:
Я могу сказать, что методы attr_accessor загромождают существующие методы доступа Active Record, потому что, когда я их удаляю, все работает нормально, поэтому решение довольно простое - просто удалите их.
Но что что именно происходит, когда здесь?
Я смотрю здесь, в Документы Rails API для Активной записи, и здесь в Собственные документы Ruby о attr_accessor
, но я все еще немного смутно представляю , как attr_accessor
это все здесь ломает.
Кто-нибудь может пролить какой-нибудь свет, чтобы остановить какую-нибудь другую бедную душу, впавшую в это нечестие?
Решение
Когда вы добавляете attr_accessor к классу, он определяет для него два метода, напримерПользователь#почтовый индекс и Пользователь#почтовый индекс=.
Если имя средства доступа равно имени атрибута модели, все ломается (если вы не будете осторожны).Когда вы назначаете атрибуты модели, вызывается User#postcode=, и в вашем случае он ничего не делает, кроме
@postcode = value
Таким образом, значение просто сохраняется в переменной экземпляра и не отображается в хэше атрибутов.
Принимая во внимание, что в обычном сценарии (без средства доступа) это привело бы к method_missing и в конечном итоге вызвало бы что-то вроде
write_attribute(:postcode, value)
И тогда это появится в атрибутах вашей модели.Надеюсь, в этом есть смысл.
Другие советы
Почему в первую очередь вы используете attr_accessor :town, :postcode, :country
?У Active Record есть методы установки / получения для вас.Просто отбрось эту фразу, все должно сработать.
Возможно, вы захотите использовать attr_accessible
в моделях ActiveRecord для обеспечения массового присвоения атрибутов.Тебе не нужно attr_accessor
поскольку получатели / установщики уже определены для атрибутов модели.