Подтвердить что ты не робот

Rails - я против @

Я следую руководству Майкла Хартла RoR, и он освещает основы шифрования паролей. Это модель пользователя, которая в настоящее время стоит:

class User < ActiveRecord::Base
    attr_accessor :password

    attr_accessible :name, :email,: password, :password_confirmation

    email_regex = /^[A-Za-z0-9._+-][email protected][A-Za-z0-9._-]+\.[A-Za-z0-9._-]+[A-Za-z]$/
                                              #tests for valid email addresses.

    validates :name, :presence => true,
                     :length => {:maximum => 50}
    validates :email, :presence => true,
                      :format => {:with => email_regex},
                      :uniqueness => {:case_sensitive => false}
    validates :password, :presence => true,
                         :length => {:maximum => 20, :minimum => 6},
                         :confirmation => true

    before_save :encrypt_password

    private

    def encrypt_password
        self.encrypted_password = encrypt(password)
    end

    def encrypt(string)
        string
    end
end

Я уже писал предыдущий вопрос о before_save, и получается, что то, что я случайно сделал, написано моим encrypt_password как:

def encrypt_password
    @encrypted_password = encrypt(password)
end

Я понимаю, что если self.encrypted_password устанавливает атрибут encrypted_password, но почему @encrypted_password не делает этого? В ответе на предыдущий пост о before_save не работает кто-то сказал, что переменная экземпляра была "забыта" после того, как метод закончился тем, как я его первоначально закодировал - почему это так? Может кто-нибудь объяснить, как я и @работают по-другому в контексте вышеприведенного кода?

ПРИМЕЧАНИЕ. Я уже рассмотрел сообщения здесь и здесь, но они оба говорят, что "self" вызывает метод attribute =, и я даже не понимаю, как этот метод может существовать здесь, так как я его никогда не создавал или не объявлял encrypted_password w/attr_accessor. Поэтому я все еще смущен, и это не повторная публикация этих вопросов.

4b9b3361

Ответ 1

Аксессоры для encrypted_password были автоматически добавлены Rails для вас, потому что поле с этим именем существует в таблице users.

Любое поле, которое вы добавите в таблицу, будет автоматически доступно через self.field_name.

Вот где учебник Майкла Хартла создает поле encrypted_password в таблице users.

Посмотрите также на user_spec.rb (листинг 7.3) на связанной странице, где автор тестирует наличие поля encrypted_password.

ОБНОВЛЕНО:

Как указывает @mu, @ используется для переменных экземпляра Ruby (иначе "iv" ). Но encrypted_password - это "атрибут", определенный Rails, и не является переменной экземпляра.

Если вы запустите User.find(1).instance_variables, вы увидите, что есть iv под названием @attributes, который имеет тип Hash.

Внутри, где iv хранится encrypted_password. Rails определил методы доступа для encrypted_password, который получает/устанавливает данные для этого атрибут в @attributes Hash.

Обратите внимание, что вы также можете получить/установить данные через @attributes["encrypted_password"], вызванный из класса User (но методы доступа являются удобным способом сделать именно это).

Ответ 2

Если вы позволите мне, я хотел бы перефразировать ответ.

Я объяснил в этом сообщении, что, как только вы создадите модель (rails-) с тем же (единственным) именем в качестве одного из (множественных) табуляций вашей базы данных, "магия" рельсов создаст сеттеры и геттеры, чтобы изменить записи в таблице.

Это связано с тем, что ваша модель наследует все методы из ActiveRecord:: Base Class, который определяет базовые CRUD-аксессоры (Create, Read, Update, Delete).

Ключевой момент, связанный с вашим вопросом, заключается в том, что вы не знаете, как rails реализует переменную экземпляра, связанную с столбцом таблицы базы данных,. И не следует.:) Все, что вам нужно знать, это то, что в этот момент у вас есть сеттеры и геттеры, доступные CRUD (создайте, прочитайте, обновите, удалите) в столбце базы данных "encrypted_password".

В вашем примере, возможно, rails использует переменную экземпляра, называемую @encrypted_password, возможно, rails использует переменную hash-instance, называемую @attributes [ "encrypted_password" ], или, может быть, rails использует переменную экземпляра, называемую @you_will_never_guess_encrypted_password.

-

И хорошо, что вы не знаете о поведении внутренних рельсов с переменными экземпляра. В 2019 году дальнейшая разработка Rails может привести к тому, что структура будет использовать переменную @complex-hash-instance для хранения значения encrypted_password.

Фактически лучший подход заключается в том, чтобы позволить рельсам управлять своим "private" "делом";) с переменными экземпляра и просто использовать методы getter и setter, которые он предоставляет вам. Таким образом, ваше приложение будет работать с encrypted_password в следующем столетии (надеюсь, что ^^).

Итак, если вы используете @encrypted_password, он может работать с некоторой "воображаемой" версией рельсов, и он больше не будет работать с другими версиями рельсов. На самом деле с текущей версией рельсов это не работает.

-

Вторая ключевая точка заключается в том, что если вы хотите использовать регенерацию " encrypted_password" Rails, созданную для столбца таблицы базы данных encrypted_password, вы префикс ее " self", чтобы сообщить Ruby:" ok Я хочу использовать метод encrypted_password моей переменной Пользователь.

В Ruby метод вызывается путем передачи его имени получателю. Вы пишете это следующим образом:

my_receiver.my_method

В вашем случае мы передаем метод encrypted_password в переменную экземпляра Пользователь. Но мы не знаем, как будет называться эта переменная экземпляра, поэтому мы используем слово self, чтобы сообщить Ruby: "Я говорю о любой переменной экземпляра User класс, который вызывает метод encrypted_password".

Например, мы могли бы назвать нашу переменную экземпляра "toto":

toto = User.new

поэтому toto.encrypted_password отобразит зашифрованный пароль, а сам в этом случае в нашем коде будет ссылаться на.

Однако, благодаря Ruby, , если вы не даете никакого приемника при вызове метода, Ruby предположит, что вы передаете его в self.

Ссылка: Руководство для прагматичного программиста

Итак, в вашем примере вам даже не нужно ставить "я". как префикс. Вы могли бы написать это так:

class User < ActiveRecord::Base

    def encrypt_password
        encrypted_password = encrypt(password)
    end
end

Надеюсь, это поможет прояснить этот интересный вопрос.

Ответ 3

TL; DR -

Всегда пишите self.widget_count = 123, если вы намерены сохранить widget_count обратно в базу данных.

(Но, пожалуйста, прочитайте длинные ответы, потому что полезно знать.)