How to parse POST request in JSON format in rails - ruby-on-rails

I'm trying to send a POST request in JSON via curl in ruby on rails. I would like to know how can I parse this request in a controller and save it in database. I've created controller and model for a player.
Below is the curl command -
curl -i -X POST -H "Content-Type: application/json" "localhost:3000/app/v2/player" -d '{
"url": "app/v2/players.json",
"para": {
"player": {
"player_id": 51275,
"email": "test#gmail.com",
"total_won": "1890000.00",
"pr_costs": "29.00",
"payment_method": "VISA",
"games": [
{
"name": "AvsB",
"matches": 1,
"value": 1100,
"category": "Cricket",
"subcategory": "Test",
"tags": [
"Aus",
"Melbourne"
],
"game_id": 12
},
{
"name": "CvsD",
"matches": 1,
"value": 790,
"category": "Cricket",
"subcategory": "T20",
"tags": [
"T20",
"20over",
"worldcup"
],
"game_id": 7
}
]
}
}
}'
Below is my player controller-
module App
module V2
class PlayersController < ApplicationController
def create
#player = Player.new(params[[:para][:player][:player_id]].first)
if #player.save
render json: #player, status: 201, location: #player
else
render json: #player.errors, status: 422
end
end
private
def player_params
#params.require(:player).permit(:url, :player_id, :email, :total_won, :pr_costs, :payment_method)
params.fetch(:url,:para, {}).permit(:player_id, :email, :total_won, :pr_costs, :payment_method)
end
end
end
end
Below is my player model -
class Player < ActiveRecord::Base
has_many :games, dependent: :destroy
validates :player_id, presence: true
attr_accessor :url,:para
end
Currently I'm getting below error while initiating the curl command -
TypeError (no implicit conversion of Symbol into Integer):
app/controllers/app/v2/players_controller.rb:21:in `[]'
app/controllers/app/v2/players_controller.rb:21:in `create'
Any pointers on how I can read JSON data and create records for players in create function and related games would be appreciated. I've not created the model for games but it'll be similar in structure to JSON data. Also one player has many games and a game will belong to a Player.
Thanks in advance!

This is badly structured.
[[:para][:player][:player_id]]
It basically means (in part) there's an array that contains the player symbole
[:player]
and you want to get the ':player_id(th)' entry of that array or string... which is where you're getting the error ("How do I convert a symbol into an integer for the array?")
[:player][:player_id]
you probably want...
params[:para][:player][:player_id]
There's no 'first' because there's no array in the :player_id entry.

As it always happens, I figured it out myself. Below is what I used for player_params function. There could be other ways as well, but this certainly worked for me.
params.require(:player).permit(:url,:para =>[:player =>[:player_id, :email, :total_won, :pr_costs, :payment_method,:games =>[:name, :matches, :value, :category, :subcategory, :game_id ]]])
#SteveTurczyn thanks for pointing me in the right direction

Related

Rails 5 - include nested associations not working

I have two simple models:
note.rb
with
:title -> string, :content -> string
has_and_belongs_to_many :tags, join_table: :tags_notes
accepts_nested_attributes_for :tags
tag.rb
with
:name -> string
has_and_belongs_to_many :notes, join_table: :tags_notes
Both models are connected through has_and_belongs_to_many relationship.
The association table is called tags_notes as indicated above.
Well, the problem I have here is, in my RESTful controller, to get notes, I have this:
GET /api/notes
This only returns Note objects:
[
{
"id": 1,
"title": "12231",
"content": "121213"
},
{
"id": 2,
"title": "test",
"content": "testtest"
}
]
However, each note has tags, and I would like to dump those in the response as well, like this:
[
{
"id": 1,
"title": "12231",
"content": "121213",
tags: [
{
"name": "test",
"id": 1
},
{
...
}
]
},
...
]
In my controller, I've tried
Note.includes(:tags).
Current controller code:
def index
notes = Note.includes(:tags)
render json: notes, status: :ok
end
They only seem to return notes, without tags. Same is the case with Note.eager_load(:tags) What am I doing wrong? Cannot find enough documentation that will help me fix this issue.
If someone can help me with this I will be grateful.
Thanks a bunch.
Shortly after posting my question I found the answer myself. The include has to go in render.
So the controller code
def index
notes = Note.all
render json: notes, :include => :tags, status: :ok
end
Seems to do the trick!

Rails Active model serializer returns array instead of json

