Merge pull request #2958 from tchak/optimize-api

Eliminate n+1 from API calls
This commit is contained in:
Paul Chavard 2018-11-08 14:55:19 +01:00 committed by GitHub
commit b9325147d1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 46 additions and 9 deletions

View file

@ -4,7 +4,7 @@ class API::V1::DossiersController < APIController
DEFAULT_PAGE_SIZE = 100 DEFAULT_PAGE_SIZE = 100
def index def index
dossiers = @procedure.dossiers.state_not_brouillon.page(params[:page]).per(per_page) dossiers = @dossiers.page(params[:page]).per(per_page)
render json: { dossiers: dossiers.map{ |dossier| DossiersSerializer.new(dossier) }, pagination: pagination(dossiers) }, status: 200 render json: { dossiers: dossiers.map{ |dossier| DossiersSerializer.new(dossier) }, pagination: pagination(dossiers) }, status: 200
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
@ -12,7 +12,7 @@ class API::V1::DossiersController < APIController
end end
def show def show
dossier = @procedure.dossiers.find(params[:id]) dossier = @dossiers.for_api.find(params[:id])
respond_to do |format| respond_to do |format|
format.json { render json: { dossier: DossierSerializer.new(dossier).as_json }, status: 200 } format.json { render json: { dossier: DossierSerializer.new(dossier).as_json }, status: 200 }
@ -36,12 +36,14 @@ class API::V1::DossiersController < APIController
end end
def fetch_procedure_and_check_token def fetch_procedure_and_check_token
@procedure = Procedure.includes(:administrateur).find(params[:procedure_id]) @procedure = Procedure.for_api.find(params[:procedure_id])
if !valid_token_for_administrateur?(@procedure.administrateur) if !valid_token_for_administrateur?(@procedure.administrateur)
render json: {}, status: :unauthorized render json: {}, status: :unauthorized
end end
@dossiers = @procedure.dossiers.state_not_brouillon
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
render json: {}, status: :not_found render json: {}, status: :not_found
end end

View file

@ -8,7 +8,7 @@ class API::V1::ProceduresController < APIController
private private
def fetch_procedure_and_check_token def fetch_procedure_and_check_token
@procedure = Procedure.includes(:administrateur).find(params[:id]) @procedure = Procedure.for_api.find(params[:id])
if !valid_token_for_administrateur?(@procedure.administrateur) if !valid_token_for_administrateur?(@procedure.administrateur)
render json: {}, status: :unauthorized render json: {}, status: :unauthorized

View file

@ -5,6 +5,11 @@ class Champ < ApplicationRecord
has_one_attached :piece_justificative_file has_one_attached :piece_justificative_file
has_one :virus_scan has_one :virus_scan
# We declare champ specific relationships (Champs::CarteChamp and Champs::SiretChamp)
# here because otherwise we can't easily use includes in our queries.
has_many :geo_areas, dependent: :destroy
belongs_to :etablissement, dependent: :destroy
delegate :libelle, :type_champ, :order_place, :mandatory?, :description, :drop_down_list, to: :type_de_champ delegate :libelle, :type_champ, :order_place, :mandatory?, :description, :drop_down_list, to: :type_de_champ
scope :updated_since?, -> (date) { where('champs.updated_at > ?', date) } scope :updated_since?, -> (date) { where('champs.updated_at > ?', date) }

View file

@ -1,6 +1,4 @@
class Champs::CarteChamp < Champ class Champs::CarteChamp < Champ
has_many :geo_areas, foreign_key: :champ_id, dependent: :destroy
# We are not using scopes here as we want to access # We are not using scopes here as we want to access
# the following collections on unsaved records. # the following collections on unsaved records.
def cadastres def cadastres

View file

@ -37,7 +37,6 @@ class Champs::SiretChamp < Champ
] ]
] ]
belongs_to :etablissement, dependent: :destroy
accepts_nested_attributes_for :etablissement, allow_destroy: true, update_only: true accepts_nested_attributes_for :etablissement, allow_destroy: true, update_only: true
def search_terms def search_terms

View file

