0

I'm pretty sure what I'm looking for is proper usage of virtual attributes?

Regardless.

Here is an overview of my ActiveRecord in-so-far:

class User < ActiveRecord::Base
  validates :email, uniqueness: { case_sensitive: false }, email: true
  validates :username, uniqueness: { case_sensitive: false }
  validates :password, confirmation: true
  validates :password_confirmation, presence: true
end

And the schema associated:

class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |u|
      u.string :email
      u.string :username
      u.string :password_hash
      u.string :salt
      u.timestamps
    end
  end
end

My goal is to be able to initialize a new record with (something like) the following:

User.new({"email"=>"emailaddresshere",
          "username"=>"usernamehere",
          "password"=>"[FILTERED]",
          "password_confirmation"=>"[FILTERED]"})

I need a way to, after all the lovely validation checks, but before attempting to create a new DB record, transform the password into the password_hash, as well as generate a salt. I know HOW to acquire the hash and salt, I just don't know how I would be able to interject a snippet of code into the record creation process, to modify the parameters provided. I am also unsure of how to make sure that it all works without throwing an UnknownAttributeError.

Any way to do this? I could obviously write a "def register" method which manually transforms everything into a new record, but then it would render the password and password_confirmation validations useless, as the record will have been transformed by the time it hits User.new().

1
  • I think my question also stems from a severe lack of overall understanding of the ActiveRecord processes... and somewhat of ruby in general Commented Nov 6, 2014 at 5:07

1 Answer 1

1

Use Activerecord Callbacks.

In your case you could use after_validation or before_save callback.

An example would be:

class User < ActiveRecord::Base
  validates :email, uniqueness: { case_sensitive: false }, email: true
  validates :username, uniqueness: { case_sensitive: false }
  validates :password, confirmation: true
  validates :password_confirmation, presence: true

  before_save :salt_new_password, :if=>:self.password_changed?

  private
  def salt_new_password
    # self.password = <whatever logic you use>
  end
end
Sign up to request clarification or add additional context in comments.

3 Comments

This seems to work. I'm going to rename the password_hash field to just password, but until I do that, I'm getting an unknown attribute error on password. I know it's a bit off-topic of the original question, but is there a way to explicitly just say not to store it in the DB?
Also, thank you for the reference material, that certainly clears things up for me a bit!
Ah, found it. attr_accessor is apparently what I was looking for. I had seen it earlier but the reference that described it did a poor job. New source: code.tutsplus.com/tutorials/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.