Doing search by count in json with params results - ruby-on-rails

I'm trying to implement a counter filter in my json. When I access the url api/v1/contacts?Results=2 [sic], I would like to get only two results from my json.
For this, I created two methods in my controller: an index that takes the information from the database and turns render into json, and a method that returns the number of times the json is returned.
class Api::V1::ContactsController < ApplicationController
before_action :results, only: [:index]
def index
#contacts = Contact.all
render json: {results: #contacts[0..#number_results]}
end
def results
if params[:results]
results = params[:results]["results"]
#number_results = results.to_i
else
#number_results = 3
end
end
end
Regardless of the value entered for results =, the value of #number_results is set to 0, so whenever I type results = I, get only the first result of json. If I do not type results = in the url, it sets #number_results to 3, and shows four results on the screen.
Can anyone help?

First, in the url you propose, "Results" is capitalized. If that is how you intend to submit it, then you'll need to search for it that way on the back end. But since all your code uses lowercase "results", we'll go with that. You should modify your url in the same way: api/v1/contacts?results=2.
If that's what your url looks like then the number you pass in is accessible in params[:results]. If you pass no parameter, then params[:results] will return nil. Don't call #to_i on the param before you check for its existence, because nil.to_i is 0.
All that said, here's what you probably want:
class Api::V1::ContactsController < ApplicationController
def index
number_results = params[:results] || 3
#contacts = Contact.all.limit(number_results.to_i)
render json: {results: #contacts}
end
end
If the result of params[:results] is nil, then number_results is assigned 3.
Now we use #limit to return only the number of contacts that was requested. This allows us to do away with the #results method entirely. You can also get rid of the before_action callback.

Related

Problem with selecting elements with the same params

What i do wrong? I want to return every products which pass condition:
def show
products = Product.select{|x| x[:category_id] == params[:id]}
render json: products
end
When i write
def show
products = Product.select{|x| x[:category_id] == 1}
render json: products
end
it works why the first example doesn't work?
I am pretty sure that there is mismatch in data type.
1=='1' #will be always false
1==1 #will be true
'1'=='1' #will be true as well
And also check for nil value from params[:id]
Please make sure to change as follows
def show
products = Product.select{|x| x.category_id == params[:id].to_i}
render json: products
end
OR
The best solution as suggested by #Eyeslandic is to use .where as it will not check for mismatch in data type. And also you don't have to take care of nil value from params[:id].
You should really be using a where to stop sql from loading all your products.
#products = Product.where('category_is = ?', params[:id])
The being said, if you are sticking to rails restful conventions, the fact you have a param called :id that is the category_id suggests you are on the category controller. So maybe consider changing your logic to:
#category = Category.includes(:products).find(params[:id])
you can then access products via
#category.products
or if your not interested in the category too much maybe
#products = Category.includes(:products).find(params[:id])&.products

Call to a collection path keeps passing an id

I have a search method in a rails app I'm writing. Here is an excerpt.
The intent is to use regex to match all items with a description which matches a search query . Then, all matching item ids are passed as a string to another page. (this all takes place in a Search controller).
The item controller then catches that string of ids, splits them up into an array and displays a list of the matching objects.
I'm currently getting a problem however, whereby rails is attaching to the redirect_to statement another paramater (which according to the trace is {"id" => "search"} and is then searching for an Item with ID ":a1". It obviously can't find one (ids are all numeric) and therefore the app crashes. Can anyone work out why this is the case?
IN THE SEARCH CONTROLLER
rquery = Regexp.new(Regexp.escape(#query), Regexp::IGNORECASE)
item_list = []
Item.all.each{|item| item_list << item if rquery.match(item.shortdescr)}
unless item_list == nil
ids = ""
maybe_matters.each do |matter|
ids += item.id.to_s + " "
end
redirect_to search_items_path(ids: ids)
return
end
IN THE ITEM CONTROLLER
def search
authorize! :show, Item
#id = params[:ids].split
#search = []
#id.each do |id|
#search << id.to_i
end
#items = Item.accessible_by(current_ability).where(id: #search).order('completed desc nulls last').page params[:page]
end
EDIT
In case it's relevant, this is (a very small) part of the routes file:
resources :items, only: [:index, :show] do
collection do
post :search
end
end
I'd recommend making search a GET request. Make sure the path to that action is a collection action in your routes.rb. If your controller is named ItemsController:
resources :items do
get 'search', on: :collection
end
You can pass your search params as a URL parameter:
GET /items/search?query=searchterm
EDIT
Just realized the POST in your routes. You can't redirect to a POST path which is probably why you're getting weird behavior. Change search action to a GET and the issue will at least be partially resolved.
Also, how are you handling URL encoding? Characters with spaces will get encoded to weird values like %20 which might give the unexpected results you're seeing when you call stuff like params[:ids].split.
If possible, I'd recommend consolidating this into a single controller action rather than redirecting.

instance variable is null in show method rails

I have developed a rest api, in which I am using instance variable. there are two methods index and show, I have created a instance variable in index method which I want to use in show method on user request.
But i do not know, the instance variable is null in show method, I am sure that I am not initaializing the class anywhere explicitly. Code snippet is below
def index
data = Hash.new
#temp = DataHelper.filter(params)
if(params[:type] == 'Student')
json = DataStudenteHelper.sfilter(params, #temp)
else
json = EmpDataHelper.empfilter(params, #temp)
end
puts data.to_json
render :status => :ok, :json => json
end
def show
puts #temp.to_json // null here
if (params[:type] == 'Student')
#h = StudentHelpHelper.shfilter(params, #temp)
else
#h = EmpDataHelpHelper.emphfilter(params, #temp)
end
render :status => :ok, :json => #h
end
in the methods sfilter, empfilter, shfilter and emphfilter, I am just processing #temp but it is null in show method...
So any idea what is the issue thanks...
You seem to be assuming that a controller will persist across multiple requests so that you can initialize a variable in an index action and still be able to use it in a subsequent show action. This is not the case. Rails controller instances exist only for the duration of the request they serve. You cannot keep values in memory like this across requests (nor should you want to as that would require that requests be served in a particular order and would leak data between different users).
If you need to initialize this variable before all of your controller actions consider using a before filter. In your case this probably means that you also need to supply the data you need in the params of the show action.

How to handle possible params on Rails 4?

I'm doing an API for my app.
Currently, you can call api/v1/clients and get the Clients JSON back, as expected. You can also do api/v1/clients?client_id=1 and get the JSON representation of the Client object with id 1.
Here's my API::V1::ClientsController:
class API::V1::ClientsController < ApplicationController
def index
if params[:client_id]
#client = Client.find(params[:client_id])
render template: 'api/v1/clients/show'
else
#clients = Client.all
end
end
end
I want that if, for example, you have a typo on the endpoint (api/v1/clients?clent_id=1), the app returns a JSON object with an error:
{
error: {
error_code: 10,
error_description: "Bad endpoint"
}
}
Is there a way to, say, make a switch statement on the params to handle the possible cases?
My suggestion:
Make a private method in your controller, this one will check your params:
If params is empty it returns false
If params contains 'client_id' and its value is a numeric it returns the value
Otherwise it raises an exception.
Then in you action method you use this result:
If the result is false you display all results
Otherwise it display the record based on the id returned by your private method
As for the exception: you use a rescue_from to display the "Bad endpoint" JSON response

rails get output from controller methods?

I have the following code in my Application Controller
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
def get_mkts(all_idx)
mkts = Set.new
all_idx.each do |idx|
m = decode_index_names(idx)
puts m[:mkt]
mkts.add(m[:mkt])
end
end
def decode_index_names(name)
mkt = name.split(/[0-9]/)[0]
type = get_first_num(mkt);
{:mkt => mkt,:type => type}
end
def get_first_num(str)
str[/\d+/]
end
end
And I'm inputting an array of strings like this:
["USEQUITIES2tv10", "USEQUITIES2tv15", "USEQUITIES2tv20", "NONUSEQUITIES2tv5", "NONUSEQUITIES2tv10", "NONUSEQUITIES2tv15", "NONUSEQUITIES2tv20", "BONDS2tv5", "BONDS2tv10", "BONDS2tv15", "BONDS2tv20"
, "ES1", "ES2tv5", "ES2tv10", "ES2tv15", "ES2tv20", "NQ1", "NQ2tv5", "NQ2tv10", "NQ2tv15", "USBONDS2tv5", "USBONDS2tv10", "USBONDS2tv15", "USBONDS2tv20", "GERMANBONDS2tv5", "GERMANBONDS2tv10", "GERMANB
ONDS2tv15", "GERMANBONDS2tv20", "EQUITIESnBONDS2tv5", "EQUITIESnBONDS2tv10", "EQUITIESnBONDS2tv15", "EQUITIESnBONDS2tv20", "COMMODITIES2tv5", "COMMODITIES2tv10", "COMMODITIES2tv15", "COMMODITIES2tv20",
"CURRENCIES2tv5"]
The method get_mkts is supposed to loop through, extract the text up tot the first number and create a unique array of symbols (which is why i used Set). However, I can't get the method to output anything other than the original input. In rails console I'm able to see from the output of "puts m[:mkt]" that each loop through is getting the correct value, I just don't know how to return the set mkts instead of the input value. Any ideas?
Ruby methods return the result of the last statement if you don't use return. In your case it's each and that's why you get the input back. You can do something like this:
def get_mkts(all_idx)
mkts = Set.new
all_idx.each do |idx|
m = decode_index_names(idx)
puts m[:mkt]
mkts.add(m[:mkt])
end
mkts
end
This will return the mkts set instead of all_idx.
The method can be rewritten has:
def get_mkts(all_idx)
all_idx.map { |idx| decode_index_names(idx) }.uniq
end
Looks more rubyish and its shorter and cleaner

Resources