Rails:Receive POST with JSON array - ruby-on-rails

I'm currently using a controller to receive POST with one json object at a time. And I want it change to receiving the whole array. How can I modify my controller?
Current Controller
def create
respond_to do |format|
#targetrecord = TargetRecord.new(targetrecord_params)
#targetrecord.save
if #targetrecord.save
format.json{ render :json => #targetrecord.to_json ,status: 200 }
else
format.json { render json: #targetrecord.errors, status: 404 }
end
end
end
end
def targetrecord_params
params.require(:targetrecord).permit(:id, :uuid, :manor, :mac, :beacon_type, :longitude, :latitude, :address, :findTime, :rssi, :finderID, :created_at, :updated_at )
end
I'm sending the POST as below right now
"targetrecord":
{"id":"","name":"",.....}
And I want to send multiple sets as an array like
"targetrecord":[
{"id":"1","name":"",.....},
{"id":"2","name":"",.....},
....]
How can I let my controller know that she needs to extract and create one by one? Thanks a lot!

If you are POSTing an array, then the array will just be part of your params object when processed by the controller action. So you should be able to loop through the array and create an array of TargetRecord objects. You'll need to modify your targetrecord_params method to allow it to accept an argument since you can't just look at 'params' in that context once you make the change. You'll also need to find a way to track whether or not all the records have saved successfully.
I haven't tested this code, but something like this should get you going in the right direction, I think:
def create
respond_to do |format|
#targetrecords = []
save_succeeded = true
params[:targetrecord].each do |record|
tr = TargetRecord.new(targetrecord_params(record))
save_succeeded = false unless tr.save
targetrecords << tr
end
if save_succeeded
format.json{ render :json => #targetrecord.to_json ,status: 200 }
else
format.json { render json: #targetrecord.errors, status: 404 }
end
end
end
end
def targetrecord_params(record)
record.require(:targetrecord).permit(:id, :uuid, :manor, :mac, :beacon_type, :longitude, :latitude, :address, :findTime, :rssi, :finderID, :created_at, :updated_at )
end

Related

How to render a dependency(project.tasks) in a two model (project + task) json result?

Given that each project has_many :tasks, I hope to render the project.task within the json result.
However, the json output also include a list of individual tasks as part of the result. See below:
#tasks = Task.all.reject do |i|
i.project.inbox == false || i.completion_status == 100
end
#projects = Project.all.reverse.reject do |i|
i.inbox == true || i.completion_status == 100
end
#all = #tasks + #projects
respond_to do |format|
format.html
format.json { paginate json: #all.sort_by(&:created_at).reverse,
per_page: 25 }
end
This means that if I simply include:
respond_to do |format|
format.html
format.json { paginate json: #all.sort_by(&:created_at).reverse,
:include => [:tasks => {:only => :id}],
per_page: 25 }
end
Rails will throw an error of undefined method tasks for Task:0x007fa0ad8d3858 since tasks does not have a task method.
How can I have the project.tasks appear in a json result which also include individual tasks result? Thank you.
Consider using active_model_serializers gem. After installing you can define a serializer for Project model like so:
class ProjectSerializer < ActiveModel::Serializer
attributes :id, :created_at, :tasks
def tasks
object.tasks.map(&:id)
end
end
Note: There might be any attributes you need. It's just an example.
Then you can do:
#projects = Project.all.reverse.reject do |i|
i.inbox == true || i.completion_status == 100
end
serialized_projects = ActiveModelSerializers::SerializableResource.new(#projects, each_serializer: ProjectSerializer).as_json
It will return you an array:
[{:id => 1, :created_at => "2017-07-13 08:13:20", tasks => [1, 2, 3, ...]}, ...]
Then for json response you can concat #tasks and serialized_projects:
all_for_json = #tasks + serialized_projects
And finally you can sort it like this:
all_for_json.sort_by { |record| record[:created_at] }.reverse
Note that you should do exactly record[:created_at], because projects are hashes, not active record models.
But I don't think this is a good idea to mix hashes and active record models in one array. So there is another solution.
You can also define a serializer for Task model:
class TaskSerializer < ActiveModel::Serializer
attributes :id, :created_at
end
Note: There might be any attributes you need. It's just an example.
And override code like this:
#tasks = Task.all.reject do |i|
i.project.inbox == false || i.completion_status == 100
end
#projects = Project.all.reverse.reject do |i|
i.inbox == true || i.completion_status == 100
end
respond_to do |format|
format.html do
#all = #tasks + #projects
end
format.json do
serialized_tasks = ActiveModelSerializers::SerializableResource.new(#tasks, each_serializer: TaskSerializer).as_json
serialized_projects = ActiveModelSerializers::SerializableResource.new(#projects, each_serializer: ProjectSerializer).as_json
all_serialized = serialized_tasks + serialized_projects
paginate json: all_serialized.sort_by { |record| record[:created_at] }.reverse, per_page: 25
end
end
To DRY your code, you can put
ActiveModelSerializers::SerializableResource.new(...).as_json
to separate method. For example:
def serialize_collection(collection, each_serializer)
ActiveModelSerializers::SerializableResource.new(collection, each_serializer: each_serializer).as_json
end
And do serializations like this:
serialized_tasks = serialize_collection(#tasks, TaskSerializer)
serialized_projects = serialize_collection(#projects, ProjectSerializer)
Profits of this solution:
You don't mix active record models and hashes in one array.
You can easily define via serializers which attributes and associations to include and set custom names for them.

Issues rendering text into json response in rails controlelr

I'm trying to return json from my method in my app
Heres what i have
doc.css(".secondary-text").each do |t|
price1 = t.text
respond_to do |format|
format.json { render :json => {:testing => price1}}
end
end
However i'm getting DoubleRenderError. Whats returned is this:
(£28.50 Ticket + £4.00 Fees)
(£35.00 Ticket + £5.25 Fees)
(£22.50 Ticket + £3.50 Fees)
(£35.00 Ticket + £5.25 Fees)
(£22.50 Ticket + £3.50 Fees)
Is it because its inside the each method?
Thanks
Yes, it's because you use render as many times as many objects are present in doc.css(".secondary-text"). Render can be used only once per scope.
If you want to render whole collection, you should do something like that:
collection = doc.css(".secondary-text").each.inject([]) do |collection, t|
collection << t.text
collection
end
respond_to do |format|
format.json { render json: { collection: collection } }
end

Rails Controller Modify JSON Response

I have this method in my controller:
# GET /bios/1
# GET /bios/1.json
def show
if member_session?
#member = MemberPresenter.new(#bio.member)
# I need something here to add a flag to the json response to signal this is a member session.
else
#member = MemberPresenter.new(#bio.member)
end
end
I need to modify the json response to return something like:
{ member: #member, member_session: true }
Thanks in advance!
You can use json param for render functions:
render json: { member: #member, member_session: true }
But it's not the best way to render JSON in rails. I'd recommend you try to use https://github.com/rails-api/active_model_serializers
I'm not sure if you specifically want to return json all the time but here's an alternative to rendering other formats as well:
respond_to do |format|
format.html
format.json { render json: { member: #member, flag: #member.status } }
end
For small and simple objects, doing this is fine, but if you had to drag the associations along, you have the choice of using a serializer, or you could override the to_json method to something like this.
# member.rb
def as_json(options = {})
options = options.merge(
except: [
:updated_at,
:created_at,
],
include: { # Getting associations here
address: {
only: [:street, :zip_code],
include: {
neighbors: { only: :name }
}
}
}
)
super.as_json(options)
end
And finally within the controller, render json: #member.to_json and it will pull all the associations you want with it. This is the lazy man's way of serializing aka what I do :)

String substitution within ruby array

I have the following code, within which I want to change certain values to csv friendly, e.g., 'nil' to ''. I need to know how to make these changes. Thank you.
def daily_door_schedule
#tickets = Ticket.where(active: true).
pluck(
:door_manufacturer,
:job_number,
:door_style,
:door_allocation_date,
:date_doors_received_in_aub,
:door_delivery_due_date,
:notes
)
respond_to do |format|
format.html
format.csv { render text: #tickets.to_csv }
end
end
This should do it:
#tickets = Ticket.where(active: true).
pluck(
:door_manufacturer,
:job_number,
:door_style,
:door_allocation_date,
:date_doors_received_in_aub,
:door_delivery_due_date,
:notes
).map { |ticket| ticket.map(&:to_s) }

How can I include a model association in a JSON response in Rails?

I've looked at similar posts but can't seem to quite figure it out.
I have the following function which works just fine. The Listing model has a foreign key called price_id which maps to the Price model and its price_range column. Price_id is returned as part of the message object in the JSON response.
How can I return the corresponding price_range value from the association instead of the price_id value (as part of the message obj, and keep the other attributes)?
def update
#listing = Listing.find(params[:listing][:id])
#if params were passed in for updating
if #listing.update_attributes(params[:listing])
#should we return the whole thing or just what's needed?
json_response = {
"success" => #listing.save, #save to DB and assign true/false based on success...
"message" => #listing.attributes #USE attributes to show output the content of the #message obj, and not another object called "message"
}
respond_to do |format|
#json response
format.html { render:json => json_response }
format.xml { render :xml => #listing }
#normal response. Consider leaving this for now?
#format.html { render :action => "detail" } #refresh this page, with new data in it. Consider trying to use redirect instead?
#format.xml { head :ok }
end
end #end if
end
add a method in your Listing model with the price_range and call it in serializable_hash
class Listing
def price_range
price.price_range
end
end
Like explain on comment you can use delegate instead this method :
class Listing
delegate :prince_range, :to => price
end
In you controller you can now do :
json_response = {
"success" => #listing.save, #save to DB and assign true/false based on success...
"message" => #listing.serializable_hash(:methods => [:price_range])
}
Based on what I read in this article, you should be able to do this:
class Listing
def as_json
super(:include => :price)
end
end
Then in your controller:
json_response = {
"success" => #listing.save,
"message" => #listing.as_json
}
If I understand correctly, you want to add #listing.price.price_range value to the "message" ?
If so, try this:
"message" => #listing.attributes[:price_range] = #listing.price.price_range

Resources