How to solve issues (errors)in rails locally? - ruby-on-rails

encountered with no method error . how to solve it and check it?
I tried rails console and couldn't able to call the method .
class dashboardcontroller
def get_meta_data
require 'link_thumbnailer'
begin
object = LinkThumbnailer.generate(params[:url])
rescue StandardError
end
respond_to do |format|
format.json do
render json: { title: object.title, image: object.images.first.src.to_s, description: object.description,
url: object.url, status: 200 }

You can do couple of things here:
Move your require file on top in the controller.
Use rescue with your controller method get_meta_data
Check your LinkThumbnailer class if its actually generating or not.
Then use puts to show actually what is it that you actually assigning in object
After all of this you must confirm if object has all the attributes you are using while rendering json.

Related

How do I send a POST request with rails API (mongo db backend)?

building a custom rails api for a rails/react/mongodb app.
GET requests working fine, but I can't get post to work.
Basically the params are not getting assigned to the object in my create method.
Request:
POST http://localhost:3000/api/v1/movies HTTP/1.1
{"title" : "Cool Movie"}
Here's my controller:
def create
movie = Movie.new(movie_params)
if movie.save
render json: MovieBlueprint.render(movie)
else
render json: { error: movie.errors.full_messages }, status: 422
end
end
private
def movie_params
params.except(:format).permit(:title, :description, :director, :genre)
end
output:
Parameters: {"{\"title\" : \"Cool Movie\"}"=>nil}
Unpermitted parameter: :{"title" : "Cool Movie"}
I get a 200 response with this. Basically the document is getting created in the database, but the fields / values are all still null. Why is it telling me unpermitted params?
And I know typically with rails you have to require the object like so:
params.require(:movie).permit(:title, :description, :director, :genre)
But when I try this, it makes matters worse, I get a 400 - bad request with this:
ActionController::ParameterMissing (param is missing or the value is empty: movie):
I assume this has something to do with the whole mongo thing and how I'm formatting my request, but I can't quite place it. Any help is appreciated.
At a glance and considering the params coming into the controller via a POST request needs to reference the entity it's changing, your data would need to should look like this to be available in the create method:
{ "movie": { "title": "Updated Song Title" } }
Depending on the version of Rails being used, you could add a debugger to test if the params are available. This will stop the runtime of the script and allow you to inspect it in the terminal.
Run your server in an individual process before trying this. For example, instead of running bin/dev run bin/rails server -p 3000.
First, modify your create method to use debugger:
def create
movie = Movie.new(movie_params)
debugger # <- Stop the script right here.
if movie.save
render json: MovieBlueprint.render(movie)
else
render json: { error: movie.errors.full_messages }, status: 422
end
end
Then, run the create action of your controller by making a request to that endpoint with your params of choice. Navigating to your terminal you'll see the program has stopped and you can type. Type params.inspect to see if the movie key is present:
params.inspect
Type continue to let the rest of the program run.

Rendering ActiveRecord validation errors with attributes AND full error messages

Here's a simple controller update action:
def update
note = Note.find(params[:id])
if note.update(note_params)
render json: note.to_json
else
render json: {errors: note.errors}, status: :unprocessable_entity
end
end
This renders errors in the form
{"errors":{"title":["can't be blank"]}}
but I want it in the form of
{"errors":{"title":["Title can't be blank"]}}
Simply using {errors: note.errors.full_messages}
gives
{:errors=>["Title can't be blank"]} and misses the attribute keys.
The only way I can get it into the desired form seems to be a bit more involved:
full_messages_with_keys = note.errors.keys.inject({}) do |hash, key|
hash[key] = note.errors.full_messages_for(key)
hash
end
render json: {errors: full_messages_with_keys}, status: :unprocessable_entity
This works, but it seems odd that I have to do this since it seems to be a pretty common use case for doing validations on a SPA front-end. Is there a built-in method/more canonical way?
You can use ActiveModel::Errors#group_by_attribute to get a hash of errors per key:
person.errors.group_by_attribute
# => {:name=>[<#ActiveModel::Error>, <#ActiveModel::Error>]}
From there is simply a matter of generating the full message from each ActiveModel::Error instance:
note.errors
.group_by_attribute
.transform_values { |errors| errors.map(&:full_message) }
Is there a built-in method/more canonical way?
Not really. A framework can't cover every possible need. It provides the tools needed to format the errors however you want.
However instead of repeating this all across your controllers this functionality can be pushed into the model layer, a serializer or even monkeypatched onto ActiveModel::Errors if you want to get crazy.
class ApplicationRecord < ActiveRecord::Base
def grouped_errors
errors.group_by_attribute
.transform_values { |errors| errors.map(&:full_message) }
end
end

Error handing and flow within private methods on controller

