Почему attr_accessor блокирует существующие переменные в этой модели в Ruby on Rails? - PullRequest
2 голосов
/ 19 сентября 2009

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

У меня есть модель User с такой схемой:

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

Когда я пытаюсь создать нового пользователя с содержимым в этом хэше params:

  --- !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 для Active Record и здесь в собственных документах Руби о attr_accessor, но я все еще немного смутно о том, как attr_accessor ломает вещи здесь.

Кто-нибудь способен пролить немного света, чтобы не допустить, чтобы какая-то другая бедняжка оскорбилась?

Ответы [ 3 ]

8 голосов
/ 19 сентября 2009

Когда вы добавляете attr_accessor в класс, он определяет для него два метода, например, Пользователь # почтовый индекс и пользователь # почтовый индекс =.

Если имя средства доступа совпадает с именем атрибута модели, все будет плохо (если вы не будете осторожны). Когда вы присваиваете атрибуты модели, вызывается User # postcode =, и в вашем случае он ничего не делает, кроме

@postcode = value

Таким образом, значение просто сохраняется в переменной экземпляра и не появляется в хэше атрибутов.

В то время как в обычном сценарии (без доступа) это будет идти к method_missing и в конечном итоге вызовет что-то вроде

write_attribute(:postcode, value)

И тогда это появится в атрибутах вашей модели. Надеюсь, что это имеет смысл.

0 голосов
/ 19 сентября 2009

Возможно, вы захотите использовать attr_accessible в моделях ActiveRecord, чтобы разрешить массовое назначение атрибутов. Вам не нужно attr_accessor, так как геттеры / сеттеры уже определены для атрибутов модели.

0 голосов
/ 19 сентября 2009

Почему в первую очередь вы используете attr_accessor :town, :postcode, :country? Active Record имеет методы установки / получения для вас. Просто отбросьте эту строку, все должно работать.

...