【问题标题】:Active Record find_by returns nullActive Record find_by 返回 null
【发布时间】:2020-04-01 02:03:19
【问题描述】:

当您像这样查询结果时,我似乎无法让 find_by 工作

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

应该返回名字为 Tyrone 且姓氏为 Slothrop 的用户。

它返回 null,因为该查询中的所有参数都是 null,除了 first_name 和 last_name。我坚持让它接受唯一的查询参数并按这些参数进行搜索。有什么建议吗?

  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

这里是 mt full repo https://github.com/jslack2537/apiDemoApp 的链接

请求的开发日志输出

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)

编辑*** 我现在收到更新代码的错误 NoMethodError(nil:NilClass 的未定义方法 `split'):

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

【问题讨论】:

  • 您是如何发送请求的?另外,如果您查看 rails 服务器日志,您会得到什么,我猜您正在接收未经许可的参数,您可以验证日志吗?
  • 我正在使用邮递员发送请求,这是请求中日志输出的内容,请将其添加到我原始帖子的底部
  • 我刚刚克隆了你的仓库并让它工作,请检查下面的答案。

标签: ruby-on-rails json activerecord


【解决方案1】:

我相信您应该允许这些参数,我下载了您的存储库,并且通过允许这些参数,我能够获得所需的查询,如下所示:

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

现在,如果您尝试此查询 http://localhost:3000/api/v1/users?first_name=Tyrone&amp;last_name=Slothrop&amp;city=Chicago,您应该会在日志中看到您传递的唯一参数正在用于搜索:

  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", "jean@email.com"], ["city", "Chicago"], ["LIMIT", 1]]

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

Rails 只允许在 user_params 上定义的参数,所以如果它们不存在,它将被忽略

编辑:返回您应该使用的匹配列表 where:

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

要允许多个参数,例如允许多个 first_name 字段,您可以这样做:

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

记得把你的数组项放在permit的末尾以避免语法错误,然后你可以像这样查询名字:http://localhost:3000/api/v1/users?first_name[]=John&amp;first_name[]=Jean

构建该 url 可能会非常乏味,因此我建议如果您正在构建一个 api,您可以随时在请求正文中发送参数,如下所示:

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

这将具有在 url 中传递参数的确切行为。

如果您严格希望发送像 id=1,2,3 这样的 id,您可以执行以下操作:

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

user_params.merge!可以解决问题,因为它会覆盖或将 id 键添加到您的 user_params 哈希中。

【讨论】:

  • 所以这行得通,我不必过滤任何这些参数,所以localhost:3000/api/v1/… 可能为空,但localhost:3000/api/v1/…" 应该返回所有以阿肯色州为状态的用户此外,如果您通过 id 查询 localhost:3030/api/v1/users.json?id=1,2,3,4 它应该返回所有四个用户,而不仅仅是第一个
  • 你应该使用 where 而不是 find_by 因为 find by 返回第一个匹配记录,where 将返回所有匹配项
  • 有这个请求localhost:3030/api/v1/users.json?id=1,2,3,4这仍然不会返回前4个用户
  • 如果你想允许参数,你需要像这样允许它们:params.permit(:last_name, :email, :city, :state, id: [], first_name: []) 和您应该添加这个查询以使 Rails 知道您正在发送数组 api/v1/users?id[]=2&id[]=1&first_name[]=John&first_name[]=Jean。注意 id 和 first_name 后面的括号,这将告诉 rails 您正在为特定字段发送多个项目。
  • 这确实有效,但我需要它接受像 .json?id=1,2,3,4 这样的参数
【解决方案2】:

我发现您向 API 发送请求的方式存在错误

尝试:/users.json?first_name=Tyrone&last_name=Slothrop"
而不是:/users.jsonfirst_name=Tyrone&last_name=Slothrop"

你看到缺少的“?”在查询字符串的开头?


修改请求地址后编辑:

也许查询的最佳方法是使用 where 而不是 find_by。
示例:

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

【讨论】:

  • 是的,我只是忘了在这里输入,我用它来发送我修复帖子的请求
  • 也许最好的查询方法是使用 where 而不是 find_by
  • 对于 ActiveRecord where(...).first = find_by(...).
  • 正如 Sebastian 所说,find_by 和 where 几乎 100% 相等,不同之处在于“.where().first”在活动记录发送的最终 SQL 中添加了“order by”子句到数据库,但主要区别当然在于 ruby​​ 语法,使用 where() 可以构建更具可读性的代码。
猜你喜欢
  • 2013-02-22
  • 1970-01-01
  • 2010-11-16
  • 1970-01-01
  • 1970-01-01
  • 2013-09-20
  • 2020-01-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多