Rails Post 方法重定向到编辑操作而不是创建 [英] Rails Post method redirecting to edit action rather than create
问题描述
我正在编写一个小型 rails 应用程序,我正在尝试为用户添加一种类似于 rails cast 274 (http://railscasts.com/episodes/274-remember-me-reset-password).我能够添加此功能,但现在它似乎已损坏.我有一个来自登录页面的 reset_password 表单的链接.Rails 代码如下:
重置密码
<%= form_tag password_resets_path, :method =>:post 做 %><div class="field"><%= label_tag :email %><%= text_field_tag :email, params[:email] %>
<div class="actions"><%= submit_tag重置密码"%></div><%结束%>
以下是浏览器生成的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">电子邮件</label><input id="email" name="email" type="text"/>
<div class="actions"><input name="commit" type="submit" value="重置密码"/></div></表单>
我对 rails 和 html 有点陌生,但我认为这个表单是通过post"方法将数据传递给我的控制器.我认为这就是我想要的,因为运行 rake 路由给了我(仅用于密码重置 - 我还有一个用户和会话资源):
users GET/users(.:format) users#indexpassword_resets GET/password_resets(.:format) password_resets#indexPOST/password_resets(.:format) password_resets#createnew_password_reset GET/password_resets/new(.:format) password_resets#newedit_password_reset GET/password_resets/:id/edit(.:format) password_resets#editpassword_reset GET/password_resets/:id(.:format) password_resets#showPUT/password_resets/:id(.:format) password_resets#update删除/password_resets/:id(.:format) password_resets#destroy
所以我认为提交这个表单应该能让我在我的 password_resets 控制器上执行创建操作.但是,我得到:
路由错误没有路由匹配 {:action=>"edit", :controller=>"password_resets", :id=>nil}
这意味着表单以某种方式试图提交给编辑操作.如果是这种情况,id=>nil 是有道理的,因为我的表单要求的是 :email,而不是 :id.我不确定为什么/如何发生这种情况,因为我将 password_resets 视为一种资源(如在 rails cast 中),并且只是使用 rails 自动生成的路由.
下面是我的 routes.rb 文件和我的 password_resets 控制器文件.
MyApp::Application.routes.draw 做资源:用户资源:会话,仅:[:new, :create, :destroy]资源:password_resets根到:'static_pages#home'匹配'/help',到:'static_pages#help'匹配'/about',到:'static_pages#help'匹配 '/signup',到:'users#new'匹配 '/remove',到:'users#remove'匹配'/signin',到:'sessions#new'匹配'/signout',到:'sessions#destroy',通过::delete结尾
还有 password_reset 控制器:
class PasswordResetsController <应用控制器定义新结尾定义创建用户 = User.find_by_email(params[:email])user.send_password_reset 如果是用户#无论是否找到用户,这都将起作用#更安全一点,但也更烦人#用户...redirect_to root_url, :notice =>电子邮件已发送并重置密码指示"结尾定义编辑@user = User.find_by_password_reset_token!(params[:id])结尾定义更新@user = User.find_by_password_reset_token!(params[:id])如果@user.password_reset_sent_at <2小时前redirect_to new_password_reset_path, :alert =>密码重置已过期."elsif @user.update_attributes(params[:user])redirect_to root_url, :notice =>密码已重置!"别的渲染:编辑结尾结尾结尾
我还创建了一个动作邮件程序来向用户发送电子邮件,但我认为还没有必要查看那里,因为在我接触到任何涉及实际发送电子邮件的代码之前我就崩溃了.我真的很感激任何关于为什么我的表单行为如此,而不是我想要的行为的想法/推测.
提前感谢大家.
更新:
谢谢皮质!按照建议,我查看了服务器日志,我的表单将执行创建操作,并且代码正在生成电子邮件.但是,我在电子邮件中给用户的 password_reset_token 作为他们重置密码的 url 的一部分,始终为零,这给了我错误.我通过以下代码生成令牌(我认为与 Rails Cast 相同)
def generate_token(列)开始self[column] = SecureRandom.urlsafe_base64结束而 User.exists?(column => self[column])结尾
我尝试通过以下方式将其分配给用户:
def send_password_resetself.password_reset_token = generate_token(:password_reset_token)self.password_reset_sent_at = Time.zone.nowself.save(验证:假)UserMailer.password_reset(self).deliver结尾
所以我现在的问题是为什么我的生成令牌方法会返回 nil 值?这很令人费解,因为我使用 generate token 方法来生成一个令牌以在整个会话中跟踪用户,并且在那里运行良好...
内森
我能够找出我的错误.本质上,
开始self[column] = SecureRandom.urlsafe_base64结束而 User.exists?(column => self[column])
导致将 nil 令牌存储在数据库中.我重新设计了函数的逻辑,现在它工作正常.感谢所有帮助过的人.
def generate_token(列)测试 = SecureRandom.urlsafe_base64如果User.exists?(列=> 测试)self.generate_token(列)别的自我[列] = 测试结尾结尾
I am writing a small rails application and I am attempting to add the ability to for users to reset their passwords in a method similar to rails cast 274 (http://railscasts.com/episodes/274-remember-me-reset-password). I was able to add this functionality, but it now seems to have broken. I have a link to a reset_password form from the signin page. The rails code is below:
<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 %>
And below is the html generated by the browser (for the password reset form, not the page source).
<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>
I am somewhat new to rails and html, but I think this form is passing data to my controller via the 'post' method. I think this is what I want, because running rake routes gives me (just for password resets - I also have a user and sessions resource):
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
So I think submitting this form should get me to the create action on my password_resets controller. However, I get:
Routing Error
No route matches {:action=>"edit", :controller=>"password_resets", :id=>nil}
Which means the form is somehow trying to submit to the edit action. If this is the case, id=>nil makes sense because my form is asking for an :email, not :id. I am not sure why/how this is happening, because I am treating password_resets like a resource (as in the rails cast), and just using the routes rails automagically generates.
Below is my routes.rb file and my password_resets controller file.
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
And the password_reset controller:
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
I have also created an action mailer to send the emails to the user, but I don't think there is a point to looking there yet because I am breaking before I get to any code that involves actually sending email. I would really appreciate any thoughts/speculation as to why my form is behaving as it is, rather than how I want it to.
Thanks to everyone in advance.
Update:
Thank you cortex! As suggested, I looked at the server log and my form was going to the create action, and the code was going through generating the email. However, the password_reset_token, which I give the user in the email as part of the url where they reset there password, is always nil, Which gives me the error. I produce the token through the following code (which I think is the same as the Rails Cast)
def generate_token(column)
begin
self[column] = SecureRandom.urlsafe_base64
end while User.exists?(column => self[column])
end
I try to assign it to the user via:
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
So my question now is why would my generate token methods return a nil value? This is puzzling because I use the generate token method to generate a token to track users throughout a session, and it is working fine there...
Nathan
I was able to figure out my bug. Essentially,
begin
self[column] = SecureRandom.urlsafe_base64
end while User.exists?(column => self[column])
was causing nil tokens to be stored in the database. I reworked the logic of the function and now it works fine. Thanks to everyone who helped.
def generate_token(column)
test = SecureRandom.urlsafe_base64
if
User.exists?(column => test)
self.generate_token(column)
else
self[column] = test
end
end
这篇关于Rails Post 方法重定向到编辑操作而不是创建的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!