0

又一个拔毛器。经过两天的斗争,我无法弄清楚这里出了什么问题。

基本上我有一个由模型触发的表单验证:

validates :user, :presence => true, :uniqueness => true
validates :email, :presence => true, :uniqueness => true, :on => :create
validates :passwordHash, :presence => true, :confirmation => true, :on => :create

非空用户在更新表单视图上工作:

= simple_form_for @user do |f|      
  = f.input :user
  = f.input :locale
  = f.input :localeLanguage, :label => 'Language', :as => :select, :collection => $language_array 
  = f.input :moderator
  = f.input :email
  = f.input :passwordHash, :label => 'Password'

但不在新用户上查看:

  = simple_form_for @user do |f|  
    %table.table-condensed
      %tr
        %td
          =f.input :user, :label => false, :placeholder => 'username'
      %tr
        %td
          = f.input :passwordHash, :label => false, :placeholder => 'password'
      %tr
        %td
          = f.input :email, :label => false, :placeholder => 'email'
      %tr
        %td
          = f.submit "Create User", :class => 'btn btn-primary'

我可以看到这些视图之间的唯一区别是,第一个视图创建了会话,因为用户已经登录,而第二个视图没有。但据我所知,这不应该有所作为。当然,update表单确实有一个实际的@user 对象,而在new其中它是空的。但我看过 Ryan Bates 的新用户验证的 railscast,他也做了几乎相同的事情。

会发生什么是users#create在提交带有空值的表单后调用的操作(这应该是不可能的)。当然我得到一个错误,因为它passwordHash是空的。

我应该指出,我没有使用任何额外的 gem 来帮助密码确认(在 railscast 中,Bates 使用bcrypt但我不能使用它,因为我们以不同的方式创建密码哈希,而且我认为这是密码确认魔法只要)。无论如何这不应该影响表单验证吗?

这里欢迎任何理论或想法,我快疯了。我将要编写一些糟糕的 javascript 来手动完成,这会很糟糕,可能需要我一个星期,我不做 javascript ;)

谢谢。

编辑

根据 Rachid 的要求,以下是newcreate操作:

  def new
    @user = User.new
  end

  def create
    #failsafe for failing form validation
    unless params[:passwordHash].present?
      redirect_to new_user_path, :notice => 'User or password cannot be blank' 
    else
      password_and_salt = User.hash_password(params[:passwordHash])
      hashed_password = password_and_salt[:password]
      user_salt = password_and_salt[:salt]
      @user = User.new(:user => params[:user], :passwordHash => hashed_password, :salt => user_salt)
      if @user.save
        session[:user_id] = @user.id
        redirect_to session[:item_to_edit]
      else
        redirect_to new_user_path, :notice => "User already exists, please pick another one"
      end
    end
  end

编辑 2

我已经create根据第一个答案重写了该方法,但仍然出现错误:

def create
    respond_to do |format|
      if params[:passwordHash].present? && params[:user].present? 
        password_and_salt = User.hash_password(params[:passwordHash])
        hashed_password = password_and_salt[:password]
        user_salt = password_and_salt[:salt]
        @user = User.new(:user => params[:user], :passwordHash => hashed_password, :salt => user_salt, :online_user => 1 )
        if @user.save
          session[:user_id] = @user.id
          redirect_to session[:item_to_edit]
        else
          format.html { render :action => "new" }
          format.json { render :json => @user.errors, :status => :unprocessable_entity }
        end
      else
          format.html { render :action => "new" }
          format.json { render :json => @user.errors, :status => :unprocessable_entity }
      end
    end
  end

错误是undefined method 'model_name' for NilClass:Class针对这一行的:

= simple_form_for @user do |f|

显然,@user = User.new它并没有回到表格中。在这一点上,我对如何编写create使其正常工作并显示错误消息的方法有点困惑。但我觉得我更接近了:)

@misha,这是update控制器动作,它只是非常标准的脚手架:

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

    respond_to do |format|
      if @user.update_attributes(params[:user])
        if session[:return_to]
          format.html { redirect_to session[:return_to], :notice => 'User was successfully updated.' }
        else
          format.html { redirect_to users_path, :notice => 'User was successfully updated.' }
        end

        format.json { head :ok }
      else
        format.html { render :action => "edit" }
        format.json { render :json => @user.errors, :status => :unprocessable_entity }
      end
    end
  end
4

1 回答 1

0

首先,您在这里假设的内容是不正确的:

会发生什么是users#create在提交带有空值的表单后调用的操作(这应该是不可能的)。当然我得到一个错误,因为密码哈希是空的。

有可能users#create被调用,实际上它应该发生。它在你处理这些东西的创建操作中。我认为您的问题是,如果@user未保存,您会进行重定向。您应该再次渲染视图,以便可以显示错误消息。

所以而不是:

redirect_to new_user_path, :notice => "User already exists, please pick another one"

尝试:

render :action => 'new'

根据您的评论进行编辑:

当验证失败时,Rails 会@user.errors自动填充。您无需在控制器中执行任何操作(即您的创建操作)!您所要做的就是在您的视图中显示错误@user.errors

关于您现在遇到的错误:

您收到错误的原因@user是未设置。您必须将您的create方法重写为以下内容:

def create
  respond_to do |format|
    if params[:user][:passwordHash].present?
      password_and_salt = User.hash_password(params[:user][:passwordHash])
      hashed_password = password_and_salt[:password]
      user_salt = password_and_salt[:salt]
    end

    @user = User.new(params[:user].merge({:passwordHash => hashed_password, :salt => user_salt, :online_user => 1}))

    if @user.save
      session[:user_id] = @user.id
      redirect_to session[:item_to_edit]
    else
      format.html { render :action => "new" }
      format.json { render :json => @user.errors, :status => :unprocessable_entity }
    end
  end
end
于 2012-05-03T12:13:15.067 回答