Search code examples
ruby-on-railsruby-on-rails-4slugfriendly-idupdate-attributes

Rails update() method causing error for custom URL


I am to create custom URLs for my Rails app. So far, I'm following the Friendy URLs documentation, as mentioned here https://gist.github.com/jcasimir/1209730.

I've replaced the default slug (ie: /books/4 ) with an attribute of the model (ie: /books/the-lord-of-the-rings ). In the book.rb model file:

# override to_param
# By default it returns the "slug" of the model
# (ie: @book.to_param => "1")
def to_param
  title.parameterize
end

Consequently, I've over-written the Book.find() method, re-defined in the book.rb file as well.

# override find
# the "super" usage is Book.find(1) => object 1
# Now, it is Book.find("bookTitle") => object of that name
def self.find(input)
  find_by_title(input)
end

This is added in order to be able to find my model without using the "slug", or ID of my model.

The issue arises when I try to update a Book entry. When @book.update(params[:book]) is called, this is the error I get from my server:

(0.2ms)  BEGIN
Book Exists (0.5ms)  SELECT 1 AS one FROM "books" WHERE ("books"."title" = 'nasty 22' AND "books"."id" != 62) LIMIT 1
Tag Load (0.6ms)  SELECT "tags".* FROM "tags" WHERE "tags"."book_id" = $1  [["book_id", 62]]
Book Load (1.3ms)  SELECT "books".* FROM "books" **WHERE "books"."title" = 62** LIMIT 1
PG::UndefinedFunction: ERROR:  operator does not exist: character varying = integer
LINE 1: ...CT  "books".* FROM "books"  WHERE "books"."title" = 62 LIMIT...

The problematic line is WHERE "books"."title" = 62

Somehow somewhere in the update method, it is reverting to trying to find my Book model using the ID instead of the Title.

Does anyone know how this problem can be solved? Much appreciated.


Solution

  • If you just continue to follow the instructions in the gist it will fix your problem. You're going to have to deal with the fact that other callers will call Book.find passing an integer id, so you'll want to handle both cases. So, you'll need to check to determine if the parameter being passed is an integer ID or a title, and then call the appropriate find method (either super or find_by_title, respectively). It just won't work any other way, I would think, and find is a pretty basic method.