Rails table_name_prefix missing
Asked Answered
B

4

28

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?

Bombazine answered 18/1, 2012 at 13:37 Comment(5)
Which version of Rails are you using?Hoopes
As Qerub mentioned, you should check your Rails version, because if im not mistaken, this feature came in from 3.0Papeterie
Did some experimenting. It works if I do a require 'repsys.rb' in models/foo/setting.rb. Seems like Rails doesn't load foo.rbif I am accessing Foo::Settings. If requiring is the only solution that would be pretty poor!Bombazine
I already have some code working correctly in my app, but now I get this error with another namespace. Using rails 3.2.6.Boyceboycey
Thanks for the question. Running into the same problem, but only when I run it on heroku, locally it all works fine. I can live with your workaround for now. Did you ever find a better solution?Interregnum
D
25

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
Devan answered 18/1, 2012 at 15:6 Comment(9)
Rails generated that module and the structure. Are you sure? If so rails generate will generate something that is not runnable.Bombazine
It generates something that's runnable, just not something that does what you want. If you're just namespacing your models then all you need is a modeDevan
Spree commerce seem to be using this method also.. github.com/spree/spree/blob/master/core/app/models/spree.rb But I cant figure out how they've done itTransubstantiation
I don't think this answer is correct. For some of my models it does magically define that method on the nested classes but for others it doesn't?Fabe
Sounds like you should ask a fresh question, showing when it works and when it doesn't - there's not really room in comments to do all thatDevan
wrong, according to the docs for table_name_prefix, the OP code should work. My guess is that it has to do with the autoloader (see my answer). Your answer is still working though, so no downvote ;)Walliw
ah, yes active record rather than calling just table_name_prefix tries to walk up the module chain calling table_name_prefix all the wayDevan
the answer below by @Walliw is much superior, as it identifies the core of the problem.Vulcanize
It is important to note, that if table_name is overrided, table_name_prefix doesn't work #29175340Robertson
W
11

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

Walliw answered 9/6, 2015 at 13:52 Comment(3)
Under some cases I have this bug tooVisser
i still had this bug intermittently show up on a CI run at work with rails 4. so we didn't have to require_dependency we required the module in an initializer. i prefer this way as opposed to needing to require_dependancy because that means any other dev that comes along will need to remember to require dependancy as well.Fiedler
Yup, I've still had this crop up in an application in Rails 4 and 5. We deal with it by creating a base model as described in the other answer, but require_dependency would work fine too. Kinda frustrating that the Rails generator gives you an unreliable default scheme for this.Kyoko
S
2

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
Stroman answered 28/11, 2016 at 1:15 Comment(0)
P
1

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.

Platonism answered 3/12, 2013 at 19:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.