I'm using grape to build my restful API, but when I try to integrate it with Swagger via grape-swagger gem, it throws
undefined method `[]' for nil:NilClass
when I visit http://localhost:3000/swagger_doc url
Here is my gem versions:
rails (4.2.4)
grape (0.8.0)
grape-swagger (0.20.0)
And here is my directory structure & files:
api/
api/base.rb
api/graduates.rb
// base.rb
module API
class Base < Grape::API
mount API::Graduates
add_swagger_documentation
end
end
// graduates.rb
module API
class Graduates < Grape::API
resource :graduates do
desc 'wow'
get :all do
Graduate.all
end
end
end
end
In my routes file, I am just mounting the grape api base.
Rails.application.routes.draw do
mount API::Base, at: "/"
end
A detail for debug purposes: when I delete resource block from graduates.rb, swagger_doc url seems fine(but of course, without resources).
For anyone who encounter this issue, here is the answer:
As compatibility table says, grape (0.8.0) and grape-swagger (0.20.0) are not compatible with each other. This is solved when I use grape (0.16.2).
Related
I have plugin that takes attribute from post's front matter and uses it in permalink. Problem is I need to clean up any accents and diacritics from the string before putting it in to the permalink. Ruby on rails has method called parametrize which does exactly what I need but I have no idea how to use it in plugin.
This is plugins code I have:
module JekyllCustomPermalink
class CustomPermalink < Jekyll::Generator
safe true
priority :low
def generate(site)
# nothing to do, wait for hook
end
Jekyll::Hooks.register :documents, :pre_render do |doc|
begin
# check if jekyll can resolve the url template
doc.url
rescue NoMethodError => error
begin
if !doc.collection.metadata.fetch("custom_permalink_placeholders").is_a?(Array)
raise CustomPermalinkSetupError, "The custom placeholders need to be an array! Check the settings of your '#{doc.collection.label}' collection."
end
def doc.url_template
#custom_url_template ||= collection.metadata.fetch("custom_permalink_placeholders").inject(collection.url_template){|o,m| o.sub ":" + m, data[m].to_s.parameterize}
end
rescue KeyError
# "custom_permalink_placeholders"
raise CustomPermalinkSetupError, "No custom placeholders defined for the '#{doc.collection.label}' collection. Define an array of placeholders under the key 'custom_permalink_placeholders'. \nCaused by: " + error.to_s
end
end
end
end
end
but I get this error:
john#arch-thinkpad ~/P/blog (master)> bundle exec jekyll serve --trace
Configuration file: /home/john/Projects/lyricall/_config.yml
Source: /home/john/Projects/lyricall
Destination: /home/john/Projects/lyricall/_site
Incremental build: disabled. Enable with --incremental
Generating...
Jekyll Feed: Generating feed for posts
Liquid Exception: undefined method `parameterize' for "Žďořšťáčik":String in feed.xml
bundler: failed to load command: jekyll (/home/john/.gem/ruby/3.0.0/bin/jekyll)
/usr/lib/ruby/gems/3.0.0/gems/jekyll_custom_permalink-0.0.1/lib/jekyll_custom_permalink/custom_permalink.rb:20:in `block in url_template': undefined method `parameterize' for "Žďořšťáčik":String (NoMethodError)
What am I doing wrong ? How can I use this method which should be part of a string class but apparently it is not ? How can I achieve same result without ruby on rails framework ?
INFO:
jekyll 4.1.1
ruby 3.0.1p64 (2021-04-05 revision 0fb782ee38) [x86_64-linux]
Thank you for help
Rails additions to base Ruby classes, like String#parameterize, are part of the Active Support Core Extensions. The activesupport gem can be installed and used independent of Rails.
To keep the default footprint low, ActiveSupport allows you to require only the individual extensions you want to use. In your case, you will need to require the string inflection extensions:
require 'active_support/core_ext/string/inflections'
"Kurt Gödel".parameterize
=> "kurt-godel"
I'm creating a ruby gem with rails 6. This is my main ruby gem file:
#lib/ruby_gem_name.rb
require 'active_support'
require 'active_record'
require 'ruby_gem_name/version'
require 'ruby_gem_name/class_methods'
# frozen_string_literal: true
puts 'The gem was loaded'
module RubyGemName; end
This is lib/ruby_gem_name/class_methods.rb
module RubyGemName
module ClassMethods
def self.ruby_gem_name_class_method
puts 'Hello'
end
end
extend ClassMethods
end
i enter in irb console and i can see:
ruby-gem-name$ irb
2.7.1 :001 > require 'ruby-gem-name'
The gem was loaded
=> true
2.7.1 :002 > RubyGemName::ClassMethods.ruby_gem_name_class_method
Hello
=> nil
Now....I've added my gem to the gemfile in my rails project:
gem 'ruby_gem_name', path: 'path_to_ruby_gem_name'
I can see the installed gem in Gemfile.lock:
PATH
remote: 'path_to_ruby_gem_name'
specs:
ruby_gem_name (0.1.0)
activerecord (~> 6)
activesupport (~> 6)
rails (~> 6)
GEM
remote: https://rubygems.org/
specs:
actioncable (6.0.3.5)
actionpack (= 6.0.3.5)
Now, i want to use this class method in models of my rails project:
i have this code:
class Cart < ApplicationRecord
extend RubyGemName::ClassMethods
end
and when i try to use this class method from my rails project console, i see:
shopping-cart$ bundle exec rails c
Running via Spring preloader in process 32494
Loading development environment (Rails 6.0.3.5)
2.7.1 :001 > Cart.ruby_gem_name_class_method
Traceback (most recent call last):
1: from (irb):1
NoMethodError (undefined method `ruby_gem_name_class_method' for Cart (call 'Cart.connection' to establish a connection):Class)
In order to use the method ruby_gem_name_class_method as a class method you need to use extend as eugen points out in their example. If you use extend then the Module's methods are already Class methods, therefore the self on your ruby_gem_name_class_method is redundant.
Your module's code should change to this:
module RubyGemName
module ClassMethods
def ruby_gem_name_class_method
puts 'Hello'
end
end
end
The other approach is to use include which will make the Module's methods available on the instance of the Class and you can achieve this by modifying your Class:
class Cart < ApplicationRecord
include RubyGemName::ClassMethods
end
and then instantiate the object and call the instance method:
Cart.new.ruby_gem_name_class_method
You can omit self on the Module's method as it refers to the newly created instance.
You'll probably want to use extend instead of include, as in
class Cart < ApplicationRecord
extend RubyGemName::ClassMethods
end
extend will add the methods from RubyGemName::ClassMethods, as opposed to include, which will add them as instance methods.
For a more detailed explanation of extend vs. include, see https://stackoverflow.com/a/5008349/163640
I need some help to get Grape::API up and running with Rails 4.
I get a Unable to autoload constant Base even though a puts tells me that the class is loaded.
What am I doing wrong?
app/api/api.rb
class API < Grape::API
prefix 'api'
format :json
default_format :json
mount V1::Base # Everything loads perfectly until I add this line.
end
app/api/v1/base.rb
module V1
class Base < API
puts "=== DEBUG - in Base"
version 'v1', using: :path, vendor: 'orwapp', cascade: false
mount Users
end
end
$ rspec spec/api
12:58:29 - INFO - Run all
12:58:29 - INFO - Running all specs
=== DEBUG - in Base
/dependencies.rb:481:in `load_missing_constant':
Unable to autoload constant Base,
expected /Users/martins/Work/myapp/app/api/v1/base.rb to define it (LoadError)
from /Users/martins/Work/myapp/app/api/api.rb:9:in `<class:API>'
from /Users/martins/Work/myapp/app/api/api.rb:3:in `<top (required)>'
spec/api/users_spec.rb
describe 'GET /api/v1/users/:id', focus: true do
let(:user) { Fabricate :user }
it 'returns that specific user' do
get "/api/v1/users/#{ user.id }", {}, https_and_authorization
response.status.should eq 200
parse_response_for(:user)['email'].should eq user.email
end
end
The versions I'm using
$ ack grape Gemfile.lock
remote: git://github.com/intridea/grape.git
grape (0.9.1)
grape-entity (0.4.4)
grape-swagger (0.8.0)
grape
grape-entity
Try having Base inherit from Grape::API instead of API:
module V1
class Base < Grape::API
...
By having it inherit from API you're creating a circular dependency: The interpreter can't know the definition of V1::Base until it knows the definition of API, but for that it would first need to know the definition of V1::Base, and so on.
Changing to mount ::V1::Base fixed it.
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.
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