portabilis / i-diario

Lançando o maior software livre de educação do Brasil!
Other
95 stars 45 forks source link

Apresentar refatoração das APIs #11

Open wilkinsondarolt opened 5 years ago

wilkinsondarolt commented 5 years ago

Avaliar problemas de

Em um dos arquivos da pasta app/controllers/api/v2

Seguindo as práticas descritas em nosso style guide

ricsdeol commented 5 years ago

Olá tenho uma sugestão que tenho usados em meus projetos, este é exemplo usando em um controller 'normal' mas é facilmente adaptado para fazer api, usando ActiveModelSerializer/Paginação/Ransack etc.

Criei um concern chamado Resoursable

module Resourceable
  extend ActiveSupport::Concern

  included do
    before_filter :set_resource, only: [:show, :edit, :update, :destroy]
    before_filter :authorize_resource
    helper_method :resource

    class_attribute :model, :model_attribute_name, :resource_actions,
                    :relationships, :permitted_parameters, :order
  end

  class_methods do
    # Define the ActiveModel::Base served by this resource controller.
    def serve(model, relationships: [], parameters: [], order: {id: :desc})
      self.model = model
      self.model_attribute_name = "@#{model.to_s.underscore}"
      self.relationships = relationships
      self.permitted_parameters = parameters
      self.order = order
    end
  end

  def index
    @search = policy_scope(model)
              .ransack(params[:q])

    @resources = @search.result.distinct
              .includes(relationships)
              .paginate(page: params[:page], per_page: params[:per_page])
              .order(order)
    respond_with @resources
  end

  def show; end

  def new
    instance_variable_set model_attribute_name, resource_build
    respond_with resource
  end

  def edit; end

  def create
    instance_variable_set model_attribute_name, resource_build
    resource.assign_attributes resource_params

    if resource.save
      flash[:success] = I18n.t('flash.actions.create.notice')
    else
      flash[:error] = resource.errors.full_messages
    end

    respond_with resource
  end

  def update
    if resource.update(resource_params)
      flash[:success] = I18n.t('flash.actions.update.notice')
    else
      flash[:error] = resource.errors.full_messages
    end

    respond_with resource
  end

  def destroy
    if resource.destroy
      flash[:success] = I18n.t('flash.actions.destroy.notice')
    else
      flash[:error] = I18n.t('flash.actions.destroy.alert')
    end
    respond_with resource, location: resources_path
  end

  def destroy_all
    if policy_scope(model).destroy_all
      flash[:success] = I18n.t('flash.actions.destroy_all.notice')
    else
      flash[:error] = I18n.t('flash.actions.destroy_all.error')
    end

    redirect_to resources_path
  end

  def settings; end

  private

  def resources_path
    polymorphic_path model
  end

  def resource_path
    polymorphic_path resource
  end

  def resource_build
    model.new
  end

  def resource
    instance_variable_get(model_attribute_name)
  end

  def set_resource
    instance_variable_set model_attribute_name,
                          policy_scope(model).
                          includes(relationships).
                          find(params[:id])
  end

  def authorize_resource
    authorize(resource || model)
  end

  def resource_params
    params.require(model.to_s.underscore.to_sym).permit permitted_parameters
  end
end

E nos controller eu faço algo do tipo:

class TasksController < ApplicationController
  include Resourceable
  before_filter :set_create_by, only: [:create]
  before_filter :set_closed_at, only: [:update]

  serve Task,
        parameters: [ :title, :description, :status, :due_date,
          :created_by_id, :closed_at, :attendance_id,
          { user_ids: []  }
        ],
        relationships: [:users],
        order: { due_date: :desc }

  def resource_build
    model.new resource_params
  end

  private

  def set_create_by
    params[:task][:created_by_id] = current_user.id
  end

  def set_closed_at
    params[:task][:closed_at] = DateTime.current if !@task.closed? && params.dig(:task, :status) == 'closed'
  end
end
class ProductItemsController < ApplicationController
  include Resourceable

  serve ProductItem,
        parameters: [:part_number, :description, :base_price, :product_type_id],
        order: {description: :asc}
end

Isso facilitaria no test com pois pderia fazer algo com https://relishapp.com/rspec/rspec-core/docs/example-groups/shared-examples mas fui inventar de usar minitest e ainda não sei como fazer algo parecido.

Ha claro isso poderia fazer parte da refatoração dos controllers de vcs tbm como previsto n issue #9

Att