Is is possible to create a custom model attribute and get its value included by default, whenever that model is called?
I have a model named Video. It has an attribute named name. It contains the name of the video sample-video.mp4. I want to create two custom attributes named iphone_url and android_url for model.
Both attributes will have different urls concatenated with name. So, iphone_url will have http://link1/+name+/playlist.m3u8 where as android_url will have http://link2/+name
Is it possible that whenevr i call that model, both attributes are automatically added(in JSON response)?
I tried solutions mentioned here.
I was able to add custom attributes by using attr_accessor, but their value is always null. May be because their value needs to be set manually first.
So how to do this?
Edit: Currently, i'm doing like this:
videos = Array.new
# Dirty, but works
Video.all.each do |video|
video = video.attributes
wowza_server = "X.X.X.X:XXXX/AppName/"
custom_attributes = {:wowza_urls => {:ios => "http://"+wowza_server+"mp4:"+video[:name])+"/playlist.m3u8", :android => "rtsp://"+wowza_server+video[:name])}}
videos << video.merge(custom_attributes)
end
render :json => videos, status: :ok
This is really what jbuilder was made for.
Jbuilder gives you a simple DSL for declaring JSON structures that beats massaging giant hash structures.
You're starting to massage a giant hash structure.
I'm assuming this is an index view, in which case it look something like this:
json.array! #videos do |video|
json.my_field video.my_field
json.iphone_url video.iphone_url
json.android_url video.android_url
end
On your app/model/video.rb
class Video
def iphone_url
"some_url_to_build"
end
...
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 start to learn ruby on rails and I want to temporary add an attribute to a model so I added the accessor to my model :
attr_accessor :dettes
And then I used the method each, here is what I have :
#depenses = Depense.where(user_id: #user.id)
#depenses.each do |d|
d.dettes = "value"
end
render json: #depenses
But this didn't work, my new attribute isn't added
I've seen others questions about this but I'm still not able to resolve this, am I missing something ?
By default, render :json only adds the permanent attributes. You can add the temporary one as well this way:
render json: #depenses, methods: :dettes
As far as I understand you want modify object within request without mutating it in the database, so you add attr_accessor.
Then you used
#depenses = Depense.where(user_id: #user.id)
Which returns instance of ActiveRecord::Relation(not explicit instances of objects which you can modify). So you when you iterates within this relation instance and change it attr_accessor the instance of modyfied object hasn't been assigned to any public variable. Basically you need to convert relation to array, then #depenses going to be an array of Depense instance objects, which you can modify and pass to render methods:
#depenses = Depense.where(user_id: #user.id).to_a
Then you need tell json that you want to use custom method for serializing, like #eiko mentioned:
render json: #depenses, methods: :dettes
(But if you have a loot of data in Depense datatable then it's not the best idea, you gonna use some limitations with offsets for where clause)
Keep rocking ;)
Is there any way to remove sensitive fields from the result set produced by the default ActiveRecord 'all', 'where', 'find', etc?
In a small project that I'm using to learn ruby I've a reference to User in every object, but for security reasons I don't want to expose the user's id. When I'm using a simple HTML response it is easy to remove the user_id simply by not using it. But for some task I'd like to return a json using something like:
def index
#my_objects = MyObject.all
respond_to do |format|
...
format.json { render json: #my_objects, ...}
...
end
end
How do I prevent user_id to be listed? Is there any way to create a helper that removes sensitive fields?
You can use the as_json to restrict the attributes serialized in the JSON response.
format.json { render json: #my_objects.as_json(only: [:id, :name]), ...}
If you want to make it the default, then simply override the method in the model itself
class MyObject
def serializable_hash(options = nil)
super((options || {}).merge(only: [:id, :name]))
end
end
Despite this approach is quick and effective, it rapidly becomes unmaintainable as soon as your app will become large enough to have several models and possibly different serialization for the same type of object.
That's why the best approach is to delegate the serialization to a serializer object. It's quite easy, but it will require some extra work to create the class.
The serializer is simply an object that returns an instance of a model, and returns a JSON-ready hash. There are several available libraries, or you can build your own.
I am creating a instance variable that gets passed to my view. This variable 'post' has a user_id associated with it and I wanted to add an extra attribute called 'username' so I can also pass that and use it in the view.
Here is an example of what I would like to do.
#post = Post.find(params[:id])
#post.username = User.find(#post.user_id).username
A username column does exist on my Users model but not my Songs model. So it won't let me use
#post.username
I know I can just make an entirely new instance variable and put that information in there but I would like to keep everything nice and neat, in one variable. Which will also make my json rendered code look cleaner.
Any ideas on how I can accomplish this?
Thanks!
Based on the presence of a user_id in your Post model, you probably already have an association set up that can retrieve the username. It will probably save a lot of trouble to simply use the existing association:
#post = Post.find(params[:id])
username = #post.user.username
If you're likely to be querying more than one post at a time (e.g., on an index page, calling .includes to tell Rails to eager-load an association will help you avoid the N+1 problem:
#posts = Post.includes(:user).all
Finally, to include the associated record in your JSON output, pass the :include parameter as you serialize:
# in controller
render :json => #post.to_json(:include => :user)
This question includes a much more comprehensive discussion of serialization options. Well worth a read.
No need to pass a separate instance variable.
1. You can use #post.user.username in view itself.
2. Or you can create a helper and pass #post.user
def username user
user.username
end
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.