设计:在用户确认后设置用户默认模板

Devise: setup user default templates upon user confirmation

我想要的:使用 Devise 进行用户注册、登录等...当用户注册并确认后,我想为该用户创建一组用户默认模板。

我尝试过的: 我试图覆盖 Confirmations#show 以便 show.html.erb 成为视图,并在成功确认后调用 #setup_user_defaults() 。 class 确认控制器 Devise::ConfirmationsController

    def show
      render('show')
      setup_user_defaults()
      super
    end

我不断收到一条错误消息,提示我只能在一个操作中进行 1 次重定向或渲染。之所以拥有这种观点对我来说很重要,是因为#setup_user_defaults() 花费的时间太长,以至于用户可能会点击刷新或搞砸进程

我的想法:我是新手,还没有学过后台工作。所以,我的问题是:这是后台工作吗?或者我怎样才能让#show 有一个显示 "Your account is being set up. This may take a few minutes." 的视图而不使用 AJAX(我还没有到那个时候)。

或有其他想法?

您收到错误是因为您正在调用 render,然后您正在调用 super,其中也有渲染或重定向。您不能在一个方法中多次调用渲染或重定向(除非它被封装到条件 if 语句中)。

此外,您不需要像在 javascript 中那样调用方法的空括号。

现在。任何大型或缓慢的 运行ning 任务都是后台处理的理想选择。即使您是新手,如果您使用的是 rails 4.2,现在的后台作业也非常简单!

我会使用 delayed_job,它简单且灵活。所以这些是步骤:

1.添加 delayed_job 和守护进程到你的 gemfile & 运行 bundle install

gem 'delayed_job_active_record'
gem 'daemons'

2。确保设置模板的方法在用户模型中

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

  def set_default_templates
    ### this is where all your setup code will go, remember that you're inside the object itself, so if you need to reference data stored already you'll use self, e.g. self.name or self.confirmed_at
  end
  handle_asynchronously :set_default_templates
end

注意 确保在 handle_asyncronously 行中添加方法名称,这告诉应该始终使用 ActiveJob 调用此方法的模型(这是允许您使用您想要的任何后台服务但您的代码在模式中不会更改的包装器)

3。现在是调用方法的时候了,有 2 个选择:从控制器调用方法,或者在 after_create 回调

中调用方法

我建议在 after_create 中执行此操作,它只是更干净一点。所以在你的模型中,使用与上面相同的代码,但在设计声明下添加这一行:

after_create :set_default_tempaltes

如果您更愿意在控制器中进行操作,您可以可以,但请记住必须在注册控制器中进行设计,因此当新用户注册时,它会发生在创建方法中:

def create
  super
  if resource.save
    resource.set_default_templates
  end
end

注意 知道在你完全理解这些设计方法在做什么之前,我不建议重写他们,并认为使用 after_create 回调

更安全

4.现在生成你的延迟作业

rails generate delayed_job:active_record

5.从命令行启动后台进程

bin/delayed_job start

此外,如果您在应用程序服务器中使用 unicorn 和 foreman,则还需要执行其他步骤,但这些步骤在教程和 Whosebug 此处进行了概述,因此如果您只是搜索或创建一个新问题卡住

你不能 double render the same page from the same action. But you can split them into two actions. First make sure that the email confirmation is successful and if it is, redirect them to another action (must override devise's Confirmations#show 不调用 super):

def show
  self.resource = resource_class.confirm_by_token(params[:confirmation_token])
  yield resource if block_given?

  if resource.errors.empty?
    flash[:notice] = "Your account is being set up. This may take a few minutes. 
                      Please wait to be redirected."
    redirect_to setup_defaults_path
  else
    respond_with_navigational(resource.errors, status: :unprocessable_entity){ render :new }
  end
end

在第二个操作中,当用户等待 setup_user_defaults 完成时,应显示上面设置的 flash 消息。成功后,最终将他们重定向到他们的个人资料或您想要的任何内容。

def setup_defaults
  if setup_user_defaults()
    redirect_to after_confirmation_path_for(resource_name, resource)
  end
end

理想情况下,您会创建一个后台作业,但要实现您想要做的事情,上面的内容应该可以做到。希望对您有所帮助!

这里还有一个关于使用 sidekiq 进行后台处理的很棒的教程:https://ryanboland.com/blog/writing-your-first-background-worker/