dhtmlxGantt mit Ruby on Rails

Diese Anleitung führt Sie durch den Prozess der Einrichtung eines Gantt-Diagramms mit einem Ruby on Rails Backend. Das Beispiel verwendet Ruby 2.4.1, Rails 5.1.3 und MySQL. Es wird vorausgesetzt, dass Sie die erforderlichen Abhängigkeiten bereits installiert haben. Wenn nicht, schauen Sie sich zuerst die offiziellen Tutorials an.

Wenn Sie mit einer anderen Technologie arbeiten, stehen Ihnen andere Integrationsmöglichkeiten zur Verfügung:

Sie können sich auch das Demo auf GitHub ansehen.


Schritt 1: Erstellen eines Projekts

Erstellen Sie zunächst ein neues Rails-Projekt mit MySQL als Datenbank:

rails new gantt-app -d mysql

Schritt 2: Hinzufügen von Gantt zur Seite

Beginnen Sie mit der Erstellung eines Controllers und einer Standardseite für die Anwendung. Navigieren Sie zum Projektordner und generieren Sie einen neuen Controller mit einer index Aktion:

cd gantt-app
rails generate controller gantt index

Sie sollten eine Bestätigung sehen, dass neue Dateien erstellt wurden.

Festlegen einer Standardroute

Aktualisieren Sie die Routing-Konfiguration in config/routes.rb, um die index Aktion des neuen Controllers als Standardroute festzulegen:

Rails.application.routes.draw do
  root :to => "gantt#index"
end

Starten Sie den Rails-Server:

rails server

Öffnen Sie http://localhost:3000/ in einem Browser. Sie sollten eine leere Seite sehen, die anzeigt, dass die App funktioniert. Fügen wir nun ein Gantt-Diagramm hinzu.

Hinzufügen von Gantt zur Ansicht

Um das Gantt-Diagramm einzuschließen, ändern Sie die Layout-Datei, um ein yield innerhalb des <head>-Tags hinzuzufügen. Dies ermöglicht das Hinzufügen von dhtmlxGantt-Dateien zur Seite:

<!DOCTYPE html>
<html>
<head>
  <title>dhtmlxGantt</title>
  <%= stylesheet_link_tag 'application', media:'all','data-turbolinks-track' => true %>
  <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>  
  <%= yield(:head) %>
  <%= csrf_meta_tags %>
</head>
<body>
  <%= yield %>
</body>
</html>

Aktualisieren Sie anschließend die gantt/index Ansicht, um das Gantt-Diagramm einzuschließen:

<% content_for :head do %>
  <%= stylesheet_link_tag 'https://cdn.dhtmlx.com/gantt/edge/dhtmlxgantt.css' %>
  <%= javascript_include_tag 'https://cdn.dhtmlx.com/gantt/edge/dhtmlxgantt.js' %>
<% end %>
 
<div id="gantt_here" style='width:100%; height:800px;'></div>
 
<script>
    gantt.init("gantt_here");
</script>

Die Gantt-Dateien werden von CDN geladen. Für die Entwicklung möchten Sie möglicherweise die Quelldateien verwenden, die im Download-Paket enthalten sind.

Öffnen Sie http://localhost:3000/ erneut in Ihrem Browser. Sie sehen jetzt ein Gantt-Diagramm, in dem Sie Aufgaben hinzufügen und ändern können. Die Speicherfunktionalität ist jedoch noch nicht verfügbar. Der nächste Schritt besteht darin, Modelle zu erstellen, um das Speichern zu ermöglichen.


Schritt 3: Erstellen von Modellen

Da wir MySQL verwenden, stellen Sie sicher, dass die Datenbankverbindungseinstellungen in config/database.yml korrekt sind:

development:
  adapter: mysql2
  encoding: utf8
  host: localhost
  database: gantt-app
  username: root
  password:

Erstellen Sie nun Modelle für tasks und links.

Generieren Sie ein Modell für Aufgaben mit den folgenden Eigenschaften:

rails generate model Task \
    text:string \
    start_date:datetime \
    duration:integer \
    parent:integer \
    progress:decimal

Für Links verwenden Sie diesen kürzeren Befehl:

rails generate model Link \
    source:integer \
    target:integer \
    link_type:string:limit1

