Upload document using grape api | ArgumentError (missing keyword: io) - ruby-on-rails

I am trying to upload image using grape api. I have done the following steps.
rails active_storage:install
rails g model user name email avatar:attachment
rails db:migrate
module API
module V1
class Users < Grape::API
include API::V1::Defaults
desc 'Create User'
params do
requires :name, type: String, desc: "User name"
requires :email, type: String, desc: "User email"
requires :avatar, :type => Rack::Multipart::UploadedFile, :desc => "Image file."
end
put "/user" do
binding.pry
User.create(params)
return {status: 'success'}
end
end
end
end
But I am getting the following error,
ArgumentError: missing keyword: io
from /Users/nnnn/.rbenv/versions/2.6.0/lib/ruby/gems/2.6.0/gems/activestorage-6.1.4/app/models/active_storage/blob.rb:97:in `build_after_unfurling'
Help me to fix this issue.
curl command to hit the server.
[![curl --location --request PUT 'localhost:3000/api/v1/user' \ --header 'Cookie: __profilin=p%3Dt' \ --form 'avatar=#"/Users/nnnn/Downloads/1623340316453.jpeg"' \ --form 'name="Tester"' \ --form 'email="tester#gmail.com"'][1]][1]

Related

How do I access an API service that doesn't have a Ruby gem?

So I want to access Glot.io that has just a barebones RESTful API from my Rails App.
Glot.io requires me to create an account and generates an API key for me -- pretty standard.
At a high-level, what is the best way for me to approach this?
Create an initializer file called glot.rb and what should I include there? Just my ENV_VARS to access the API service? Or do I not need that?
Then using the docs available to CREATE a snippet, what's the best approach to actually doing that? Should I use a CURL gem like curb to re-create this POST request?
curl --request POST \
--header 'Authorization: Token 99090-7abba-12389abcde' \
--header 'Content-type: application/json' \
--data '{"language": "python", "title": "test", "public": false, "files": [{"name": "main.py", "content": "print(42)"}]}' \
--url 'https://snippets.glot.io/snippets'
If so, what might the above look like?
Ideally I would love to get a high-level overview of the approach and then some code snippets of how I might proceed.
I would create a library (either create my own gem, or if just using it here, then in /lib) using net/http.
http://ruby-doc.org/stdlib-2.3.1/libdoc/net/http/rdoc/Net/HTTP.html
This is a very basic example, and could be done a number of ways. This example will allow you to to instantiate SnippetApi and set the URL. You can then call new_snippet, which will take the URL that you supplied, and make the API call.
To continue extending, you can change def new_snippet to def new_snippet(data), and then supply the data with your call.
Note: the filename should be snippet_api.rb to ensure that the "rails magic" works for autoloading.
lib/snippet_api.rb
require 'uri'
require 'net/http'
require 'net/https'
class SnippetApi
def initialize(url, api_token = ENV['API_TOKEN'])
#url = url
#api_token = api_token
end
def url
#url
end
def api_token
#api_token
end
def new_snippet
# https://snippets.glot.io/snippets
uri = URI.parse(self.url)
post_object = {'language': 'python', 'title': 'test', 'public': false, 'files': [{'name': 'main.py', 'content': 'print(42)'}]}
https = Net::HTTP.new(uri.host, uri.port)
https.use_ssl = true
req = Net::HTTP::Post.new(uri.path, initheader = {'Content-Type' => 'application/json', 'Authorization': "Token #{self.api_token}"})
req.body = "[ #{post_object} ]"
res = https.request(req)
puts "Response #{res.code} #{res.message}: #{res.body}"
end
end
Usage
2.3.0 :001 > snippet_api = SnippetApi.new('https://snippets.glot.io/snippets')
=> #<SnippetApi:0x00000003b6bc20 #url="https://snippets.glot.io/snippets">
2.3.0 :002 > snippet_api.new_snippet
Response 404 Not Found: {"message":"Wrong auth token"}
To ensure that files in /lib are loaded, be sure to add this to application.rb:
config.autoload_paths += Dir["#{config.root}/lib/**/"]
Usage with API Token
[brian#...]$ export API_TOKEN='token from env'
2.3.0 :001 > snippet_api = SnippetApi.new('https://snippets.glot.io/snippets')
=> #<SnippetApi:0x0000000342e8e0 #url="https://snippets.glot.io/snippets", #api_token="token from env">
2.3.0 :002 > snippet_api.api_token
=> "token from env"
2.3.0 :003 > snippet_api = SnippetApi.new('https://snippets.glot.io/snippets','from init')
=> #<SnippetApi:0x000000033a60d0 #url="https://snippets.glot.io/snippets", #api_token="from init">
2.3.0 :004 > snippet_api.api_token
=> "from init"
Edit 1: Added information about loading lib files.

Error occurred while parsing request parameters JSON::ParserError - 795: unexpected token at

I am trying to write the API methods for user to sign up on spree app. It's working properly on my local machine but not on server. here is my code of user_decorator_controller.rb
def sign_up
#user = Spree::User.find_by_email(params[:user][:email])
if #user.present?
render "spree/api/users/user_exists", :status => 401 and return
end
#user = Spree::User.new(user_params)
if !#user.save
unauthorized
return
end
#user.generate_spree_api_key!
end
and sign_up.v1.rabl is
object #user
attributes :id, :spree_api_key, :email, :firstname, :lastname, :mobile
child(:bill_address => :bill_address) do
extends "spree/api/addresses/show"
end
child(:ship_address => :ship_address) do
extends "spree/api/addresses/show"
end
when I CURL the server with below request
curl -v -H 'Content-Type: application/json' -H 'Accept: application/json' -X POST -d {"user":{"email":"ml5698#gmail.com","password":"12345678", "firstname":"M", "lastname":"L", "mobile":"9999888877"}} http://localhost:3000/api/users/sign_up
It gives me above error below is extracts from web server log
Started POST "/api/users/sign_up" for 127.0.0.1 at 2015-10-15 11:23:36 +0530
ActiveRecord::SchemaMigration Load (0.3ms) SELECT `schema_migrations`.* FROM `schema_migrations`
Error occurred while parsing request parameters.
Contents:
{user:{email:ml5698#gmail.com,password:12345678,
JSON::ParserError - 795: unexpected token at '{user:{email:ml5698#gmail.com,password:12345678,':
json (1.8.3) lib/json/common.rb:155:in `parse'
activesupport (4.2.4) lib/active_support/json/decoding.rb:26:in `decode'
I am using Ruby 2.2 , rails 4, json 1.8.3 , what could be the issue, please help me resolve it.
Your error is actually in your use of your command line curl. You use the -d switch, and pass parameters to it. The parameters are only parsed until the next space, so your parameters being passed in are
{user:{email:ml5698#gmail.com,password:12345678,
This is what you're seeing in the error message, and is obviously not well formed JSON, so you get the parsing error.
Try quoting your -d parameters like so:
curl -v -H 'Content-Type: application/json' -H 'Accept: application/json' -X POST -d '{"user":{"email":"ml5698#gmail.com","password":"12345678","firstname":"M","lastname":"L","mobile":"9999888877"}}' http://localhost:3000/api/users/sign_up

Api request not working on development mode

I have rails app and i have event controller
def create
#event = Event.create(event_params)
#event.location_id = Location.find_by_address(params[:address]).id
#event.owner = current_user
if params[:clot_id].present?
#event.clot_id = params[:clot_id]
end
render json: #event, status: 201, location: #event
end
def event_params
params.require(:event).permit(:venue, :clot_id, :contact, :cost, :description, :name, :tag_list,:location_id,
compound_started_at_attributes: [:date, :time],
compound_ended_at_attributes: [:date, :time], location_attributes: [:id, :address])
end
When i try to make curl request on localhost its working fine
curl -i -H 'Authorization: Token token'="NXNW8kxzZ2z8czHF6" -X POST -d 'event[venue]=indore&event[contact]=9977966105&event[cost]=52&event[name]=forencis&event[compound_started_at_attributes][date]= 2015-08-20&event[compound_started_at_attributes][time]= 09.05&event[compound_ended_at_attributes][date]= 2015-08-25&event[compound_ended_at_attributes][time]= 10.05&event[location_id]=10&event[clot_id]=26' http://localhost:3000/api/events
curl to server
curl -i -H 'Authorization: Token token'="oKSMrppRXEiRSH61okn5" -X POST -d 'event[venue]=indore&event[contact]=9977966105&event[cost]=52&event[name]=forencis&event[compound_started_at_attributes][date]= 2015-08-20&event[compound_started_at_attributes][time]= 09.05&event[compound_ended_at_attributes][date]= 2015-08-25&event[compound_ended_at_attributes][time]= 10.05&event[location][address]=indore&event[clot_id]=1' 104.236.233.57/api/events
But when i m trying to make same curl request to production server its giving error in production.log
F, [2015-07-02T14:20:47.041280 #29752] FATAL -- :
NoMethodError (undefined method `id' for nil:NilClass):
app/controllers/api/events_controller.rb:34:in `create
i.e error in line
#event.location_id = Location.find_by_address(params[:address]).id
I checked the database for the presence of location_id = 10 in production database and i also checked other values in database before sending api request.
Please help me solve the error.
you're using the :address param and in the query string, address is inside location param: event[location][address]=indore.
Shouldn't be event[address]=indore?
And your code assumes that always 'Location' will be found. You shouldn't assume that and add some validation to Event class (or other workaround that makes sense to you):
#event.location_id = Location.find_by_address(params[:address]).try(:id)
And in Event class:
class Event
validates_presence_of :location_id
end

How to test REST API request (rails)

I have REST API, for example: I already create REST users, for creating user end point is go to "localhost:3000/users" POST method.
So pattern of param should be like this :
:user => {:name => "apple", :address => "heaven"}
My question is :
How to create pattern above, then I test it to endpoint POST method ?
I already test with postman client, but failed because my pattern incorrect (miss root : user)
Thanks
A controller test will catch the type of error you're describing, and is more efficient than an end-to-end test. Example in RSpec:
it 'creates a new user' do
post :create, user: {name: 'apple', address: 'heaven'}, format: 'json'
assert_response :success
expect(response).to render_template(:create)
expect(assigns(:user).name).to eq('apple')
expect(assigns(:user).address).to eq('heaven')
end
I have used curl (in code) to test APIs end-to-end. The Faraday gem would probably work as well.
With the curl request, you'll need to pass the -X POST parameter and a -d parameter for the data. -d can have the following formats:
-d "user[name]=apple" -d "user[address]=heaven"
-d {"user": {"name": "apple", "address": "heaven"}}
You can also pass headers with -H.
Altogether:
curl http://your_url -X POST -H "Content-type: application/json" -d {"user": {"name": "apple", "address": "heaven"}}

Converting curl to ruby equivalent

I'm having trouble converting a curl to a ruby script. Basically I'm trying to consume the parse.com RESTful api. Here is the curl
curl -X POST \
-H "X-Parse-Application-Id: XXX" \
-H "X-Parse-REST-API-Key: YYY" \
-H "Content-Type: application/json" \
-d '{
"channels": [
"Giants",
"Mets"
],
"data": {
"alert": "test message"
}
}' \
https://api.parse.com/1/push
And this Is what I've been trying to do (using HttParty)
puts "hello world"
require 'httparty'
require 'json'
class Parse
include HTTParty
base_uri "api.parse.com:443"
headers "X-Parse-Application-Id" => "XXX", "X-Parse-REST-API-Key" => "YYY", "Content-Type" => "application/json"
end
option = {:channels => "Giants", :data => {:alert => "un mensaje de mierda"}}
puts Parse.post("/1/push", body: option.to_json)
)
I'm getting an error code 107 saying invalid json. Any suggestions will be appreciated.
I think you just need to serialise the ruby structure to JSON in the second param. The param should be the string to POST, not a Ruby struct.
I think this will work (only other possible problem I can see is whether you'll connect via https as the code is written):
data = {"channels": ['Giants'], "data": {alert: 'un mensaje '}}
puts Parse.post("/1/push", body: data.to_json)
. . . the JSON-like format in the Ruby data structure is not JSON,
foo: "bar"
is just another Ruby (1.9+) way of saying
:foo => "bar"

Resources