Reviewing a coworker's PR I came across a pattern I have not seen before, where a private method was called and or return appended to the end if that method failed. I found a blog post mentioning this (number 2) but it feels strange to me.
The code sort of looks like this:
class OurController < ApplicationController
def index
amount = BigDecimal.new(params[:amount]).to_i
if amount < 0
cancel_processing(amount) or return
else
process(amount)
end
render json: {success: true}
end
private
def cancel_processing(amount)
response = CancelProcessingService.call(amount)
if response
log_stuff
else
render json: {error: true} and return
end
end
end
Since the render error is being called from within the method, it's not ending, and it's therefore going to the end of the index action and double rendering (without the or render after cancel_processing).
This feels like a smell to me. renders and returns are respected within before_filters, so them not being respected in methods feels inconsistent. Maybe it just feels wrong because I haven't encountered this or return pattern before, but I ask: is there a way to get Rails to respect render... and returns from within methods (which are not before_filters or actions)?
I feel like advocating for rewriting these methods to simply return JSON, and pass the response to render later on in the method -- but if this is a normal pattern then I have no ground to suggest that.
What are your thoughts?
render ... and/or return is a bogus pattern. Rails documentation uses it in a couple of places but I believe it should not. It's bogus because although render returns a truthy value (the rendered response body) when it succeeds, when it fails it does not return a falsy value but raises an error. So there is no point in handling the nonexistent case when it returns a falsy value. (The same applies to redirect_to.)
In an action, to avoid misleading anyone about how render works, just do
render # options
return
to render and then exit.
In a private method called by an action, you can't say return and exit from the calling action, because Ruby methods don't work that way. Instead, make the method return a value that the action can interpret and return early if appropriate. Something like this:
def index
amount = BigDecimal.new(params[:amount]).to_i
if amount < 0
if !cancel_processing(amount)
return
end
else
process(amount)
end
render json: {success: true}
end
def cancel_processing(amount)
response = CancelProcessingService.call(amount)
if response
log_stuff
else
render json: {error: true}
end
response
end
In a controller you can call performed? to find out if a render/redirect has already been called. For example:
performed? # => false
render json: {error: true}
performed? # => true

JSON Decode Parameter Issue

I have a rails 4 application that uses postgresql. I also have a backbone.js application that pushes JSON to the rails 4 app.
Here's my controller:
def create
#product = Product.new(ActiveSupport::JSON.decode product_params)
respond_to do |format|
if #product.save
format.json { render action: 'show', status: :created, location: #product }
else
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
def product_params
params.require(:product).permit(:title, :data)
end
I'm trying to parse the JSON and insert the product, but on insert, I'm getting the error:
TypeError (no implicit conversion of ActionController::Parameters into String):
Thanks for all help!
Your mileage may vary, but I fixed a smilar problem by a bandaid code like this:
hash = product_params
hash = JSON.parse(hash) if hash.is_a?(String)
#product = Product.new(hash)
The particular problem I had was that if I was just doing JSON.parse on the params that contained the object I wanted to create, I was getting this error while unit testing, but the code was working just fine when my web forms were submitting the data. Eventually, after losing 1 hour on logging all sorts of stupid things, I realized that my unit tests were somehow passing the request parameter in a "pure" form -- namely, the object was a Hash already, but when my webforms (or manual headless testing via cURL) did sumbit the data, the params were as you expect -- a string representation of a hash.
Using this small code snippet above is, of course, a bandaid, but it delivers.
Hope that helps.
Convert hash into JSON using to_json
The error is telling you that ActiveSupport::JSON.decode expects to be provided with a string, but is unable to coerce the argument you are providing it into a string. The argument provided to it here is "product_params" which returns a ActionController::Parameters (a loosely wrapped Hash).
If you are using "out of the box" style Backbone there is no need to decode what is being POSTed to that action. Just change the action to:
#product = Product.new(product_params)
The structure of your product_params method indicates that the action is expecting the data you are POSTing to look like this:
{
product: {
title: "Foo",
data: "bar"
}
}
and that your Product model has two attributes that will be populated by .new: title and data.
If you are explicitly encoding something into JSON on the client side you need to figure out what POST parameter it is being submitted as and the decode it on the server (again - there is almost certainly not a good reason to jump through hoops like that).

Define timer method controller rails

I have a method in controller that calls another method created in a module like this example:
def example
#var1 = ModuleName::ClassName.get()
respond_to do |format|
format.json { render json: #var1}
end
end
The method get() goes to a website looking for information and returns an array.
Everything works perfectly, but I wonder if in the controller there is a way to set a timeout if the application takes a long time to run! Is it possible?
here is one way (a more general way) you could do that..
def example
Timeout::timeout(40) do # 40 sec, change it to anything you like
#var1 = ModuleName::ClassName.get()
rescue Timeout::error
# do something (maybe set #var1's value if it couldn't get desired array)
end
respond_to do |format|
format.json { render json: #var1}
end
end
If under ModuleName::ClassName.get() you imply some kind of third-party ruby http library, then it's likely that you should set some kind of timeout parameter (depends on library). You just pass a desired timeout in seconds (or whatever measurement you want).
Thus the pseudo-code might look like this:
ModuleName::ClassName.get(10)
For more detailed answer, can you please be more specific about how are you doing a call to external service?

Resources