Rails 4如何在出错时覆盖设计响应路径

时间:2013-10-24 19:15:58

标签: ruby-on-rails devise

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

  1. 毕业生
  2. 雇主
  3. 和一个设计用户可以通过多态: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。我尝试用respond_with替换redirect_to,但最终我丢失了带有相关错误消息的资源对象。任何人都知道如何做到这一点?

    这些是我的模特:

    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 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      /   
    

3 个答案:

答案 0 :(得分:6)

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

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

答案 1 :(得分:3)

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

我认为您要做的是代替new动作。请尝试以下方法:

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

答案 2 :(得分:0)

  

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

     

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

     

如果存在验证错误,则响应会呈现默认操作,   这是:新邮件请求或:编辑补丁或放置。

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

对于您的情况,render 'view_path'代替respond_with块的内容应该有效。