I have a model called Event, which in turn has_one association with EventType
event = Event.last
event.as_json(include: {event_type: {only: :name}}, only: :event_type)
This is giving me output
{ :event_type=> { "name"=>"Chat" } }
But my desired response is
{ :event_type => "Chat" }
How can I achieve this?
You could create an instance method on event and include it in the serialized response, using the :methods key (see the documentation for as_json).
But you don't want to create an event_type method, because the association has_one has created one for you. Maybe you can do event_method_name? If you must get exactly the response you wanted, it seems something like JBuilder or Active Model Serializers will give you a better control on the output.
You can do this in event.rb.
def as_json
options = {event_type: event_type[:name]}
super
end
You might also consider creating and calling a new method to avoid overriding the method in case you need the full object elsewhere.
def event_type_as_json
{event_type: event_type[:name]}.as_json
end
Related
I am building rest APIs in ruby
I am using #object.as_json() for the response in json format
I am getting stuck in the mid while transfer the data in as_json. I need to more customize the response
I am listing what exactly I want and where I am getting stuck
I am using below code
#videos = Video.all.map{|m| m.as_json(
only: [:title],
method: [:watch_count],
include: {
user: {
only: [:first_name],
method: [:role]
}
}
).merge(
is_upvoted: m.is_upvoted(current_user)
) }
But I need to customise it.
1- I need to pass manual key and value (which is not in db) in video and user object, currently it can be possible with video but not with user. It should e possible with parent object and its child associate object. I don't want to to use :method for the same
2-I need to pass parameter in :method, like video model has a method is_upvoted but having a parameter like current user. So I am unable to pass parameter in :method. currently I can do with merge as I am doing but It can not be possible with user object.
3- I need to change key name while use include: {user: {method: []}}.
I need to use key "owner" at the place of "user"
Many Thanks in Advance
You can do it with JBuilder, which much more flexible and allow to make all things from your list. Result code will be like this:
#videos = JBuilder.encode do |json|
json.array! Video.all do |video|
json.(video, :title, :watch_count)
json.is_upvoted video.is_upvoted(current_user)
json.owner do
json.(video.user, :first_name, :role)
json.field video.user.with_param(some_param)
end
end
end
You may find details about JBuilder in documentation.
I have a model that won't update properly with update_attributes, but will update using update_column. I'm assuming this is because a callback is interfering. Unfortunately, it's not throwing any errors, so I can't figure out where exactly the problem is coming from.
Is there a way to trace callbacks so I can go through them, one by one, until I find the culprit?
The API documentation shows how you can access the callback chain.
Here's some one liners that you can use in your console that should give you the idea:
# Print before_validate callbacks
Post._validate_callbacks.select { |cb| cb.kind.eql? :before }.each { |cb| puts cb.filter }
# Print after_update callbacks
Post._update_callbacks.select { |cb| cb.kind.eql? :after }.each { |cb| puts cb.filter }
Remember that updates to models will also call save so it's a good idea to trawl through them all.
Check to see that the params you are passing to the update_attributes() method are mass assignable.
They should be defined as :attr_accessible in your rails model otherwise they will be stripped out before saving.
class Widget < ActiveRecord::Base
attr_accessible :name
end
More info here http://guides.rubyonrails.org/security.html
Is Rails' find(x) method on a model lazy? If not, what is the equivalent?
I am new to Rails, so I found myself writing scopes like this:
class Course < ActiveRecord::Base
scope :by_instructor_id, lambda { |instructor_id| where(:instructor_id => instructor_id) }
scope :by_course_template_id, lambda { |course_template_id| where(:course_template_id => course_template_id ) }
scope :by_company_id, lambda { |company_id| joins(:instructor).merge(CompanyUser.by_company_id(company_id)) }
end
It's not a lot of work, but now I'm asking myself... if Rails provided these with a scope, I wouldn't have to write them.
So, does Rails offer them? Can I do something like the below code and only make it do 1 database call?
Company.find(params[:id]).instructors.courses
instead of
Course.by_company_id(params[:id])
Which is correct? I know Course.by_company_id(params[:id]) is only 1 database call. It is very familiar to writing SQL or queries in Hibernate. But if you can write it the other way, maybe one should?
However, I don't want to write Company.find(params[:id]).instructors.courses if it results in more than 1 database call. I can see the advantage though because it means never having to write the 3 scopes I showed you above, but I am worried that Company.find(x) is not lazy. Is it?
Try using #scoped method on a model before calling #find:
user = User.scoped.instructors.courses.find(params[:id])
To make find by id query lazy you can add new method to your controller and then add this method as helper.
# company
def company
#company ||= Company.find(params[:id])
end
helper :company
#view
<%= company.name %>
To get more information you can check great RailsCast - Decent Exposure
So I have a model called Image that belongs_to :user. Each user has a first and last name.
I have a flash app that I am returning a json object back to of Images.
the service I will be calling on the Images controller would look something like this
def getimages
#images = Image.all
render :json => #images
end
My json would look something like this
[{"image":{"created_at":"2011-01-22T19:04:30Z","img_path":"assets/img/bowl_93847566_3_0.png","updated_at":"2011-01-22T19:04:30Z","id":9,"user_id":3}}]
what I would like to do is also include the users first and last name with in the image object that gets passed back.
once I have an image object I am able to do something like image.user.first_name but I am not clear how I would return something like an array of image objects and include the user along with it.
what would be great is if I could get my array of images to look like the following.
[{"image":{"created_at":"2011-01-22T19:04:30Z","img_path":"assets/img/bowl_93847566_3_0.png","updated_at":"2011-01-22T19:04:30Z","id":9,"user_id":3, "first_name":"Matthew", "last_name":"Wallace"}}]
I am thinking this may include adding some kind of model method or somthing that I am not familiar with.
What would be the best practice for achieving this?
You could:
render :json => #images.to_json(:include => :users)
See http://apidock.com/rails/ActiveRecord/Serialization/to_json (and http://apidock.com/rails/Array/to_json shows it works on Arrays). Finally, http://apidock.com/rails/ActionController/Base/render describes using to_json in a json render as optional and not required, which implies it should cause no harm (I couldn't see another way to pass the required options in).
Perhaps cleaner json:
render :json => #images.to_json(:include => { :user => { :only => [:first_name, :last_name] } })
Besides the answer provided by #apneadiving, you can also override the Image's to_json method and return a string containing whatever JSON you need.
How can I pass a method with an argument to #to_xml?
#object.to_xml(:methods => [:a_method_with_args] )
Is there a way to do this? What is the correct syntax?
Thanks.
to_xml is supposed to express your model's state. and as such it shouldn't need any external 'location' arguments. if this is really what you need it looks like you need a 'give me an xml representation of my model when on location X'. I guess you can just add a 'set_default_location' to your model and change the price_points_for_location to have a default value for the argument:
attr_writer :default_location
def price_points_for_location(location = #default_location)
...
end
You could try redefining the to_xml method like
def to_xml(location)
# do your stuff
super()
end
But not sure it would work that well. Other option would be to create some new XML view method for your model, like:
def as_xml(location)
self.price_points_for_location(location)
self.to_xml
end
Thanks for the answers, they look like good options. What I actually ended up doing is using a proc. I was aware that I could use procs with to_xml, but it seems that you can't access the current object in the array when iterating over multiple objects. To get around this I did something like this:
price_points = #items.map { |item| item.price_points_for_location(location) }
price_point = Proc.new {|options| options[:builder].tag!('price_points', price_points.shift) }
#items.to_xml(:procs => [price_point])