gorootde
gorootde

Reputation: 4073

Rails table_name_prefix missing

I have got the following dir structure

models/foo/setting.rb
models/foo.rb

foo.rb content

 module Foo
  def self.table_name_prefix
    'foo_'
  end
 end

and setting.rb content

class Foo::Setting < ActiveRecord::Base
end

As soon as I am calling Foo::Setting.find… I am getting an error SQLException: no such table: settings which is indeed correct because the table is named foo_settings so rails seems to ignore the table prefix specified for the module Foo.

What can I do so that rails considers the prefix?

Upvotes: 28

Views: 18570

Answers (4)

papar
papar

Reputation: 1084

Just create a base class in inside your namespaced model directory and require Foo in it, then extend your models from the base class.

Say I have app/models/foo.rb

module Foo
  def self.table_name_prefix
    'tble_prefix_'
  end
end

Then in app/models/foo/base_record.rb

require_dependency 'foo'
module Foo
  class BaseRecord < ActiveRecord::Base
    self.abstract_class = true
  end
end

Then extend from the BaseRecord

module Foo
  class Bar < BaseRecord

  end
end

Upvotes: 2

m_x
m_x

Reputation: 12554

This is probably caused by rails' autoloader. When doing this :

module Foo
  class Bar
  end
end

And then trying to use Foo::Bar, the autoloader first tries to locate app/models/foo/bar.rb. The file is loaded, and module Foo is defined here (albeit as a module containing solely Bar) so the autoloader never attempts to load app/models/foo.rb.

This should only happen in development mode, as in production mode all of your files are require'd on startup.

There are two workarounds AFAIK :

Cheat the autoloader

declare your class using class Foo::Bar, to force the autoloader to resolve a constant lookup for Foo.

This has the annoying side effect that the constant lookup inside Bar will NOT be scoped inside Foo, for instance :

# app/models/foo.rb
module Foo
 BAZ = "baz"
end

# app/models/foo/bar.rb
class Foo::Bar
  def baz
    BAZ
  end
end

here, Foo::Bar.new.bazwill fail, unless you reference the constant using Foo::BAZ. This can get really a mess when defining ActiveRecord associations, for instance.

Require the module

using require_dependency :

require_dependency 'foo'
module Foo
  class Bar
  end
end

This is IMHO the right solution, as it does not break the constant lookup, but it is also a bit annoying as you have to add the require statement on top of each namespaced file.

Note :

This bug seems to have been resolved in rails 4. I used the second workaround a lot while on rails 3, but I've tried to reproduce the bug in rails 4 and it does not show up anymore. I think they modified the way the autoloader works... For more info, see the rails guides on autoloading and reloading constants

Upvotes: 11

guapolo
guapolo

Reputation: 2543

I had the same issue. Solved it by changing either of my application's namespace or the model's.

Take a look at this question. Using the same namespace for the application as for models causes to models not pick up the parent namespace table_name_prefix correctly.

Upvotes: 1

Frederick Cheung
Frederick Cheung

Reputation: 84114

You've define a method inside a module (Foo). This doesn't magically define that method on a class nested in that module.

I'd try something like

class Foo < ActiveRecord::Base
  self.abstract_class = true
  self.table_name_prefix = 'foo_'
end

And then inherit from Foo

class Foo::Setting < Foo
...
end

Upvotes: 25

Related Questions