Merge pull request #2958 from tchak/optimize-api
Eliminate n+1 from API calls
This commit is contained in:
commit
b9325147d1
9 changed files with 46 additions and 9 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) }
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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) }
|
||||||
|
|
Loading…
Reference in a new issue