Rails Post方法重定向到编辑动作而不是创建

时间:2013-07-04 18:50:58

标签: ruby-on-rails runtime-error token rails-routing

我正在编写一个小型rails应用程序,我试图为用户添加一个能够以类似于rails cast 274(http://railscasts.com/episodes/274-remember-me-reset-password)的方法重置密码的功能。我能够添加此功能,但它现在似乎已经破碎。我从登录页面链接到reset_password表单。 rails代码如下:

 <h1>Reset Password</h1>

<%= form_tag password_resets_path, :method => :post do %>
  <div class="field">
    <%= label_tag  :email %>
    <%= text_field_tag :email, params[:email] %>
  </div>
  <div class="actions"><%= submit_tag "Reset Password" %></div>
<% end %>

以下是浏览器生成的html(用于密码重置表单,而不是页面源)。

<form accept-charset="UTF-8" action="/password_resets" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="&#x2713;" /><input name="authenticity_token" type="hidden" value="1UwA3fS90cean/z/g60M3CJYs1RNtHjyy4a1yAssWo0=" /></div>
  <div class="field">
    <label for="email">Email</label>
    <input id="email" name="email" type="text" />
  </div>
  <div class="actions"><input name="commit" type="submit" value="Reset Password" /></div>
</form>

我对rails和html有点新,但我认为这种形式是通过'post'方法将数据传递给我的控制器。我认为这就是我想要的,因为运行rake路由给了我(仅用于密码重置 - 我还有用户和会话资源):

users GET    /users(.:format)                    users#index

    password_resets GET    /password_resets(.:format)          password_resets#index
                    POST   /password_resets(.:format)          password_resets#create
 new_password_reset GET    /password_resets/new(.:format)      password_resets#new
edit_password_reset GET    /password_resets/:id/edit(.:format) password_resets#edit
     password_reset GET    /password_resets/:id(.:format)      password_resets#show
                    PUT    /password_resets/:id(.:format)      password_resets#update
                    DELETE /password_resets/:id(.:format)      password_resets#destroy

所以我认为提交此表单应该让我在我的password_resets控制器上进行创建操作。但是,我得到了:

Routing Error

No route matches {:action=>"edit", :controller=>"password_resets", :id=>nil} 

这意味着表单以某种方式尝试提交到编辑操作。如果是这种情况,id =&gt; nil是有道理的,因为我的表单要求的是:email,而不是:id。我不确定为什么/如何发生这种情况,因为我将password_resets视为资源(如在rails中),并且只使用rails自动生成的路由。

下面是我的routes.rb文件和我的password_resets控制器文件。

MyApp::Application.routes.draw do

  resources :users
  resources :sessions, only: [:new, :create, :destroy]
  resources :password_resets
  root to: 'static_pages#home'

  match '/help',    to: 'static_pages#help'
  match '/about',   to: 'static_pages#help'
  match '/signup',  to: 'users#new'
  match '/remove',  to: 'users#remove'
  match '/signin',  to: 'sessions#new'
  match '/signout', to: 'sessions#destroy', via: :delete
end

和password_reset控制器:

class PasswordResetsController < ApplicationController
  def new
  end

  def create
    user = User.find_by_email(params[:email])
    user.send_password_reset if user
    #this will work regardless of whether user is found
    #a bit more secure, but also a bit more annoying to the
    #user...
    redirect_to root_url,  :notice =>
        "Email was sent with password reset 
        instructions"
  end

  def edit
    @user = User.find_by_password_reset_token!(params[:id])
  end

  def update
    @user = User.find_by_password_reset_token!(params[:id])
    if @user.password_reset_sent_at < 2.hours.ago
      redirect_to new_password_reset_path, :alert => 
        "Password reset has expired."
    elsif @user.update_attributes(params[:user])
      redirect_to root_url, :notice => "Password has been reset!"
    else
      render :edit
    end      
  end
end

我还创建了一个动作邮件程序来将电子邮件发送给用户,但我认为还没有意义,因为在我找到任何涉及实际发送电子邮件的代码之前我已经破了。我真的很感激任何想法/猜测为什么我的表格表现得如此,而不是我想要它。

提前感谢所有人。

更新

谢谢皮质!正如所建议的那样,我查看了服务器日志,我的表单进入了创建操作,代码正在生成电子邮件。但是,我将电子邮件中的用户作为重置密码的网址的一部分给予用户的password_reset_token总是为零,这给了我错误。我通过以下代码生成令牌(我认为它与Rails Cast相同)

  def generate_token(column)
    begin
      self[column] = SecureRandom.urlsafe_base64
    end while User.exists?(column => self[column])
  end

我尝试通过以下方式将其分配给用户:

  def send_password_reset
    self.password_reset_token = generate_token(:password_reset_token)
    self.password_reset_sent_at = Time.zone.now
    self.save(validate: false)
    UserMailer.password_reset(self).deliver
  end

所以现在我的问题是为什么我的生成令牌方法会返回一个nil值?这很令人费解,因为我使用生成令牌方法生成一个令牌来跟踪整个会话中的用户,并且它在那里工作得很好......

内森

1 个答案:

答案 0 :(得分:0)

我能够找出我的错误。基本上,

begin
  self[column] = SecureRandom.urlsafe_base64
end while User.exists?(column => self[column])

导致nil令牌存储在数据库中。我重写了函数的逻辑,现在它工作正常。感谢所有帮助过的人。

 def generate_token(column)
    test = SecureRandom.urlsafe_base64
    if
      User.exists?(column => test)
      self.generate_token(column)
    else
      self[column] = test 
    end
end