我们在新的分支上进行开发
git checkout -b second/delegate
git branch
master
* second/delegate
rails g migration CreateProductInfoes
商品补充信息表 | product_infoes |
---|---|
添加模型文件
填充数据
案例应用delegate
为products表添加外键
rails g migration AddProductInfoIdToProducts
rake db:migrate
填充数据
使用场景
最常见的是我们通过product.product_info.Weight访问关联表的数据。如果我们想要product.Weight的方式来得到关联表的数据就可以使用delegate方法。然后我们product.Weight访问的时候,它就会自动去查找关联的product_info.Weight。
添加belongs_to :product_info(必须添加,下面会讲原因)和delegate
添加路由
添加动作
#second
def delegate
@products = Product.limit(3)
end
添加视图文件
页面效果
控制台输出
delegate原理
上面我们访问Weight的原理其实很简单,就是我们自定义一个方法返回关联表的Weight字段。我们以PreSaleAmount为例子,product.PreSaleAmount其实不是访问product模型的PreSaleAmount字段,而是调用模型的PreSaleAmount方法
因为PreSaleAmount方法中需要访问关联表,所以我们必须添加模型关联belongs_to :product_info,这也就是我们前面说的delegate必须确保有belongs_to的理由
如上products表中ProductInfoID为info22的记录访问不到关联的数据表数据,所以返回PreSaleAmount为0
delegate的原理就是如上定义方法返回关联表的字段,product.Weight实际上是调用product模型的Weight方法。只不过这是rails提供的接口,我们就不需要为每个字段定义这样的方法。
我们自定义的PreSaleAmount处理了关联表数据不存在的特殊情况,但是delegate则没有处理这类异常,如下ProductInfoID为info22的记录访问不到关联的数据表数据,所以访问Weight字段值报错
既然delegate接口没有处理异常,那么我们可以在视图文件中添加判断语句
delegate方法优先级高于模型字段,如果我们在delegate中添加了Price,那么我们product.Price时,就不会访问products表的Price字段,而是访问product_infoes表的Price字段。
使用includes解决n+1问题
控制台输出:
我们可以使用includes
def delegate
@products = Product.includes(:product_info).limit(3)
end
使用includes之后控制台输出信息
提交到git仓库
git add .
git commit -m "delegate原理与使用"
git push -u https://github.com/xiaohuacc/active_record.git second/delegate
然后我们在git仓库就可以看到新提交的分支了
然后我们返回主分支,把这次分支的修改合并到主分支
git checkout master
git merge second/delegate
Updating bf2bd5a..6dd2565
Fast-forward
.idea/workspace.xml | 179 ++++++++++++++++++++++++++++----------
app/controllers/products_controller.rb | 5 ++
app/models/product.rb | 10 +++
app/models/product_info.rb | 3 +
app/views/products/delegate.html.erb | 5 ++
config/routes.rb | 6 +-
db/migrate/20161127081543_create_product_infoes.rb | 11 +++
db/migrate/20161127095910_add_product_info_id_to_products.rb | 5 ++
db/schema.rb | 24 +++--
9 files changed, 193 insertions(+), 55 deletions(-)
create mode 100644 app/models/product_info.rb
create mode 100644 app/views/products/delegate.html.erb
create mode 100644 db/migrate/20161127081543_create_product_infoes.rb
create mode 100644 db/migrate/20161127095910_add_product_info_id_to_products.rb