The problem is this: the original code. The Html.erb page has a SELECT element with each item corresponding to the class constant in the model:
<%= f.select:p ay_type,order::P ayment_types,prompt: ' Select a PAYMENT method '%>
The constants in the class are defined as follows:
Class Order < activerecord::base payment_types = ["Check", "Credit card", "Purchase Order"]end
Now I want to reconstruct the payment_types to the table in the database, so we have a tentative first step, first create a model as follows:
Rails g model Payment_types type:string
Rake Db:migrate
The second step is to write a script to import the constants into the table:
Paymenttype.transaction do Order::P ayment_types.each do |type| Paymenttype.create (type:type) endend
But there was an error running rails runner script/load_payment_types.rb, as follows:
/var/lib/gems/2.1.0/gems/activerecord-4.2.0/lib/active_record/inheritance.rb:215:in ' subclass_from_attributes ': Invalid single-table inheritance Type:check is not a subclass of Paymenttype (Activerecord::subclassnotfound)
After confirming that there is no syntax error, it is possible that the type name and a method or property in the frame are in conflict, so that only the name is changed:
Rails g Migration Rename_type_to_payment_types
Modify the name of the type in the. rb file that is generated in the Migrate directory:
Class Renametypetopaymenttypes < activerecord::migration def change rename_column:p ayment_types,:type,: Pay_type EndEnd
Then rake db:migrate, and then modify the code in the LOAD_PAYMENT_TYPES.RB to conform to the changes:
Paymenttype.transaction do paymenttype.delete_all Order::P ayment_types.each do |type| Paymenttype.create (pay_type:type) endend
Then execute Rails runner script/load_payment_types.rb, then there's no problem:), the third step is to modify the new method in the controller, adding the following line:
@payment_types = PaymentType.all.map {|type|type.pay_type}
The fourth step is to modify the code in the. Html.erb as follows:
<%= f.select:p Ay_type, @payment_types, prompt: ' Select a payment method '%>
Fifth step don't forget to modify the model's validation code:
Class Order < ActiveRecord::Base Validates:name,:address,:email,:p ay_type,presence:true #validates:p ay _type,inclusion:payment_types validates:p ay_type,inclusion:paymenttype.all.map {|type|type.pay_type}end
Running it seems to be no problem. But wait! If New.html.erb all blank to submit the order, it will report an error, indicating that nil object does not have empty? Method! Think about it a little bit. The validation method of the order class is called when the Order.save is left blank, so the validation fails, the Save method will fail, and the render will be re-new.html.erb, but then the value of @payment_types does not exist. So in the Create method, add the new method to the sentence!
What about the horse? There are so many @payment_types in the code that violate the dry principle! We can consider putting it in the class variable of the order controller, but consider if the Pay_ in the database Types has the problem of modifying how to react to class variables in a timely manner. For simplicity's sake, the pay_type in the Payment_types table is rarely modified, and if modified can restart the Rails server to apply the changes, it can be further refactored:
First, class variables and class variable properties are added to the order controller:
Class Orderscontroller < Applicationcontroller @ @payment_types = PaymentType.all.map {|type|type.pay_type} def self.payment_types @ @payment_types endend
Then make the following changes in the New.html.erb and order model
#in new.html.erb<%= f.select:p ay_type,orderscontroller.payment_types,prompt: ' Select a payment method '%> #in Order.rbvalidates:p Ay_type,inclusion:orderscontroller.payment_types
At this time the original new and create variables @payment_types can delete the bird. This refactoring is over! :
Rails reconstructs class constants into tables corresponding to the database