@ -59,6 +59,26 @@ class Dossier < ApplicationRecord
scope :with_champs, -> { includes(champs: :type_de_champ) } scope :with_champs, -> { includes(champs: :type_de_champ) }
scope :nearing_end_of_retention, -> (duration = '1 month') { joins(:procedure).where("en_instruction_at + (duree_conservation_dossiers_dans_ds * interval '1 month') - now() < interval ?", duration) } scope :nearing_end_of_retention, -> (duration = '1 month') { joins(:procedure).where("en_instruction_at + (duree_conservation_dossiers_dans_ds * interval '1 month') - now() < interval ?", duration) }
scope :for_api, -> {
includes(commentaires: [],
champs: [
:geo_areas,
:etablissement,
piece_justificative_file_attachment: :blob
],
champs_private: [
:geo_areas,
:etablissement,
piece_justificative_file_attachment: :blob
],
pieces_justificatives: [],
quartier_prioritaires: [],
cadastres: [],
etablissement: [],
individual: [],
user: [])
}
accepts_nested_attributes_for :individual accepts_nested_attributes_for :individual
delegate :siret, :siren, to: :etablissement, allow_nil: true delegate :siret, :siren, to: :etablissement, allow_nil: true

View file

@ -47,6 +47,16 @@ class Procedure < ApplicationRecord
scope :cloned_from_library, -> { where(cloned_from_library: true) } scope :cloned_from_library, -> { where(cloned_from_library: true) }
scope :avec_lien, -> { where.not(path: nil) } scope :avec_lien, -> { where.not(path: nil) }
scope :for_api, -> {
includes(
:administrateur,
:types_de_champ_private,
:types_de_champ,
:types_de_piece_justificative,
:module_api_carto
)
}
validates :libelle, presence: true, allow_blank: false, allow_nil: false validates :libelle, presence: true, allow_blank: false, allow_nil: false
validates :description, presence: true, allow_blank: false, allow_nil: false validates :description, presence: true, allow_blank: false, allow_nil: false
validate :check_juridique validate :check_juridique

View file

@ -67,6 +67,9 @@ namespace :'2018_07_31_nutriscore' do
libelle: 'Numéro SIRET' libelle: 'Numéro SIRET'
) )
) do |d, target_tdc| ) do |d, target_tdc|
if d.etablissement.present?
d.etablissement.signature = d.etablissement.sign
end
target_tdc.champ.create( target_tdc.champ.create(
value: d.etablissement&.siret, value: d.etablissement&.siret,
etablissement: d.etablissement, etablissement: d.etablissement,

View file

@ -136,7 +136,7 @@ describe API::V1::DossiersController do
context 'when dossier exists and belongs to procedure' do context 'when dossier exists and belongs to procedure' do
let(:procedure_id) { procedure.id } let(:procedure_id) { procedure.id }
let(:date_creation) { Time.zone.local(2008, 9, 1, 10, 5, 0) } let(:date_creation) { Time.zone.local(2008, 9, 1, 10, 5, 0) }
let!(:dossier) { Timecop.freeze(date_creation) { create(:dossier, :with_entreprise, procedure: procedure, motivation: "Motivation") } } let!(:dossier) { Timecop.freeze(date_creation) { create(:dossier, :with_entreprise, :en_construction, procedure: procedure, motivation: "Motivation") } }
let(:dossier_id) { dossier.id } let(:dossier_id) { dossier.id }
let(:body) { JSON.parse(retour.body, symbolize_names: true) } let(:body) { JSON.parse(retour.body, symbolize_names: true) }
let(:field_list) { [:id, :created_at, :updated_at, :archived, :individual, :entreprise, :etablissement, :cerfa, :types_de_piece_justificative, :pieces_justificatives, :champs, :champs_private, :commentaires, :state, :simplified_state, :initiated_at, :processed_at, :received_at, :motivation, :email, :instructeurs] } let(:field_list) { [:id, :created_at, :updated_at, :archived, :individual, :entreprise, :etablissement, :cerfa, :types_de_piece_justificative, :pieces_justificatives, :champs, :champs_private, :commentaires, :state, :simplified_state, :initiated_at, :processed_at, :received_at, :motivation, :email, :instructeurs] }
@ -147,7 +147,7 @@ describe API::V1::DossiersController do
end end
it { expect(subject[:id]).to eq(dossier.id) } it { expect(subject[:id]).to eq(dossier.id) }
it { expect(subject[:state]).to eq(dossier.state) } it { expect(subject[:state]).to eq('initiated') }
it { expect(subject[:created_at]).to eq('2008-09-01T08:05:00.000Z') } it { expect(subject[:created_at]).to eq('2008-09-01T08:05:00.000Z') }
it { expect(subject[:updated_at]).to eq('2008-09-01T08:05:00.000Z') } it { expect(subject[:updated_at]).to eq('2008-09-01T08:05:00.000Z') }
it { expect(subject[:archived]).to eq(dossier.archived) } it { expect(subject[:archived]).to eq(dossier.archived) }