I am following this article to learn about writing api using grape gem. But in the response I am not getting the root key. Here is my directory structure,
app
|––controllers
|––api
|––base.rb
|––v1
|––base.rb
|––graduates.rb
In app/controllers/api/v1/graduates.rb:
module API
module V1
class Graduates < Grape::API
include API::V1::Defaults
resource :graduates do
desc "Return all graduates"
get "", root: :graduates do
Graduate.all
end
desc "Return a graduate"
params do
requires :id, type: String, desc: "ID of the
graduate"
end
get ":id", root: "graduate" do
Graduate.where(id: permitted_params[:id]).first!
end
end
end
end
end
in app/controllers/api/v1/defaults.rb
module API
module V1
module Defaults
extend ActiveSupport::Concern
included do
prefix "api"
version "v1", using: :path
default_format :json
format :json
formatter :json,
Grape::Formatter::ActiveModelSerializers
helpers do
def permitted_params
#permitted_params ||= declared(params,
include_missing: false)
end
def logger
Rails.logger
end
end
rescue_from ActiveRecord::RecordNotFound do |e|
error_response(message: e.message, status: 404)
end
rescue_from ActiveRecord::RecordInvalid do |e|
error_response(message: e.message, status: 422)
end
end
end
end
end
I have used grape-active_model_serializers gem to serialize like the following,
In app/serializers/graduate_serializer.rb
class GraduateSerializer < ActiveModel::Serializer
attributes :id, :name
end
I got the following output. [{"id":1,"name":"aaaa"},{"id":2,"name":"bbbb"},{"id":3,"name":"cccc"},{"id":4,"name":"dddd"}]
But As I added get "", root: :graduates do in app/controllers/api/v1/graduates.rb file, I am expecting the following output,
{"graduates": [{"id":1,"name":"aaaa"},{"id":2,"name":"bbbb"},{"id":3,"name":"cccc"},{"id":4,"name":"dddd"}]}
What I am missing. why graduates is not added as root. Help me to fix this issue.
Dirty fix: use in app/controllers/api/v1/graduates.rb
get "" do
{ graduates: Graduate.all }
end
Or you can delete gem grape-active_model_serializers, delete class GraduateSerializer, delete row formatter :json, Grape::Formatter::ActiveModelSerializers from defaults.rb, and add gem grape-entity to Gemfile, install it, add code to app/app/entities/graduate_entity.rb:
class GraduateEntity < Grape::Entity
root 'graduates', 'graduate'
expose :id
expose :name
end
Change code in app/app/controllers/api/v1/graduates.rb:
get "" do
present Graduate.all, with: GraduateEntity
end
I was struggling with similar issue as you, I resolved it by adding
ActiveModelSerializers.config.adapter = :json
in config/initializers/serializer.rb
Let me know if it could help you
Related
I would like to use the rails URL helper instead of hard coding the path to access the article.
I checked into the documentation but nothing is specified.
The article_path helper method exists (I checked by running rake routes)
class V3::ArticlesController < Api::V3::BaseController
def index
articles = Article.all
render json: ::V3::ArticleItemSerializer.new(articles).serialized_json
end
end
class V3::ArticleItemSerializer
include FastJsonapi::ObjectSerializer
attributes :title
link :working_url do |object|
"http://article.com/#{object.title}"
end
# link :what_i_want_url do |object|
# article_path(object)
# end
end
What you want to do is pass in the context to your serializer from your controller:
module ContextAware
def initialize(resource, options = {})
super
#context = options[:context]
end
end
class V3::ArticleItemSerializer
include FastJsonapi::ObjectSerializer
include ContextAware
attributes :title
link :working_url do |object|
#context.article_path(object)
end
end
class V3::ArticlesController < Api::V3::BaseController
def index
articles = Article.all
render json: ::V3::ArticleItemSerializer.new(articles, context: self).serialized_json
end
end
You should also switch to the jsonapi-serializer gem which is currently maintained as fast_jsonapi was abandoned by Netflix.
I found a solution thanks to max's example.
I also changed the gem to jsonapi-serializer
class V3::ArticlesController < Api::V3::BaseController
def index
articles = Article.all
render json: ::V3::ArticleItemSerializer.new(articles, params: { context: self }).serialized_json
end
end
class V3::ArticleItemSerializer
include JSONAPI::Serializer
attributes :title
link :working_url do |object|
"http://article.com/#{object.title}"
end
link :also_working_url do |object, params|
params[:context].article_path(object)
end
end
I am struggling with understanding how to save a model to MongoDB using mongoid and rails_admin.
I've got my model:
class PictureAsset < ActiveRecord::Base
include Mongoid::Document
field :data_file_name, type: String
field :data_content_type, type: String
field :data_file_size, type: Integer
end
This was made through a generation:
bundle exec rails g model PictureAsset data_file_name:string data_content_type:string data_file_size:integer
Rails admin side loads up just fine, and I can navigate to the index page for PictureAsset.
When I try to access my custom action, asset_action, I get the following error:
undefined method `belongs_to' for #<RailsAdmin::AbstractModel:0xbf2e791>
My action looks like this:
module RailsAdmin
module Config
module Actions
class AssetAction < RailsAdmin::Config::Actions::Base
RailsAdmin::Config::Actions.register(self)
register_instance_option :collection do
true
end
register_instance_option :http_methods do
[:get, :put]
end
register_instance_option :controller do
proc do
if request.get? # EDIT
binding.pry
respond_to do |format|
format.html { render #action.template_name }
format.js { render #action.template_name, layout: false }
end
elsif request.put? # UPDATE
binding.pry
#newUserPropVal.save
end
end
end
register_instance_option :link_icon do
'icon-list-alt'
end
end
end
end
end
Can someone please explain what I'm doing wrong here?
Your model includes code for both ActiveRecord and Mongoid. Pick one and remove code for the other.
ActiveRecord will look like this:
class PictureAsset < ActiveRecord::Base
# No field definitions needed
end
Mongoid will look like this:
# Does not derive from anything
class PictureAsset
include Mongoid::Document
field :data_file_name, type: String
field :data_content_type, type: String
field :data_file_size, type: Integer
end
This may not solve the error you are getting but is a good start.
I know this questions is asked several times but I checked those answers but nothing seems to fix my issue.
users_controller.rb on path app/controllers/api/v1/
module Api
module V1
class UsersController < ApplicationController
def create_user
#users = User.new(user_params)
if #users.save
render json: { status: '201', message: 'User created successfully' }
else
render json: { status: '400', message: 'Invalid user info', data: #users.errors }
end
end
def user_params
params.permit(:first_name, :last_name, :email, :password)
end
end
end
end
routes.rb
namespace 'api' do
namespace 'v1' do
post "user/createuser", to: "user#create_user"
end
end
What I have tried:
Checked the directory structure it is as mentioned
Restarted the server and checked
Folder name: all simple controllers > api > v1
But this works fine when I changed the routes.rb
post "user/createuser", to: "user#create_user"
to resource :users
and
def create_user
to def create
Why things does not work when I define custom routes instead of using default routes? How to get this work with custom routes
Due to Rails conventions I believe you need to update your route with
post "user/createuser", to: "users#create"
instead of
post "user/createuser", to: "user#create_user"
I am building web API with Grape gem on Ruby on Rails 4.1, with their 'version' function.
Sample code here.
# app/api/api.rb
class API < Grape::API
prefix 'api'
format :json
formatter :json, Grape::Formatter::Rabl
default_format :json
mount V1::Root
end
# app/api/v1/root.rb
module V1
class Root < Grape::API
version 'v1'
resource :users, rabl: "users" do
get '/' do
#users = User.all
end
end
end
end
# config/routes.rb
mount API => "/"
with these code, app/views/api/users.rabl is used for view template on request to http://localhost:3000/api/v1/users.
I want to use template in app/views/api/v1 for v1 request. Is there any way to do that ?
current
/api/v1/users -> app/views/api/users.rabl
/api/v2/users -> app/views/api/users.rabl
want
/api/v1/users -> app/views/api/v1/users.rabl
/api/v2/users -> app/views/api/v2/users.rabl
I'm using Grape Entity:https://github.com/intridea/grape-entity
So I created a directory on v1 folder called entities
ex:
api/v1/entities/token_response_entity.rb
module ExampleAPI::V1::Entities
class TokenResponseEntity < Grape::Entity
expose :token , documentation: { type: 'string', desc: 'Token String' }
end
end
So when I need to present I just need to use:
present tokens, with: ExampleAPI::V1::Entities::TokenResponseEntity
I finally took Jan's way.
resource :users, rabl: "v1/users" do
I'm working with a team on checking a user's email input when they sign up for a web app. The user will not be allowed to sign up if their email is not found with the following API call using HTTParty. We are getting method_errors for whatever syntax is first within the function. For, example, in the method below, "include" comes up as an undefined method error.
def email_checker
include HTTParty
default_params :output => 'json'
format :json
base_uri 'app.close.io'
basic_auth 'insert_api_code_here', ' '
response = HTTParty.get('/api/v1/contact/')
#email_database = []
response['data'].each do |x|
x['emails'].each do |contact_info|
#email_database << contact_info['email']
end
end
unless #email_database.include? :email
errors.add :email, 'According to our records, your email has not been found!'
end
end
UPDATE: So we went with the inline version of using HTTParty and our registrations controller (working with devise) looks like this:
class RegistrationsController < Devise::RegistrationsController
def email_checker(email)
YAML.load(File.read('config/environments/local_env.yml')).each {|k, v| ENV[k.to_s] = v}
api_options = {
query: => {:output => 'json'},
format: :json,
base_uri: 'app.close.io',
basic_auth: ENV["API_KEY"], ' '
}
response = HTTParty.get('/api/v1/contact/', api_options)
#email_database = []
response['data'].each do |x|
x['emails'].each do |contact_info|
#email_database << contact_info['email']
end
end
unless #email_database.include? email
return false
else
return true
end
end
def create
super
if email_checker == false
direct_to 'users/sign_up'
#and return to signup with errors
else
User.save!
end
end
end
We're getting syntax error: "syntax error, unexpected =>" Did we screw up the format?
There are two different ways to use HTTParty, and you're trying to use both. Pick one :).
The class-based method would look something like this:
class CloseIo
include HTTParty
default_params :output => 'json'
format :json
base_uri 'app.close.io'
basic_auth 'insert_api_code_here', ' '
end
class UserController
def email_checker
response = CloseIo.get('/api/v1/contact/')
# ... the rest of your stuff
end
end
An inline version would look something like this
class UserController
def email_checker
api_options = {
query: :output => 'json',
format: :json,
base_uri: 'app.close.io',
basic_auth: 'insert_api_code_here'
}
response = HTTParty.get('/api/v1/contact/', api_options)
# ... do stuff
end
end