如何重定向以创建另一个控制器的操作

时间:2013-02-27 20:01:54

标签: ruby-on-rails redirect omniauth

我知道我无法对HTML重定向进行POST,但我的情况要求我在对用户进行身份验证后重定向以创建操作。我想知道如何绕过这个限制:

特别是,我想允许用户填写帖子而无需使用Omniauth登录。我使用AJAX调用将帖子保存到session [:post]。然后,用户可以使用omniauth登录并保留帖子。

我有一个带有创建操作的PostsController,用于处理初始ajax调用,并在验证用户后处理html请求:

  def create    
    @post = Post.new(params[:post])   
    respond_to do |format|    
      format.html{
        if @post.save
          redirect_to @post, notice: 'Post was successfully created.'
        else
          render action: "new"
        end
      }
      format.json {
        if session[:post] = @post
          render json: @post, status: :created, location: @post
        else
          render json: @post.errors, status: :unprocessable_entity
        end
      }
    end
  end
end 

然后,在我处理来自Facebook的回调的控制器中,我有:

class ServicesController < ApplicationController
  def create
    ... authentication logic here ...
    sign_in(:user, service.user)
    redirect_to :controller => "posts", :action =>"create"
  end
  method_alias: :facebook, :create

但是,这不起作用,因为我无法重定向到“创建”操作。我怎样才能完成这项任务?

3 个答案:

答案 0 :(得分:1)

在您发布的代码中,您永远不会阅读会话的内容。我认为如果你改变你的代码它可以工作:

更改@post的初始化:

@post = Post.new(params[:post]) || session[:post]  # Find object in session if not 

post.save之后添加:

session.delete :post   # clean session after successful creation

新的完整方法:

  def create    
    @post = Post.new(params[:post]) || session[:post]  # Find object in session if not in params  
    respond_to do |format|    
      format.html{
        if @post.save
          redirect_to @post, notice: 'Post was successfully created.'
          session.delete :post   # clean session after successful creation
        else
          render action: "new"
        end
      }
      format.json {
        if session[:post] = @post
          render json: @post, status: :created, location: @post
        else
          render json: @post.errors, status: :unprocessable_entity
        end
      }
    end
  end
end

答案 1 :(得分:1)

你可以在Post模型上创建一个方法,并从PostsController和ServicesController中调用它来保存帖子(虽然在这种情况下它非常简单:新的,然后保存,所以你在DRY方面没有任何成就,可能是一些封装的好处)。或者使用所有逻辑创建包含create_post方法的公共mixin。然后将其包含在SessionsController和PostsController中,并从“create”调用它。

在mixin模块中:

def create_post(allow_json=false)
  @post = Post.new(params[:post])   
  respond_to do |format|    
    format.html {
      if @post.save
        redirect_to @post, notice: 'Post was successfully created.'
      else
        render "posts/new"
      end
    }
    if allow_json
      ... your post-saving & json-processing logic ...
    end
  end
end

在PostsController中:

def create
  create_post(true)
end

在SessionsController中:

def create
  ... authentication logic here ...
  sign_in(:user, service.user)
  create_post(false)
end

我没有编译和尝试,所以我只希望它有效。总的来说,我必须说有一些基本上是错误的,所以我会寻找其他架构解决方案来实现相同的结果,但作为一种快速而肮脏的方法它应该可行。

答案 2 :(得分:1)

我发现了一个黑客来避免这个问题:我让#create处理AJAX调用并写入会话,然后创建另一个操作以在用户进行身份验证后将其持久保存到我的数据库中:

class PostsController < ApplicationController

  def create  
    @post = Post.new(params[:post])    
    respond_to do |format|
      format.json {
        if session[:post] = @post
          render json: @post, status: :created, location: @post
        else
          render json: @post.errors, status: :unprocessable_entity
        end
      }
    end
  end

  def persist
    @post = session[:post]
    if @post.save
       session.delete :post
       redirect_to @post, notice: 'Post was successfully created.'
     else
       render action: "new"
     end
  end

然后在我的routes.rb中,我有:

  resources :posts do
    collection do
      get 'persist'
    end
  end

最后,在我的ServicesController中:

sign_in(:user, service.user) 
redirect_to persist_posts_path