I am using Rails to create APIs containing basic todo information: name, list, and items. I want it to return json format, to look something like this:
{
"data": [
{
"type": "posts",
"id": "1",
"attributes": {
"title": "JSON API is awesome!",
"body": "You should be using JSON API",
"created": "2015-05-22T14:56:29.000Z",
"updated": "2015-05-22T14:56:28.000Z"
}
}
],
"links": {
"href": "http://example.com/api/posts",
"meta": {
"count": 10
}
}
}
^code from Active Serializer's Github.
When I look on my localhost http://localhost:3000/api/users/, it shows
[{"id":1,"username":"Iggy1","items":[{"id":1,"list_id":1,"name":"Wash dishes","completed":true},{"id":7,"list_id":1,"name":"Finish this assignment","completed":false}],"lists":[{"id":1,"name":"Important!","user_id":1,"permission":"private"},...
It is returning an array of hashes. I am sure I missed an important step when I was setting up my serializer. How can I reformat my array of hashes into JSON API format?
I've read getting started guide, rendering, and JSON API section but I still couldn't figure it out. I might have overlooked it.
Some of my codes:
app/serializers/user_serializer.rb
class UserSerializer < ActiveModel::Serializer
attributes :id, :username#, :email
has_many :items, through: :lists
has_many :lists
end
app/controllers/api/users_controller.rb
def index
#users = User.all
render json: #users, each_serializer: UserSerializer
end
routes
Rails.application.routes.draw do
namespace :api, defaults: { format: :json } do
resources :users do
resources :lists
end
end
end
Let me know if I can clarify it better. Thanks!!
(Answer from comments)
To use the JSON API adapter, you need to declare you want to use it.
ActiveModelSerializers.config.adapter = ActiveModelSerializers::Adapter::JsonApi
As per the AMS readme.
ActiveModelSerializers.config.adapter = :json_api # Default: `:attributes`
from 0-10-stable documentation
However, this did not solve my problem. It was due to the Hash being nested as discussed in this SO post

Add method to json output with include in rails

I am getting info from my database
#teams = Team.select(:id,:name)
Then, I am rendering this info with an assosiation
render json: #teams, include: :players
This produce me the following input:
[
{
"id": 1,
"name": "Lyon Gaming",
"players": [
{
"name": "Jirall",
"position": "Superior",
},
{
"name": "Oddie",
"position": "Jungla",
}
]
}
]
How ever I need to sort the players in an specific order (not alphabetical)
I already have the sql statement to do it; how ever I dont know how to apply this method to each association.
I am looking something like:
render json: #teams, (include: :players, method: custom_order)
But this raise me an error.
Any ideas?
This should work:
render json: #teams, include: :players, methods: :custom_order
I'd like to add that if you will always want to return the object this way, you can add this to your model instead:
def as_json(options = nil)
super(include: :players, methods: :custom_order)
end
As Adam has mentioned, active_model_serializers is good to have if your render json's start getting ugly. If the complexity doesn't grow too much, I always recommend keeping the dependencies down.
https://github.com/rails-api/active_model_serializers
You need to read more about serializers in rails(This is good practice)
Here you have a nice article about this https://www.sitepoint.com/active-model-serializers-rails-and-json-oh-my/
Then you can make something like this
app/serializers/team_serializer.rb
class TeamSerializer < ActiveModel::Serializer
attributes :id, :name, :ordered_players
end
app/controllers/teams_controller.rb
def index
respond_with(Team.all.map(&TeamSerializer.method(:new)))
end

How to get nested JSON / hash elements using postgres_ext-serializers?

I'm trying to get the postgres_ext-serializers gem working, and I built a test project very similar to https://github.com/dockyard/postgres_ext-serializers/blob/master/test/test_helper.rb
class UserSerializer < ActiveModel::Serializer
attributes :id, :name, :mobile
embed :ids, include: true
has_one :address, serializer: AddressSerializer
def include_mobile?
false
end
alias_method :include_address?, :include_mobile?
end
class AddressSerializer < ActiveModel::Serializer
attributes :id, :district_name
embed :ids, include: true
end
When I try to run the serializers the output doesn't seem to have nested elements. For example my serializer to_json output is:
"{\"users\":[{\"id\":1,\"name\":\"Aaron\",\"mobile\":null}, \n {\"id\":2,\"name\":\"Bob\",\"mobile\":null}],\"addresses\":[{\"id\":1,\"district_name\":\"Rob's Address\"}]}"
Notice how users and address are two separate elements of a hash, intead of being nested. If I remove the postgres_ext-serializers gem, then the output is as expected:
"[{\"id\":1,\"name\":\"Rob\",\"mobile\":null,\"address\":{\"id\":1,\"district_name\":\"Rob's Address\"}},{\"id\":2,\"name\":\"Bob\",\"mobile\":null,\"address\":null}]"
The address is embedded in the user hash exactly how I'm expecting it.
What am I missing, do I need to change anything to make the elements nested when using postgres_ext-serializers?
Thanks!
It seems, that the JSON you receive after serialization is what postgres_ext-serializers expects. Take a look into this test. expected_json in the first test case case is:
{
"users": [
{
"id": <UserID>,
"name": "John",
"mobile": "51111111",
"offer_ids": [],
"reviewed_offer_ids": []
}
],
"offers": [],
"addresses": [
{
"id": <AddressID>,
"district_name": "mumbai"
}
]
}
It looks very similar to the JSON you have received. But, to be honest, as include_address? method in your example returns false, I expect you must have not "addresses" field included into resulting JSON at all.

Rails 3: Wrapping as_json response with additional lines

I was very happy to learn of as_json to make my code DRY. And I've added the following to a model:
class ProductType < ActiveRecord::Base
has_many :component_types
def as_json(parameter)
{:name => self.name,
:description => self.description,
:children => self.componentTypes}
end
end
This is great. The only thing is that for my client side application, I need to wrap the response I get into this format, (where "items" contains what is created by as_json):
{
"identifier": "name",
"label": "name",
"items":
[
{
"name": "myName1",
"description": "myDesc1",
"children":[]
},
{
"name": "myName2",
"description": "myDesc2",
"children":[]
}
]
}
There are a lot of limitations to overriding as_json, and your issue is one of them. I'd suggest having a look at the RABL gem as I think it will help you reach your goal.

Resources