Ho prima saputo di Data, context, and interaction (DCI) tramite this blog post. Affascinato dal concetto, ho cercato di integrarlo nella mia prossima applicazione Rails. Dato che DCI lavora in tandem con MVC, ho pensato che non sarebbe stato troppo difficile rendere l'API RESTful allo stesso tempo. Quindi ho creato una risorsa RESTful, Report
e l'ho estesa con vari contesti. Il modo in cui ho implementato i contesti in Rails è stato creando una directory, /app/contexts/
, per i moduli che estendono le azioni del controller. Quindi il mio reports_controller.rb
assomiglia a questo:Contesti DCI RESTful in Rails
class ReportsController < ApplicationController
before_filter :only => :new do |c|
c.switch_context("submission")
end
# GET /reports
def index
@context.report_list
end
# GET /reports/1
def show
@context.display_report
end
# GET /reports/new
def new
@context.new_report
end
# GET /reports/1/edit
def edit
@context.edit_report
end
# POST /reports
def create
@context.create_report
end
def update
@context.update_report
end
# DELETE /reports/1
def destroy
@context.destroy_report
end
protected
def switch_context(context_name)
session[:context] = context_name
context = session[:context].camelize.constantize
@context ||= self.extend context
end
end
E nel application_controller.rb
ho impostato il contesto con un before_filter
:
class ApplicationController < ActionController::Base
before_filter :contextualize
protect_from_forgery
protected
# Sets the context of both current_user and self
# by extending with /app/roles/role_name
# and /app/contexts/context_name respectively
def contextualize
# Extend self (ActionController::Base) with context
if session[:context]
context_class = session[:context].camelize.constantize
if current_user.allowed_contexts.include?(context_class)
context_class = current_user.context if context_class == Visiting
else
context_class = Visiting
end
else
context_class = current_user.context
end
@context ||= self.extend context_class
end
end
Avviso porgo current_user
con un Role
in aggiunta al contesto controller.
Ecco come funziona:
- un utente si collega
- ruolo dell'utente è
RegisteredUser
.. RegisteredUser
Il contesto predefinito èSearch
(come definito in/app/roles/registered_user.rb
).- All'interno del contesto
Search
, l'utente può solo visualizzare i report pubblicati. - L'utente preme il pulsante "crea nuovo report" e il contesto viene modificato in
Submission
e memorizzato nella sessione dicurrent_user
. - L'utente procede quindi a inviare un rapporto attraverso un modulo a più fasi.
- Ogni volta che l'utente salva il report passando il modulo, il contesto
/app/contexts/submission.rb
gestisce l'azione.
Sono diversi altri contesti (revisione, editoriale, ecc.) E ruoli (co-autore, editor, ecc.).
Finora questo approccio ha funzionato bene per la maggior parte. Ma c'è un difetto: quando un utente apre più finestre del browser e cambia i contesti in uno di essi, tutte le altre finestre si troveranno nel contesto sbagliato. Questo potrebbe essere un problema se l'utente si trova nel mezzo del modulo multi-step e quindi apre una finestra nel contesto Search
. Quando si torna al modulo e si preme "Avanti", il controller eseguirà l'azione definita dal contesto Search
anziché dal contesto Submission
.
Ci sono 2 modi possibili in tutto questo che mi viene in mente:
- Namespace la risorsa
Report
con il nome del contesto. Quindi l'utente visiterebbe gli URL come/search/reports
e/submission/reports/1
. Questo non mi sembra RESTful e preferirei mantenere l'URL il più pulito possibile. - Inserire il nome del contesto in un campo nascosto. Questo metodo richiede agli sviluppatori di ricordare di inserire il campo nascosto in ogni forma sul sito e non funziona per le richieste GET.
Esistono altri modi per risolvere questo problema o implementazioni generali migliori?
So di this project, ma è troppo limitato per le nostre esigenze.
Haveyou ha esaminato gli esempi di Rickard Öberg di fare DCI e REST in Java con Qi4J. Credo che utilizzi la struttura URI per costruire il contesto, tale che la richiesta stessa porti tutte le informazioni necessarie per ricostruire il contesto sul server. Potresti anche provare a postare questo nel gruppo google di composizione degli oggetti. –
forse memorizzare il passaggio precedente nei cookie può aiutare? – Fivell
Il contesto corrente è già memorizzato nella sessione tramite cookie. Non vedo cosa memorizzare il passaggio precedente in questa situazione. Sarebbe anche reso inutile eseguendo un'azione in un'altra finestra del browser. –