【问题标题】:Refactoring code inside a Ruby Proc in a rails_admin custom action在 rails_admin 自定义操作中重构 Ruby Proc 中的代码
【发布时间】:2014-09-05 22:59:32
【问题描述】:

一点背景:

我的应用程序有tools,其中有permission_levels。有User 对某些tools 具有授权,而对其他则没有。管理面板是使用rails_admin gem 构建的。

如果管理员正在编辑User,并且User 有权访问管理员没有的tools,则这些工具不会显示在编辑视图中(这是需要的)。但是,当管理员更新 User 时,User 会丢失与未显示的 toolspermission_levels 的关联。

为了解决这个问题,我覆盖了 RailsAdmin 中的 #edit 操作。生成的代码有点乱,我想通过将相关代码提取到方法中来进行重构,但该部分被包裹在 Proc 中。

如何将下面的代码提取到方法中?具体来说,register_instance_option :controller 部分。

.
.
.
module Actions
  class Edit < RailsAdmin::Config::Actions::Base

    register_instance_option :member? do
      true
    end

    register_instance_option :route_fragment do
      'edit'
    end

    register_instance_option :http_methods do
      [:get, :put]
    end

    register_instance_option :visible? do
      authorized?
    end

    register_instance_option :controller do
      Proc.new do
        if @object.class.base_class.name == 'User'
          if request.get?
            session[:tools] = (@object.tools - Tool.admined_by(current_user)).map(&:id)
            pl = session[:tools].map do |t|
              tl = Tool.find(t)
              tl.permission_levels
            end
            session[:permission_levels] = []
            pl.flatten.each do |p|
              session[:permission_levels] << p if @object.permission_levels.include?(p)
            end
            session[:permission_levels].map!(&:id)
          elsif request.put?
            duped_tools = session[:tools].dup
            params[:user][:tool_ids] = duped_tools.
              concat(params[:user][:tool_ids]).uniq!.delete_if { |id| id == "" }.
              map { |id| id.to_i }
            duped_permission_levels = session[:permission_levels].dup
            params[:user][:permission_level_ids] = duped_permission_levels.
              concat(params[:user][:permission_level_ids]).uniq!.delete_if { |id| id == "" }.
              map { |id| id.to_i }
            if @object.update_attributes(params.require(:user).permit!)
              session[:tools] = nil
              session[:permission_levels] = nil
              duped_session = nil
              flash[:success] = t("admin.flash.successful", :name => @model_config.label, :action => t("admin.actions.edit.done"))
              redirect_to index_path
            else
              flash[:error] = t("admin.flash.error", :name => @model_config.label, :action => t("admin.actions.edit.done"))
              redirect_path = back_or_index
            end
          end
        end
      end
    end

    register_instance_option :link_icon do
      'icon-pencil'
    end
  end
end
.
.
.

【问题讨论】:

    标签: ruby-on-rails ruby ruby-on-rails-4 rails-admin ruby-2.1


    【解决方案1】:

    为了使用更少的行数和可能更好的性能,这里有一些代码改进:

    使用更少的行数:

    # All `register_instance_option` can be refactored in a one-line bock:
    register_instance_option :member? do
      true
    end
    # to
    register_instance_option(:member?) { true }
    

    更好地使用 Rails 的方法:

    if @object.class.base_class.name == 'User'
    # can be changed to:
    if @object.kind_of?(User) # will not work if @object is a Admin which inherits from User class
    
    array_of_ids.delete_if { |id| id == "" }
    # can be changed to:
    array_of_ids.select(&:present?)
    
    array = session[:tools].map do
      # your logic
    end
    array = array.flatten
    # can be changed to:
    array = session[:tools].flat_map do
      # your logic
    end
    # no need for a flatten (thanks to `.flat_map`)
    
    session[:tools] = nil
    session[:permission_levels] = nil
    duped_session = nil
    # can be changed to:
    session[:tools] = session[:permission_levels] = duped_session = nil
    

    我会将您的代码重构为:(请随意评论)

    if @object.kind_of?(User)
      if request.get?
        session[:tools] = @object.tools.where('id NOT IN (?)', Tool.admined_by(current_user).pluck(:id)) # better performances
        session[:tools] = session[:tools].includes(:permission_levels).flat_map(&:permission_levels)
        session[:permission_levels] = []
        session[:tools].each do |p|
          session[:permission_levels] << p.id if @object.permission_levels.include?(p)
        end
    
      elsif request.put?
        duped_tools = session[:tools].dup
        params[:user][:tool_ids] = duped_tools.concat(params[:user][:tool_ids]).uniq.select(&:present?).map(&:to_i)
        duped_permission_levels = session[:permission_levels].dup
        params[:user][:permission_level_ids] = duped_permission_levels.concat(params[:user][:permission_level_ids]).uniq.select(&:present?).map(&:to_i)
        if @object.update_attributes(params.require(:user).permit!)
          session[:tools] = session[:permission_levels] = nil
          flash[:success] = t("admin.flash.successful", name: @model_config.label, name: t("admin.actions.edit.done"))
          redirect_to index_path
        else
          flash[:error] = t("admin.flash.error", name: @model_config.label, action: t("admin.actions.edit.done"))
          redirect_path = back_or_index
        end
      end
    end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-10
      • 1970-01-01
      • 2023-04-04
      • 1970-01-01
      • 2010-09-07
      • 1970-01-01
      相关资源
      最近更新 更多