rails-tips

##Hash#dig ruby 2.3 中引入了dig方法: 通过在每个步骤调用dig从给定key中提取嵌套参数。如果中间步骤为nil,则返回nil ❌:

... if params[:user] && params[:user][:address] && params[:user][:address][:somewhere_deep]

✔️:

... if params.dig(:user, :address, :somewhere_deep)

Object#presence_in

如果接收方包含在参数中,则返回接收方,否则返回nil。参数必须是响应#include?的任何对象。 ❌:

sort_options = [:by_date, :by_title, :by_author]
...
sort = sort_options.include?(params[:sort])
  ? params[:sort]
  : :by_date
# Another option
sort = (sort_options.include?(params[:sort]) && params[:sort]) || :by_date

✔️:

params[:sort].presence_in(sort_options) || :by_date

crush

class Object
  def crush
    self
  end
end

class Array
  def crush
    r = map(&:crush).compact

    r.empty? ? nil : r
  end
end

class Hash
  def crush
    r = each_with_object({}) do |(k, v), h|
      if (_v = v.crush)
        h[k] = _v
      end
    end

    r.empty? ? nil : r
  end
end

preload scope

错误的案例:

class Comment < ActiveRecord::Base
  belongs_to :post

  scope :active, -> { where(soft_deleted: false) }
end
class Post < ActiveRecord::Base
  def active_comments
    comments.active
  end
end

这样势必会造成post.active_comments的时候会where,导致N+1 正确的案例:

class Post
  has_many :comments
  has_many :active_comments, -> { active }, class_name: "Comment"
end

class Comment
  belongs_to :post
  scope :active, -> { where(soft_deleted: false) }
end

class PostsController
  def index
    @posts = Post.includes(:active_comments)
  end
end