Ruby on Rails: Find a record by an attribute not a

2019-08-12 06:27发布

问题:

I'm very new to rails so please be patient with me.

In short I'm trying to create a form in which guests to a wedding can enter a simple code (invite_code) and then RSVP. The from should take the invite_code and then take the use straight to the correct invites#show view.

So far so good, but I'm stuck trying to get rails to find a record by something other than and id, I want to find by invite_code. Say I've got an Invite with an id of 4 and an invite_id of 1234, the form is finding the correct record when I enter '4' into the from but not '1234'. Here's some code to explain:

routes.rb

get 'invites/search', to: 'invites#show', controller: :invites

form

...
<%= form_tag invites_search_path, method: :get do %>
  <%= label_tag :invite_code, "#" %>
  <%= text_field_tag :invite_code, nil %>
  <%= submit_tag "Search", name: nil %>
<% end %>
...

invites_controller

...
  def show
    if params.has_key?(:invite_code)
      @invite = Invite.find(params[:invite_code])
    else
      @invite = Invite.find(params[:id])
    end
  end
...

rake routes output

       Prefix Verb   URI Pattern                                   Controller#Action
   info_index GET    /info/index(.:format)                         info#index
      invites GET    /invites(.:format)                            invites#index
              POST   /invites(.:format)                            invites#create
   new_invite GET    /invites/new(.:format)                        invites#new
  edit_invite GET    /invites/:id/edit(.:format)                   invites#edit
       invite GET    /invites/:id(.:format)                        invites#show
              PATCH  /invites/:id(.:format)                        invites#update
              PUT    /invites/:id(.:format)                        invites#update
              DELETE /invites/:id(.:format)                        invites#destroy

invites_search GET /invites/search(.:format) invites#show root GET / info#index

URL example

.../invites/search?utf8=%E2%9C%93&invite_code=1234

"utf8"=>"✓", "invite_code"=>"1234", "id"=>"search"

The application seems to be ignoring the invite_id part of if statement in the controller...

Any help appreciated, it's taken me a long time to get this far...

回答1:

You've got a couple of options. find_by_invite_code will return you the first match:

Invite.find_by_invite_code(params[:invite_code]) # First match or nil

While where will give you all the matches as an Array

Invite.where(invite_code: params[:invite_code]) # Array of matches. May be empty

You can also use the following syntax for find_by:

Invite.find_by(invite_code: params[:invite_code]) # First match or nil


回答2:

find uses id field by default, use where instead

if params.has_key?(:invite_code)
  @invite = Invite.where(invite_code: params[:invite_code]).first


回答3:

...
  def show
    if params.has_key?(:invite_code)
      @invite = Invite.find_by(invite_code: params[:invite_code])
      # find_by argument: value
      # returns first match or nil
      # same as find, where find searches by id
      # Invite.find_by_invite_code params[:invite_code] is deprecated  
    else
      @invite = Invite.find params[:id]
    end
  end
...