Rails - 基于id以外的属性查找记录?

时间:2013-09-13 20:37:37

标签: ruby-on-rails ruby

我正在使用Rails v4,我有一个通过脚手架生成的控制器。我希望更新操作的路由基于我定义的模型的machine_name属性,而不是ID。但是,在routes.rb中,正在为模式资源生成路由。

以下是资源的默认路由:

                rooms GET    /rooms(.:format)                           rooms#index
                      POST   /rooms(.:format)                           rooms#create
             new_room GET    /rooms/new(.:format)                       rooms#new
            edit_room GET    /rooms/:id/edit(.:format)                  rooms#edit
                 room GET    /rooms/:id(.:format)                       rooms#show
                      PATCH  /rooms/:id(.:format)                       rooms#update
                      PUT    /rooms/:id(.:format)                       rooms#update
                      DELETE /rooms/:id(.:format)                       rooms#destroy

因此,对于PATCH / PUT请求,更新方法将在我提交时触发,例如/ rooms / folsom_prison。然后Rails会将folsom_prison视为ID,并尝试将参数与id列中的值匹配,而不是machine_name列。如何让Rails更改正在查看记录的列?

我正在使用的当前代码:

  # PATCH/PUT /rooms/1
  # PATCH/PUT /rooms/1.json
  def update
    @room = Room.find_by_machine_name(params[:id])
    room_params.delete(:id)
    respond_to do |format|
      if Room.update(@room.id,room_params)
        format.html { redirect_to @room, notice: 'Room was successfully updated.' }
        format.json { head :no_content }
      else
        format.html { render action: 'edit' }
        format.json { render json: @room.errors, status: :unprocessable_entity }
      end
    end
  end

来自日志的结果错误消息:

Started PATCH "/rooms/folsom_prison" for 127.0.0.1 at 2013-09-13 16:28:53 -0400
  Room Load (0.1ms)  SELECT "rooms".* FROM "rooms" WHERE "rooms"."id" = ? LIMIT 1  [["id", "folsom_prison"]]

ActiveRecord::RecordNotFound (Couldn't find Room with id=folsom_prison):
  app/controllers/rooms_controller.rb:69:in `set_room'

...以及我正在测试的cURL请求:

curl -i -H "Accept: application/json" -X PATCH -d "room[booked]=1" localhost:3000/rooms/folsom_prison

3 个答案:

答案 0 :(得分:1)

您正在寻找friendly_id gem:https://github.com/norman/friendly_id

答案 1 :(得分:1)

你不想在Rails 4中使用find_by_*助手。这就是你想要做的事情

Room.where(machine_name: params[:id])

要让您的路线正常运作,您需要覆盖to_param型号中的Room

require "uri"

class Room < ActiveRecord::Base
  # ...

  def to_param
    URI.escape(machine_name)
  end
end

假设你有一个房间实例

@room = Room.new machine_name: "foo"

当你创建链接时,一切都会很精彩!

<%= link_to @room.machine_name, @room %>
#=> <a href="/rooms/foo">foo</a>

答案 2 :(得分:0)

@naomik对于已删除的find_by_*方法是正确的,但是,find_by方法取代了where方法,而不是Room.find_by(machine_name: params[:id])

where

这将找到1条记录并将其返回,但{{1}}将找到与此匹配的所有记录,并始终以数组形式返回它们,即使只有一条记录。