ruby-on-rails - Rails 中的 RESTful DCI 上下文

标签 ruby-on-rails ruby rest dci

我首先了解到Data, context, and interaction (DCI) 通过 this blog post .我对这个概念着迷,努力将它构建到我的下一个 Rails 应用程序中。由于 DCI 与 MVC 协同工作,我认为同时使 API 成为 RESTful 不会太难。所以我制作了一个 RESTful 资源 Report 并使用各种上下文扩展它。我在 Rails 中实现上下文的方式是为扩展 Controller 操作的模块创建目录 /app/contexts/。所以我的 reports_controller.rb 看起来像这样:

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

application_controller.rb 中,我使用 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

请注意,除了 Controller 上下文之外,我还使用 Role 扩展了 current_user

这是它的工作原理:

  1. 用户登录。
  2. 用户的角色是RegisteredUser
  3. RegisteredUser 的默认上下文是 Search(在 /app/roles/registered_user.rb 中定义)。
  4. Search 上下文中,用户只能查看已发布的报告。
  5. 用户按下“创建新报告”按钮,上下文更改为Submission 并存储在current_user 的 session 中。
  6. 然后用户继续通过多步骤表单提交报告。
  7. 每次用户通过单步执行表单保存报告时,/app/contexts/submission.rb 上下文都会处理该操作。

还有其他一些背景(评论、编辑等)和角色(合著者、编辑等)。

到目前为止,这种方法在大多数情况下都运行良好。但是有一个缺陷:当用户打开多个浏览器窗口并更改其中一个的上下文时,所有其他窗口都将处于错误的上下文中。如果用户处于多步骤表单的中间,然后在 Search 上下文中打开一个窗口,这可能会成为一个问题。当他切换回表单并点击“下一步”时, Controller 将执行由 Search 上下文而不是 Submission 上下文定义的操作。

我可以想到两种可能的解决方法:

  1. 使用上下文名称命名Report 资源。因此,用户会访问诸如 /search/reports/submission/reports/1 之类的 URL。这对我来说似乎不是 RESTful,我宁愿保持 URL 尽可能干净。
  2. 将上下文名称放在隐藏字段中。此方法要求开发人员记住将隐藏字段放在网站上的每个表单中,并且它不适用于 GET 请求。

有没有其他方法可以解决这个问题,或者更好的整体实现?

我知道this project ,但它对我们的需求来说太有限了。

最佳答案

如果你想允许多个上下文,那么显然你必须将确定当前上下文的信息放在一些不在选项卡之间共享的存储中。在 Rack/Rails 中实现的 session 使用 cookie,并且 cookie 在选项卡之间共享。

只需将上下文放入不共享的内容中。 context=viewer URL 参数怎么样?

说到 REST 我认为资源在不同上下文中是否相同是有争议的。有人可能会争辩说,“访问”用户的报告与“管理”用户的报告不同。在那种情况下,RESTy 方法可能会对请求命名空间(再次将上下文放入 URL),例如/visiting/reports/1 与/administering/reports/1。

将上下文放入 URL 的第三种方法是将其用作域名的一部分。

关于ruby-on-rails - Rails 中的 RESTful DCI 上下文,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9114393/

相关文章:

ruby-on-rails - Kaminari 是否存在下一页?

ruby-on-rails - 无法用 font-awesome 的字体覆盖 bootstrap-sass 的字体

ruby-on-rails - ruby on rails devise gem 数据库在哪里

ruby 数组检查 nil 数组

javascript - 当没有数据返回时,GraphQL 变异返回类型应该是什么?

javascript - ng-token-auth ui-router 解析器导致黑屏

ruby - 注入(inject)结果为零

ruby-on-rails - Heroku - 只读文件系统 -/var/www?

json - 戈朗 : Json from URL as map

git - Azure DevOps 通过 REST API 获取链接到工作项的提交