Créer un objet indirect
Cet exemple s’appuie sur la gestion de campus, avec des objets administration/Location.
Créer le modèle et la migration
rails g model administration/Location
name:string
slug:string
summary:text
university:references
address:string
city:string
zipcode:string
country:string
latitude:float
longitude:float
phone:string
url:string La propriété university permet de gérer le multitenant.
Les propriétés name et slug permettent de créer les permaliens.
Nourrir le modèle
class Administration::Location < ApplicationRecord
include AsIndirectObject
include Sanitizable
include Contentful
include Sluggable
include WebsitesLinkable
include WithBlobs
include WithCountry
include WithGitFiles
include WithGeolocation
include WithPermalink
include WithUniversity
scope :ordered, -> { order(:name) }
validates :name, :address, :city, :zipcode, :country, presence: true
def to_s
"#{name}"
end
def git_path(website)
"#{git_path_content_prefix(website)}locations/#{slug}/_index.html" if for_website?(website)
end
def dependencies
active_storage_blobs +
contents_dependencies +
programs +
schools
end
def references
[]
end
endAsIndirectObjectest en charge de toute la logique des objets indirects.Sanitizablesécurise les entrées dans la base de donnnées.Contentfulajoute les blocs et les titres.Sluggablegénère les slugs uniques à partir du nom.WebsitesLinkablepermet de créer des sites Web à propos de l’objet.WithBlobspermet de lister les blobs dans les dépendances.WithCountrygère le champcountryavec des codes ISO officiels.WithGitFilespermet de générer des fichiers statiques et de les mettre à jour.WithGeolocationremplitlatitudeetlongitudeà partir de l’adresse.WithPermalinkcrée les chemins et garde trace des redirections.WithUniversitygère le multi-tenant.
La méthode git_path(website) est utilisée pour définir le chemin du fichier sur le référentiel git.
Les dépendances sont les objets nécessaires pour l’affichage.
Les références sont les objets qui peuvent citer l’objet courant.
Créer le controller
En partant d’une copie d’un autre controller.
class Admin::Administration::LocationsController < Admin::Administration::ApplicationController
load_and_authorize_resource class: Administration::Location,
through: :current_university
def index
breadcrumb
end
def show
breadcrumb
end
def static
@about = @location
@website = @location.websites&.first
render_as_plain_text
end
def new
breadcrumb
end
def edit
breadcrumb
add_breadcrumb t('edit')
end
def create
if @location.save
redirect_to [:admin, @location],
notice: t('admin.successfully_created_html', model: @location.to_s)
else
breadcrumb
render :new, status: :unprocessable_entity
end
end
def update
if @location.update(location_params)
redirect_to [:admin, @location],
notice: t('admin.successfully_updated_html', model: @location.to_s)
else
breadcrumb
add_breadcrumb t('edit')
render :edit, status: :unprocessable_entity
end
end
def destroy
@location.destroy
redirect_to admin_education_locations_url,
notice: t('admin.successfully_destroyed_html', model: @location.to_s)
end
private
def breadcrumb
super
add_breadcrumb Administration::Location.model_name.human(count: 2), admin_administration_locations_path
breadcrumb_for @location
end
def location_params
params.require(:administration_location)
.permit(:name, :address, :zipcode, :city, :country, :url, :phone, school_ids: [], program_ids: [])
.merge(
university_id: current_university.id
)
end
endCréer les vues
En partant d’une copie d’un autre dossier de vues.
<%= simple_form_for [:admin, location] do |f| %>
<%= f.error_notification %>
<%= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present? %>
<div class="row mb-5">
<div class="col-lg-4">
<%= f.input :name %>
<%= render 'admin/application/summary/form', f: f, about: location %>
</div>
<div class="col-lg-4">
<%= f.input :address %>
<div class="row pure__row--small">
<div class="col-md-4">
<%= f.input :zipcode %>
</div>
<div class="col-md-8">
<%= f.input :city %>
</div>
</div>
<%= f.input :country, input_html: { class: 'form-select' } %>
</div>
<div class="col-lg-4">
<%= f.input :phone %>
<%= f.input :url %>
</div>
</div>
<% content_for :action_bar_right do %>
<%= submit f %>
<% end %>
<% end %><div class="table-responsive">
<table class="<%= table_classes %>">
<thead>
<tr>
<th><%= Administration::Location.human_attribute_name('name') %></th>
<th><%= Administration::Location.human_attribute_name('address') %></th>
<th></th>
</tr>
</thead>
<tbody>
<% locations.ordered.each do |location| %>
<tr>
<td><%= link_to location, [:admin, location] %></td>
<td><%= location.full_street_address %></td>
<td class="text-end">
<div class="btn-group" role="group">
<%= edit_link location %>
<%= destroy_link location %>
</div>
</td>
</tr>
<% end %>
</tbody>
</table>
</div><% content_for :title, @location %>
<%= render 'form', location: @location %><% content_for :title, Administration::Location.model_name.human(count: 2) %>
<%= render 'admin/administration/locations/list', locations: @locations %>
<% content_for :action_bar_right do %>
<%= create_link Administration::Location %>
<% end %><% content_for :title, Administration::Location.model_name.human %>
<%= render 'form', location: @location %><% content_for :title, @location %>
<div class="row">
<div class="col-lg-4">
<%= osuny_panel t('metadata') do %>
<%= osuny_label Education::School.human_attribute_name('address') %>
<p>
<%= @location.address %><br>
<%= @location.zipcode %> <%= @location.city %><br>
<%= @location.country %>
</p>
<% if @location.phone.present? %>
<%= osuny_label Education::School.human_attribute_name('phone') %>
<p><%= @location.phone %></p>
<% end %>
<% if @location.url.present? %>
<%= osuny_label Administration::Location.human_attribute_name('url') %>
<p><%= link_to @location.url, @location.url, target: :_blank %></p>
<% end %>
<% end %>
</div>
<% if @location.websites.any? %>
<div class="col-lg-4">
<%= osuny_panel Administration::Location.human_attribute_name('websites') do %>
<ul class="list-unstyled">
<% @location.websites.each do |website| %>
<li><%= link_to website, [:admin, website] %></li>
<% end %>
</ul>
<% end %>
</div>
<% end %>
</div>
<%= render 'admin/communication/blocks/content/editor', about: @location %>
<%= render 'admin/application/connections/list', about: @location %>
<% content_for :action_bar_left do %>
<%= destroy_link @location %>
<%= static_link static_admin_administration_location_path(@location) %>
<% end %>
<% content_for :action_bar_right do %>
<%= edit_link @location %>
<% end %>---
title: >
<%= prepare_text_for_static @about.name %>
<%= render 'admin/application/static/permalink' if @website %>
<%= render 'admin/application/static/design', full_width: true, toc_offcanvas: true %>
<% if @website %>
<%= render 'admin/application/static/breadcrumbs',
pages: @website.special_page(Communication::Website::Page::AdministrationLocation).ancestors_and_self,
current: @about %>
<% end %>
<%= render 'admin/communication/blocks/content/static', about: @about %>
---Déclarer la nouvelle partie
def self.parts
[
[Administration::Location, :admin_administration_locations_path],
[Administration::Qualiopi, :admin_administration_qualiopi_criterions_path],
]
endCela permet de construire le menu et les pages d’accueil de royaumes.
Créer la page spéciale
C’est la page qui va apparaître dans l’arborescence du site Web pour lister les objets.
class Communication::Website::Page::AdministrationLocation < Communication::Website::Page
def is_necessary_for_website?
website.about && website.about&.respond_to?(:administration_locations)
end
def editable_width?
false
end
def full_width_by_default?
true
end
def full_width
true
end
def dependencies
super +
[website.config_default_languages] +
website.administration_locations
end
protected
def current_git_path
@current_git_path ||= "#{git_path_prefix}locations/_index.html"
end
endIl faut aussi la déclarer dans le fichier qui les liste (le fichier est écourté pour la lisibilité).
module Communication::Website::Page::WithType
extend ActiveSupport::Concern
included do
TYPES = [
...
# Administration
Communication::Website::Page::AdministrationLocation,
...
]
end
endDéfinir la structure des permaliens
class Communication::Website::Permalink::Location < Communication::Website::Permalink
def self.required_in_config?(website)
website.has_administration_locations?
end
def self.static_config_key
:locations
end
# /campus/:slug/
def self.pattern_in_website(website, language)
"/#{website.special_page(Communication::Website::Page::AdministrationLocation, language: language).slug_with_ancestors}/:slug/"
end
endclass Communication::Website::Permalink < ApplicationRecord
MAPPING = {
...
"Administration::Location" => Communication::Website::Permalink::Location,
...
}
endAssocier l’objet au site Web
...
def administration_locations
has_administration_locations? ? about.administration_locations : Administration::Location.none
end
...
def has_administration_locations?
about && about.has_administration_locations?
end
...Il faut aussi le déclarer dans les méthodes à implémenter pours les objets qui peuvent être liés à un site Web.
...
def has_administration_locations?
raise NotImplementedError
end
...Tous les objets qui intègrent le concern WebsitesLinkable doivent intégrer la méthode, même si c’est pour renvoyer false.
Ajouter les locales
activerecord:
models:
administration/location:
one: Site
other: Campus
...
attributes:
administration/location:
address: Adresse
city: Ville
country: Pays
name: Nom
phone: Téléphone
programs: Formations dispensées
schools: Écoles
url: Site Web
websites: Sites Web associés
zipcode: Code postal