How add extra attribute in model object response in rails - ruby-on-rails

I have a method to render user details after login. The method is as follows
def respond_with(resource, _opts = {})
render json:resource
I get the User object in the resource variable. I want to add a new attribute called token before rendering it. I tried resource.attributes.merge(new:"value") but its not working.

I think following will work
render json: resource.as_json.merge(new: 'value')
If you want to have new attribute for your model, you can define a attr_accessor inside that model Class

Related

Pass arguments from view/controller to model - Rails

I'm looking to pass arguments from the controller to the model, but I keep getting wrong number of arguments.
Model:
before_create :embed_info
def embed_info(embed_url)
something = embed_url
## Do some stuff
self.title = "Title" ##This works.
end
Controller:
Create action:
#post = Post.new post_params
#post.embed_info(params[:title])
if #post.save
redirect_to root_url, notice: 'post created'
else
render 'new'
end
You can not pass arguments from controller to model callback like this.
You can use attr_accessor to create a virtual attribute and then set that attribute as part of your create action from controller.
If you're manually invoking the embed_info method, you shouldn't also be invoking it automatically via a before_create callback. Remove the line before_create :embed_info as it's currently serving no purpose except to invoking embed_info with no arguments when you attempt to save your model.
It's possible that you intended to add a validation, which is different than a before_create callback. If your intent was to make sure that embed_info had been called then you should use validations to insure that whatever side effects embed_info has leave the model in a valid state.
but I keep getting wrong number of arguments.
You are getting an arguments error because of this: before_create :embed_info. You can delete that line and then explicitly call the method like you are already doing in the controller.
This is probably not best practice but I think it will get your code working.
Another thing you could do is to move the logic for deriving the title to the controller and then pass the title in with the params.
# controller
def create
#post = Post.new post_params.merge(title: embed_info)
...
def embed_info
something = params[:title]
## Do some stuff
...
You could use attr_accessor to create a virtual attribute of embed_url. Pass it in new action itself. And when you call save, before_save will be called by itself and you can use embed_url there (as its a virtual attribute).
Let me know if you need help if the explanation is not clear.

How to create default options for all controller render calls

I'm writing a Rails API using ActiveModel::Serializers. I am following the JSON API spec and would like to include some data about current_user for authorization and authentication in the response's top-level meta key. With ActiveModel::Serializers, top-level meta information is specified like this:
render json: #posts, meta: { 'current-user': #current_user }
But I would like to have this information available on all JSON responses. It's a big hassle to define this information every single time I call render in each of my controllers.
Is there any way I can pass the meta: option to all my controller's render calls by default, say somewhere in my ApplicationController or something?
Create a def and append to before_action in application controller
This might work for you
Create this def in application controller
def append_user_to_json(data)
user = current_user.to_json
data = data.to_json
return data = data+user
end

How to calculate a field based on retrieved fields and incorporate into JSON in rails

I have a controller method which retrieves all the data from one table based on a userID. I want to do a simple addition of two of the integer fields in that table for that user and have that as part of the returned JSON. This is what I have so far:
def show
#user = User.find(params[:id])
respond_to do |format|
# Here we need to remove the layout because the request
# is done via ajax and the layout is already loaded.
format.json { render json: #user.to_json }
end
The fields I want to add together to make this new field are 'Score1' and 'Score2'. I assume I have to do something like #user.OverallScore = #user.Score1 + #user.Score2
You can define an instance method score_sum in the User model
def score_sum
self.Score1 + self.Score2
end
and use #user.to_json(:methods => [:score_sum]) in your controller.
The shortest way to handle this is probably something like this:
In your User model, add a method:
class User
def overall_score
score1 + score2
end
end
Then in your controller, you keep what you have and change the last line into:
format.json { render json: #user.as_json(methods: [:overall_score]) }
Also I suggest to use as_json and leave the hash-to-json conversion to the render method itself, unless you need to manipulate the converted string itself

Rails - Return additional attributes with object from controller using JSON

This is the code in my People Controller for the Create action :
def create
#person = Person.new(person_params)
#person.branch_id = session[:branch_id]
#person.added_by = current_user.id
if #person.save
respond_to do |format|
format.json { render json: #person}
end
end
end
And I have a method in my Person Model to get the person's full name :
def full_name
[self.first_name, self.middle_name, self.last_name].reject(&:blank?).join(" ")
end
What is the best way to add the Person's full name to #person when it is returned back as a JSON object
As you want it to be in the JSON you could just override the as_json method of the Person class to include the options to add the full_name method:
def as_json(options = {})
super options.merge(methods: [:full_name])
end
This method is used by Rails whenever an object should be serialized into a JSON string, for example by render json: #person. If you only want to add the extra method on this single occasion you can also call it directly inline using render json: #person.as_json(methods: [:full_name]) or if you want to make more complex customizations to the JSON output you could think about using dedicated serializer classes, for example by using the ActiveModel::Serializers gem. However, as you only want to add one method and that probably everywhere you are serializing #person, the best way for your case would be to just override as_json as described in the beginning.
Try this
#person.as_json(methods: :full_name)
Check out this article:
http://www.tigraine.at/2011/11/17/rails-to_json-nested-includes-and-methods
It's got instructions for doing exactly what you're trying to do, the short story being that you need to pass in :my_method => full_name to the json rendering.

Mass assignment, nested form and current user as author

I have a couple of objects, foo, bar and user.
I have a form for creating a new foo object, which uses simple_fields_for and accepts_nested_attributes_for to create a new child bar object at the same time.
Now, I want to set the current_user as the author attribute for the new bar, but I can't figure out how best to do this. (still new to Rails.)
I have tried the following in my create method within the foo controller:
def create
#foo = Foo.build(params[:foo])
#foo.bars.find(:first).author = current_user
However when I run this I get an exception.
undefined method `author=' for nil:NilClass
Can anyone offer any advice on how best to go about this?
You likely need to build the Bar object under #foo. ie
def new
#foo = Foo.new
#foo.bars.build
end
def create
#foo = Foo.new(params[:foo])
#foo.bars.first.author = current_user
if #foo.save
redirect_to #foo
else
render action: "new"
end
end
A good resource for nested forms: http://railscasts.com/episodes/196-nested-model-form-part-1?view=asciicast
Provided you set accepts_nested_attributes_for in your model and correctly used fields_for in your form, params[:foo] will contain an element called bar_attributes that will contain the data entered on the form about the bar object. Look through the railcast I linked to for more info.

Resources