【问题标题】:How to redirect to create action of another controller如何重定向以创建另一个控制器的操作
【发布时间】:2013-02-27 20:01:54
【问题描述】:

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

特别是,我希望允许用户在不使用 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

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

【问题讨论】:

  • 我认为是render action =&gt; :create,但我正在努力寻找它的文档。
  • @Cort3z :如果你能找到我将不胜感激。我也去找找。
  • 您应该创建一个答案而不是编辑您的问题,这对于未来的访问者来说会更具可读性。查看以下 url,了解如何添加 persist 路由而不会出现错误(在您的情况下使用收集路由):guides.rubyonrails.org/routing.html#adding-more-restful-actions
  • @Baldrick:非常感谢关于收集路线的提示。我将修改我的代码并将其添加为答案。
  • 不客气。现在您可以接受自己的答案,因此这是第一个可见的答案。

标签: ruby-on-rails redirect omniauth


【解决方案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

【讨论】:

  • 感谢您指出错误。但是,我收到的错误消息是由于我无法重定向以创建操作,因为它是一个 POST。我从来没有改变过通过 HTML 请求来#create :)
【解决方案2】:

您可以在 Post 模型上创建一个方法,并从 PostsController 和 ServicesController 调用它来保存帖子(尽管在这种情况下它非常简单:新建,然后保存,因此您在 DRY 方面一无所获,可能有些封装的好处)。或者创建一个包含所有逻辑的 create_post 方法的通用 mixin。然后将其包含到 SessionsController 和 PostsController 中并从“create”中调用它。

在混合模块中:

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

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

【讨论】:

  • @Cort3z 我认为重点不在于显示您可以通过渲染执行的操作(渲染“posts/new”,因为我相信这里“posts/create”是一个 POST 请求,而不是有一个视图)但实际上创建了帖子(它只存储在会话中,而不是最初在 format.json 块中的 db 中创建)。所以,渲染不是你需要的。好吧,redirect_to 不能重定向到 POST 请求,所以你最终要对你的架构做一些事情来达到同样的结果。
  • 感谢您的回答。创建一个模块来在两个控制器之间共享一个方法对我来说是一个新的学习。但是,这可能表明这里存在根本性错误:)。我想出了另一个解决方案,可以避免像您建议的第一种方法那样从两个控制器调用方法(请参阅我的更新)。
【解决方案3】:

我发现了一个技巧来避免这个问题:我让#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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-13
    • 1970-01-01
    • 2012-05-24
    • 2012-09-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多