Das Gantt-Link-Objekt erfordert eine Eigenschaft namens type, um den Beziehungstyp zu speichern. Da type von ActiveRecord reserviert ist, verwenden wir stattdessen link_type und behandeln die Zuordnung im Controller.

Führen Sie die Migration aus, um die Datenbank zu aktualisieren:

rake db:migrate

Fügen Sie einige Testdaten hinzu:

  1. Öffnen Sie die Rails-Konsole:

    rails c
  2. Fügen Sie Aufgaben und Links hinzu:

    Task.create :text=>"Task 1", :start_date=>"2015-10-25",  :duration=>2, :progress=>0;
    Task.create :text=>"Task 2", :start_date=>"2015-10-27",  :duration=>3, :progress=>0.5;
    Link.create :source=>1, :target=>2, :link_type=>"0";
  3. Verlassen Sie die Konsole:

    exit

Laden und speichern wir als nächstes Daten im Gantt-Diagramm mithilfe von Controllern.


Schritt 4: Laden von Daten

Mit den Modellen und der Datenbank bereit, ist der nächste Schritt, Daten in das Gantt-Diagramm zu laden. dhtmlxGantt erwartet Daten im JSON-Format. Fügen Sie eine neue Aktion zu GanttController hinzu, um die Daten zu lesen, zu formatieren und auszugeben:

class GanttController < ApplicationController
  def index
  end
 
  def data 
    tasks = Task.all
    links = Link.all
 
    render :json => {
      :data => tasks.map { |task| {
        :id => task.id,
        :text => task.text,
        :start_date => task.start_date.to_formatted_s(:db),
        :duration => task.duration,
        :progress => task.progress,
        :parent => task.parent,
        :open => true
      }},
      :links => links.map { |link| {
        :id => link.id,
        :source => link.source,
        :target => link.target,
        :type => link.link_type
      }}
    }
  end
end

Fügen Sie eine Route für diese Aktion in routes.rb hinzu:

Rails.application.routes.draw do
  root :to => "gantt#index"
 
  scope '/api' do
    get "/data", :to => "gantt#data"
  end
end

Auf der Clientseite rufen Sie diese Aktion mit der gantt.load Methode auf:

gantt.config.date_format = "%Y-%m-%d %H:%i:%s";
 
gantt.init("gantt_here");
gantt.load("/api/data");

Die date_format Konfiguration stellt sicher, dass das Datumsformat dem Format des Servers entspricht.

Führen Sie den Server aus und öffnen Sie http://localhost:3000/ im Browser. Sie sollten das Gantt-Diagramm sehen, das mit Daten aus der Datenbank gefüllt ist. Änderungen werden jedoch noch nicht gespeichert. Lassen Sie uns das als nächstes angehen.


Schritt 5: Speichern von Änderungen

dhtmlxGantt kann benutzergemachte Änderungen an eine RESTful API im Backend senden, um sie zu speichern. Details über das Protokoll finden Sie hier.

Beginnen Sie damit, das Posten von Änderungen auf dem Client zu aktivieren:

gantt.config.date_format = "%Y-%m-%d %H:%i:%s";
 
gantt.init("gantt_here");
gantt.load("/api/data");
 
var dp = new gantt.dataProcessor("/api");
dp.init(gantt);
dp.setTransactionMode("REST");

Erstellen Sie als nächstes Controller für Aufgaben und Links und implementieren Sie die erforderlichen Aktionen.

Erstellen des Task Controllers

Generieren Sie einen Controller für Aufgaben:

rails generate controller task --no-helper --no-assets --no-view-specs

Da dieser Controller keine Ansichten benötigt, werden mit den --no-* Flags unnötige Dateien übersprungen.

Implementieren Sie Aktionen zum Erstellen, Aktualisieren und Löschen von Aufgaben:

class TaskController < ApplicationController
    protect_from_forgery
 
    def update
        task = Task.find(params["id"])
        task.text = params["text"]
        task.start_date = params["start_date"]
        task.duration = params["duration"]
        task.progress = params["progress"] || 0
        task.parent = params["parent"]
        task.save
 
        render :json => { :action => "updated" }
    end
 
    def add
        task = Task.create(
            :text => params["text"], 
            :start_date => params["start_date"], 
            :duration => params["duration"],
            :progress => params["progress"] || 0, 
            :parent => params["parent"]
        )
 
        render :json => { :action => "inserted", :tid => task.id }
    end
 
    def delete
        Task.find(params["id"]).destroy
        render :json => { :action => "deleted" }
    end
