Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure Tournament Sandbox #727

Open
kevinhughes27 opened this issue Sep 7, 2017 · 0 comments
Open

Ensure Tournament Sandbox #727

kevinhughes27 opened this issue Sep 7, 2017 · 0 comments
Labels

Comments

@kevinhughes27
Copy link
Owner

Shopify uses a pattern like this to sandbox things:

umbrella model concern (eg. tournament):

# frozen_string_literal: true
module TrackCurrentInThread
  extend ActiveSupport::Concern

  module ClassMethods
    def current
      Thread.current["#{name}::current"]
    end

    def current=(obj)
      Thread.current["#{name}::current"] = obj
    end
  end
end

Then set Tournament.current in the controller before action. This is where the tournament is always fetched from. FYI this current stuff may land in Rails https://twitter.com/dhh/status/891058020976926720 this year

A middleware is added to ensure this state is cleared before each request

# frozen_string_literal: true
module Middleware
  class ResetState
    def initialize(app)
      @app = app
    end

    def call(env)
      @app.call(env)
    ensure
      Organization.current = nil
    end
  end
end

Lastly the cool part: active record is patched with this:

# frozen_string_literal: true

module ActiveRecordOrganizationScopedResult
  def initialize(columns, rows, column_types = {})
    return super unless Organization.current

    organization_id = Organization.current.id
    org_id_column = columns.index('organization_id')
    return super unless org_id_column

    rows.each do |row|
      next if row[org_id_column].nil?
      if row[org_id_column] != organization_id.to_i
        Rails.logger.warn("Request for org=#{organization_id} accessed a record " \
          "from org=#{row[org_id_column]}\n#{caller.join("\n")}")
      end
    end
    super
  end
end

ActiveSupport.on_load(:active_record) do
  ActiveRecord::Result.prepend(ActiveRecordOrganizationScopedResult)
end

which implements the sandbox.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant