Rails 4 сильных параметра получают разрешение от вложенной модели

Есть несколько вопросов для сильных параметров, но я не смог найти ответа для достижения своей цели. Пожалуйста, извините за любые дубликаты (и, возможно, укажите мне в правильном направлении). Я использую сильные параметры в модели, которая имеет несколько ассоциаций has_one и вложенные атрибуты с accepts_attributes_for.

В моих маршрутах у меня есть: (обновлено для лучшего понимания)

  resources :organisations do
    resources :contact_details
  end

То есть, для одной связанной модели я должен использовать

def organisation_params
  params.require(:organisation).permit(:org_reference, :supplier_reference, :org_type, :name, :org_members, :business, :contact_person, contact_detail_attributes: [:id, :contactable_id, :contactable_type, :phone, :fax, :mail, :state, :province, :zip_code, :street, :po_box, :salutation, :title, :last_name, :first_name, :description])
end

Это работает, но я должен перепечатать все мои разрешенные параметры для каждой связанной модели. Когда я изменяю свои разрешенные атрибуты для contact_details, я должен изменить его в нескольких местах (каждая модель, имеющая полиморфную ассоциацию).

Есть ли способ получить белый список параметров contact_details и включить его в родительский белый список?

Что-то вроде:

def organisation_params
  my_params = [:org_reference, :supplier_reference, :org_type, :name, :org_members, :business, :contact_person]
  contact_params = #get permitted params, that are defined in contact_details_controller
  params.require(:organisation).permit(my_params, contact_params)
end

Я не хочу обойти защиту, но я уже определил разрешенные атрибуты для contact_details и не хочу повторять это в каждой связанной "родительской" модели (потому что это утомительно и очень склонно к глупым ошибкам, таким как пропуск одного атрибута в одна из нескольких родительских моделей).

2 ответа

Решение

Используйте метод, определенный внутри ApplicationControllerили общий модуль:

  1. ApplicationController:

    class ApplicationController
      def contact_details_permitted_attributes
        [:id, :contactable_id, :contactable_type, ...]
      end
    end
    
    class ContactDetailsController < ApplicationController
      def contact_details_params
        params
          .require(contact_details)
          .permit(*contact_details_permitted_attributes)
      end
    end
    
    class OrganisationsController < ApplicationController
      def organisation_params
        params
          .require(:organisation)
          .permit(:org_reference, ..., 
                  contact_detail_attributes: contact_details_permitted_attributes)
      end
    end
    
  2. Общий модуль:

    module ContactDetailsPermittedAttributes
      def contact_details_permitted_attributes
        [:id, :contactable_id, :contactable_type, ...]
      end
    end
    
    class ContactDetailsController < ApplicationController
      include ContactDetailsPermittedAttributes
    
      def contact_details_params
        params
          .require(contact_details)
          .permit(*contact_details_permitted_attributes)
      end
    end
    
    class OrganisationsController < ApplicationController
      include ContactDetailsPermittedAttributes
    
      def organisation_params
        params
          .require(:organisation)
          .permit(:org_reference, ..., 
                  contact_detail_attributes: contact_details_permitted_attributes)
      end
    end
    

В Rails есть даже специальные каталоги для общих модулей, concerns внутри app/controllers а также app/models; действительно, в вашем случае вы должны использовать app/controllers/concerns

Я не понимаю, почему нет. В вашем ApplicationController вы могли бы иметь

def contact_attributes
  [:id, :contactable_id, :contactable_type, :phone, :fax, 
   :mail, :state, :province, :zip_code, :street, :po_box, 
   :salutation, :title, :last_name, :first_name, :description]
end

Тогда в вашей организации_парамс

def organisation_params
  my_params = [:org_reference, :supplier_reference, :org_type, :name, :org_members, :business, :contact_person]

  params.require(:organisation).permit(*my_params, contact_detail_attributes: contact_attributes)
end

В другом месте вы можете сделать...

def contact_params
params.require(:contact).permit(*contact_attributes)
end
Другие вопросы по тегам