5

フィールドを持つテーブルがあります: emailpassword_hashおよびsalt

ユーザー登録時に、パスワードの有効化とパスワードの確認を行いたいのですがcan't be blank、パスワードの入力に対して常にエラーが発生します。

これは私のモデルです:

attr_accessor :password

validates :password, :presence     => true,
                     :confirmation => true,
                     :length       => { :within => 6..40 }

データベースではないフィールドを検証できませんが、ユーザーが入力したパスワードを検証するにはどうすればよいですか?

password取得した入力を暗号化してからdbフィールドに保存するため、データベースにパスワードフィールドがありませんpassword_hash

編集 :

これはデータベーステーブルです:

class CreateStudents < ActiveRecord::Migration
  def change
    create_table :students do |t|
      t.string :first_name
      t.string :last_name
      t.string :email
      t.string :password_hash
      t.string :salt

      t.boolean :activated

      t.timestamps
    end
  end
end

これは登録用のビューです。

<%= form_for @student, url: {action: 'create'} do |form| %>

  <p style="font-size:smaller; color:red">
  <% @student.errors.messages.each do |att, msg| %>
    <%= msg[0] %><br>
  <% end %>
  <p>
  <%= form.label :first_name %><br>
  <%= form.text_field :first_name %>
  <p>
  <%= form.label :last_name %><br>
  <%= form.text_field :last_name %>
  <p>
  <%= form.label :email %><br>
  <%= form.text_field :email %>
  <p>
  <%= form.label :password %><br>
  <%= form.password_field :password %>
  <p>
  <%= form.label :password_confirmation %><br>
  <%= form.password_field :password_confirmation %>
  <p>
  <%= form.submit %>

<% end %>

これはコントローラーです:

def sing_up
    @student = Student.new
    render 'sing_up'
end

def create
    @student = Student.new
    @student.first_name = params[:student][:first_name]
    @student.last_name = params[:student][:last_name]
    @student.email = params[:student][:email]

    @student.salt = BCrypt::Engine.generate_salt
    @student.password_hash = BCrypt::Engine.hash_secret(params[:student][:password], @student.salt)
    if @student.save
        redirect_to controller: 'singups', action: 'index'
    else
        render 'sing_up'
    end
end

最後に、これはモデルです

class Student < ActiveRecord::Base
  attr_accessor :password
    validates :first_name, :length => { minimum: 3, message: "first_name" }
    validates :last_name, :length => { minimum: 3, message: "last_name" }
    validates :email, :presence => { message: 'email' },
              :format => { with: /\A[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+\z/ , message: 'email format' },
              :uniqueness => { message: 'uniqueness?' }
    validates :password, :confirmation => { message: 'password' },
                         :length => { minimum: 6, message: 'password length' }
end

ユーザーがパスワードを入力するたびに:confirmation => { message: 'password' }、パスワードが何であれ、最初の検証で失敗します。

一部を削除するvalidates :passwordと、すべて正常に動作しますが、ユーザーが入力したパスワードは検証されません。

4

4 に答える 4

3

ユーザーのpassword属性を検証していますが、最初から値を割り当てていません。少なくとも、これをコントローラー コードに追加する必要があります。

@student.password = params[:student][:password]
@student.password_confirmation = params[:student][:password_confirmation]

ただし、より簡潔な方法は、一括割り当てを使用することです。 @student.xxx = yyy をすべて削除して、次のように置き換えます。

@student = Studen.new(params[:student])

次に、パスワード ハッシュ メソッドをモデルに移動し、パスワード属性が存在する場合、各保存の前に自動的にトリガーします。

class User < ActiveRecord::Base
  # ...
  before_save :hash_password, :if => proc{ |u| !u.password.blank? }
  # ....

  protected

  def hash_password
    self.salt = BCrypt::Engine.generate_salt
    self.password_hash = BCrypt::Engine.hash_secret(password, salt)
  end
end

この方法では、コントローラーで何もする必要はありませんが、これは次のとおりです。

def create
  @student = Student.new(params[:student])
  if @student.save
    redirect_to controller: 'singups', action: 'index'
  else
    render 'sing_up'
  end
end

モデルが属する他のすべてのロジックをモデルに含めます。

編集: Rails 3 の最新バージョンで一括割り当てを機能させるには、次のように、割り当てたい属性をそのようにする必要がありますattr_accessible

class Student < ActiveRecord::Base
  # ...
  attr_accessible :first_name, :last_name, :email, :password # but NOT the hash or salt!!

end
于 2012-04-14T15:39:25.997 に答える
1

認証を最初から扱っているRailscastをチェックする必要があります。すべてはここで説明されていますhttp://railscasts.com/episodes/250-authentication-from-scratch

ここに更新されたキャストがありますhttp://railscasts.com/episodes/250-authentication-from-scratch-revisedですが、それを表示するにはサブスクリプションが必要です(IMOの価値は十分にあります)

于 2012-04-14T04:26:19.900 に答える
0

ユーザーが入力したパスワードを暗号化された値に変換してから、暗号化された値をpassword_hashの値と比較して、それらが一致するかどうかを確認する必要があります。これが、ユーザーが正しいユーザーであることを検証する方法です。パスワードの値を直接比較しないため、モデルにパスワードフィールドがないかどうかは関係ありません(あるべきではありません)。

暗号化にはさまざまな方法がありますが、重要なのは、最初に元のパスワードをpassword_hashに暗号化する方法です(「password_hash」をどのように生成しましたか?)。同じ方法を使用して、新しいパスワードの送信を確認します。

于 2012-04-14T04:04:49.560 に答える
0

password と password_confirmation を確認するためのカスタム検証を行うことができます。

class User< ActiveRecord::Base
  attr_accessor :password, :password_confirmation 
  validate :valid_password

  def valid_password
    if password.blank? || password_confirmation.blank?
      errors.add(:password, 'password must not be blank')
    end

    if password != password_confirmation
      errors.add(:password, 'password and confirmation does not match')
    end
  end

end

このようにして、パスワードと確認が存在し、同時に存在するかどうかを確認します。

于 2012-04-14T07:15:56.950 に答える