Modelisation - rodinux/plannings_cinema GitHub Wiki
L'application a quatre objets principaux, l'objet Film, l'objet Seance, l'objet Village et l'objet User, puis ont été ajouter l'objet Classification pour les calssifications des films et Disponibilité pour un calendrier des indisponibilités des projectionnistes ou caissières.
Voici le schéma des tables dans le fichier.
Base de données
db/schema.rb :
# This file is auto-generated from the current state of the database. Instead
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# Note that this schema.rb definition is the authoritative source for your
# database schema. If you need to create the application database on another
# system, you should be using db:schema:load, not running all the migrations
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
# you'll amass, the slower it'll run and the greater likelihood for issues).
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2017_04_06_102111) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "classifications", id: :serial, force: :cascade do |t|
t.string "nom_classification"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "classifications_films", id: false, force: :cascade do |t|
t.integer "classification_id", null: false
t.integer "film_id", null: false
end
create_table "disponibilites", id: :serial, force: :cascade do |t|
t.string "nom"
t.datetime "start_time"
t.datetime "end_time"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "films", id: :serial, force: :cascade do |t|
t.string "titrefilm"
t.string "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "distribution"
t.string "affiche"
end
create_table "seances", id: :serial, force: :cascade do |t|
t.string "projection"
t.string "caisse"
t.datetime "horaire"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "annulee"
t.string "version"
t.string "commentaire"
t.integer "film_id"
t.integer "village_id"
t.string "extras"
t.integer "billets_adultes"
t.integer "billets_enfants"
t.integer "billets_scolaires"
t.integer "total_billets"
end
create_table "users", force: :cascade do |t|
t.string "email", null: false
t.string "crypted_password"
t.string "salt"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "nom"
t.string "prenom"
t.string "telephone"
t.string "role"
t.index ["email"], name: "index_users_on_email", unique: true
end
create_table "villages", id: :serial, force: :cascade do |t|
t.string "commune"
t.string "salle"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
Modèles
Une association est créée entre les tables Films et Villages avec la table Seances, elles sont liées pas avec les colonnes film_id (qui aura le même nombre que l'id du film correspondant à la séance) et avec village_id (qui aura le même nombre que l'id du village correspondant à la séance). Les tables Films et Villages sont liés à travers la Séance. Une association aussi est créée entres les tables Classifications et Film avec la table Classifications_films et sont liés à travers la Séance.
Ceci grâce aux modèles :
models/seance.rb
class Seance < ApplicationRecord
belongs_to :film, :inverse_of => :seances, optional: true
belongs_to :village, :inverse_of => :seances, optional: true
validates :film_id, :presence => true
validates :village_id, :presence => true
validates :horaire, :presence => true
before_create :setup_default_value_for_new_seances
#throw(:abort)
before_update :setup_default_value_for_updated_seances
#throw(:abort)
def self.lieuxtest
lieuxtest = Hash[
"lamastre" => Seance.order(horaire: :asc).map{ |seance|
seance if seance.village.commune.upcase == "LAMASTRE" },
"vernoux" => Seance.all.order(horaire: :asc).map{ |seance| seance if seance.village.commune.upcase == "VERNOUX" },
"chalencon" => Seance.all.order(horaire: :asc).map{ |seance| seance if seance.village.commune.upcase == "CHALENCON" },
"itinerance" => Seance.all.order(horaire: :asc).map{ |seance| seance if seance.village.commune.upcase != "LAMASTRE" &&
seance.village.commune.upcase != "VERNOUX" && seance.village.commune.upcase != "CHALENCON" },
"tous les lieux" => Seance.all.order(horaire: :asc).map{|seance| seance }
]
end
def self.seances_calendrier
seances_calendrier = Seance.where({horaire: ((Date.today - 6.day)..(Date.today + 6.day))})
end
def self.seances_a_venir
seances_a_venir = Seance.where({horaire: (Date.today..Date.today + 60)})
end
def self.seances_passees_3_semaines
seances_passees_3_semaines = Seance.where({horaire: (3.week.ago..(Date.today + 1))}).order(horaire: :asc)
end
def self.seances_passees_1_mois
seances_passees_1_mois = Seance.where({horaire: (30.days.ago..Date.today)}).order(horaire: :desc)
end
def self.seances_semaine
seances_semaine = Seance.where({horaire: (Date.today.midnight..(Date.today + 7))}).order(horaire: :desc)
end
def self.seances_1_mois_avant_apres
seances_1_mois_avant_apres = Seance.where({horaire: (1.month.ago..(Date.today + 60))}).order(horaire: :asc)
end
def self.seances_1_semaine_avant_2_mois_apres
seances_1_semaine_avant_1_mois_apres = Seance.where({horaire: (1.week.ago..(Date.today + 60))}).order(horaire: :asc)
end
def self.seances_asc
seances_asc = Seance.order(horaire: :asc)
end
def self.seances_a_completer_projection
seances_a_completer_projection = Seance.where(projection: [nil, ""]).order(horaire: :asc)
end
def self.seances_a_completer_caisse
seances_a_completer_caisse = Seance.where(caisse: [nil, ""]).order(horaire: :asc)
end
def self.seances_date_range
seances_date_range = Seance.where({horaire: (range.to_i.days.ago..Date.today)})
end
def self.seances_annulee
seances_annulee = Seance.where(annulee: "Annulée")
end
private
def setup_default_value_for_new_seances
if self.billets_adultes.blank?
self.billets_adultes = 0
end
if self.billets_enfants.blank?
self.billets_enfants = 0
end
if self.billets_scolaires.blank?
self.billets_scolaires = 0
end
if self.total_billets.blank?
self.total_billets = 0
end
end
def setup_default_value_for_updated_seances
self.total_billets = self.billets_adultes + self.billets_enfants + self.billets_scolaires
end
end
Ici on remarque aussi des conditions, une séance doit avoir un film_id, un village_id et un horaire (la date et horaire du film) pour être validée avec la condition :validates. Ensuite, une condition setup_default_value_for_new_seances pour que les billets (enfants, adultes,scolaires et total) est une valeur de 0 au moment de créer une séance pour éviter une erreur sql qui n'accepte pas que sa valeur soit nulle. Une condition aussi setup_default_value_for_updated_seances qui permet d'additionner toutes les entrées (adultes, enfants, scolaires) quand on édite les entrées et que l'on met à jour une séance.
Une méthode self.lieuxtest avec une array qui va permettre de regrouper les séances par lieux de la tournée du cinéma d'Ecran Village ou "tous les lieux". Ceci permet de jongler avec des calendriers par lieu et des séances par lieu. Pour les vues, j'utilise ensuite une variable lieu qui se trouve dans les controleurs des objets concernés.
before_action :get_lieu
def get_lieu
@lieu = params[:lieu]
end
Les autres méthodes sont surtout utilisées pour ranger des séances dans des périodes définies.
models/film.rb
class Film < ApplicationRecord
has_many :seances, :dependent => :destroy, :inverse_of => :film
accepts_nested_attributes_for :seances, :allow_destroy => true
has_many :villages, :through => :seances
has_and_belongs_to_many :classifications
validates :id, :uniqueness => true, :case_sensitive => false
validates :titrefilm, :uniqueness => true, :case_sensitive => false
def self.films_3_semaines
films_3_semaines = Film.where({ updated_at: (3.week.ago.midnight..(Date.today + 1))}).order(updated_at: :desc)
end
def self.films_2_mois_avant
films_2_mois_avant = Film.where({ updated_at: (2.month.ago.midnight..(Date.today + 1))})
end
def self.films_mois
films_mois = Film.where({updated_at: 1.month.ago.midnight..(Date.today + 1)}).order(created_at: :asc)
end
def self.films_entrees
films_entrees = film.seances.where(horaire: date_range)
end
end
Ici on peut remarquer la condition :allow_destroy => true qui détruit les séances qui se rapportent à un film si on supprime un film. la relation avec le lieu à travers la séance et l'unicité de l'id d'un film et de son titre avec la condition :uniqueness => true, ceci par soucis de la méthode qui permet de récupérer les films venant du site d'Ecran Village à partir d'un fichier .json.
models/village.rb
class Village < ApplicationRecord
has_many :seances, :dependent => :destroy, :inverse_of => :village
accepts_nested_attributes_for :seances, :allow_destroy => true
has_many :films, :through => :seances
validates :id, :uniqueness => true, :case_sensitive => false
validates :commune, :presence => true, :case_sensitive => false
validates :salle, :presence => true, :case_sensitive => false
end
Ici on remarque juste le lien avec les seances et avec les films à travers elles avec la méthode :through.
models/user.rb
class User < ApplicationRecord
authenticates_with_sorcery!
before_create :setup_default_role_for_new_users
ROLES = %w[guest manager admin]
validates :password, length: { minimum: 5 }, if: -> { new_record? || changes["password"] }
validates :password, confirmation: true, if: -> { new_record? || changes["password"] }
validates :password_confirmation, presence: true, if: -> { new_record? || changes["password"] }
validates :email, uniqueness: true
validates :prenom, uniqueness: true
def self.users_alphabet
users_alphabet = User.order(prenom: :asc)
end
private
def setup_default_role_for_new_users
if self.role.blank?
self.role = "guest"
end
end
end
La classe User pour les utilisateur est créée au départ avec la gem Sorcery qui permet l'authentification sécurisée. La condition before_create :setup_default_role_for_new_users permet de donner aux inscrits un role guest (invité) lors de l'inscription.
models/ability.rb
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user (not logged in)
if user.role == "manager"
can :read, Village
can :update, User
can :update, Seance
cannot :update, Village
cannot :destroy, User
cannot :destroy, Seance
cannot :rails_admin
cannot :import, :all
end
# alias_action :update, :destroy, :create, :to => :write
if user.role == "admin"
can :manage, :all
# can :write, :all
can :update, :all
can :destroy, :all
can :rails_admin
can :dashboard
can :import, :all
end
# https://github.com/CanCanCommunity/cancancan/wiki/Defining-Abilities
end
end
Ici ce fichier est là pour les permissions suivant les roles des utilisateurs gérer grâces à la gem Cancancan. Le rôle manager, celui des bénévoles pour les projections et la caisse des séances, peut modifier une séance pour s'inscrire et modifier les utilisateurs. En réalité dans les vues, il ne pourra éditer que la projection ou la caisse pour les séances et il ne pourra modifier que son utilisateur (lui-même).
models/classification.rb
class Classification < ApplicationRecord
has_and_belongs_to_many :films
has_many :seances, :through => :films
end
les classifications liées aux films et aux séances à travers les films. Elles seront liées car la table classifications est créée en lien avec la table classifications_films.
models/disponibilite.rb
class Disponibilite < ApplicationRecord
validates :start_time, :presence => true
validates :end_time, :presence => true
end
Les disponibilités utilisent la gem Simple Calendar. Les méthodes :validates permettent de ne pas avoir d'erreur sql si un utilisateur oublie de rentrer un champ date à remplir dans le formulaire.
models/calendar.rb
class Calendar < Struct.new(:view, :date, :callback)
def table(lieu)
content_tag :table, class: "calendar table table-bordered table-striped table-responsive table-croped" do
header + week_rows
end
end
HEADER = %w[Mercredi Jeudi Vendredi Samedi Dimanche Lundi Mardi]
START_DAY = :wednesday
def header
content_tag :thead do
HEADER.map { |day| content_tag :th, day }.join.html_safe
end
end
def weeks
first = date.beginning_of_week(START_DAY)
last = date.end_of_week(START_DAY)
(first..last).to_a.in_groups_of(7)
end
delegate :content_tag, to: :view
def week_rows
weeks.map do |week|
content_tag :tr do
week.map { |day| day_cell(day) }.join.html_safe
end
end.join.html_safe
end
def day_cell(day)
content_tag :td, view.capture(day, &callback), class: day_classes(day)
end
def day_classes(day)
classes = []
classes << "today" if day == Date.today
classes << "nodate" if day.month != date.month
classes.empty? ? nil : classes.join(" ")
end
end
Ici c'est la structure qui permet d'éditer les calendriers, premier édifice de mon application.
Controlleurs
controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_action :set_locale
def set_locale
I18n.locale = :fr
end
before_action :require_login
rescue_from CanCan::AccessDenied do |exception|
redirect_to main_app.root_path, :alert => exception.message
# Rails.logger.debug "Access denied on #{exception.action} #{exception.subject.inspect}"
end
def current_ability
@current_ability ||= Ability.new(current_user)
end
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
private
# Overwrite the method sorcery calls when it
# detects a non-authenticated request.
def not_authenticated
# Make sure that we reference the route from the main app.
redirect_to main_app.log_in_path
end
def allow_iframe
response.headers.delete "X-Frame-Options"
response.headers["Access-Control-Allow-Origin"] = "*"
end
end
On définit la locale fr pour qu'il prenne en compte les fichiers de traduction en français de certaines extensions. Les conditions pour la gem Cancancan sont là pour les permissions et en dessous pour la gem Sorcery qui sert à l'authentification, si on a pas les permissions, on est redirigé vers la page de connexion. J'ai ajouté la possibilité d'avoir un iframe pour intégrer le calendrier sur des sites, mais isolé dans une page à cet effet.
##controllers/films_controller.rb
class FilmsController < ApplicationController
skip_before_action :require_login, only: [:index, :films_a_venir, :ecranvillage, :show, :tous_les_films]
before_action :set_film, only: [:show, :edit, :update, :destroy]
require 'httparty'
# GET /ecranvillage.json
def ecranvillage
@films = Film.all
response = HTTParty.get('https://www.ecranvillage.net/wp-json/ecranvillage-api/v2/export/?nocache')
puts response.body, response.code, response.message, response.headers.inspect
JSON.parse(response.body).each do |item|
nouveaux_films = Film.new( :id => item["id"], :titrefilm => item["titrefilm"], :description => item["description"], :affiche => item["affiche"] )
nouveaux_films.save
end
end
# GET /films
# GET /films.json
def index
@films = Film.all
@seances = Seance.all
@search = Film.search(params[:q])
@films = @search.result(distinct: true).page params[:page]
end
# GET /films
# GET /films.json
def films_a_venir
@seances = Seance.all
@films = Film.all
end
# GET /films
# GET /films.json
def tous_les_films
@films = Film.all
end
# GET /films/1
# GET /films/1.json
def show
end
# GET /films/new
def new
@film = Film.new
end
# GET /films/1/edit
def edit
end
# POST /films
# POST /films.json
def create
@film = Film.new(film_params)
respond_to do |format|
if @film.save
format.html { redirect_to @film, notice: 'Le Film a bien été créé.' }
format.json { render :show, status: :created, location: @film }
else
format.html { render :new }
format.json { render json: @film.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /films/1
# PATCH/PUT /films/1.json
def update
respond_to do |format|
if @film.update(film_params)
format.html { redirect_to @film, notice: 'Le Film a bien été mis à jour.' }
format.json { render :show, status: :ok, location: @film }
else
format.html { render :edit }
format.json { render json: @film.errors, status: :unprocessable_entity }
end
end
end
# DELETE /films/1
# DELETE /films/1.json
def destroy
@film.destroy
respond_to do |format|
format.html { redirect_to films_url, notice: 'Le Film a bien été supprimé.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_film
@film = Film.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def film_params
params.require(:film).permit(:titrefilm, :description, :distribution, :affiche, :updated_at, classification_ids:[])
end
end
Ici on définit les pages et les requêttes POST ou GET pour chaque page des Films. Nous avons un CRUD (Create, Read, Update, Destroy). La condition skip_before_action :require_login, only: permet de rendre public les pages choisies entre les crochets. La page index est une page de recherche qui permet de rechercher un film avec la gem ransack, le paramètre :page va permettre de ranger les résultats avec un rendu de 10 résultats et de naviguer de 10 en 10 résultats pour ne pas surcharger les requêttes sql. La page films_a_venir permet de voir les films à venir. La page ecranvillage est intéressante, c'est elle qui permet grâce à une gem (librairie) Httparty de récupérer les films en .json du site d'Ecran Village. Si on se rend sur la page ecranvillage, l'application va inspecter le lien de la page .json créée par l'api-ecranvillage et rentrer le nouveaux films qui ne sont pas encore créer dans la base de données avec leur description, leur titre et leur id.
controllers/calendar_controller.rb
class CalendarController < ApplicationController
skip_before_action :require_login
before_action :get_lieu
def calendrier
@seances = Seance.all
@films = Film.all
@villages = Village.all
@date = params[:date] ? Date.parse(params[:date]) : Date.today
respond_to do |format|
format.pdf do
render :pdf => "calendrier.pdf",
:orientation => 'Landscape',
:layout => "layouts/pdf.html",
:disable_javascript => false,
show_as_html: params[:debug].present?
end
format.json
format.html
end
end
def aide
end
private
def get_lieu
@lieu = params[:lieu]
end
end
Ici, c'est juste la page de bienvenue avec le calendrier des séances. C'est la page root de l'application, il n'y a pas de paramètres requis pour cette page. Pour la page calendrier on appelle les paramètres @date pour les dates du calendrier. Le calendrier fait appel à un fichier models/calendar.rb qui structure le calendrier et à un helper helpers/calendar_helper.rb. Sinon on a aussi un rendu en format pdf avec la gem wicked_pdf pour cette page. Ici on fait appel à la méthode get_lieu pour avoir des pages et des méthodes par lieux.
controllers/seances_controller.rb
class SeancesController < ApplicationController
before_action :get_lieu
before_action :require_login
before_action :set_seance, only: [:show, :edit, :update, :destroy]
def index
@seances = Seance.all
@disponibilites = Disponibilite.all
respond_to do |format|
format.pdf do
render :pdf => "index.pdf",
:orientation => 'Landscape',
:layout => "layouts/pdf.html",
:disable_javascript => false,
show_as_html: params[:debug].present?
end
format.html
end
end
def seances_passees
@seances = Seance.all
respond_to do |format|
format.pdf do
render :pdf => "seances_passees.pdf",
:orientation => 'Landscape',
:layout => "layouts/pdf.html",
:disable_javascript => false,
show_as_html: params[:debug].present?
end
format.html
end
end
def mes_seances
@seances = Seance.all
@users = User.all
user = current_user
end
def a_completer
@seances = Seance.all
@disponibilites = Disponibilite.all
end
def edition_calendrier
@seances = Seance.all
@date = params[:date] ? Date.parse(params[:date]) : Date.today
respond_to do |format|
format.pdf do
render :pdf => "edition_calendrier.pdf",
:orientation => 'Landscape',
:layout => "layouts/pdf.html",
:disable_javascript => false,
show_as_html: params[:debug].present?
end
format.html
end
end
def entrees
@search = SeanceSearch.new(params[:search])
@seances = @search.scope
@stats = EntreeFacade.new(@seances)
@films = Film.all
respond_to do |format|
format.pdf do
render :pdf => "entrees.pdf",
:layout => "layouts/pdf.html",
:disable_javascript => false,
show_as_html: params[:debug].present?
end
format.html
end
end
# GET /seances/1
# GET /seances/1.json
def show
end
# GET /seances/new
def new
@seance = Seance.new(params[:seance])
@films = Film.all
@villages = Village.all
end
# GET /seances/1/edit
def edit
@seances = Seance.all
@villages = Village.all
end
# POST /seances
# POST /seances.json
def create
film_selectionne = Film.find_by_id(params["seance"]["film_id"])
village_selectionne = Village.find_by_id(params["seance"]["village_id"])
seance = Seance.new(seance_params)
seance.film_id = film_selectionne.id
seance.village_id = village_selectionne.id
seance.save
redirect_to films_a_venir_url, notice: 'la Séance a bien été créée.'
end
# PATCH/PUT /seances/1
# PATCH/PUT /seances/1.json
def update
respond_to do |format|
if @seance.update(seance_params)
format.html { redirect_to seance_path, notice: 'La séance a bien été modifiée.' }
else
format.html { render :edit }
format.json { render json: @seance.errors, status: :unprocessable_entity }
end
end
end
# DELETE /seances/1
# DELETE /seances/1.json
def destroy
@seance.destroy
respond_to do |format|
format.html { redirect_to films_a_venir_url, notice: 'La Séance a bien été suprimée.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_seance
@seance = Seance.find(params[:id])
end
def get_lieu
@lieu = params[:lieu]
end
# Never trust parameters from the scary internet, only allow the white list through.
def seance_params
params.require(:seance).permit(:horaire, :film_id, :village_id, :version, :projection, :commentaire, :caisse, :extras, :annulee, :billets_adultes, :billets_scolaires, :billets_enfants, :total_billets )
end
end
Ici plusieurs pages sont créées. L'objet séances est un CRUD, la page index correspond à la liste des séances à venir, j'ai rajouté une page seances_passes pour les séances passées, une page a_completer pour les séances à compléter, une page mes_seances pour les séances où est déjà inscrit l'utilisateur connecté. Une page edition_calendrier (avec des calendriers par lieu), c'est vers elle que l'on se redirige en se connectant à l'application. La page entrees avec un calcul des entrées inscrites par film et par lieu pour la billetterie. Elle fait appel à des méthodes éditées dans un fichier entree_facade.rb créé dans un dossier facades isolé. Dans la page create on voit la méthode qui lie les tables de données avec l'association entre la colonne village_id qui obtiendra la même valeur que l'id du lieu de la séance) et entre la colonne film_id l'id du film qui auront les même valeurs. Ceci permet grâce aux associations de table et aux méthodes de Rails d'utiliser des méthodes comme :
<%= @seance.village.salle %> = le lieu de la seance
<%= @village.seances.where(statut: "seances scolaires").count %> le nombre de séances scolaire pour le village
<%= @seance.film.titrefilm %> = le titre du film de la séance
<%= @film.seances.count %> = le nombre de séances pour le film, etc...
Très pratique, c'est la magie de Rails !
controllers/villages_controller.rb
class VillagesController < ApplicationController
skip_before_action :require_login, only: [:index, :show ]
before_action :set_village, only: [:show, :edit, :update, :destroy]
# GET /villages
# GET /villages.json
def index
@villages = Village.all
end
# GET /villages/1
# GET /villages/1.json
def show
end
# GET /villages/new
def new
@village = Village.new
end
# GET /villages/1/edit
def edit
end
# POST /villages
# POST /villages.json
def create
@village = Village.new(village_params)
respond_to do |format|
if @village.save
format.html { redirect_to @village, notice: 'Le lieu a bien été créé.' }
else
format.html { render :new }
end
end
end
# PATCH/PUT /villages/1
# PATCH/PUT /villages/1.json
def update
respond_to do |format|
if @village.update(village_params)
format.html { redirect_to @village, notice: 'La modification est bien prise en compte.' }
format.json { render :show, status: :ok, location: @village }
else
format.html { render :edit }
format.json { render json: @village.errors, status: :unprocessable_entity }
end
end
end
# DELETE /villages/1
# DELETE /villages/1.json
def destroy
@village.destroy
respond_to do |format|
format.html { redirect_to villages_url, notice: 'Le lieu a bien été supprimé.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_village
@village = Village.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def village_params
params.require(:village).permit(:commune, :salle)
end
end
Les lieux sont issus d'un simple CRUD.
controllers/users.rb
class UsersController < ApplicationController
skip_before_action :require_login, only: [:index, :new, :create]
before_action :set_user, only: [:show, :edit, :update, :destroy]
# GET /users
# GET /users.json
def index
@users = User.all
respond_to do |format|
format.pdf do
render :pdf => "users.pdf",
:layout => "layouts/pdf.html",
:disable_javascript => false,
show_as_html: params[:debug].present?
end
format.html
end
end
# GET /users/1
# GET /users/1.json
def show
end
# GET /users/new
def new
@user = User.new
end
# GET /users/1/edit
def edit
end
# POST /users
# POST /users.json
def create
@user = User.new(user_params)
if @user.save
login(params[:user][:email], params[:user][:password])
redirect_to root_path, notice: 'Bienvenue !'
else
render 'new'
end
end
# PATCH/PUT /users/1
# PATCH/PUT /users/1.json
def update
respond_to do |format|
if @user.update(user_params)
format.html { redirect_to @user, notice: 'L\'utilisateur a bien été modifié.' }
format.json { render :show, status: :ok, location: @user }
else
format.html { render :edit }
format.json { render json: @user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
@user.destroy
respond_to do |format|
format.html { redirect_to users_url, notice: 'L\'utilisateur a bien été supprimé.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user
@user = User.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params.require(:user).permit(:email, :password, :password_confirmation, :nom, :prenom, :telephone, :role)
end
end
Les utilisateurs, au début le fichier est créer avec la gem Sorcery.
controllers/users_sessions_controller.rb
class UserSessionsController < ApplicationController
skip_before_action :require_login, except: [:destroy]
def new
@user = User.new
end
def create
if @user = login(params[:email], params[:password])
if @user.role == "guest"
redirect_back_or_to(root_path, notice: 'Connexion réussie !')
else
redirect_back_or_to(edition_calendrier_path(:lieu => "tous les lieux"), notice: 'Connexion réussie !')
end
else
flash.now[:error] = "Oups! une erreur semble-t-il... veuillez recommencez s'il vous plaît."
render action: 'new'
end
end
def destroy
logout
redirect_back_or_to(root_path, notice: 'Déconnecté !')
end
end
Le controlleur de sessions, toujours liés à la gem Sorcery, ici on peut noter une condition, si on vient de s'insrire, on est redirigé vers la page de départ correspondant à la page public calendrier qui n'est pas une page d'édition, sinon on sera redirigé vers la page edition_calendrier.
controllers/classifications_controller.rb
class ClassificationsController < ApplicationController
before_action :set_classification, only: [:show, :edit, :update, :destroy]
# GET /classifications
# GET /classifications.json
def index
@classifications = Classification.all
@films = Film.all
@seances = Seance.all
end
# GET /classifications/1
# GET /classifications/1.json
def show
end
# GET /classifications/new
def new
@classification = Classification.new
end
# GET /classifications/1/edit
def edit
end
# POST /classifications
# POST /classifications.json
def create
@classification = Classification.new(classification_params)
respond_to do |format|
if @classification.save
format.html { redirect_to @classification, notice: 'la classification a bien été créée.' }
format.json { render :show, status: :created, location: @classification }
else
format.html { render :new }
format.json { render json: @classification.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /classifications/1
# PATCH/PUT /classifications/1.json
def update
respond_to do |format|
if @classification.update(classification_params)
format.html { redirect_to @classification, notice: 'la classification a bien été mise à jour.' }
format.json { render :show, status: :ok, location: @classification }
else
format.html { render :edit }
format.json { render json: @classification.errors, status: :unprocessable_entity }
end
end
end
# DELETE /classifications/1
# DELETE /classifications/1.json
def destroy
@classification.destroy
respond_to do |format|
format.html { redirect_to classifications_url, notice: 'la classification a été supprimée.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_classification
@classification = Classification.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def classification_params
params.require(:classification).permit(:nom_classification, :film_id)
end
end
Classifications sert à classer les films par label (Art et Essai, Patrimoine et Répertoire, Recherche et Découvertes, Jeune Public), utile pour les envois au CNC.
controllers/disponibilites_contoller.rb
class DisponibilitesController < ApplicationController
before_action :set_disponibilite, only: [:show, :edit, :update, :destroy]
# GET /disponibilites
# GET /disponibilites.json
def index
@disponibilites = Disponibilite.all
@date = params[:date] ? Date.parse(params[:date]) : Date.today
end
# GET /disponibilites/1
# GET /disponibilites/1.json
def show
end
# GET /disponibilites/new
def new
@disponibilite = Disponibilite.new
end
# GET /disponibilites/1/edit
def edit
end
# POST /disponibilites
# POST /disponibilites.json
def create
@disponibilite = Disponibilite.new(disponibilite_params)
respond_to do |format|
if @disponibilite.save
format.html { redirect_to @disponibilite, notice: 'Disponibilité créée avec succés.' }
format.json { render :show, status: :created, location: @disponibilite }
else
format.html { render :new }
format.json { render json: @disponibilite.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /disponibilites/1
# PATCH/PUT /disponibilites/1.json
def update
respond_to do |format|
if @disponibilite.update(disponibilite_params)
format.html { redirect_to @disponibilite, notice: 'Disponibilité bien mise à jour.' }
format.json { render :show, status: :ok, location: @disponibilite }
else
format.html { render :edit }
format.json { render json: @disponibilite.errors, status: :unprocessable_entity }
end
end
end
# DELETE /disponibilites/1
# DELETE /disponibilites/1.json
def destroy
@disponibilite.destroy
respond_to do |format|
format.html { redirect_to disponibilites_url, notice: 'Disponibilité bien supprimée.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_disponibilite
@disponibilite = Disponibilite.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def disponibilite_params
params.require(:disponibilite).permit(:nom, :start_time, :end_time)
end
end
Disponibilites, sert aux bénévoles et salariés à marquer leurs indisponnibilitées dans un calendrier qui utilise la gem Simple Calendar, cet objet a été crééer avec cette gem.
controllers/iframe_controller.rb
class IframeController < ApplicationController
layout "layouts/iframe"
skip_before_action :require_login
before_action :get_lieu
after_action :allow_iframe, only: :calendrier_iframe
def calendrier_iframe
@seances = Seance.all
@films = Film.all
@villages = Village.all
@date = params[:date] ? Date.parse(params[:date]) : Date.today
end
private
def get_lieu
@lieu = params[:lieu]
end
end
Ici ce controlleur me sert juste à éditer une page qui sert de iframe pour avoir une vue de calendrier sur d'autre sites avec un bout de code html.