0
votes

I cant seem to get find_by to work, when you query the results like

GET /users.json?first_name=Tyrone&last_name=Slothrop"

should return Users whose first_name is Tyrone and whose last_name is Slothrop.

It returns null because all the params are null in that query except first_name and last_name. Im stuck as to get it to accept the only the query params and search by those. any advice?

  class Api::V1::UsersController < ApplicationController

  def index
    @users = User.find_by(id: params[:id], first_name: params[:first_name], 
                            last_name: params[:last_name], email: params[:email],
                            city: params[:city], state: params[:state])
    respond_to do |format|
      format.json { render json: @users.to_json, status: :ok }
    end
  end
end

here is a link to mt full repo https://github.com/jslack2537/apiDemoApp

dev log output for request

Started GET "/api/v1/users.json?first_name=Tyrone&last_name=Slothrop" for 10.0.2.2 at 2020-04-01 02:42:17 +0000
Cannot render console from 10.0.2.2! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Processing by Api::V1::UsersController#index as JSON
  Parameters: {"first_name"=>"Tyrone", "last_name"=>"Slothrop"}
  [1m[36mUser Load (4.4ms)[0m  [1m[34mSELECT  "users".* FROM "users" WHERE "users"."id" IS NULL AND "users"."first_name" = ? AND "users"."last_name" = ? AND "users"."email" IS NULL AND "users"."city" IS NULL AND "users"."state" IS NULL LIMIT ?[0m  [["first_name", "Tyrone"], ["last_name", "Slothrop"], ["LIMIT", 1]]
  ↳ app/controllers/api/v1/users_controller.rb:5
Completed 200 OK in 7ms (Views: 0.1ms | ActiveRecord: 4.4ms)

EDIT*** I now receive this error with my updated code NoMethodError (undefined method `split' for nil:NilClass):

class Api::V1::UsersController < ApplicationController

  def index
    ids = params[:id].split(",")
    if params[:id].present?
  @users = User.where(user_params.merge!(id: ids)).paginate(:per_page => params[:size], :page => params[:page]).order('id DESC')
   respond_to do |format|
    format.json { render json: @users.to_json, status: :ok }
    end
   else
    @users = User.where(user_params).paginate(:per_page => params[:size], :page => params[:page]).order('id DESC')
    respond_to do |format|
     format.json { render json: @users.to_json, status: :ok }
     end
    end
  end

  private

  def user_params
   params.permit(:first_name, :last_name, :email, :city, :state)
  end
end
2
how are you sending the request? Also if you take a look at the rails server log, what are you getting, I'm guesing you are receiving unpermitted parameters, can you verify the logs? - jean182
Im using postman to send the request, and heres what the log outputs on the request ill add it to the bottom of my original post - Joe Slack
I just cloned your repo and made it work, check the answer below. - jean182

2 Answers

2
votes

I believe you should permit the params, I downloaded your repo and I was able to get the desired query by permitting the params, like this:

class Api::V1::UsersController < ApplicationController

 def index
  @users = User.find_by(user_params)
  respond_to do |format|
   format.json { render json: @users.to_json, status: :ok }
  end
 end

 private

 def user_params
  params.permit(:first_name, :last_name, :email, :city, :state)
 end
end

Now if you try this query http://localhost:3000/api/v1/users?first_name=Tyrone&last_name=Slothrop&city=Chicago you should see on the logs that the only the params that you passed are being used for the search:

  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."first_name" = ? AND "users"."last_name" = ? AND "users"."email" = ? AND "users"."city" = ? LIMIT ?  [["first_name", "Tyrone"], ["last_name", "Slothrop"], ["email", "[email protected]"], ["city", "Chicago"], ["LIMIT", 1]]

↳ app/controllers/api/v1/users_controller.rb:11

Rails is just permitting the params defined on the user_params, so if they're not present, it will just be ignored

Edit: TO return the list of matches you should use where:

  def index
   @users = User.where(user_params)
   respond_to do |format|
    format.json { render json: @users.to_json, status: :ok }
   end
  end

To allow multiple parameters, for example to allow for multiple first_name fields you can do:

  def user_params
   params.permit(:last_name, :email, :city, :state, first_name: [])
  end

Remember to put your array items in the end of the permit to avoid syntax errors, and after that you can query the first name like this: http://localhost:3000/api/v1/users?first_name[]=John&first_name[]=Jean,

That url can get pretty tedious to build, so I would suggest that if you are building an api you can always send the params in the body of the request, like this:

{
 "first_name": ["John", "Jean"]
}

And that will have the exact behavior of passing the params in the url.

If you strictly want to send the id like id=1,2,3 that you can do something like:

class Api::V1::UsersController < ApplicationController

 def index
  ids = params[:id].split(",")
  @users = User.where(user_params.merge!(id: ids))
  respond_to do |format|
   format.json { render json: @users.to_json, status: :ok }
  end
 end

 private

 def user_params
  params.permit(:last_name, :email, :city, :state, :first_name)
 end
end

The user_params.merge! will do the trick since it will overwrite or add the id key to your user_params hash.

0
votes

I can see an error in the way you are sending the request to the API

try: /users.json?first_name=Tyrone&last_name=Slothrop"
instead of: /users.jsonfirst_name=Tyrone&last_name=Slothrop"

do you see the missing "?" at the begining of the query string?


Edit after fix the request url:

maybe the best approach for your query is use where instead of find_by.
example:

user = User.where(id: params[:id])
.where(first_name: params[:first_name])
.where(last_name: params[:last_name])
.where(email: params[:email])
.where(city: params[:city])
.where(state: params[:state])
.first