spira icon indicating copy to clipboard operation
spira copied to clipboard

Spira.repository unavailable in Rails controller

Open kardeiz opened this issue 11 years ago • 5 comments

I'm getting the following error when I try to reference a Spira::Base in a Rails (3.2.14) controller:

Spira::NoRepositoryError

I'm using the current master version of this gem. I'm currently setting the repository in an initializer. Presumably this error is related to the new repository threadsafe feature, as I can access Spira.repository and my Spira::Base objects just fine from Rails console.

I can get around this by doing (in my controller):

before_filter do
  Spira.repository ||= RDF::DataObjects::Repository.new('sqlite3:test.db')
end

but I don't want to have to do this. Is there some way to make the repository play nice with Rails controllers, or is there a better/recommended place to define my repository where this won't be an issue?

kardeiz avatar Dec 05 '13 17:12 kardeiz

@kardeiz sorry for the late response.

Indeed the threadsafe feature makes the initialization useless since each request creates a new thread. It is very practical when filling RDF repositories in a multithread env.

Since you only use a single repository in your case, I could add a new way to set it, like:

Spira.global_repository = RDF::DataObjects::Repository.new('sqlite3:test.db')

Spira.repository will have precedence on Spira.global_repository on the queries. This way we still can work on another repositories in a specific thread.

@cordawyn, @gkellogg : are you okay with this approach ?

abrisse avatar Apr 17 '14 13:04 abrisse

I think we should try and follow Rails approach to persistent DB connections (or even reuse their database connection pool and related classes and architecture, if possible). I'll have to look it up in the Rails code though -- it's been some time since I dug into the Rails core that deep. But off the top of my head, the before_filter solution doesn't sound that bad, considering the "stateless" nature of HTTP. Anyway, I'll update you on my findings in a couple of days, I guess.

cordawyn avatar Apr 17 '14 23:04 cordawyn

@abrisse I would like to have a global_repository, since I'm using it as a single readonly dataset for my app.

Hampei avatar Aug 18 '15 09:08 Hampei

Workaround: load it in a middleware:

lib/spira_repo_injector.rb:

require 'spira'
require 'sparql'

class SpiraRepoInjector
  def initialize(app)
    @app = app
  end

  def call(env)
    Spira.repository = RDF::DataObjects::Repository.new('sqlite3:test.db')

    @app.call(env)
  end
end

config/application.rb:

require "./lib/spira_repo_injector"

module MyApp
  class Application < Rails::Application
    config.middleware.unshift SpiraRepoInjector
  end
end

mike-burns avatar Oct 06 '18 05:10 mike-burns

My original issue is almost 5 years old, and I no longer use this library. But what benefit is there to putting this in a middleware? It calls Repository.new for every single request, even when the action may not require connecting to Spira.repository. I don't know everything involved with Repository.new, but it probably makes a database connection and other potentially costly calls. At least with :before_filter one can control which controllers load the Spira repository.

But shouldn't connection pooling be handled upstream, probably in the specific database adapters in RDF::DataObjects::Repository?

In any case, if I were still using this library, I would be tempted to just monkey patch Spira:

module Spira
  class << self
    def repository; @repository; end
    def repository=(v); @repository = v; end
  end
end

kardeiz avatar Oct 08 '18 15:10 kardeiz