0

On a rails 4.1.4 application some parameters are not processed by the model, presumably depending on their type. When making a POST request like the following, all parameters get processed correctly and the new recipe is saved to the database with the correct values in place:

POST /api/v0/recipes HTTP/1.1
Host: localhost:3000
Content-Type: application/json
Cache-Control: no-cache
Postman-Token: f49d43b3-9007-9687-a24f-92e7e7c873bd

{"recipe":{"name":"Spaghetti Carbonara","description":"Catchy description", "body":"Steps here","preparation_time":200,"category_id":"1","ingredients_attributes":[{"food_id":2,"quantity":100,"unit":"g"}, {"food_id":2,"quantity":150,"unit":"g"}]}}

Notice that the value for preparation_time is passed as an integer and the value for category_id is passed as a string. However, when the value for preparation time is passed as a string, like the one for category_id, validation fails, complaining that preparation_time is required per the model's validation rules.

Here is the failing request:

POST /api/v0/recipes HTTP/1.1
Host: localhost:3000
Content-Type: application/json
Cache-Control: no-cache
Postman-Token: 70500362-9573-8684-bdaf-8dd0a0b3b05d

{"recipe":{"name":"Spaghetti Carbonara","description":"Catchy description", "body":"Steps here","preparation_time":"200","category_id":"1","ingredients_attributes":[{"food_id":2,"quantity":100,"unit":"g"}, {"food_id":2,"quantity":150,"unit":"g"}]}}

And here is the log for that request, which shows that the preparation_time parameter arrived correctly:

Started POST "/api/v0/recipes" for 10.0.2.2 at 2014-07-20 17:11:08 +0200
Processing by Api::V0::RecipesController#create as */*
  Parameters: {"recipe"=>{"name"=>"Spaghetti Carbonara 2", "description"=>"Catchy description", "body"=>"Steps here", "preparation_time"=>"200", "category_id"=>"1", "ingredients_attributes"=>[{"food_id"=>2, "quantity"=>100, "unit"=>"g"}, {"food_id"=>2, "quantity"=>150, "unit"=>"g"}]}}
   (0.2ms)  begin transaction
  Food Load (1.3ms)  SELECT  "foods".* FROM "foods"  WHERE "foods"."id" = ? LIMIT 1  [["id", 2]]
  CACHE (0.0ms)  SELECT  "foods".* FROM "foods"  WHERE "foods"."id" = ? LIMIT 1  [["id", 2]]
  Recipe Exists (0.4ms)  SELECT  1 AS one FROM "recipes"  WHERE "recipes"."name" = 'Spaghetti Carbonara 2' LIMIT 1
   (0.2ms)  rollback transaction
Completed 422 Unprocessable Entity in 44ms (Views: 0.3ms | ActiveRecord: 2.1ms)

The response contains an error message stating that the preparation_time parameter is not set:

{"preparation_time":["can't be blank","is not a number"]}

The status is 422 Unprocessable Entity.

The validation rules in place for category_id and preparation_time are exactly the same:

  validates :preparation_time, presence: true, numericality: { only_integer: true, greater_than: 0 }
  validates :category_id, presence: true, numericality: { only_integer: true, greater_than: 0 }

Why does this happen just with one parameter? Is it something I am missing? Is it a bug in rails?

ehp
  • 1,689
  • 3
  • 14
  • 20

1 Answers1

1

You'll need to change the type for the preparation_time column. You can achieve this like so:

rails generate migration change_preparation_time_column

Then in the generated migration:

class ChangePreparationTimeColumn < ActiveRecord::Migration

  def change
    #change preparation time columntype from time to integer
    change_column :recipes, :preparation_time, :integer
  end
end

If for some reason you wanted to keep the type as time but ensure the parameter gets converted first you can always do the following in the model (although I'd recommend doing the former)

Class Recipe
    ...

    before_save :convert_prep_time

    def convert_prep_time
      self.preparation_time = self.preparation_time.to_i unless self.preparation_time.blank?
    end

end
Jay
  • 930
  • 7
  • 11
  • Yes and I permitted preparation_time, but why would it reject preparation_time only if it is a string. – ehp Jul 20 '14 at 16:03
  • Ah sorry, read your question wrong. I'll give this some thought. – Jay Jul 20 '14 at 16:09
  • What type of column are you using on your recipe table for preparation_time? If it's set to string, Rails won't auto-convert to integer. – Jay Jul 20 '14 at 16:21
  • It is set to time. What should I do to properly save the number of seconds it takes to prepare the recipe properly? – ehp Jul 20 '14 at 16:31
  • Thanks a lot for your interest BTW :) – ehp Jul 20 '14 at 16:31