Rails Post 方法重定向到编辑操作而不是创建 [英] Rails Post method redirecting to edit action rather than create

查看:54
本文介绍了Rails Post 方法重定向到编辑操作而不是创建的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个小型 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="&#x2713;"/><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="&#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>

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屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