Rails REST API - генерирует разрешенные поля для ввода json на основе вложенных ассоциаций модели без атрибутов жесткого кодирования - PullRequest
0 голосов
/ 06 ноября 2018

Я разрабатываю REST Api для заводских генераторов приложения, чтобы можно было также создавать экземпляры модели с помощью REST, и мне интересно, как я могу разрешить вложенные атрибуты модели без жесткого кодирования атрибутов.

Предположим, у меня есть модель под названием Ресторан

class Restaurant < ApplicationRecord
  has_one :cost, dependent: :destroy, inverse_of: :grant
  has_one :address, dependent: :destroy, inverse_of: :grant
  has_one :owner, dependent: :destroy, inverse_of: :grant

  accepts_nested_attributes_for :cost, :address, :owner
  ...

, где его ассоциации также имеют свои собственные атрибуты модели и фабрику

FactoryGirl.define do factory :restaurant, class Restaurant do

  after(:create) do |restaurant|
    restaurant.cost = assign_attributes(attributse_for(:cost_factory))
    restuarnat.address = assign_attributes(attributes_for(:address_factory))
    restaurant.owner = assign_attributes(attributes_for(:owner_factory))
  end
 ...
end

, где его вложенные ассоциации также имеют свою собственную фабрику. Я передаю тело JSON через REST API в этом формате

{
  "restaurant": {
    "cost_attributes": {
     "staff": 123
     "tables": 123
    }
}

Я знаю, что могу разрешить атрибуты таким образом

params.permit(:restaurant)
      .permit(cost_attributes: [:staff, :tables],
              address_attributes: [:address_attr_1],
              owner_attributes: [:owner_attr_1]]

но у реальной модели, над которой я работаю, много ассоциаций. Будет больно жестко все кодировать. Есть ли способ, которым я могу разрешить передачу параметров вместо жесткого кодирования в моем контроллере? В настоящее время это то, что я думаю

params.permit(Restaurant.nested_attributes_options.keys)

но, очевидно, это не сработает.

Ответы [ 2 ]

0 голосов
/ 02 декабря 2018

Чтобы улучшить ответ yoones, вот способ рекурсивно собрать все глубоко вложенные имена атрибутов, используя отражения:

  def get_nested_attributes(model, _attributes = [])

    # base case
    if model.nested_attributes_options.empty?
      nil

    # recurse deeper
    else
      associations_list = model.reflect_on_all_associations(:has_one)
      associations_list = associations_list.push(model.reflect_on_all_associations(:has_many)).flatten

      nested_attributes = associations_list.each_with_object({}) do |association , hash|

        association_model = association.klass.nil? ? association.name.to_s.classify.constantize : association.klass

        # include attributes of association model
        # { _attributes => [attributes_1, attribute_2] }
        attribute_name = :"#{association.name.to_s}_attributes"
        hash[attribute_name] = association_model
                               .send(:attribute_names)
                               .map(&:to_sym)

        # recurse deeper into tree, get the result and append
        # { _attributes => [attributes_1, attribute_2, { } ] }
        result = get_nested_attributes(association_model, hash[attribute_name])
        if !result.nil?
          hash[attribute_name].push(result)
        end
      end
      nested_attributes
    end
  end

model = Restaurant
nested_attributes = get_nested_attributes(model)
params.permit(nested_attributes)
0 голосов
/ 06 ноября 2018

Вот один из способов собрать имена вложенных атрибутов:

mod = Restaurant

nested_attributes = mod.nested_attributes_options.keys.each_with_object({}) do |association, hash|
  hash[:"#{association}_attributes"] = association.
                                       to_s.
                                       classify.
                                       constantize.
                                       send(:attribute_names).
                                       map(&:to_sym)
end
params.permit(:restaurant).permit(nested_attributes)

Этот код довольно общий, не стесняйтесь адаптировать его к вашему конкретному варианту использования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...