Ruby ROR Optimization Tips

gracezhangyaofei · 2020年12月16日 · 最后由 lithium4010 回复于 2020年12月18日 · 670 次阅读

案例背景

Model

  • 音乐 Music
  • 活动 Event
    • Event has_many users, Event has_many musics
    • User has_many musics
  • 人员 User
    • 对应 Event 的角色:[host, viewer]
    • 对应音乐的角色:[owner, participator]
    • 特殊权限的用户:[system_admin]

Policy Objects

用来处理 permissions, roles, and policies 的工具,需要处理比如某 object 是否有执行某 action 的权限,虽然很多 gem 已经做了类似的事情,比如 pundit, Cancan, and Cancancan,也是用了这个 pattern,但是还是有很多特殊场景,需要手动创建 policy 来满足需求。

需求

对 Music 有编辑权限的 3 种场景

  • event host: music belongs_to event
  • music owner: music belongs_to event && music owner belongs_to event
  • 有特殊权限的用户

实现

app/policies/musics_edition_policy.rb

class MusicsEditionPolicy
  attr_reader :event, :user, :music

  def initialize(event, user, music)
    @event = event
    @user = user
    @music = music
  end

  def edit?
    event_host? || music_owner? || special_guest?
  end

  private

  # implement your logic with each methods
  def event_host? ;end

  def music_owner? ;end

  def special_guest? ;end

end

分析

(why 适合用 policy objects 实现)

  • 涉及到多个 model 的关系
  • 判断 edit? 的地方比较多,也分布在 view/controller
  • condition 可能变化,不是一成不变

Presenter Pattern

把大量的判断逻辑放到 view 里面,一方面会让 view 很 heavy,另一方面会让测试很麻烦,可以把一些 view 上面臃肿的逻辑放到 presenter 里面,仅对 presenter 写单元测试也更聚焦。presenter 是很好的后台 model 和前端 view 的一个桥梁。(decorator 有类似的效果,略有不同,这个链接不错哦 Presenter VS Decorator

需求

用户自己 login 的导航/对外 music 的封面/用户管理页面,显示不同的用户名字

实现

app/presenters/user_presenter.rb

class UserPresenter < SimpleDelegator

  def display_name
  end

  def official_name_for_music
  end

  def official_name_for_admin
  end

end

分析

(why 适合用 presenter pattern 实现)

  • 用在 view 层面,并且很多地方适用
  • 有判断逻辑,比如:是否登陆还是站外,当前显示在 what 页面等
  • 不是一个简单的 helper 方法可以 hold 住

Query Objects

总有一些判断 query 条件是在很多地方用到,api v2/graphql/normal controller etc,

  • 放到 model 很 fat
  • 放到 service 里面让 service 本身的功能不聚焦,去做了查询的事
  • 放到 base controller 里面会出现不是所有场景都可以继承,有 duplicate code
  • 放到 concern 里面制作 query,确定合适么 query objects 就是来解决上面的问题。

需求

查询所有 current_user 有权限编辑的音乐

实现

app/queries/music_query.rb

class MusicQuery
  attr_reader :user

  def initialize(user:)
    @user = user
  end

  def editable ;end

  def active ;end

end

分析

(why 适合用 query objects 实现)

  • 同样 query 逻辑多处被使用
  • 放到其他的位置,单元测试需要考虑不同条件下返回的情况,使自己本身的使命不清楚
  • 参考此处开头位置

模型需求纯属自编自演,如有雷同个纯属巧合。ENDING!!!

policy 也可以用来写 scope

需要 登录 后方可回复, 如果你还没有账号请 注册新账号