首页 > 解决方案 > Rails 6在渲染中传递参数:保存失败后的新参数

问题描述

我在负责创建新Transaction记录的控制器中有一个标准的创建方法。交易记录有一个必填字段,我将其隐藏在视图中,并通过传递一个 params[:filter] 自动为其分配一个值,因此我对交易和交易transaction_type都有一个 _form ,如下所示:withdrawaldeposit

#index.html.erb
<%= link_to 'Add funds', new_transaction_path(filter: 'deposit') %>
<%= link_to 'Withdraw Funds', new_transaction_path(filter: 'withdrawal') %>

#new.html.erb
<%= render 'form', transaction: @transaction, transaction_type: params[:filter] %>

#_form.html.erb
<%= simple_form_for @transaction do |f| %>
  <%= f.error_notification %>
  <%= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present? %>

  <%= f.text_field :transaction_type, value: transaction_type, type: "hidden" %>
  <%= f.input :amount, placeholder: 'Amount', label: false %>

  <%= f.button :submit, 'Submit' %>
<% end %>

如果由于某种原因验证失败,为了正确显示错误,将呈现 :new 视图。不幸的是,在这种情况下,如果用户再次填写整个表单(在第一次失败后),将不会创建记录,因为 params[:filter] 没有传递。有没有办法将原始 params[:filter] 直接传递给视图?

#controller
  # POST /transactions
  def create
    @transaction = wallet.transactions.new(transaction_params)

    if @transaction.save
      redirect_to :index, notice: 'Transaction was successfully created.'
    else
      render :new
    end
  end

标签: ruby-on-rails

解决方案


虽然我了解重用视图代码的方面,但您确实应该考虑创建单独的路由和控制器,并通过使用继承和局部变量而不是通过隐藏参数来解决代码重复问题。

resources :deposits, :withdrawls, only: [:new, :create]
class TransactionsController < ApplicationController

  helper_method :create_transaction_path

  def new
    @transaction = Transaction.new 
    render 'transactions/new'
  end

  def create
    @transaction = Transaction.new(transaction_params) do |t|
      t.transaction_type = transaction_type
    end

    if @transaction.save
       yield @transaction if block_given?
       success_response
    else
       yield @transaction if block_given?
       failure_response 
    end
  end

  private

  def transaction_type
    controller_name.singularize
  end

  def create_transaction_path 
    polymorphic_path(controller_name)
  end
  
  def transaction_params
    params.require(:transaction)
          .permit(:foo, :bar, :baz)
  end

  def success_response
     redirect_to transactions_path, 
       notice: 'Transaction was successfully created.'
  end

  def failure_response
    render 'transactions/new'
  end
end
class DepositsController < TransactionsController
  # POST /deposits
  def create
    super do |transaction|
      # do something just when making a deposit
    end
  end
end
class WithdrawlsController < TransactionsController
  # POST /withdrawls
  def create
    super do |transaction|
      # do something just when making a withdrawl
    end
  end
end
# app/views/transactions/_form.html.erb
<%= simple_form_for transaction, url: create_transaction_path do |f| %>
  <%= f.error_notification %>
  <%= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present? %>
  <%= f.input :amount %> # Do not use placeholders instead of labels
  <%= f.button :submit, 'Submit' %> 
<% end %>
<%= link_to 'Add funds', new_deposit_path %>
<%= link_to 'Withdraw Funds', new_withdrawl_path %>

为什么?

因为它为您提供了完成一项工作的端点,并且当需求出现分歧时,它还为您提供了明显的代码结构,因为它们肯定会发生分歧。


推荐阅读