small medium large xlarge

Generic-user-small
10 Oct 2017, 06:58
James West (104 posts)

On page 180 of the pdf eBook you define an enum called pay_type for the order model class I would expect this variable name to conflict with the pay_type field from the database orders table. When the validation is added for the pay_type field this enum is referenced as pay_types not pay_type on page 187 validates :pay_type, inclusion: pay_types.keys

I think a brief explanation around enums as to why there is no conflict and why when referenced you are referencing a pluralised version of the variable is warranted here.

Dmfcb_pragsmall
10 Oct 2017, 12:19
David Copeland (488 posts)

It’s that way on purpose—because we have a field called pay_type that is an integer, using enum tells Rails what the integers mean. This lets you assign pay_type human-readable values, but have them stored as an integer (formatted to point out the key things):

irb(main):005:0> Order.create!(name: "foo",
                            address: "123 any st",
                              email: "pat@example.com",
                           pay_type: "Credit card") # <-------------
 (0.1ms)  begin transaction
  SQL (0.8ms)  INSERT INTO "orders" ("name",
                                     "address",
                                     "email",
                                     "pay_type",
                                     "created_at",
                                     "updated_at")
               VALUES (?, ?, ?, ?, ?, ?) [
                 ["name"       , "foo"],
                 ["address"    , "123 any st"],
                 ["email"      , "pat@example.com"],
                 ["pay_type"   , 1], -- <---------------------
                 ["created_at" , "2017-10-10 12:16:27.881361"],
                 ["updated_at" , "2017-10-10 12:16:27.881361"]]
 (5.1ms)  commit transaction
=> #<Order id: 1, name: "foo", address: "123 any st", email: "pat@example.com", pay_type: "Credit card", created_at: "2017-10-10 12:16:27", updated_at: "2017-10-10 12:16:27">
Generic-user-small
10 Oct 2017, 13:56
James West (104 posts)

So if I had a text field called fred and a string variable called fred in the same model there would be no conflict?

Dmfcb_pragsmall
10 Oct 2017, 14:35
David Copeland (488 posts)

No. Your assumption that enum pay_type: is creating a field is wrong. That code tells rails that the existing field called pay_type should be treated specially.

If that enum code was missing, pay_type would still be a field on the model and return integers from the database. enum pay_type: ... tells rails to translate the values when reads and writes them.

Generic-user-small
10 Oct 2017, 18:49
James West (104 posts)

I think we are misunderstanding each other but forstly thank you for the information So, the way I read it is 1) ` enum pay_type: { “PayPal” => 0, “Cheque” => 1, “Credit card” => 2, “Purchase order” => 3 }` Is just a local variable of type enum. this local variable is used for selection and validation purposes right? In the same way a local variable of type integer or string or any other type might be declared? So why does this local variable called pay_type not conflict with the field name pay_type? Presumably the enum could be called wibble or anything you want it to be called so long as it is referenced as wibble right?

so validates :pay_type, inclusion: pay_types.keys could become validates :pay_type, inclusion: wibble.keys and a similar change needed in the order _form.html.erb right?

2) Why is the enum variable referenced as a plural and not it’s singular name in the validation etc..? I would have expected validates :pay_type, inclusion: pay_types.keys to be validates :pay_type, inclusion: pay_type.keys

So I’m suggesting that this naming potentially warrants a little explanation in the pdf as to why an enum is treated very differently to a normal local variable

I can conclude that the enum called PayType is overriding the field name which has only just clicked with me. Possibly I’m a little slow on the uptake but I’m sure a simple explanation would be very useful in the pdf

Hope that makes sense

Dmfcb_pragsmall
10 Oct 2017, 23:50
David Copeland (488 posts)

I totally agree that this section could benefit from a bit more explanation. In lieu of that (the book is in production and off to the printers), let me see if I can explain what’s going on:

enum pay_type: { ... }

is not declaring a variable. If you are coming to Ruby from another language, a lot of Rails looks weird because you can play fast and loose with the syntax.

What’s going on here is that enum is a method (in fact, a class method). Its argument is a hash:

def self.enum(args)
  # ...
end

In Java, this might be

public class Order extends ApplicationRecord {
  public static void enum(Map<Symbol,Map<String,Object>> args) {
    // ...
  }
}

So, a totally legal, but much more verbose way to use enum would be:

class Order < ApplicationRecord

  enum({ :pay_type => { "Credit card" => 0, "Check" => 1, "Purchase order" => 2}})

end

So, where does the pay_type method come from? If you didn’t call enum, Rails would declare that method for you and it would provide a pass-through of the value. You could imagine it like so:

def pay_type
  @pay_type
end

def pay_type=(new_pay_type)
  @pay_type = new_pay_type
end

Calling enum likely redefines these methods:

def pay_type
  { 
    "Credit card" => 0,
    "Check" => 1,
    "Purchase order" => 2
  }.select { |key,value|
    return key if @pay_type == value
  }
end

def pay_type=(new_pay_type)
  @pay_type = { 
    "Credit card" => 0,
    "Check" => 1,
    "Purchase order" => 2
  }[new_pay_type]
end

Not sure if that makes it make more sense.

You must be logged in to comment