I'm trying to render some specific json based on whether the destroy worked or not. However, the code gets past the #attachment.destroy... then throws an exception when it tries to render the json. Not sure what's going on here.
def delete
#attachment = Attachment.find(params[:attachment_id])
if #attachment.destroy
render json: {
status: 200,
message: MESSAGES_SUCCESS
}
else
render json: {
status: 422,
message: MESSAGES_FAILED
}
end
end
Destroy attachment and then check if there are any errors.
def delete
#attachment = Attachment.find(params[:attachment_id])
#attachment.destroy
if #attachment.errors.any?
render json: {
status: :unprocessable_entity, # 422
message: MESSAGES_FAILED
}
else
render json: {
status: :ok, # 200
message: MESSAGES_SUCCESS
}
end
end
Related
I've searched through the rails docs but not find any method which can check if record was corectly updated from outside transaction block because I dont want to put respond_to block into my transaction because it is bad practise. Is there any method like persisted? which I use with create/save method...
def update
ActiveRecord::Base.transaction do
address = Address.find_or_create_by(address_params)
#invoice_account = InvoiceAccount.find_or_create_by(invoice_account_params
.merge({ :invoice_address_id => address.id }))
#invoice = Invoice.find_by_id(params[:id])
#invoice.update(invoice_params.merge({ purchaser_id: #invoice_account.id }))
end
respond_to do |format|
if #invoice.method `some method to check if invoice was updated`
format.html { redirect_to invoice_url(#invoice), notice: "Invoice was successfully updated." }
format.json { render :show, status: :ok, location: #invoice }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #invoice.errors, status: :unprocessable_entity }
end
end
end
I just edit my code as bellow, capture result of the transaction to variable is_updated. When in transaction error occurred then is_updated would be false and changes are rolled back. If no error occurred is_updated true.
def update
is_updated =
ActiveRecord::Base.transaction do
address = Address.find_or_create_by(address_params)
#invoice_account = InvoiceAccount.find_or_create_by(invoice_account_params
.merge({ :invoice_address_id => address.id }))
#invoice = Invoice.find_by_id(params[:id])
#invoice.update(invoice_params.merge({ purchaser_id: #invoice_account.id }))
end
respond_to do |format|
if is_updated
format.html { redirect_to invoice_url(#invoice), notice: "Invoice was successfully updated." }
format.json { render :show, status: :ok, location: #invoice }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #invoice.errors, status: :unprocessable_entity }
end
end end
Calling .update on an ActiveRecord object will return true if it was able to store it to db or false if any error occurred.
I'd take advantage of that and store its result on a variable, like the following:
def update
updated = false
ActiveRecord::Base.transaction do
address = Address.find_or_create_by(address_params)
#invoice_account = InvoiceAccount.find_or_create_by(invoice_account_params
.merge({ :invoice_address_id => address.id }))
#invoice = Invoice.find_by_id(params[:id])
updated = #invoice.update(invoice_params.merge({ purchaser_id: #invoice_account.id }))
end
respond_to do |format|
if updated
format.html { redirect_to invoice_url(#invoice), notice: "Invoice was successfully updated." }
format.json { render :show, status: :ok, location: #invoice }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #invoice.errors, status: :unprocessable_entity }
end
end
end
I'm having trouble testing for a thrown AASM error.
Here is my controller method:
# controllers/jobs_controller.rb
def change_state
respond_to do |format|
if #job.close && #job.save
format.html { redirect_to #job, notice: 'Job has been closed.' }
format.json { render :show, status: :ok, location: #job }
else
format.html { render :show, notice: 'Job could not be closed.' }
format.json { render json: #job.errors, status: :unprocessable_entity }
end
end
end
My spec looks like this:
# spec/controllers/jobs_controller_spec.rb
describe "POST #change_state" do
it "cannot transition job from closed" do
job.aasm_state = "closed"
job.save!
post :change_state, params: {id: job.hash_id, user_id: user.id}
expect { response }.to raise_error(AASM::InvalidTransition)
end
end
The test fails (with the expected/desired failure):
Failure/Error: if #job.close && #job.save
AASM::InvalidTransition:Event 'close' cannot transition from 'closed'.
I'm just unable to figure out the right syntax to pass the test. I've tried a few variations of the expect line but can't seem to piece it together.
Any guidance is appreciated.
The exception is happening before the expect statement. Try it:
expect {
post(:change_state, params: { id: job.hash_id, user_id: user.id })
}.to(
raise_error(AASM::InvalidTransition)
)
I have a RoR app with postgresql as database
Currently, I have this code:
def return_mssg_as_json
id = params[:id].to_i
#message = Message.find(id)
render json: #message
end
and it returns this JSON:
{"id":13,"created_at":"2017-10-27T19:03:52.196Z","updated_at":"2017-10-27T19:03:52.196Z","text":"ASDF"}
How can I make it return only {"text":"ASDF"}
A few things here...
First, you don't need to do to_i here:
def return_mssg_as_json
id = params[:id].to_i
#message = Message.find(id)
render json: #message
end
You can just do:
def return_mssg_as_json
#message = Message.find(params[:id])
render json: #message
end
Now, if there's any chance that you might receive an id that doesn't have a matching record, you might want to do something like:
def return_mssg_as_json
begin
#message = Message.find(params[:id])
render json: #message
rescue ActiveRecord::RecordNotFound
render json: {errors: :not_found}, status: :not_found
end
end
Otherwise, if your record doesn't exist, you'll have an unhandled critical error. Instead, however, you could do:
def return_mssg_as_json
if #message = Message.find_by(id: params[:id])
render json: #message
else
render json: {errors: :not_found}, status: :not_found
end
end
Now, back to your main question, you could do (as in the accepted answer)
def return_mssg_as_json
if #message = Message.find_by(id: params[:id])
render json: { message: #message[:text] }
else
render json: {errors: :not_found}, status: :not_found
end
end
Although, to save yourself three characters, it seems you could do:
def return_mssg_as_json
if #message = Message.find_by(id: params[:id])
render json: { message: #message.text }
else
render json: {errors: :not_found}, status: :not_found
end
end
Which is a great answer! But, in the future, if you want to return multiple values from #message (for example), you could do something like (assuming #message responds to foo and bar):
def return_mssg_as_json
if #message = Message.find_by(id: params[:id])
render json: #message.attributes.with_indifferent_access.slice(:text, :foo, :bar)
else
render json: {errors: :not_found}, status: :not_found
end
end
This bit:
#message.attributes
converts the record into a hash of its values. This bit:
.with_indifferent_access
allows you to select key-value pairs using symbols instead of strings. And this bit:
.slice(:text, :foo, :bar)
specifies which key-value pairs to return. So, this would return something along the lines of (in JSON format, naturally):
{text: 'blah', foo: 'blah', bar: 'blah'}
Now, in your example, you didn't want text, you wanted message. So, you could do:
def return_mssg_as_json
if #message = Message.find_by(id: params[:id])
attr = #message.attributes.with_indifferent_access
render json: attr.slice(:foo, :bar).merge!(message: attr[:text])
else
render json: {errors: :not_found}, status: :not_found
end
end
Which would return something along the lines of (in JSON format, naturally):
{message: 'blah', foo: 'blah', bar: 'blah'}
Simply use the following:
render json: { message: #message[:text] }
Also you can use jbuilder to achieve such behavior, check an example here https://richonrails.com/articles/getting-started-with-jbuilder
The join method below in the teams_controller.rb is sent the following data through submission of a form using EmberJs
{"id"=>"3", "user_id"=>"42", "action"=>"join", "controller"=>"teams"}
The record is getting created with the join method below (according to the console), but the code for what happens after the save is throwing an error
ArgumentError (too few arguments):
app/controllers/teams_controller.rb:145:in `format'
app/controllers/teams_controller.rb:145:in `join'
I copied the code following the #team.save method from the Rails scaffold generator, so I'm a little surprised. The hope is that it will respond with the json, but I left in the html format just because (maybe there's a graceful degradation benefit). Can you tell me why that error's being thrown and/or how I could avoid it?
Rails method
def join
#team = Team.find(params[:id])
id = params[:user_id]
#team.user_ids = #team.user_ids.push(id)
if #team.save
format.html { redirect_to #team, notice: 'Joined Team' }
format.json { render json: #team, status: :created, location: #team }
else
format.html { render action: 'new' }
format.json { render json: #team.errors, status: :unprocessable_entity }
end
end
Update,
I should also note that, based on the line number of the error message, the method seems to be treating the format as html, however, I wanted it to be treated as json
I forgot to put respond_to do |format| around the code.
respond_to do |format|
if #team.save
format.html { redirect_to #team, notice: 'Joined Team' }
format.json { render json: #team, status: :created, location: #team }
else
format.html { render action: 'new' }
format.json { render json: #team.errors, status: :unprocessable_entity }
end
end
I recently updated a controller from a plain
render :json => #something
to
respond_to do |format|
format.html {
redirect_to #something
}
format.json {
puts "found json format"
format.json { render json: #something, status: :created }
}
end
But, now I'm getting ActionView::MissingTemplate errors. My question is, if I use the respond_to do |format| block, am I required to use a template? What if I just want to return plain json?
Btw, the puts statement in the json respond_to block is being called successfully.
I think the problem is puts being called inside of your format.json block and the nesting of format.json inside of it's own block. Try removing both (as below).
respond_to do |format|
format.html {
redirect_to #something
}
format.json {
puts "found json format"
format.json { render json: #something, status: :created }
}
end
Try:
respond_to do |format|
format.html { redirect_to #something }
format.json { render json: #something, status: :created }
end
You are telling that you accept HTML and JSON formats. Since your request comes from HTML you'll have the HTML template rendered.
If you want to return only JSON remove that line from your code. Also check the docs on respond_to.
Probably you already know it, but there's a guide on Layouts and Rendering.
Remove the format.json part from within the json rendering block (you have an unnecessary block within your block):
respond_to do |format|
format.html {
redirect_to #something
}
format.json {
render json: #something, status: :created
}
end
I think the reason your code is prompting an error it's because you have
format.json {
format.json { render json: #something , status: :created }
}
You should have:
format.json {
render json: #something , status: :created
}