【问题标题】:Can you do a before create action on a rails controller您可以在 Rails 控制器上执行创建前操作吗
【发布时间】:2015-10-21 22:56:18
【问题描述】:

我有一个创建操作,但我只希望创建操作在尝试创建的表单中创建 IF 2 项为真。是否可以在完成创建操作之前执行 if 语句,还是让我的控制器太胖?

我有一个表格,我想提交给我的数据库,但根据表格中的一些问题,我希望表格在将表格信息放入数据库之前显示另一个页面(支付页面) .只有在充电成功后,如果充电通过,控制器才会将信息放入数据库中。

所以我想知道是否可以在控制器中放入创建操作之前的逻辑?

--附加信息--

所以我仍在努力解决这个问题... 在我的表单控制器中,我有

def intermediary
  if @model.who_pays == true
    @amount = @model.how_much_to_pay
    redirect_to charge_path, :notice => "Please make payment before proceeding"
  else
    redirect_to model_path #to create object
  end
end

然后以我的实际形式出现

Model.new

但我将其更改为

<%= form_for [@model, url: [intermediary_path]] do |f| %>

这个逻辑正确吗?

【问题讨论】:

  • 你能提供更多细节吗?不过,根据您所写的内容,这听起来像是属于模型或表单对象验证的应用程序逻辑。
  • 只是为了检查我是否正确理解了您想要的行为:提交表单 -> 检查 Attrs :x:y -> 如果两个 Attrs 都为真,则创建记录 || Elsif Either Attr False,呈现付款视图 -> 提交付款表格 -> 创建付款记录并创建原始记录。无需深入了解如何发生这种情况,这大致就是您想要发生的事情——对吧?
  • 对不起,实际上是提交表单 -> 检查 Attrs :x -> 如果 Attrs X 为假,则创建记录 || Elsif Attr True -> 从 Attrs 获取付款金额:Y,呈现付款视图,将 Attrs Y 显示为应付金额 -> 提交付款表格 -> 成功收费 -> 创建原始记录
  • 关于该流程的棘手部分是您需要保留一些状态(在这种情况下,是原始表单提交的属性的知识),而用户执行另一个完整的“往返”来处理付款(这可能本身由于多种原因而失败)。所以这不是你可以在控制器中轻松处理的事情——你需要将那些原始属性踢到数据库中,以便在请求之间保留它们。考虑创建一个“原始事物”数据库记录,将:is_paid 列设置为false,然后单独处理支付流程。
  • 我一直在保留关于“这可以在控制器中完成”的原始问题的反馈,但是有很多方法可以在 Rails 中完成之前我'd 建议达到 Javascript。没有什么不利于 JS 本身——在 Rails“层”中保持这样的流程更容易(而不是开始涉及客户端逻辑和交互)。第一条评论(re:使用模型来处理这个业务逻辑)是我建议的方向。如果不进一步了解 Rails 应用程序的现有移动部分,很难深入了解它。

标签: ruby-on-rails model-view-controller


【解决方案1】:

如果没有额外的形式,这应该在你的模型中处理validations

#app/controllers/your_controller.rb
class YourController < ApplicationController
   def new
      @model = Model.new
   end

   def create
      @model = Model.new model_params
      @model.save
   end
end

在你的模型中...

#app/models/model.rb
class Model < ActiveRecord::Base
   validate :true_questions, on: :create

   private

   def true_questions
      errors.add(:option1, "Must be true") unless option1
      errors.add(:option2, "Must be true") unless option2
   end   
end

使用表单,您将有多种选择:

  1. 带有会话/cookie 的“中间”操作
  2. JS/Ajax

正如 cmets 中提到的,这是"state" 的问题——即您如何能够在整个过程中保持数据完整性。

您应该查看stripe 是如何处理此问题的 - 他们将用户发送到身份验证页面(他们在其中接收令牌),然后被重定向回“确认”页面,他们可以从该页面继续操作。

-

中介

如果您有中间操作,则必须稍微更改流程:

#config/routes.rb
resources :controller do
   get :intermediary, on: :collection
end

#app/controllers/your_controller.rb
class YourController < ApplicationController
   def intermediary
      # perform validations in the controller
      # set instance or session vars if necessary
      # render payment page
   end
   def create
      # returned from payment system - input into DB
   end
end

这会很好用,尽管这意味着有自定义路线和其他操作。

-

Ajax

另一种方法是使用 Ajax / JS。

这可以通过将数据发送到您的应用(可能是您的“创建”操作)并定义某些开关来实现。这些将使您能够在调用付款视图之前执行所需的验证。

支付视图将是 Ajax 的用武之地:

#app/assets/javascripts/application.js
$(document).on("submit", "#____", function(){
   $.ajax({
      url: "controller",
      method: "POST",
      data: .......
      success: function(data){
         // show payment page
      }
   });
});

#app/controllers/your_controller.rb
class YourController < ApplicationController
   def create
      if params[:x] 
          # perform validation
          # return payment form
      else
          # capture payment data
          # save to db
      end
   end
end

【讨论】:

  • 好的,谢谢 Rich。我正在尝试实现这一点,但要确保我理解你。中间操作实际上是在表单到达最终目的地之前将表单发送到另一条路线吗?那么我的表格不应该提交给中介吗?我的视图是否应该显示类似 &lt;%= form_for [:interemdiary_path], :validate =&gt; true do |f| %&gt; 的内容,然后在我的充电控制器上它提交给最初打算的真实表单?
  • 你需要使用form_for @object, url: [intermediary_path],但是这就是我的想法:)。就个人而言,我会尝试使用条带实现——它将帮助您了解他们是如何做到的;他们的过程非常相似
  • 我们可以私下讨论一下吗?我在如何设置这个问题上遇到了一点小问题。
  • 好的,让我看看如何进行私人聊天
  • 我查看了您发布的所有选项,我认为最好的解决方案是允许记录,但如果它...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多