问题是这样:原来代码.html.erb页面中有一个select元素,其每个item对应的是model中的类常量:

<%= f.select :pay_type,Order::PAYMENT_TYPES,prompt:'Select a payment method' %>

类中的常量定义如下:

class Order < ActiveRecord::Base
  PAYMENT_TYPES = ["Check","Credit card","Purchase order"]
end

现在想把PAYMENT_TYPES重构至数据库中的表里去,于是有了尝试性的第一步,首先创建一个model如下:

rails g model payment_types type:string

rake db:migrate

第二步是写一个脚本将常量导入至表中:

PaymentType.transaction do
  Order::PAYMENT_TYPES.each do |type|
    PaymentType.create(type:type)
  end
end

但是运行rails runner script/load_payment_types.rb时出错了,提示如下:

/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)

确认没有语法上的错误后推测,可能type名称和框架中某个方法或属性冲突了,这样只有更改该名称了:

rails g migration rename_type_to_payment_types

在migrate目录中生成的.rb文件中修改type的名称:

class RenameTypeToPaymentTypes < ActiveRecord::Migration
  def change
    rename_column :payment_types,:type,:pay_type
  end
end

然后rake db:migrate,接下来再修改load_payment_types.rb中的代码以顺应更改:

PaymentType.transaction do
  PaymentType.delete_all
  Order::PAYMENT_TYPES.each do |type|
    PaymentType.create(pay_type:type)
  end
end

接着再执行rails runner script/load_payment_types.rb,这时没有问题了:) ,第三步是修改控制器中的new方法,添加以下一行:

    @payment_types = PaymentType.all.map {|type|type.pay_type}

第四步是修改.html.erb中的代码如下:

<%= f.select :pay_type,@payment_types,prompt:'Select a payment method' %>

第五步别忘了修改model的验证代码:

class Order < ActiveRecord::Base
  validates :name,:address,:email,:pay_type,presence:true
  #validates :pay_type,inclusion:PAYMENT_TYPES
  validates :pay_type,inclusion:PaymentType.all.map {|type|type.pay_type}
end

运行一下貌似没有问题.可是等等!如果new.html.erb全部留空提交订单,则会报错,提示nil对象没有empty?方法!稍微想一下可知,提交订单会转至Order#create方法,在order.save时会调用Order类的验证方法,因为前面留空,所以验证失败,save方法会出错;这时会重新render到new.html.erb中去,但这时@payment_types不存在其值当然为空喽!于是乎在create方法中也加上new方法中的那一句吧!

还有神马呢?代码中有这么多@payment_types的重复,违反了DRY原则哦!我们可以考虑将其放到Order控制器的类变量中去,不过这还要考虑如果数据库中的pay_types有修改怎么及时反应到类变量中去的问题.我们简单起见,payment_types表中的pay_type很少修改,如果修改可以重启rails服务器来应用变更;于是可以进一步重构:

首先在Order控制器中加入类变量以及类变量属性:

class OrdersController < ApplicationController
  @@payment_types = PaymentType.all.map {|type|type.pay_type}

  def self.payment_types
    @@payment_types
  end
end

然后在new.html.erb和Order model中做如下修改

#in new.html.erb
<%= f.select :pay_type,OrdersController.payment_types,prompt:'Select a payment method' %>

#in Order.rb
validates :pay_type,inclusion:OrdersController.payment_types

这时原先new和create中的变量@payment_types都可以删掉鸟.至此重构告一段落! :