end

Einige Hinweise: - Die get Aktion wird nicht benötigt, da Daten über gantt#data geladen werden. - Die progress Eigenschaft wird standardmäßig auf 0 gesetzt, wenn sie nicht vom Client initialisiert wird. - Die Aktion zum Erstellen neuer Elemente gibt die Datenbank-ID des eingefügten Datensatzes an den Client zurück.

Aktualisieren Sie die Routen-Konfiguration:

Rails.application.routes.draw do
  root :to => "gantt#index"
 
  scope '/api' do
    get "/data", :to => "gantt#data"
 
    post "/task", :to => "task#add"
    put "/task/:id", :to => "task#update"
    delete "/task/:id", :to => "task#delete"
  end
end

Für Links wird der gleiche Ansatz verfolgt.

Erstellen des Link Controllers

Um zu beginnen, generieren Sie einen Link-Controller mit folgendem Befehl:

rails generate controller link --no-helper --no-assets --no-view-specs

Hier ist ein Beispiel dafür, wie die Implementierung aussehen könnte:

app/controllers/link_controller.rb

class LinkController < ApplicationController
    protect_from_forgery
 
    def update
        link = Link.find(params["id"])
        link.source = params["source"]
        link.target = params["target"]
        link.link_type = params["type"]
        link.save
 
        render :json => {:action => "updated"}
    end
 
    def add
        link = Link.create( 
            :source => params["source"], 
            :target => params["target"], 
            :link_type => params["type"]
        )
 
        render :json => {:action => "inserted", :tid => link.id}
    end
 
    def delete
        Link.find(params["id"]).destroy
        render :json => {:action => "deleted"}
    end
end

Richten Sie als nächstes Routen für diese Aktionen ein:

config/routes.rb

Rails.application.routes.draw do
  root :to => "gantt#index"
 
  scope '/api' do
    get "/data", :to => "gantt#data"
 
    post "/task", :to => "task#add"
    put "/task/:id", :to => "task#update"
    delete "/task/:id", :to => "task#delete"
 
    post "/link", :to => "link#add"    put "/link/:id", :to => "link#update"    delete "/link/:id", :to => "link#delete"  end
end

An diesem Punkt, wenn Sie Ihre Anwendung ausführen, haben Sie ein interaktives Gantt-Diagramm betrieben von Rails und MySQL.

Für weitere Funktionen von dhtmlxGantt, werfen Sie einen Blick auf unsere Anleitungen.

Speicherung der Reihenfolge von Aufgaben

Das Gantt-Diagramm auf der Clientseite unterstützt das Umordnen von Aufgaben durch Ziehen und Ablegen. Wenn Sie diese Funktion verwenden möchten, müssen Sie die Aufgabenreihenfolge in der Datenbank speichern. Eine allgemeine Beschreibung dieses Prozesses finden Sie hier.

Lassen Sie uns diese Funktionalität zur App hinzufügen.

Aktivieren der Aufgaben-Reihenfolge auf dem Client

Um Benutzern das Umordnen von Aufgaben in der Benutzeroberfläche zu ermöglichen, aktualisieren Sie die Gantt-Konfiguration in der Index Ansicht:

app/views/gantt/index.html.erb

gantt.config.order_branch = true;gantt.config.order_branch_free = true; 
gantt.init("gantt_here");

Aktualisieren des Backends für die Aufgabenreihenfolge

Um die Aufgabenreihenfolge zu speichern, fügen Sie dem Modell ein sortorder Feld hinzu. Sie können entweder ein neues Modell generieren oder das bestehende ändern.

Um ein neues Modell zu generieren:

rails generate model Task \
    text:string \
    start_date:datetime \
    duration:integer \
    parent:integer \
    progress:decimal \ 
    sortorder:integer

Um ein bestehendes Modell zu ändern:

  1. Erstellen Sie eine Migration:
