rom-rb/rom-rails

Unclear From Documentation How To Properly Access ROM in Rails/RSpec

ylg opened this issue · 7 comments

ylg commented

The documentation shows ROM.env as the way to access things from Rails' CLI, e.g., ROM.env.relations(:users)`. If used in specs, this seems to set things up a little differently than the subsequent documentation demonstrates. For example, with:

class UsersRelation < ROM::Relation[:sql]
  def by_username(search_username)
    [etc]

Running a spec containing something like this will work:

ROM.env.relation(:users).count

But this will not:

ROM.env.relation(:users).by_username('testuser')

 Failure/Error: ROM.env.relation(:users).by_username('testuser')
 NoMethodError:
   undefined method `by_username' for #<#<Class:0x007fe701c8f240>:0x007fe6fe26e930>

If ROM.env is returning the same thing that the documentation just refers to as the local variable "rom" later on, then something is missing.

Similarly, trying to wrap all that in a Repository (unclear if those are deprecated) nets a similar result:

class UserRepository < ROM::Repository::Base
  relations :users

  def by_username(username)
    users.by_username(username)
    [etc]

UserRepository.new(ROM.env).by_username('testuser')

Failure/Error: found = UserRepository.new(ROM.env).by_username('testuser')
NoMethodError:
    undefined method `by_username' for #<ROM::Repository::LoadingProxy:0x007fd95ad44870>

After showing the ROM.env example for use in the CLI, the documentation just shows rom as in rom.relation(). I couldn't find where that rom might be defined (and therefore how.)

ylg commented

After looking at this again: it seems more likely there is a step missing, or that I am missing, required to get ROM / Rails to load relations classes.

For example, even if I delete the UsersRelation's file entirely, ROM.env.relations(:users).count and ROM.env.command(:users).create.call still work—presumably ROM is coming up with the relations by scanning the DB rather than by looking at the relations classes, which raising the question: how does one get relations class in the mix, i.e., so that methods defined in UsersRelations are available?

Yes, you're getting the initial / pre-seeded relation from the database.

I suspect it's possible you're not loading Rails in the spec? Does the spec pass when you run everything, and only fail in isolation?

ylg commented

They fail in both approaches. The specs require 'rails_helper'; I don't see any other wiring steps in the docs or the tasks project (unfortunately for me the specs in that one are empty.) If it were an across the board loading failure, one would expect ROM.env.command(:users) to fail, no?

@ylg make sure that your relations are being required in test mode

ylg commented

Thanks. To be clear (or less unclear), what I was attempting to point out was that I can't really tell if I'm "doing it right" by calling "rom" everywhere in Rails and "ROM.env" in Rspec, and therefore when I have problems, like the commands working but the relations not, I'm left scratching my head as to whether I've just made a dumb typo somewhere or if everything I've done is based on a wrong assumption...

Using ROM.env is not encouraged, it's only there because Rails needs global access. You should expose rom components through your own interface. ie I have a persistence singleton object that exposes access to various rom components, it's available in specs through a helper so I can do things like persistence.users.by_name('Jane'). In general I use a container with dependencies in my apps, so I have access to various things through a simple interface like Something.app['repositories.posts'] and provide helpers for those in tests to make it more concise.

If you don't see your methods in relations in tests then I'm 100% sure your relation classes were not loaded, thus they were not registered and so ROM inferred them from db schema. If you are using rails things should just work™. What's your rails version?

Bug cleanups; closing due to inactivity