实施数据网格 gem 和会话辅助方法

Implementing datagrid gem & session helper methods

我是一个尝试实现 datagrid gem (https://github.com/bogdan/datagrid) 的新手。不幸的是,我收到了三条错误消息:

Error 1: undefined method 'filter' for #<UsersGrid:0x000000044e9400>
Referring to: line `@grid.filter` in def index

Error 2: undefined local variable or method 'user' for #<UsersController:0x007f821f434808>
Referring to: line `link_to view_context.image_tag("delete.gif",...` in the controller.

Error 3: undefined method `image_tag' for UsersGrid:Class
Referring to: line `link_to image_tag(user.avatar.url,` in users_grid.rb
Placing `view_context` in front of link_to in users_grid.rb doesn't work either: undefined local variable or method 'view_context' for UsersGrid:Class.
Also tried `ActionController::Base.helpers.image_tag`. Although that seems to solve the image_tag issue, I then get the error message: `undefined method 'user_path' for #<ActionView::Base:0x007f821d3115b8>` referring to that same line.

删除上面的所有行,表格有效:-)

关于如何更改下面的代码以针对这些错误进行调整的任何建议?


我的代码: 安装后 gem 我创建了 /app/grids/users_grid.rb:

class UsersGrid
  include Datagrid

  scope do
    User.order("users.created_at desc")
  end

  filter(:id, :integer)
  filter(:email, :string) { |value| where('email like ?', "%#{value}%") }
  filter(:organization, :string) { |value| where('organization like ?', "%#{value}%") }
  filter(:verified, :xboolean)
  filter(:created_at, :date, :range => true, :default => proc { [1.month.ago.to_date, Date.today]})

  column(:id)
  column(:avatar) do |user|
    if user.avatar?
      link_to image_tag(user.avatar.url, alt: "Profile"), user_path(user)       #Error3
    else
      link_to image_tag("profile.gif", alt: "Profile"), user_path(user)
    end
  end
  column(:organization)
  column(:verified) do |user|
    image_tag("verifiedaccount.gif", title: "verified") if user.verified
  end
  column(:created_at) do |model|
    model.created_at.to_date
  end
end

用户控制器:

def index
  @grid = UsersGrid.new(params[:users_grid]) do |scope|
    scope.where(admin: false).page(params[:page]).per_page(30)
  end
  @grid.assets
  if (current_user && current_user.admin?)        # This is a Sessions helper method.
    @grid.filter(:activated, :xboolean, :default => true)                    #Error1
    @grid.column(:myadmin, :header => "My admin?") do |user|
      view_context.image_tag("adminamina.png", title: "admin") if user.myadmin
    end
    @grid.column(:activated) do |user|
      user.activated_at.strftime('%v') if user.activated
    end
    @grid.column(:remove) do |user|
      link_to view_context.image_tag("delete.gif", title: "remove"), user, method: :delete,
                                    data: { confirm: "Please confirm" }       #Error2
    end
  end
end

观点:

<%= datagrid_form_for @grid, :method => :get, :url => users_path %>
<%= will_paginate(@grid.assets) %>
<%= datagrid_table(@grid) %>
<%= will_paginate(@grid.assets) %>

这个 DataGrid 的设置似乎或多或少像一个模型 class,我认为这是一个重要的暗示,表明他们认真对待面向对象和封装:[=47= 的内部结构] 不会自动访问外部世界,您需要手动指定您需要的信息。

一种叫做 依赖注入 的技术在这里可能会有用,幸运的是 DataGrid 似乎对它有很好的支持。引自 this wiki page:

To pass an object to the Grid instance, simply merge it to the params hash on initialization:

grid = TheGrid.new(params[:the_grid].merge(current_user: current_user))

You can then access it in the Grid object by declaring the corresponding getter

def TheGrid
   ...
   attr_accessor :current_user
   ...
end

因此,当您 new 创建 UserGrid 对象时,将 current_user: current_user 指定为散列的一部分,那么网格应该可以访问它。

然后你会遇到另一个问题:UserGrid 对象将有权访问 current_user,但 UserGrid class 不会,并且您已经在 class 级别编写了条件。 wiki 再次对此有一个答案,它称为 dynamic columns,您可以单击 link 查看几个示例。

一个简短的动态列示例:在控制器(或您创建 UserGrid 的任何地方)中,尝试类似以下的操作(同样,上面的更多示例 link):

user_grid = UserGrid.new(same_params_as_before)

# The Grid object has been created, but we can still add columns to it after-the-fact
if current_user && current_user.admin?
  # This block will only execute if the above condition is met. We can
  # define as many extra columns as we feel like here (or change the 
  # user_grid object in any other way we want)
  user_grid.column(:myadmin, header: "My admin?") do |user|
    image_tag("adminamina.png", title: "admin") if user.myadmin
  end

  ...
end

关于这个例子的一些说明:

  • UserGrid 对象甚至不需要知道 current_user。它不在乎你是管理员;控制器只是决定您是否是管理员,如果是,则对 UserGrid 对象进行一些更改。
  • 因此,您可以删除 UserGrid class 中的 current_user 方法定义,以及引用它的所有代码。
  • 这是一个糟糕的面向对象编程的例子,因为控制器的任务是管理另一个对象的内部状态(即在某些特定的情况下手动在 UsersGrid 上定义更多列)状况)。我喜欢这种方法,因为它直接且更容易理解,但请注意,有更好的方法来组织此代码,以便所有 UserGrid“列定义内容”都保存在同一位置,而不是分散在不同的文件中。