#gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
-gem 'devise'
\ No newline at end of file
+gem 'devise'
+gem "bootstrap_form", ">= 4.2.0"
+gem "audited", "~> 4.9"
minitest (~> 5.1)
tzinfo (~> 1.1)
arel (9.0.0)
+ audited (4.9.0)
+ activerecord (>= 4.2, < 6.1)
bcrypt (3.1.13)
bindex (0.8.1)
bootsnap (1.4.4)
msgpack (~> 1.0)
+ bootstrap_form (4.2.0)
+ actionpack (>= 5.0)
+ activemodel (>= 5.0)
builder (3.2.3)
byebug (11.0.1)
coffee-rails (4.2.2)
ruby
DEPENDENCIES
+ audited (~> 4.9)
bootsnap (>= 1.1.0)
+ bootstrap_form (>= 4.2.0)
byebug
coffee-rails (~> 4.2)
devise
--- /dev/null
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://coffeescript.org/
--- /dev/null
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://coffeescript.org/
*= require_tree .
*= require_self
*= require bootstrap/dist/css/bootstrap
+ *= require rails_bootstrap_forms
*/
--- /dev/null
+// Place all the styles related to the Organisations controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
--- /dev/null
+body {
+ background-color: #fff;
+ color: #333;
+ margin: 33px;
+ font-family: verdana, arial, helvetica, sans-serif;
+ font-size: 13px;
+ line-height: 18px;
+}
+
+p, ol, ul, td {
+ font-family: verdana, arial, helvetica, sans-serif;
+ font-size: 13px;
+ line-height: 18px;
+}
+
+pre {
+ background-color: #eee;
+ padding: 10px;
+ font-size: 11px;
+}
+
+a {
+ color: #000;
+
+ &:visited {
+ color: #666;
+ }
+
+ &:hover {
+ color: #fff;
+ background-color: #000;
+ }
+}
+
+th {
+ padding-bottom: 5px;
+}
+
+td {
+ padding: 0 5px 7px;
+}
+
+div {
+ &.field, &.actions {
+ margin-bottom: 10px;
+ }
+}
+
+#notice {
+ color: green;
+}
+
+.field_with_errors {
+ padding: 2px;
+ background-color: red;
+ display: table;
+}
+
+#error_explanation {
+ width: 450px;
+ border: 2px solid red;
+ padding: 7px 7px 0;
+ margin-bottom: 20px;
+ background-color: #f0f0f0;
+
+ h2 {
+ text-align: left;
+ font-weight: bold;
+ padding: 5px 5px 5px 15px;
+ font-size: 12px;
+ margin: -7px -7px 0;
+ background-color: #c00;
+ color: #fff;
+ }
+
+ ul li {
+ font-size: 12px;
+ list-style: square;
+ }
+}
+
+label {
+ display: block;
+}
--- /dev/null
+// Place all the styles related to the Structures controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
--- /dev/null
+class OrganisationsController < ApplicationController
+ before_action :set_organisation, only: [:show, :edit, :update, :destroy]
+
+ # GET /organisations
+ # GET /organisations.json
+ def index
+ @organisations = Organisation.all
+ end
+
+ # GET /organisations/1
+ # GET /organisations/1.json
+ def show
+ end
+
+ # GET /organisations/new
+ def new
+ @organisation = Organisation.new
+ 3.times { @organisation.structures.build }
+ end
+
+ # GET /organisations/1/edit
+ def edit
+ 1.times { @organisation.structures.build }
+ end
+
+ # POST /organisations
+ # POST /organisations.json
+ def create
+ @organisation = Organisation.new(organisation_params)
+
+ respond_to do |format|
+ if @organisation.save
+ format.html { redirect_to @organisation, notice: 'Organisation was successfully created.' }
+ format.json { render :show, status: :created, location: @organisation }
+ else
+ format.html { render :new }
+ format.json { render json: @organisation.errors, status: :unprocessable_entity }
+ end
+ end
+ end
+
+ # PATCH/PUT /organisations/1
+ # PATCH/PUT /organisations/1.json
+ def update
+ respond_to do |format|
+ if @organisation.update(organisation_params)
+ format.html { redirect_to @organisation, notice: 'Organisation was successfully updated.' }
+ format.json { render :show, status: :ok, location: @organisation }
+ else
+ format.html { render :edit }
+ format.json { render json: @organisation.errors, status: :unprocessable_entity }
+ end
+ end
+ end
+
+ # DELETE /organisations/1
+ # DELETE /organisations/1.json
+ def destroy
+ @organisation.destroy
+ respond_to do |format|
+ format.html { redirect_to organisations_url, notice: 'Organisation was successfully destroyed.' }
+ format.json { head :no_content }
+ end
+ end
+
+ private
+ # Use callbacks to share common setup or constraints between actions.
+ def set_organisation
+ @organisation = Organisation.find(params[:id])
+ end
+
+ # Never trust parameters from the scary internet, only allow the white list through.
+ def organisation_params
+ params.require(:organisation).permit(:nom, :adresse, :cp, :ville, :téléphone, :email, :logo,
+ structures_attributes: [:id, :nom, :_destroy])
+ end
+end
--- /dev/null
+class StructuresController < ApplicationController
+ before_action :set_structure, only: [:show, :edit, :update, :destroy]
+
+ # GET /structures
+ # GET /structures.json
+ def index
+ @structures = Structure.all
+ end
+
+ # GET /structures/1
+ # GET /structures/1.json
+ def show
+ end
+
+ # GET /structures/new
+ def new
+ @structure = Structure.new
+ end
+
+ # GET /structures/1/edit
+ def edit
+ end
+
+ # POST /structures
+ # POST /structures.json
+ def create
+ @structure = Structure.new(structure_params)
+
+ respond_to do |format|
+ if @structure.save
+ format.html { redirect_to @structure, notice: 'Structure was successfully created.' }
+ format.json { render :show, status: :created, location: @structure }
+ else
+ format.html { render :new }
+ format.json { render json: @structure.errors, status: :unprocessable_entity }
+ end
+ end
+ end
+
+ # PATCH/PUT /structures/1
+ # PATCH/PUT /structures/1.json
+ def update
+ respond_to do |format|
+ if @structure.update(structure_params)
+ format.html { redirect_to @structure, notice: 'Structure was successfully updated.' }
+ format.json { render :show, status: :ok, location: @structure }
+ else
+ format.html { render :edit }
+ format.json { render json: @structure.errors, status: :unprocessable_entity }
+ end
+ end
+ end
+
+ # DELETE /structures/1
+ # DELETE /structures/1.json
+ def destroy
+ @structure.destroy
+ respond_to do |format|
+ format.html { redirect_to structures_url, notice: 'Structure was successfully destroyed.' }
+ format.json { head :no_content }
+ end
+ end
+
+ private
+ # Use callbacks to share common setup or constraints between actions.
+ def set_structure
+ @structure = Structure.find(params[:id])
+ end
+
+ # Never trust parameters from the scary internet, only allow the white list through.
+ def structure_params
+ params.require(:structure).permit(:organisation_id, :nom, :adresse, :cp, :ville)
+ end
+end
--- /dev/null
+module OrganisationsHelper
+end
--- /dev/null
+module StructuresHelper
+end
--- /dev/null
+class Organisation < ApplicationRecord
+
+ audited
+
+ has_one_attached :logo
+
+ has_many :structures, inverse_of: :organisation
+
+ accepts_nested_attributes_for :structures, reject_if: proc { |attributes| attributes[:nom].blank? }, allow_destroy: true
+
+ validates :nom, :email, presence: true
+
+end
--- /dev/null
+class Structure < ApplicationRecord
+
+ audited
+
+ belongs_to :organisation, inverse_of: :structures
+
+end
class User < ApplicationRecord
+
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable,
:recoverable,
:rememberable,
:validatable
+
+ audited
+
end
--- /dev/null
+<%= bootstrap_form_with(model: organisation, local: true) do |form| %>
+ <% if organisation.errors.any? %>
+ <div id="error_explanation">
+ <h2><%= pluralize(organisation.errors.count, "error") %> prohibited this organisation from being saved:</h2>
+
+ <ul>
+ <% organisation.errors.full_messages.each do |message| %>
+ <li><%= message %></li>
+ <% end %>
+ </ul>
+ </div>
+ <% end %>
+
+ <%= form.text_field :nom %>
+ <%= form.text_field :adresse %>
+ <%= form.text_field :cp %>
+ <%= form.text_field :ville %>
+ <%= form.text_field :téléphone %>
+ <%= form.text_field :email %>
+ <%= form.file_field :logo %>
+
+ <%= form.fields_for :structures do |structure_form| %>
+ <p>
+ Structure: <%= structure_form.text_field :nom %>
+ <%= structure_form.check_box :_destroy, label: "Supprimer ?" %>
+ </p>
+ <% end %>
+
+ <div class="actions">
+ <%= form.submit %>
+ </div>
+<% end %>
--- /dev/null
+json.extract! organisation, :id, :nom, :adresse, :cp, :ville, :téléphone, :email, :created_at, :updated_at
+json.url organisation_url(organisation, format: :json)
--- /dev/null
+<h1>Editing Organisation</h1>
+
+<%= render 'form', organisation: @organisation %>
+
+<%= link_to 'Show', @organisation %> |
+<%= link_to 'Back', organisations_path %>
--- /dev/null
+<h1>Organisations</h1>
+
+<table class="table table-striped">
+ <thead>
+ <tr>
+ <th>Nom</th>
+ <th>Adresse</th>
+ <th>Cp</th>
+ <th>Ville</th>
+ <th>Téléphone</th>
+ <th>Email</th>
+ <th colspan="3"></th>
+ </tr>
+ </thead>
+
+ <tbody>
+ <% @organisations.each do |organisation| %>
+ <tr>
+ <td><%= organisation.nom %></td>
+ <td><%= organisation.adresse %></td>
+ <td><%= organisation.cp %></td>
+ <td><%= organisation.ville %></td>
+ <td><%= organisation.téléphone %></td>
+ <td><%= organisation.email %></td>
+ <td><%= link_to 'Show', organisation %></td>
+ <td><%= link_to 'Edit', edit_organisation_path(organisation) %></td>
+ <td><%= link_to 'Destroy', organisation, method: :delete, data: { confirm: 'Are you sure?' } %></td>
+ </tr>
+ <% end %>
+ </tbody>
+</table>
+
+<br>
+
+<%= link_to 'New Organisation', new_organisation_path %>
--- /dev/null
+json.array! @organisations, partial: "organisations/organisation", as: :organisation
--- /dev/null
+<h1>New Organisation</h1>
+
+<%= render 'form', organisation: @organisation %>
+
+<%= link_to 'Back', organisations_path %>
--- /dev/null
+<p id="notice"><%= notice %></p>
+
+<p>
+ <strong>Nom:</strong>
+ <%= @organisation.nom %>
+</p>
+
+<p>
+ <strong>Adresse:</strong>
+ <%= @organisation.adresse %>
+</p>
+
+<p>
+ <strong>Cp:</strong>
+ <%= @organisation.cp %>
+</p>
+
+<p>
+ <strong>Ville:</strong>
+ <%= @organisation.ville %>
+</p>
+
+<p>
+ <strong>Téléphone:</strong>
+ <%= @organisation.téléphone %>
+</p>
+
+<p>
+ <strong>Email:</strong>
+ <%= @organisation.email %>
+</p>
+
+<p>
+ <%= image_tag url_for(@organisation.logo) %>
+</p>
+
+<p>
+ <h3>Structures</h3>
+ <% @organisation.structures.each do |structure| %>
+ nom: <%= structure.nom %><br />
+ <% end %>
+</p>
+
+<%= link_to 'Edit', edit_organisation_path(@organisation) %> |
+<%= link_to 'Back', organisations_path %>
--- /dev/null
+json.partial! "organisations/organisation", organisation: @organisation
--- /dev/null
+<%= form_with(model: structure, local: true) do |form| %>
+ <% if structure.errors.any? %>
+ <div id="error_explanation">
+ <h2><%= pluralize(structure.errors.count, "error") %> prohibited this structure from being saved:</h2>
+
+ <ul>
+ <% structure.errors.full_messages.each do |message| %>
+ <li><%= message %></li>
+ <% end %>
+ </ul>
+ </div>
+ <% end %>
+
+ <div class="field">
+ <%= form.label :organisation_id %>
+ <%= form.text_field :organisation_id %>
+ </div>
+
+ <div class="field">
+ <%= form.label :nom %>
+ <%= form.text_field :nom %>
+ </div>
+
+ <div class="field">
+ <%= form.label :adresse %>
+ <%= form.text_field :adresse %>
+ </div>
+
+ <div class="field">
+ <%= form.label :cp %>
+ <%= form.text_field :cp %>
+ </div>
+
+ <div class="field">
+ <%= form.label :ville %>
+ <%= form.text_field :ville %>
+ </div>
+
+ <div class="actions">
+ <%= form.submit %>
+ </div>
+<% end %>
--- /dev/null
+json.extract! structure, :id, :organisation_id, :nom, :adresse, :cp, :ville, :created_at, :updated_at
+json.url structure_url(structure, format: :json)
--- /dev/null
+<h1>Editing Structure</h1>
+
+<%= render 'form', structure: @structure %>
+
+<%= link_to 'Show', @structure %> |
+<%= link_to 'Back', structures_path %>
--- /dev/null
+<p id="notice"><%= notice %></p>
+
+<h1>Structures</h1>
+
+<table>
+ <thead>
+ <tr>
+ <th>Organisation</th>
+ <th>Nom</th>
+ <th>Adresse</th>
+ <th>Cp</th>
+ <th>Ville</th>
+ <th colspan="3"></th>
+ </tr>
+ </thead>
+
+ <tbody>
+ <% @structures.each do |structure| %>
+ <tr>
+ <td><%= structure.organisation %></td>
+ <td><%= structure.nom %></td>
+ <td><%= structure.adresse %></td>
+ <td><%= structure.cp %></td>
+ <td><%= structure.ville %></td>
+ <td><%= link_to 'Show', structure %></td>
+ <td><%= link_to 'Edit', edit_structure_path(structure) %></td>
+ <td><%= link_to 'Destroy', structure, method: :delete, data: { confirm: 'Are you sure?' } %></td>
+ </tr>
+ <% end %>
+ </tbody>
+</table>
+
+<br>
+
+<%= link_to 'New Structure', new_structure_path %>
--- /dev/null
+json.array! @structures, partial: "structures/structure", as: :structure
--- /dev/null
+<h1>New Structure</h1>
+
+<%= render 'form', structure: @structure %>
+
+<%= link_to 'Back', structures_path %>
--- /dev/null
+<p id="notice"><%= notice %></p>
+
+<p>
+ <strong>Organisation:</strong>
+ <%= @structure.organisation %>
+</p>
+
+<p>
+ <strong>Nom:</strong>
+ <%= @structure.nom %>
+</p>
+
+<p>
+ <strong>Adresse:</strong>
+ <%= @structure.adresse %>
+</p>
+
+<p>
+ <strong>Cp:</strong>
+ <%= @structure.cp %>
+</p>
+
+<p>
+ <strong>Ville:</strong>
+ <%= @structure.ville %>
+</p>
+
+<%= link_to 'Edit', edit_structure_path(@structure) %> |
+<%= link_to 'Back', structures_path %>
--- /dev/null
+json.partial! "structures/structure", structure: @structure
Rails.application.routes.draw do
+ resources :structures
+ resources :organisations
devise_for :users
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
--- /dev/null
+class CreateOrganisations < ActiveRecord::Migration[5.2]
+ def change
+ create_table :organisations do |t|
+ t.string :nom, null: false, default: ""
+ t.string :adresse
+ t.string :cp
+ t.string :ville
+ t.string :téléphone
+ t.string :email
+
+ t.timestamps
+ end
+ end
+end
--- /dev/null
+# This migration comes from active_storage (originally 20170806125915)
+class CreateActiveStorageTables < ActiveRecord::Migration[5.2]
+ def change
+ create_table :active_storage_blobs do |t|
+ t.string :key, null: false
+ t.string :filename, null: false
+ t.string :content_type
+ t.text :metadata
+ t.bigint :byte_size, null: false
+ t.string :checksum, null: false
+ t.datetime :created_at, null: false
+
+ t.index [ :key ], unique: true
+ end
+
+ create_table :active_storage_attachments do |t|
+ t.string :name, null: false
+ t.references :record, null: false, polymorphic: true, index: false
+ t.references :blob, null: false
+
+ t.datetime :created_at, null: false
+
+ t.index [ :record_type, :record_id, :name, :blob_id ], name: "index_active_storage_attachments_uniqueness", unique: true
+ t.foreign_key :active_storage_blobs, column: :blob_id
+ end
+ end
+end
--- /dev/null
+class CreateStructures < ActiveRecord::Migration[5.2]
+ def change
+ create_table :structures do |t|
+ t.references :organisation, foreign_key: true
+ t.string :nom, null: false, default: ""
+ t.string :adresse
+ t.string :cp
+ t.string :ville
+
+ t.timestamps
+ end
+ end
+end
--- /dev/null
+class InstallAudited < ActiveRecord::Migration[5.2]
+ def self.up
+ create_table :audits, :force => true do |t|
+ t.column :auditable_id, :integer
+ t.column :auditable_type, :string
+ t.column :associated_id, :integer
+ t.column :associated_type, :string
+ t.column :user_id, :integer
+ t.column :user_type, :string
+ t.column :username, :string
+ t.column :action, :string
+ t.column :audited_changes, :jsonb
+ t.column :version, :integer, :default => 0
+ t.column :comment, :string
+ t.column :remote_address, :string
+ t.column :request_uuid, :string
+ t.column :created_at, :datetime
+ end
+
+ add_index :audits, [:auditable_type, :auditable_id, :version], :name => 'auditable_index'
+ add_index :audits, [:associated_type, :associated_id], :name => 'associated_index'
+ add_index :audits, [:user_id, :user_type], :name => 'user_index'
+ add_index :audits, :request_uuid
+ add_index :audits, :created_at
+ end
+
+ def self.down
+ drop_table :audits
+ end
+end
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 2019_08_26_150849) do
+ActiveRecord::Schema.define(version: 2019_08_27_110858) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
+ create_table "active_storage_attachments", force: :cascade do |t|
+ t.string "name", null: false
+ t.string "record_type", null: false
+ t.bigint "record_id", null: false
+ t.bigint "blob_id", null: false
+ t.datetime "created_at", null: false
+ t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id"
+ t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true
+ end
+
+ create_table "active_storage_blobs", force: :cascade do |t|
+ t.string "key", null: false
+ t.string "filename", null: false
+ t.string "content_type"
+ t.text "metadata"
+ t.bigint "byte_size", null: false
+ t.string "checksum", null: false
+ t.datetime "created_at", null: false
+ t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true
+ end
+
+ create_table "audits", force: :cascade do |t|
+ t.integer "auditable_id"
+ t.string "auditable_type"
+ t.integer "associated_id"
+ t.string "associated_type"
+ t.integer "user_id"
+ t.string "user_type"
+ t.string "username"
+ t.string "action"
+ t.jsonb "audited_changes"
+ t.integer "version", default: 0
+ t.string "comment"
+ t.string "remote_address"
+ t.string "request_uuid"
+ t.datetime "created_at"
+ t.index ["associated_type", "associated_id"], name: "associated_index"
+ t.index ["auditable_type", "auditable_id", "version"], name: "auditable_index"
+ t.index ["created_at"], name: "index_audits_on_created_at"
+ t.index ["request_uuid"], name: "index_audits_on_request_uuid"
+ t.index ["user_id", "user_type"], name: "user_index"
+ end
+
+ create_table "organisations", force: :cascade do |t|
+ t.string "nom", default: "", null: false
+ t.string "adresse"
+ t.string "cp"
+ t.string "ville"
+ t.string "téléphone"
+ t.string "email"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ end
+
+ create_table "structures", force: :cascade do |t|
+ t.bigint "organisation_id"
+ t.string "nom", default: "", null: false
+ t.string "adresse"
+ t.string "cp"
+ t.string "ville"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["organisation_id"], name: "index_structures_on_organisation_id"
+ end
+
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
+ add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
+ add_foreign_key "structures", "organisations"
end