rails generate migration add_sortorder_to_tasks sortorder:integer
  1. Fügen Sie im Migrationsfile einen Standardwert für die sortorder Spalte hinzu:
class AddSortorderToTasks < ActiveRecord::Migration[5.1]
  def change
    add_column :tasks, :sortorder, :integer, :default=>0
  end
end
  1. Führen Sie die Migration aus:
rake db:migrate

Aktualisieren der Controller für die Aufgabenreihenfolge

  • Stellen Sie sicher, dass die data Aktion Aufgaben nach der sortorder Spalte sortiert zurückgibt:

app/controllers/gantt_controller.rb

class GanttController < ApplicationController
  def index
  end
 
  def data 
    tasks = Task.all
    links = Link.all
 
    render :json=>{
      :data => tasks.order(:sortorder).map{|task|{         :id => task.id,
        :text => task.text,
        :start_date => task.start_date.to_formatted_s(:db),
        :duration => task.duration,
        :progress => task.progress,
        :parent => task.parent,
        :open => true
      }},
      :links => links.map{|link|{
        :id => link.id,
        :source => link.source,
        :target => link.target,
        :type => link.link_type
      }}
    }
  end
end
  • Weisen Sie einen initialen sortorder Wert zu, wenn neue Aufgaben hinzugefügt werden:

app/controllers/task_controller.rb

class TaskController < ApplicationController
    ...
    def add
        maxOrder = Task.maximum("sortorder") || 0 
        task = Task.create( 
            :text => params["text"], 
            :start_date=> params["start_date"], 
            :duration => params["duration"],
            :progress => params["progress"] || 0, 
            :parent => params["parent"],
            :sortorder => maxOrder + 1        )
 
        render :json => {:action => "inserted", :tid => task.id}
    end
end
  • Aktualisieren Sie die Aufgabenreihenfolge, wenn ein Benutzer Aufgaben neu anordnet:

app/controllers/task_controller.rb

class TaskController < ApplicationController
    protect_from_forgery
 
    def update
        task = Task.find(params["id"])
        task.text = params["text"]
        task.start_date = params["start_date"]
        task.duration = params["duration"]
        task.progress = params["progress"] || 0
        task.parent = params["parent"]
        task.save
 
        if(params['target'])            Task.updateOrder(task.id, params['target'])        end 
        render :json => {:action => "updated"}
    end
 
    ...
end

Implementieren von Task.updateOrder

app/models/task.rb

class Task < ApplicationRecord
    def self.updateOrder(taskId, target)
        nextTask = false
        targetId = target
 
        if(target.start_with?('next:'))
            targetId = target['next:'.length, target.length]
            nextTask = true;
        end
 
        if(targetId == 'null')
            return
        end
 
        targetTask = self.find(targetId)
 
        targetOrder = targetTask.sortorder
 
        if(nextTask)
            targetOrder += 1
        end
 
        self.where("sortorder >= ?", targetOrder).
            update_all('sortorder = sortorder + 1')
 
        task = self.find(taskId)
        task.sortorder = targetOrder
        task.save
    end
end

Anwendungssicherheit

Beachten Sie, dass Gantt keinen eingebauten Schutz gegen Bedrohungen wie SQL-Injections, XSS- oder CSRF-Angriffe bietet. Die Sicherstellung der Sicherheit Ihrer Anwendung liegt in der Verantwortung der Entwickler, die das Backend verwalten. Weitere Details finden Sie hier.

Fehlerbehebung

Wenn Aufgaben und Links nach Abschluss der Schritte nicht auf der Seite angezeigt werden, lesen Sie die Fehlerbehebungsanleitung unter Fehlerbehebung bei Backend-Integrationsproblemen, um Hilfe bei der Identifizierung und Behebung von Problemen zu erhalten.

Was kommt als Nächstes

Ihr Gantt-Diagramm ist jetzt vollständig betriebsbereit. Sie können den vollständigen Code auf GitHub finden. Fühlen Sie sich frei, ihn für Ihre Projekte zu klonen oder herunterzuladen.

Für weitere Funktionen, erkunden Sie unsere Anleitungen oder schauen Sie sich Tutorials zur Integration von Gantt mit anderen Backend-Frameworks an.

Zurück nach oben