fixture_builder
fixture_builder copied to clipboard
How to handle JSONB columns on name-spaced tables?
Here's the situation: Imagine you have a name-spaced table, e.g. admin_users
, representing the model Admin::User
, and this table has a JSONB column, say details
.
The fixture_builder
gem won't ever call serialized_value_if_needed
. The key method is dump_tables
in builder.rb
, which calculates the class name with the following code:
table_klass = table_name.classify.constantize rescue nil
The trace is as follows:
"admin_users".classify => "AdminUser" # should be "Admin::User"
"AdminUser".constantize => error
Any ideas how to handle this?
I also tried naming the table admin/users
, but fixture_builder
gave the following error trace (which was fixable by manually creating a spec/fixtures/admin
folder):
Errno::ENOENT: No such file or directory @ rb_sysopen - /Users/jack/code/PROJECT/spec/fixtures/admin/users.yml
/Users/jack/.rvm/gems/ruby-2.5.0/gems/fixture_builder-0.5.1/lib/fixture_builder/builder.rb:151:in `initialize'
/Users/jack/.rvm/gems/ruby-2.5.0/gems/fixture_builder-0.5.1/lib/fixture_builder/builder.rb:151:in `open'
/Users/jack/.rvm/gems/ruby-2.5.0/gems/fixture_builder-0.5.1/lib/fixture_builder/builder.rb:151:in `write_fixture_file'
/Users/jack/.rvm/gems/ruby-2.5.0/gems/fixture_builder-0.5.1/lib/fixture_builder/builder.rb:90:in `block in dump_empty_fixtures_for_all_tables'
/Users/jack/.rvm/gems/ruby-2.5.0/gems/fixture_builder-0.5.1/lib/fixture_builder/builder.rb:89:in `each'
/Users/jack/.rvm/gems/ruby-2.5.0/gems/fixture_builder-0.5.1/lib/fixture_builder/builder.rb:89:in `dump_empty_fixtures_for_all_tables'
/Users/jack/.rvm/gems/ruby-2.5.0/gems/fixture_builder-0.5.1/lib/fixture_builder/builder.rb:65:in `write_data_to_files'
/Users/jack/.rvm/gems/ruby-2.5.0/gems/fixture_builder-0.5.1/lib/fixture_builder/builder.rb:17:in `generate!'
/Users/jack/.rvm/gems/ruby-2.5.0/gems/fixture_builder-0.5.1/lib/fixture_builder/configuration.rb:34:in `factory'
Ahh.. I think I am running into this issue with the audited gem. Because the table class is Audited::Audit
, it seems to not be serializing the JSONB fields correctly and instead stores the fields as strings, which breaks my specs unfortunately. I guess I can just not test reading the audit logs, but it's a bit unfortunate...
Hmm, based on the issue, I think a hacky workaround might be to just add define the un-namespaced class somewhere appropriate to get FixtureBuilder to find the right class. I put it in my fixture builder block and it seems to resolve the issue without affecting other places. Though this may not be possible if the un-namespaced class already exists. But e.g.
Audit = Audited::Audit
@jackkinsella @ibrahima As anyone who knows me will attest I'm a fan of namespaces, so I've run into this issue a number of times. The problem, as you've no doubt determined, is FixtureBuilder trying to determine the class from the table name. In the example of the Audited gem (which I also use and quite like), the table name is audits
; applying the line of code that @jackkinsella identified we end up with:
table_klass = table_name.classify.constantize rescue nil
# "audits".classify => "Audit"
# "Audit".contantize => *BOOM* since Audit is not a top-level constant
# rescue nil => nil
I've worked around it by adding an explicit configure_tables
block, in which you can set the class that should be associated with a given table, as well as what file to store the YAML in. For example:
builder.factory do
builder.configure_tables(
audits: { class: "Audited::Audit", file: 'audited/audits' }
)
end
I hope to merge this functionality into the gem (I've spoken with the maintainers, and they're amendable; I just haven't gotten around to it, so the delay is entirely my fault), but in the meantime I've been using my fork for the past year or so without any problems.
I hope this helps.