lazybios

Rails: 通过模型中添加Vitrual Attribute精简控制层代码

最近在看Rails Best Practices网站上的文章,虽然文章发布的时间比较久远(最后一篇是4年前发布的),但里面仍然有大把干货,打算把他们逐个过一遍,顺道会在这里翻译记录一下,有兴趣的同学可以持续关注哈。

坏味道的代码

视图层
<% form_for @user do |f| %>
  <%= text_field_tag :full_name %>
<% end %>
控制器层
class UsersController < ApplicationController
  def create
    @user = User.new(params[:user])
    @user.first_name = params([:full_name]).split(' ', 2).first
    @user.last_name = params([:full_name]).split(' ', 2).last
    @user.save
  end
end

上面代码实现的功能是从视图中的表单提交一个full_name字段,在控制层中再手动把它分成first_namelast_name两部分最后再保存到user模型中。

重构

但是给Model赋值并不应该是Contoller的职责,正确的做法应该是在Model一层来实现这个功能。

模型层
class User < ActiveRecord::Base
  def full_name
    [first_name, last_name]. compact.join(" ").strip
  end

  def full_name=(name)
    split = name.split(' ', 2)
    self.first_name = split.first
    self.last_name = split.last
  end
end
视图层
<% form_for @user do |f| %>
  <%= f.text_field :full_name %>
<% end %>
控制层
class UsersController < ApplicationController
  def create
    @user = User.create(params[:user])
  end
end

视图层依然没有,变化最大的是模型层和控制层,模型中通过添加一个虚拟的属性full_name=,来为first_namelast_name赋值,如此一来,我们可以直接像create传入带full_name字段的参数,复杂的数据相关逻辑全部丢给了Model来做。

上面的做法其实是要达到一种「fat model, skinny controller」 的效果,除了通过添加虚拟属性的方式之外,还可以借助attr_accesstor+callback的方式来实现这一效果,如下代码

控制层
class User < ActiveRecord::Base
  attr_accessor  :full_name
  before_save : split_full_name

  private
  def split_full_name
    self.first_name, self.last_name = full_name.splite(" ")
  end
end

参考引用

-完-

微信关注「日拱一卒」公众号