2012-02-02 45 views
12

Lần đầu tiên tôi tìm hiểu về Data, context, and interaction (DCI) thông qua this blog post. Bị cuốn hút bởi khái niệm này, tôi cố gắng xây dựng nó trong ứng dụng Rails tiếp theo của mình. Vì DCI làm việc song song với MVC, tôi nghĩ rằng sẽ không quá khó để làm cho RESTful API cùng một lúc. Vì vậy, tôi đã tạo một tài nguyên RESTful, Report và mở rộng nó với các ngữ cảnh khác nhau. Cách tôi thực hiện bối cảnh trong Rails là bằng cách tạo một thư mục, /app/contexts/, cho các mô-đun mở rộng các hành động của bộ điều khiển. Vì vậy, reports_controller.rb của tôi trông như thế này:bối cảnh DCI yên tĩnh trong 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 

Và trong application_controller.rb tôi đặt bối cảnh với một 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 

Thông báo tôi mở rộng current_user với một Role ngoài bối cảnh điều khiển.

Dưới đây là cách hoạt động:

  1. Một người dùng đăng nhập
  2. vai trò của người dùng là RegisteredUser..
  3. RegisteredUser ngữ cảnh mặc định là Search (như được định nghĩa trong /app/roles/registered_user.rb).
  4. Bên trong ngữ cảnh Search, người dùng chỉ có thể xem báo cáo đã xuất bản.
  5. Người dùng nhấn nút "tạo báo cáo mới" và ngữ cảnh được thay đổi thành Submission và được lưu trữ trong phiên của current_user.
  6. Người dùng sau đó tiến hành gửi báo cáo qua biểu mẫu nhiều bước.
  7. Mỗi lần người dùng lưu báo cáo bằng cách bước qua biểu mẫu, bối cảnh /app/contexts/submission.rb sẽ xử lý hành động.

Có một số ngữ cảnh khác (đánh giá, biên tập, v.v.) và vai trò (đồng tác giả, biên tập viên, v.v.).

Cho đến nay phương pháp này đã hoạt động tốt cho hầu hết các phần. Nhưng có một lỗ hổng: khi người dùng mở nhiều cửa sổ trình duyệt và thay đổi ngữ cảnh trong một trong số đó, tất cả các cửa sổ khác sẽ nằm trong ngữ cảnh sai. Điều này có thể là vấn đề nếu người dùng ở giữa biểu mẫu nhiều bước và sau đó mở một cửa sổ trong ngữ cảnh Search. Khi anh ta quay lại biểu mẫu và nhấn "Tiếp theo", bộ điều khiển sẽ thực hiện hành động được xác định bởi ngữ cảnh Search thay vì ngữ cảnh Submission.

Có 2 cách có thể xung quanh này mà tôi có thể nghĩ đến:

  1. Namespace tài nguyên Report với tên ngữ cảnh. Vì vậy, người dùng sẽ truy cập vào URL của chẳng hạn như /search/reports/submission/reports/1. Điều này dường như không yên tĩnh với tôi và tôi muốn giữ URL càng sạch càng tốt.
  2. Đặt tên ngữ cảnh vào trường ẩn. Phương pháp này yêu cầu các nhà phát triển phải nhớ đặt trường ẩn trong mọi biểu mẫu trên trang web và nó không hoạt động cho các yêu cầu GET.

Có cách nào khác xung quanh vấn đề này hoặc triển khai tổng thể tốt hơn không?

Tôi biết về this project, nhưng quá hạn chế đối với nhu cầu của chúng tôi.

+1

Haveyou xem xét các ví dụ về việc thực hiện DCI và REST trong Java bằng Qi4J của Rickard Öberg. Tôi tin rằng anh ta sử dụng cấu trúc URI để xây dựng bối cảnh, chẳng hạn yêu cầu tự nó mang tất cả các thông tin cần thiết để xây dựng lại bối cảnh trên máy chủ. Ngoài ra, bạn có thể thử đăng bài này lên nhóm google thành phần đối tượng. –

+0

có thể lưu trữ các bước trước đó trong cookie có thể giúp bạn? – Fivell

+0

Ngữ cảnh hiện tại đã được lưu trữ trong phiên qua cookie. Tôi không thấy những gì lưu trữ các bước trước đó sẽ thêm vào tình trạng này. Nó cũng sẽ được thực hiện vô ích bằng cách thực hiện một số hành động trong một cửa sổ trình duyệt khác. –

Trả lời

3

Nếu bạn muốn cho phép nhiều bối cảnh thì rõ ràng bạn phải đặt thông tin xác định bối cảnh hiện tại trong một số bộ nhớ không được chia sẻ giữa các tab. Phiên, như được triển khai trong Rack/Rails, sử dụng cookie và cookie được chia sẻ giữa các tab.

Chỉ cần đặt ngữ cảnh vào nội dung nào đó, không được chia sẻ. Làm thế nào về một tham số URL context = viewer?

Để nói về REST Tôi cho rằng có thể tranh cãi được liệu tài nguyên có giống nhau hay không trong các ngữ cảnh khác nhau. Người ta có thể lập luận rằng báo cáo cho người dùng "Truy cập" khác với báo cáo cho người dùng "Quản trị". Trong trường hợp đó, một cách tiếp cận RESTy có lẽ sẽ không gian tên các yêu cầu (một lần nữa đặt ngữ cảnh vào URL), ví dụ:/lượt truy cập/báo cáo/1 so với/quản trị/báo cáo/1.

Và cách thứ ba để đặt ngữ cảnh vào URL sẽ là sử dụng ngữ cảnh đó làm một phần của tên miền.

+0

Tôi đã kết thúc bằng cách sử dụng không gian tên. –

Các vấn đề liên quan