rails将类常量重构到数据库对应的表中之一的更多相关文章

  1. rails将类常量重构到数据库对应的表中之二

    在博文之一中我们将Order中的常量重构到了数据库的表中,也做了一些测试,貌似一切都很完美.可是...梦魔还未开始啊!我们少做了一步测试,就是rake test! 结果惨不忍睹,所有测试都是E,全部出 ...

  2. rails将类常量重构到数据库对应的表中之三

    经过博文之一和之二的重构,貌似代码表现的还不错,正常运行和test都通过鸟,但是,感觉告诉我们还是有什么地方不对劲啊!究竟是哪里不对劲呢?我们再来好好看一下. 我们把数据库表中的支付方式集合直接放在实 ...

  3. rails将类常量重构到数据库对应的表之后记

    怎么还有啊!别急,有强迫症的人伤不起!有点小事没说完感觉痒痒的:就是如果表payment_types经常变动该怎么办?每次都要关闭rails网页服务器,然后重启吗?那也太麻烦鸟,最终的解决方案是,在O ...

  4. 【Java/JDBC】利用ResultSetMetaData从数据库的某表中获取字段信息并存到csv文件

    代码下载:https://files.cnblogs.com/files/xiandedanteng/FindNotnullColumns20191102-2.rar 这篇还不够完善,请看更完善的续篇 ...

  5. iOS-查询数据库-->指定数据表中的当前数据行的总数量

    很多时候,我们在查询一个表的时候,不想得到里面的记录内容,只是想简单的得到符合查询条件的记录条数. FMDB中有一个很简单的方法就可以实现,见下面的代码实例: #import "FMdata ...

  6. Mysql 导出数据库和指定表中的数据

    参考地址:http://jingyan.baidu.com/article/b7001fe14240ab0e7282dde9.html [root@youo zw]# mysqldump -u roo ...

  7. 4.mysql数据库创建,表中创建模具模板脚本,mysql_SQL99标准连接查询(恩,外部连接,全外连接,交叉连接)

     mysql数据库创建,表创建模等模板脚本 -- 用root用户登录系统,运行脚本 -- 创建数据库 create database mydb61 character set utf8 ; -- ...

  8. 用SQL语句将远程SQL Server数据库中表数据导入到本地数据库相应的表中

    一.方法一 访问不同电脑上的数据库(远程访问,只好联好网就一样),如果经常访问或数据量较大,建议用链接服务器方法. 1.创建链接服务器 exec sp_addlinkedserver ‘srv_lnk ...

  9. 修改MySQL数据库中表和表中字段的编码方式的方法

    今天向MySQL数据库中的一张表添加含有中文的数据,可是老是出异常,检查程序并没有发现错误,无奈呀,后来重新检查这张表发现表的编码方式为latin1并且原想可以插入中文的字段的编码方式也是latin1 ...

随机推荐

  1. 如何将Provisioning Profile安装到开发的Mac系统上

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交 ...

  2. 关于在eclipse开发环境上打开手机data文件

    使用Eclipse开发Android上的数据库应用,需要把数据库文件放到/data/data/mynamespace/database文件夹下,普通手机通过ROOT后经常还是看不到这个文件夹,这时需要 ...

  3. 内存管理单元--MMU

    现代操作系统普遍采用虚拟内存管理(Virtual Memory Management)机制,这需要处理器中的MMU(Memory Management Unit,内存管理单元)提供支持,本节简要介绍M ...

  4. iOS让软键盘消失的简单方法

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 一些文本输入控件等待输入时会弹出软键盘,我们可以设置这些控件的 ...

  5. Java并发框架——公平性

    所谓公平性指所有线程对临界资源申请访问权限的成功率都一样,不会让某些线程拥有优先权.通过前面的CLH Node FIFO学习知道了等待队列是一个先进先出的队列,那么是否就可以说每条线程获取锁时就是公平 ...

  6. android 使用Vysor投影到电脑

    有没有好的投影软件可以将android屏幕投影到电脑,当然这种很多,比如360就自带了投影功能,小米盒子也可以(不过貌似只能支持到4.4版本),今天要说的是Vysor,google的一款投影软件. V ...

  7. Hibernate超简单多表操作

    所谓一对多映射 在数据库中我们通常会通过添加外键的方式将表关联起来,表现一对多的关系. 而在Hibernate中,我们则要通过在一方持有多方的集合来实现,即在"一"的一端中使用元素 ...

  8. Cocos2D iOS之旅:如何写一个敲地鼠游戏(七):弹出地鼠

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交流 ...

  9. python访问redis

    python访问redis 1 Linux上安装redis a) 下载 $ wget http://download.redis.io/releases/redis-3.0.5.tar.gz b) 编 ...

  10. Android绘图基础Paint和Canvas介绍-android学习之旅(六十一)

    canvas介绍 Paint类介绍 代码示例 效果图