oaken icon indicating copy to clipboard operation
oaken copied to clipboard

Add `grant_fixture_access` with all the caveats

Open kaspth opened this issue 2 months ago • 4 comments

I'm slightly unsure about adding this to Oaken itself, but I have successfully used this pattern in an app.

kaspth avatar Nov 02 '25 17:11 kaspth

I like this approach! I experimented with Oaken on a smaller microservice at my last job, and was really liking it!

Awesome, thank you so much!

One of the questions I got asked was, how/if the gem could be brought over to our monorepo, a very large codebase with a combination of fixtures and FactoryBot. I really didn't have a solution for that with all the files and tests we had in place. I could see this really helping towards that gradual implementation

Yeah, it's one of the things I'm trying to figure out. For FactoryBot I'm working on something like this and I've got most of the pieces:

# db/seeds.rb # or somewhere better
class FactoryBotProvider < Oaken::Stored::ActiveRecord
  def attributes_for(**) = FactoryBot.attributes_for(factory_name, **)
  def factory_name = @factory_name ||= key.singularize # I basically just need to see if this works
end

Oaken.loader = Oaken.loader.with(provider: FactoryBotProvider)
Oaken.seed :something

This will let Oaken pull attributes/defaults from existing factories when creating seed records.

kaspth avatar Nov 07 '25 14:11 kaspth

@cpalafox I'd also love to talk some time about your experience with Oaken if you'd like? I'm curious to hear how it works for people and how we could improve Oaken.

kaspth avatar Nov 07 '25 15:11 kaspth

# db/seeds.rb # or somewhere better
class FactoryBotProvider < Oaken::Stored::ActiveRecord
  def attributes_for(**) = FactoryBot.attributes_for(factory_name, **)
  def factory_name = @factory_name ||= key.singularize # I basically just need to see if this works
end

Oaken.loader = Oaken.loader.with(provider: FactoryBotProvider)
Oaken.seed :something

This will let Oaken pull attributes/defaults from existing factories when creating seed records.

Although I like the idea behind it, and would get Oaken into the project faster, I do find myself reeling at this a bit at first glance.

The good things:

  • Gets Oaken into the project, and allows new file (or migrate existing files) to use Oaken faster.
  • Test files load seeds vs reliance on FactoryBot api.

The not so good things:

  • There's little motivation to rewrite factories into seed declarations.
  • How do you mix FactoryBotProvider and Oaken's Loader so I can have regular seed declarations and factories.
  • How do I communicate to developers, other than extensive peer to peer communication or not super obvious documentation that factories are deprecated.
  • I could easily see this become yet another half baked migration at my old place. Bring in new technology, without a proper migration plan, and now the monolith has fixtures, and factories, and seeds, and you need a mix of all 3 in a file to make things work?
    • Of course this is more of a company's engineering/management problem, but also not unusual in a very old monolith with a lot high business priorities and de-prioritized maintenance. Maybe this is not the kind of project Oaken is meant for, and that'd be fine?

Didn't get a chance to try the fixture conversion, but maybe a factory conversion, even if it's one that supports the most common/general scenarios of FactoryBot would be enough?

The team had a wrapper object around FactoryBot, so that it would never be called like FactoryBot.create(...) or the shorthand create(...) In theory, a combination of using the FactoryBotLoader for the attribute/factory retrieval, and a change in this wrapper object to rely on oaken could, in theory, make the full transition possible, but I'm curious how that would work with a bunch of let(:object) { create.a(:object, params) } scattered across all rspec files 🤔

@kaspth I'd love and open to talk, full disclosure tho, I'm no longer with the company I pulled this and without visibility on how they are carrying it forward, but I'd say i do have some insight.

cpalafox avatar Nov 07 '25 16:11 cpalafox

@cpalafox thank you for the feedback, I was out sick this week, so I'm writing back now.

Although I like the idea behind it, and would get Oaken into the project faster, I do find myself reeling at this a bit at first glance.

Totally! It's also pretty specific to the API I've been trialing out.

The good things:

  • Gets Oaken into the project, and allows new file (or migrate existing files) to use Oaken faster.
  • Test files load seeds vs reliance on FactoryBot api.

Yeah, exactly. The point is that if you have a FactoryBot.define { factory(:account) { name { Faker::Name.name } }, then you could reuse the defaults with the FactoryBotProvider above to hopefully kickstart the integration. E.g. accounts.create :something would then have the Faker::Name.name passed over.

Though honestly, writing this out, maybe it's better to just advocate that people migrate one factory at a time.

  • There's little motivation to rewrite factories into seed declarations.

Large apps might not be able to ever migrate fully, so I wanted to give some grace for that in that Oaken and Factories are meant to be able to co-exist, if need be.

  • How do you mix FactoryBotProvider and Oaken's Loader so I can have regular seed declarations and factories.

You can do Oaken.seed calls upfront for non-factory based seeds and then override with FactoryBotProvider later and call Oaken.seed for the factory based ones. But maybe that's also intricate.

  • How do I communicate to developers, other than extensive peer to peer communication or not super obvious documentation that factories are deprecated.

Yeah, true. My thinking was that a team using factories could get Oaken in quickly, and seed the 5-10 records that they reuse in almost all tests ahead of time, then reinject those back into the test cases.

After that, it's a little more murky. I'm not sure about deprecations yet. Maybe it makes more sense to make Oaken the default, and then have factories build attributes from Oaken instead? I don't know yet.

I could easily see this become yet another half baked migration at my old place. Bring in new technology, without a proper migration plan, and now the monolith has fixtures, and factories, and seeds, and you need a mix of all 3 in a file to make things work?

  • Of course this is more of a company's engineering/management problem, but also not unusual in a very old monolith with a lot high business priorities and de-prioritized maintenance. Maybe this is not the kind of project Oaken is meant for, and that'd be fine?

Yeah, I'm really not sure. And I think there's limits to what we can push from the code side here. Ultimately, I like Conway's Law: that companies are doomed to mirror the communication structures in their software, so those org problems will end up spilling out into code.

Didn't get a chance to try the fixture conversion, but maybe a factory conversion, even if it's one that supports the most common/general scenarios of FactoryBot would be enough?

Yeah, I have no ideas how we could do that. Maybe there's a resolver that you run your whole suite with and we try to detect which factories you'd get the most bang for your buck by extracting?

The team had a wrapper object around FactoryBot, so that it would never be called like FactoryBot.create(...) or the shorthand create(...) In theory, a combination of using the FactoryBotLoader for the attribute/factory retrieval, and a change in this wrapper object to rely on oaken could, in theory, make the full transition possible, but I'm curious how that would work with a bunch of let(:object) { create.a(:object, params) } scattered across all rspec files 🤔

Ah yeah. Since there's tons of ways that people have their data setup currently, I'm mostly trying to keep Oaken lightweight and flexible, so users could stretch for what they need.

@kaspth I'd love and open to talk, full disclosure tho, I'm no longer with the company I pulled this and without visibility on how they are carrying it forward, but I'd say i do have some insight.

Awesome, I'd love that! Yeah, that's alright, I'm still curious to hear your experience. I'm also happy to talk to a team member that inherited it. I'll send you an email shortly. Thanks again for all your detailed thoughts, it's interesting to hear how this lands to someone else ❤️

kaspth avatar Nov 14 '25 22:11 kaspth