Rails在提交空表单时不返回任何验证错误

时间:2013-03-27 21:29:37

标签: ruby-on-rails ruby-on-rails-3 devise ruby-on-rails-3.2

简短:我有一个设计模型用户我正在为用户添加一个选项,以便能够在他们的个人资料页面中更改他们的密码,而无需通过“忘记密码”选项。无论如何,这需要一个带有字段的其他表单::old_password, :new_password and :new_password_confirmation最初不在模型中我必须为它们创建新的单独验证,

表格:

<%= form_for(@user, :url => {:controller => :members, :action => :editpass}, :html => {:method => :post}) do |f| %>

    <input name="authenticity_token" type="hidden" value="<%= form_authenticity_token %>">
    <table class="tables no-border">
        <tr>
            <%= f.label :old_password, "Old password" %>
        </tr>
        <tr>
            <%= f.password_field :old_password, :autofocus => :true %>
        </tr>
        <tr>
            <%= f.label :new_password, "New password" %>
        </tr>
        <tr>
            <%= f.password_field :new_password %>
        </tr>
        <tr>
            <%= f.label :new_password_confirmation, "Repeat new password" %>
        </tr>
        <tr>
            <%= f.password_field :new_password_confirmation %>
        </tr>
        <tr>
            <input type="submit" value="Change" class="btn" />
        </tr>
    </table>
</form>

  <%= @user.errors.full_messages %>

<% end %>

控制器:

class MembersController < ApplicationController

  before_filter :authenticate_user!
  skip_before_filter :check_for_main

  def index
    @users = User.all
  end

  def show
    @user = User.find(params[:id])
  end

  def editpass

    current_user.change_password(params[:old_password], params[:new_password])
    redirect_to member_path(current_user.id)

  end

  # User access restriction
  def ban
  end

  def unban
  end



end

模型:查看:字段验证:old_password /:new_password ..

class User < ActiveRecord::Base

    # Virtual attributes
    # _password attributes serve in-profile password change and are not part of the model
    attr_accessor :login, :apiid, :vcode, :old_password, :new_password, :new_password_confirmation

    # Include default devise modules. Others available are:
    # :token_authenticatable, :confirmable,
    # :lockable, :timeoutable and :omniauthable
    devise  :database_authenticatable, :registerable, :confirmable,
            :recoverable, :rememberable, :trackable, :validatable, :authentication_keys => [:login]

    # Registration show/edit form validation
    validates :username,    :presence   => true,
                            :length     => { :minimum => 6, :maximum => 255 },
                            :uniqueness => true

    validates :apiid,       :presence   => true,
                            :numericality => { :only_integer => true },
                            :acc_api    => true,
                            :on         => :create

    validates :vcode,       :presence   => true,
                            :length     => { :minimum => 20, :maximum => 255 },
                            :on         => :create

    # In profile password
    validates :old_password,    :presence   => true,
                                :length     => { :minimum => 8, :maximum => 255 },
                                :if         => :password_changed?

    validates :new_password,    :presence   => true,
                                :length     => { :minimum => 8, :maximum => 255 },
                                :if         => :password_changed?,
                                :confirmation   => true

    validates :new_password_confirmation,   
                                :presence   => true


    attr_accessible :login, :username, :group, :apiid, :vcode, :email, :password, :password_confirmation, :remember_me

    # Register character belonging to user
    after_create :register_characters

    # Model association
    has_many :apis
    has_many :characters

    # Allows user to reset password in profile
    # for Forgot Password look at Devise
    def change_password(oldpass, newpass)
        if self.valid_password?(oldpass)
            # User is logged out automatically by devise upon
            # password change
            self.password = newpass
            self.save
        else
            return false
        end
    end

    # Register account characters
    def register_characters
        require 'nokogiri'
        require 'open-uri'

        # Fetch account level xml
        uri = "https://api.eveonline.com/account/Characters.xml.aspx?keyID=#{self.apiid}&vCode=#{self.vcode}"
        xml = Nokogiri::XML(open(uri))
        row = xml.xpath("//row")

        # Create characters bound to user
        row.each do |entry|
            # Register new character
            character = Character.new(
                :charid     =>  entry['characterID'].to_i,
                :user_id    =>  self.id,
                :name       =>  entry['name'],
                :corp       =>  entry['corporationName']
                )
            character.save

            # Register character associated api credentials
            api = Api.new(
                :user_id        =>  self.id,
                :character_id   =>  character.id,
                :apiid          =>  self.apiid,
                :vcode          =>  self.vcode
                )
            api.save

            character.update_character
        end
    end

    # Check if user is banned before login
    def active_for_authentication?
      super && self.banned == false
    end

    # Redefine authentication procedure to allow login with username or email
    def self.find_for_database_authentication(warden_conditions)
      conditions = warden_conditions.dup
      if login = conditions.delete(:login).downcase
        where(conditions).where("username = '#{login}' OR email = '#{login}'").first
      else
        where(conditions).first
      end
    end

end

2 个答案:

答案 0 :(得分:1)

基本上,您的密码验证未达到。

使用change_password方法,您只需将控制器中的值传递给该方法,并使用它们来设置password。该模型未设置old_passwordnew_password,因此无法对其进行验证。此外,由于您没有传递password_confirmation而只是直接在模型中设置密码(self.password = newpass),因此也未使用password_confirmation

正如另一个答案中所提到的,最好使用update_attributes或Devise文档中推荐的任何内容。希望我的解释能够为您的方法无法正常工作提供一些见解。

如果您想坚持使用change_password方法,则必须将值传递给属性,以便模型验证它们。尝试这样的事情:

  #controller

  @user = current_user

  if @user.change_password(params[:old_password], params[:new_password], params[:new_password_confirmation])
    redirect_to member_path(current_user.id)
  else
    @errors = @user.errors.full_messages
    render 'edit_password_view' # not sure what this action is named
    # you now have an array of errors (@errors) that you can render however you see fit in the view
  end


  #model
  def change_password(oldpass, newpass, newpass_conf)
     self.password = newpass
     self.old_password = oldpass
     self.new_password = newpass
     self.new_password_confirmation = newpass_conf
     return self.save
  end

答案 1 :(得分:0)

我认为正确的方法是更新用户属性而不是使用更改密码。也许本指南可以提供帮助:

https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-edit-their-password