Techioz Blog

両方の関連付けられたテーブルに多くのフィールドを含む has_many アソシエーションの accepts_nested_attributes_for のパラメータを処理する方法

概要

建物モデルと has_many の関連付けを持つユーザー モデルがあります。最初は user.create と user.buildings.create を使用してユーザーと建物を別々に作成していました。テーブルにそのフィールドが true の場合にのみ建物を作成するようなフィールドがあり、建物には次の条件もありました。建物内の条件付きフィールドが true の場合、より多くのフィールド データが建物に追加されます。ユーザーが単一の建物を作成するまでは、すべてがスムーズに実行されていました。しかし、ユーザーがさらに建物を作成し始めると、コードがバーストしてしまいます。 以下は users_controller のコードです

def create
      role = Role.find_by(id: params[:user][:role_id])
      if role.nil?
        render json: { error: 'invalid role' }, status: :unprocessable_entity
      else
        user = User.new(user_params)
        user.role_id = role.id
        ActiveRecord::Base.transaction do
          if user.save
            # If the user is a technician, handle equipment_params
            if role.name.downcase == 'technician'
              equipment_ids = params[:user][:equipment_id]
              handle_technician_params(user, equipment_ids)
            end
            # If the user is a customer, handle customer_params
            if role.name.downcase == 'customer'
              handle_customer_params(user)
            end
            # Generate a new authentication token for the user
            token, refresh_token = generate_tokens(user.id)
            render json: {  message: 'User created successfully', authentication_token: token, user: user, meta: {photos: UserSerializer.new(user) }}, status: :ok
          else
            render json: { errors: user.errors.full_messages }, status: :unprocessable_entity
          end
        end
      end
    end
def handle_customer_params(user)
      if user_params[:is_customer_direct_point_of_contact] == 'true'
        handle_building_params(user)
      else
        handle_service_params(user)
      end
    end

    def handle_building_params(user)
      building_params = params.require(:building).permit(:service_address_line1, :service_address_line2, :service_zip_code, service_images: [])
      building = user.buildings.create(building_params)
    end
    def handle_service_params(user)
      service_params = params.require(:building).permit(:service_address_line1, :service_address_line2, :service_zip_code, :name, :phone_number, :email, :tax_id, service_images: [])
      building = user.buildings.create(service_params)
    end

ユーザーを直接作成してビルドするために accepts_nested_attributes_for を使用するように変更しようとしましたが、その方法がわかりませんでした。 それを行う他の方法もありますか?

解決策

ここでクリーンアップできる非常に基本的なものがたくさんあります。これらには、コントローラー (user.technician?) ではなくモデル内で実行する必要がある値のテストなどが含まれます。モデルメソッドである必要があります。しかし、あなたの特定の質問に答えるために:

アプリの機能を実験しないでください。テストを書くことでより優れたコーダーになり、コード ベースがより良くなり、反復してより速く学習できるようになります。

https://translate.google.com/translate?hl=ja&sl=en&tl=ja&u=https://guides.rubyonrails.org/testing.html#functional-tests-for-your-controllers

そして、高頻度の反復テストにはガードを使用することをお勧めします。 https://translate.google.com/translate?hl=ja&sl=en&tl=ja&u=https://github.com/guard/guard