0

Rails is so magical that I need help from someone who knows a little better than I do.

Since I have a lot of crud API basic endpoints repeated over and over I decided to automate their creations (see my final post in the following github issue).

For the sake of having some basic valid swagger documentation I automated also the creation of the Grape::Entities by adding some custom code to my ApplicationRecord (see github SOLUTION snippet added to this question: Inheriting class definition from parent class).

With the above 2 customizations I can create API endpoint by simply doing:

V1::Base.show Book

The above method will create an endpoint and it will use the automagically created Entity like so that it gets automagically documented with default values that can be overridden later on if needed in the Book model class:

Book::Entity

There is 1 exception when the above code seems to break: it seems that whenever I interact in an early state during the bootstrap of my Rails application (initializers for example), when I call V1::Base.show Book (to create the api endpoint) which calls Book::Entity the following error is returned:

NameError: uninitialized constant Book::Entity

Could anybody give me a hint on what it could be? the early interaction with the model can be a simple Book.all, it smells like a thread issue.

Francesco Meli
  • 2,484
  • 2
  • 21
  • 52
  • Actually sounds more like an autoload issue than a thread issue. I actually created a very similar concept recently for templating endpoints in Grape unfortuantely the code is far too verbose and application specific to post here. That being said why would you need to call this in an initializer? Why not handle the generation of the needed endpoints in a lazy method or inside of V1::Base directly ? – engineersmnky Nov 21 '17 at 19:00
  • The generation of the endpoint is a static method in V1::Base indeed. It's the generation of the Grape::Entity that is generated when ApplicationRecord is inherited: the reason why I did so is because I wanted to have the entity defined as Model::Entity and Model::EntitiesList. Do you think this is a bad approach to have the Grape::Entity as a subclass on the model? – Francesco Meli Nov 21 '17 at 20:33
  • Since I hate the idea of any business or presentation logic in a model (or subclass there of) I separate the 2 concerns and generate the entities in their own namespace dynamically. While our code base has many concerns involved the simplified version is just `Entities::Book = Class.new(Grape::Entity) { expose *Book.attribute_names}`. It seems this concept could easily be patched into your `#show` method directly since you are already checking constant definitions – engineersmnky Nov 21 '17 at 20:47
  • I think your main issue right now is that `Book` is not loaded and thus `Book::Entity` is invalid because `Book` is not currently a valid namespace. If you were to do this in an initializer you would essentially need to load every model (which are generally lazy loaded as needed) so that you would have a declared namespace in which to generate the `Entity` class. Constant lookup requires a depth chart where `class Book; class Entity; end; end;` can resolve the `Book` namespace but `class Book::Entity; end;` cannot [Nice Reasonably Concise Article](https://cirw.in/blog/constant-lookup.html) – engineersmnky Nov 21 '17 at 21:10
  • I was actually able to get it working it was a matter of constant not yet created and linked to the correct class. Now though I'm more concerted of what you said, I hate a lot the presentation login in the model too. I think I will refactor. – Francesco Meli Nov 21 '17 at 21:16
  • Glad you got everything sorted. Best of luck – engineersmnky Nov 21 '17 at 21:18

0 Answers0