Как создавать динамические маршруты API с помощью Grape on Rails и проверять пользовательские параметры

Я использую виноград для разработки API для рельсов, который работает довольно хорошо для всей модели, кроме формы динамической модели. У нас есть следующие модели..

1- product_type
2- product_fields
3- products

product_type имеет has_many связь как с product_fields, так и с products моделями. При создании нового product_type мы можем создать различные атрибуты поля для этого product. Каждый product имеет разные атрибуты, но мы храним их в отдельной таблице "products". Я хочу динамически генерировать API всякий раз, когда добавляется product_type.

Я пробовал, как показано ниже, но продолжаю получать ошибки при публикации записи. Цените любое предложение.

require 'grape'

module API  
    module V1
        class Products < Grape::API
            include API::V1::Defaults            
            @product_type=ProductType.all
            @product_type.each do |producttype|
                resource :"#{producttype.name}" do
                    desc "Create a new product for #{producttype.name}"
                    params do
                        requires :product_type_id , type: "Integer",  desc: "product type Id"
                        producttype.productfields.each do |field|
                            if field.is_required? 
                              requires :"#{field.field_name}" , type: "#{field.filed_type}",  desc: "#{field.field_name}"
                            else
                              optional :"#{field.field_name}", type: "#{field.filed_type}", desc: "#{field.field_name}"
                            end
                        end
                    end
                    post do
                        Products.create!({
                            product_type_id:params[:product_type_id],
                            ........
                            ........
                            ........
                        })
                    end
                end
            end
        end
    end
end   

Ошибка:

  NoMethodError - undefined method `collect' for nil:NilClass:
  grape-swagger (0.10.1) lib/grape-swagger.rb:70:in `block in combine_namespace_routes'
  grape-swagger (0.10.1) lib/grape-swagger.rb:65:in `combine_namespace_routes'
  grape-swagger (0.10.1) lib/grape-swagger.rb:39:in `add_swagger_documentation'
  app/controllers/api/v1/base.rb:10:in `<class:Base>'
  app/controllers/api/v1/base.rb:6:in `<module:V1>'
  app/controllers/api/v1/base.rb:5:in `<module:API>'
  app/controllers/api/v1/base.rb:4:in `<top (required)>'

person Sri    schedule 10.08.2015    source источник
comment
Не могли бы вы 1) уточнить свой вопрос и дополнить его примером и тем, как вы хотите, чтобы URL-адреса API выглядели, и 2) убедиться, что документация по винограду не охватывает эту проблему.   -  person croeck    schedule 10.08.2015
comment
Привет croeck, я обновил свой вопрос.   -  person Sri    schedule 11.08.2015


Ответы (1)


Хорошо, спасибо за обновление вашего вопроса, теперь можно увидеть проблему.

Насколько я понял, вы собираетесь создать маршрут API для каждого типа продукта. Однако ваш подход не сработает так, как вы планировали. Grape генерирует маршруты API только на этапе инициализации приложения, а не во время выполнения.

Вместо этого вам нужно определить свой маршрут следующим образом:

params do
  requires :producttype_id, type: Integer, desc: "The product type's ID"
end
post '/:producttype_id' do
  # check if params[:producttype_id] is valid, otherwise raise 404
  ProductType.find([params[:producttype_id]])

  # raise an error if the ProductType was not found
  error! 'ProductType not found', 404

  # do some stuff...

  # return your response
  { producttype_id: params[:producttype_id] }
end

Для ProductTypes должен быть только один маршрут API, чтобы охватить все текущие и будущие экземпляры объекта. Однако затем вам необходимо подтвердить существование экземпляра!

Это решает вашу проблему создания динамических маршрутов API, но не распространяется на проверку параметров в зависимости от того, требуется ли поле ProductType или нет. Лично я бы встроил эту логику проверки в код, а не в сам маршрут. Тем не менее, вы также можете написать собственный валидатор, который загружает экземпляр ProductType, а затем проверяет остальные параметры. Я недавно описал этот подход в Как проверить этот хэш-параметр?

person croeck    schedule 11.08.2015