【问题标题】:Rails 4 How Overwrite Devise Respond Path Upon ErrorRails 4如何在错误时覆盖设计响应路径
【发布时间】:2013-10-24 19:15:57
【问题描述】:

我一直在努力解决这个问题。我有一个 Rails4/Devise 3.1 应用程序,系统中有两个用户:

  1. 毕业生
  2. 雇主

还有一个通过多态:profile 关联设计可以成为毕业生或雇主的用户。我让毕业生通过/graduate/sign_up 路径和雇主通过/employer/sign_up 路径注册,这两个路径都指向相同的/views/devise/registrations/new.html.erb 视图(因为他们的注册表单几乎相同 - 电子邮件和密码)。一切正常,除非出现验证错误,RegistrationsController#create.respond_with resource 总是将两种用户类型重定向到/users 路径,我需要将它们重定向回它们最初来自的位置,例如/graduate/sign_up/employer/sign_up 分别。我尝试用redirect_to 替换respond_with,但我最终丢失了带有相关错误消息的资源对象。有知道如何做到这一点的人吗?

这些是我的模型:

class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

  belongs_to :profile, polymorphic: true
end

class Graduate < ActiveRecord::Base
  has_one :user, as: :profile 
end

class Employer < ActiveRecord::Base
  has_one :user, as: :profile
end

注册控制器:

class RegistrationsController < Devise::RegistrationsController

  def create
    build_resource sign_up_params

    user_type = params[:user][:user_type]
    # This gets set to either 'Graduate' or 'Employer'
    child_class_name = user_type.downcase.camelize
    resource.profile = child_class_name.constantize.new

    if resource.save
      if resource.active_for_authentication?
        set_flash_message :notice, :signed_up if is_navigational_format?
        sign_up(resource_name, resource)
        respond_with resource, :location => after_sign_up_path_for(resource)
      else
        set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_navigational_format?
        expire_session_data_after_sign_in!
        respond_with resource, :location => after_inactive_sign_up_path_for(resource)
      end
    else
      clean_up_passwords(resource)
      respond_with resource
    end
  end
end

注册视图(毕业生和雇主都一样):

<h2>Sign up</h2>

<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
  <%= devise_error_messages! %>

  <div><%= f.label :email %><br />
  <%= f.email_field :email, :autofocus => true %></div>

  <div><%= f.label :password %><br />
  <%= f.password_field :password %></div>

  <div><%= f.label :password_confirmation %><br />
  <%= f.password_field :password_confirmation %></div>
  <%= hidden_field resource_name, :user_type, value: params[:user][:user_type] %>

  <div><%= f.submit "Sign up" %></div>
<% end %>

<%= render "devise/shared/links" %>

这些是我的路线:

 devise_for :users, :controllers => { :registrations => 'registrations' }

 devise_scope :user do
    match 'graduate/sign_up', to: 'registrations#new', user: { user_type: 'graduate' }, via: [:get]
    match 'employer/sign_up', to: 'registrations#new', user: { user_type: 'employer' }, via: [:get]
  end

  root to: 'home#index'

rake 路由的输出;

$ rake routes
                  Prefix Verb     URI Pattern                    Controller#Action
        new_user_session GET      /users/sign_in(.:format)       devise/sessions#new
            user_session POST     /users/sign_in(.:format)       devise/sessions#create
    destroy_user_session DELETE   /users/sign_out(.:format)      devise/sessions#destroy
           user_password POST     /users/password(.:format)      devise/passwords#create
       new_user_password GET      /users/password/new(.:format)  devise/passwords#new
      edit_user_password GET      /users/password/edit(.:format) devise/passwords#edit
                         PATCH    /users/password(.:format)      devise/passwords#update
                         PUT      /users/password(.:format)      devise/passwords#update
cancel_user_registration GET      /users/cancel(.:format)        registrations#cancel
       user_registration POST     /users(.:format)               registrations#create
   new_user_registration GET      /users/sign_up(.:format)       registrations#new
  edit_user_registration GET      /users/edit(.:format)          registrations#edit
                         PATCH    /users(.:format)               registrations#update
                         PUT      /users(.:format)               registrations#update
                         DELETE   /users(.:format)               registrations#destroy
        graduate_sign_up GET /graduate/sign_up(.:format)    registrations#new {:user=>{:user_type=>"graduate"}}
        employer_sign_up GET /employer/sign_up(.:format)    registrations#new {:user=>{:user_type=>"employer"}}
                    root GET      /   

【问题讨论】:

  • 我注意到,如果我将注册视图 &lt;%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %&gt; 中的 url: value 替换为 &lt;%= form_for(resource, url: "sign_up") do |f| %&gt;,那么它可以工作。但是,这似乎不是正确的做法。
  • +1 对于我来说,我遇到了这个问题,无法弄清楚源代码中发生这种情况的位置。
  • 我也有同样的问题,你终于解决了?

标签: ruby-on-rails devise


【解决方案1】:

Apparently,如果您有一个名为#index 的现有模板,则忽略:location 参数。我仍然不明白为什么当资源出现错误时,Devise 会重定向到 #index 或 #show。

我会在发现更多信息后更新此答案。

【讨论】:

    【解决方案2】:

    调用respond_with 将呈现该资源的默认操作。我认为这是index 操作(/users/),因此是重定向的原因。

    我认为您想要做的是呈现 new 操作。请尝试以下操作:

    if resource.save
      ...
    else
      clean_up_passwords(resource)
      render :action => 'new'
    end
    

    【讨论】:

      【解决方案3】:

      在respond_with的情况下,对于html响应-如果请求方法是get,则会引发异常,但对于其他请求(例如post),响应取决于资源是否有任何验证错误(即假设尝试已经用于保存资源,例如通过创建操作)-

      如果没有错误,即资源保存成功,则 响应重定向到资源,即它的显示操作。

      如果存在验证错误,则响应呈现默认操作, 这是 :new 用于发布请求或 :edit 用于补丁或放置。

      来源:http://apidock.com/rails/v4.1.8/ActionController/MimeResponds/respond_with

      对于您的情况,render 'view_path' 代替 respond_with 块应该可以工作。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-09
        • 2013-02-27
        • 1970-01-01
        相关资源
        最近更新 更多