我正在编写一个小型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="✓" /><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值?这很令人费解,因为我使用生成令牌方法生成一个令牌来跟踪整个会话中的用户,并且它在那里工作得很好......
内森答案 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