5

質問

私には子供である親がいaccepts_nested_attributes_forます。そのため、親用のフォームがある場合はbuild、子用のフォーム フィールドも表示できるようにする必要があります。私が知りたいのはbuild、子供はどこに行けばいいですか? モデル、ビュー、またはコントローラーで?

なぜ私はこれを求めているのですか

あなたは頭を振って、私がこのような質問をする狂人だと思っているかもしれません.

私は次のようなモデルを持っていCustomerます:accepts_nested_attributes_forbilling_address

class Customer
  belongs_to :billing_address, class_name: 'Address'
  accepts_nested_attributes_for :billing_address
end

ユーザーに新しいフォームを提示するとき、ユーザーが実際に のフィールドを見ることができるようにCustomer、空白があることを確認したいと思います。したがって、コントローラーには次のようなものがあります。billing_addressbilling_address

def new
  @customer = Customer.new
  @customer.build_billing_address
end

ただし、ユーザーがフィールドに入力せずに無効なフォームを送信しようとすると、コントローラーのアクションにこのようなものを配置しない限り、billing_addressのフィールドがなくなったフォームが表示されます:billing_addresscreate

def create
  @customer = Customer.new(params[:customer])
  @customer.build_billing_address if @customer.billing_address.nil?
end

もう 1 つの問題があります。ユーザーが を編集しようとして、CustomerまだCustomerが関連付けられていない場合、billing_addressのフィールドが表示されないということbilling_addressです。したがって、次のようなものをコントローラーに追加する必要があります。

def edit
  @customer = Customer.find(params[:id])
  @customer.build_billing_address if @customer.billing_address.nil?
end

updateまた、コントローラーのメソッドでも同様のことが発生する必要があります。

とにかく、これは非常に反復的であるため、モデルで何かを行うことを考えました. 私の最初の考えは、次のafter_initializeように、モデルのイベントにコールバックを追加することでした:

class CustomerModel
  after_initialize :build_billing_address, if: 'billing_address.nil?'
end

しかし、私のスパイダーマンの感覚はチクチクし始めました。Customer将来、コードの他の部分で a をインスタンス化して、これが予期しない方法で大混乱を引き起こすことはないと誰が言いますか。

したがって、私の現在の考えでは、これを行うのに最適な場所はフォームビュー自体であるということです。私が達成しようとしているのはフォームに空白を設けることでbilling_addressあり、フォーム自体はコード内で私が知っている唯一の場所だからです。のフォームを表示しようとしていることを確認してbilling_addressください。

しかし、ご存知のように、私はインターネット上の単なる男です。どこに行けばいいbuild_billing_addressですか?

4

5 に答える 5

3

Xavier Shayによるこのアドバイスは 2011 年のものですが、「これはビューの問題なので (フィールドを表示するかしないか?)」ビューに入れることを提案しています。

app/helpers/form_helper.rb:

module FormHelper
  def setup_user(user)
    user.address ||= Address.new
    user
  end
end

アプリ/ビュー/ユーザー/_form.html.erb:

<%= form_for setup_user(@user) do |f| %>

ヘルパー メソッドを次のように変更する必要があることに注意してください。

  def setup_user(user)
    user.addresses.build if user.addresses.empty?
    user
  end

コントローラーはまったく変更されていません。

于 2015-03-15T05:57:22.997 に答える
2

モデルに常に請求先住所が必要であることがわかっている場合は、ドキュメントで説明されているように、モデル クラスでこの属性の getter をオーバーライドできます。

def billing_address
    super || build_billing_address
end

build_billing_address必要に応じて、特定のニーズに応じて任意の属性を渡します。

于 2013-12-27T14:55:06.507 に答える
1

何かを構築して後で保存したい場合は、build を使用します。ネストされたルートで使用します。

def create
 @address = @customer.billing_addresses.build(params[:billing_address])
 if @address.save
   redirect_to @customer.billing_addresses
 else
   render "create"
 end
end

そんな感じ。コンソールにいるときもビルドを使用します。

于 2013-10-25T06:43:29.443 に答える
1

MVCの原則を覚えておく必要があります。これは、アプリのさまざまな可動部分に効率的に分散される DRY (自分自身を繰り返さない) コードを作成することです。

accepts_nested_attributes_for物を乾いた状態に保つのに最適です

accepts_nested_attributes_for関連付けを介して別のモデルにデータを渡すことができるモデル関数です。これが存在する理由は、単一のフォームに基づいて別のモデルのデータを入力する機能を提供するためであり、余分なコードを追加せずに機能を拡張するのに優れています

あなたが挙げている問題は、アプリの他の領域でコードを使用したい場合、あらゆる種類の問題が発生することです

それに対する私の反論は、できるだけ効率的なアプリケーションを作成するためには、コードをできるだけ少なくして、Rails にすべてを処理させたいということです。関数を使用するとこれaccepts_nested_attributes_forを実行できますが、使用するたびに対応する必要があるという点で明らかにコストがかかります

私が推奨するのは、あなたができる最も効率的なコードを使用することですが、規則も守ることです。これにより、速度と効率が保証されます

于 2013-10-25T08:16:51.340 に答える