I want to do an API for an Android app. When searching, I found {grape}. I'm following this tutorial, but I have a problem launching the Rails server:
=> Booting WEBrick
=> Rails 4.0.2 application starting in development on http://0.0.0.0:80
=> Run `rails server -h` for more startup options
=> Ctrl-C to shutdown server
Exiting
C:/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/activesupport-4.0.2/lib/act
ive_support/dependencies.rb:464:in `load_missing_constant': Unable to autoload c
onstant Usuarios, expected C:/Sites/appCerca/app/api/v1/usuarios.rb to define it
(LoadError)
My directory:
app
..api
....api.rb
....v1
......root.rb
......usuarios.rb
and the files:
#application.rb
module AppCerca
class Application < Rails::Application
config.paths.add "app/api", glob: "**/*.rb"
config.autoload_paths += Dir["#{Rails.root}/app/api/*"]
end
end
#routes.rb
AppCerca::Application.routes.draw do
mount API::Root => '/'
[...]
#app/api/root.rb
module API
class Root < Grape::API
prefix 'api'
mount API::V1::Root
end
end
# app/api/v1/root.rb
module API
module V1
class Root < Grape::API
mount API::V1::Usuarios
end
end
end
# app/api/v1/usuarios.rb
module API
module V1
class Usuarios < Grape::API
version 'v1'
format :json
resource :usuarios do
desc "Return list of authors"
get do
Usuario.all
end
end
end
end
end
Why am I getting this error? I am using Ruby 1.9.3p484 and Rails-4.0.2.
Try either
Moving your API code's files from app/api to app/api/api, or
Moving your API classes outside the API module (i.e. deleting all the module API lines and their corresponding end statements).
From Grape's documentation:
Place API files into app/api. Rails expects a subdirectory that matches the name of the Ruby module and a file name that matches the name of the class. In our example, the file name location and directory for Twitter::API should be app/api/twitter/api.rb.
Thus the correct location for your API::Root class would actually be app/api/api/root.rb.
With this change your code starts and works fine for me on Rails 4.0.2.
Related
I'm trying to update my app from Rails 5.2 to 6.1, and use Zeitwerk autoload, and I am having some issues for autoloading /lib classes.
I included this in config/application.rb:
config.load_defaults 5.2
config.autoloader = :zeitwerk
config.enable_dependency_loading = true
config.autoload_paths += Dir[Rails.root.join('lib/**/*')]
config.eager_load_paths += Dir[Rails.root.join('lib/**/*')]
And, when I run zeitwerk:check, it alerts me that:
Hold on, I am eager loading the application.
expected file lib/facades/coconut/v2/foo.rb to define constant Foo
It is declared as:
# /lib/facades/coconut/v2/foo.rb
module Coconut
module V2
class Foo
# ...
end
end
end
When I try to debug it (putting a binding.pry in some test file), Zeitwerk says it do not defined, until I call it without modules (namespaces):
[1] pry(#<#filename>)> Coconut::V2::Foo
NameError: uninitialized constant Coconut::V2::Foo
from (pry):1:in `setup`
[2] pry(#<#filename>)> Foo
Zeitwerk::NameError: expected file /my-app/lib/api/coconut/v2/foo.rb to define constant Foo, but didn't
from /usr/local/bundle/gems/zeitwerk-2.5.4/lib/zeitwerk/loader/callbacks.rb:25:in `on_file_autoloaded'
[3] pry(#<#filename>)> Coconut::V2::Foo
=> Coconut::V2::Foo
It sounds really strange, because there are another classes in /lib that follows the same structure, but it works well, example
# /lib/api/services/youtube/client.rb
module Services
module Youtube
class Client
# ...
end
end
end
Inspecting it with binding.pry in some test:
pry(#<#filename>)> Services::Youtube::Client
=> Services::Youtube::Client
Has anyone had this problem or know what could be happening?
System:
ruby 2.7.6p219
Rails 6.1.6
Zeitwerk (2.5.4)
An autoload path is a root directory, not its contents.
You need to remove the wildcards as documented here.
Whenever i hit the endpoints (example: greet ) exposed by rails engine i receive this error.
Error:
"LoadError(Unable to autoload constant TestingController,
expected /local_path/app/controllers/testing_controller.rb to define it):
/Users/xxxxx/.rvm/gems/ruby-2.5.1/gems/activesupport-5.2.1/lib/active_support/
dependencies.rb:507:in `load_missing_constant'"
Engine:
I have an engine with action method greet defined as below
# type: class
# path: app/controllers/testing_controller.rb
# file name: testing_controller.rb
module Parent
module Child
class TestingController < ApplicationController
def initialize
#name = 'BOB'
end
def greet
render json: {'hi': 'hi', 'name': #name}
end
end
end
end
routes defined as
# type: route
# path: app/config/routes.rb
# file name: routes.rb
Parent::Child::Engine.routes.draw do
get 'greet', to: 'testing#greet', as: :greet
end
Details:
This engine has been mounted to a gem ABC which is then used in the rails app called Example. When i hit the greet route in the app via
http://localhost:3000/greet for the first time i receive LoadError.
However if i refresh the page it renders the
json as expected. {"hi":"hi","name":"BOB"}.
we have development.rb (app/config/env/) has cache and eager load defined as below
config.cache_classes = false
config.eager_load = false
Ruby: 2.5.1
Rails: 5.2.1
Thanks for your help, much appreciated.
The message seems to be coming from the expectation that in the root level of the file testing_controller.rb has a definition of a TestingController class whilst you have that class defined nested within Parent::Child:: modules.
I guess that if you put your testing_controller.rb file in the following path: app/controllers/parent/child/testing_controller.rb the error will disappear.
For a Rails project I'm working on, I'm having an issue with loading Sidekiq and having nested modules in the lib directory.
my lib/scraper/v2.rb looks like this:
require 'scraper/v2/client'
module Scraper
module V2
end
end
my lib/scraper/v2/client.rb looks like this:
module Scraper
module V2
class Client
def initialize
...
end
end
end
end
I then have a Sidekiq job in the jobs directory that looks like this:
class RefreshTokenJob < ApplicationJob
queue_as :default
def perform
client = Scraper::V2::Client.new
...
end
end
If I run bundle exec sidekiq with this configuration, Sidekiq starts, but running Scraper::V2::Client.new form the Rails console returns:
NameError: uninitialized constant Scraper::V2
If I add config.autoload_paths += %W(#{config.root}/lib) to my application.rb file, I can run Scraper::V2::Client.new, but starting Sidekiq gives me and uninitialized constant error from a completely different file (within app/jobs/concerns/).
Any help with this would be much appreciated!
You must follow Rails' conventions for naming files if you want Rails autoloading to work correctly.
For a module named Scraper::V2, it should be in a file named scraper/v2.rb, not scraper_v2.rb.
I am developing a gem which is also a Rails::Engine
I would like the engine to add a custom middleware to the host application and I have done that with the following code
module MyModule
class Engine < ::Rails::Engine
isolate_namespace MyModule
initializer "my_gem.middleware" do |app|
app.config.app_middleware.use "MyModule::MyMiddleware"
end
end
end
However this also adds the middleware to those routes defined in the routes.rb file of the Engine. How can I avoid this? I only want the middleware to be added to the host app.
For example, consider the following routes defined in the host application
Rails.application.routes.draw do
mount MyModule::Engine => "/engine"
root :to => Proc.new { |env| [200, {'Content-Type' => 'text/html'}, ["Hello World"]] }
end
Everything under /engine should NOT go through MyMiddleware
I am probably going down the wrong path to achieve this and may be I should look at some other solution?
I don't see how you can do that without putting it in the engine. The initializer is run on boot. You could create an URL matcher in your middleware to skip whatever it does if url is /engine. Note that I had to use app.config.middleware.use, not app.config.app_middleware.use
I've got a vanilla rails 4 application and I'm trying to add a versioned Grape API. The rails server starts up fine, but when I try to access the API URL (http://localhost:3000/v1/user/ping), I get the error:
undefined method `call' for V1:Module
So far, the API I have setup is very simple, but I can't figure out why it is not working
root/app/api/api.rb:
# root/app/api/api.rb
class API < Grape::API
mount V1
end
Within the version folder, I want to have all the classes that the version of the API supports: root/app/api/v1/user.rb:
# root/app/api/v1/user.rb
module V1
class user < Grape::API
get :ping do
{ :ping => params[:pong] || 'pong' }
end
end
end
root/config/routes:
TestApp::Application.routes.draw do
mount API => '/'
end
I split my api up into folders:
v1/resources/users.rb
v1/resources/orders.rb
v1/entities/order.rb
v2/resources/orders.rb
and then in api.rb just mount the individual files ...
mount V1::Resources::Users
mount V1::Resources::Orders
mount V2::Resources::Orders
And then:
version ['v2','v1'], cascade: true
version 'v2', cascade: true