【问题标题】:Implementing datagrid gem & session helper methods实现数据网格 gem 和会话助手方法
【发布时间】:2015-08-07 02:12:59
【问题描述】:

我是一个尝试实现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) %>

【问题讨论】:

    标签: ruby-on-rails ruby ruby-on-rails-4 datagrid


    【解决方案1】:

    这个 DataGrid 的设置似乎或多或少像一个 Model 类,我认为这是一个重要的暗示,表明他们对面向对象和封装很认真:类的内部不会自动访问外部世界,你需要手动指定你需要的信息。

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

    要将对象传递给 Grid 实例,只需在初始化时将其合并到 params 哈希:

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

    然后你可以通过声明相应的getter在Grid对象中访问它

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

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

    那么您将遇到另一个问题:UserGrid 对象可以访问current_user,但 UserGrid class 不能,并且您已经在类级别编写了条件. wiki 对此再次给出了答案,它被称为 dynamic columns,您可以单击该链接查看几个示例。

    一个简短的动态列示例:在控制器(或您创建 UserGrid 的任何位置)中,尝试以下操作(同样,以上链接中的更多示例):

    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 类中的 current_user 方法定义,以及引用它的所有代码。
    • 这是糟糕的面向对象编程的示例,因为控制器的任务是管理另一个对象的内部状态(即,在特定条件下手动在 UsersGrid 上定义更多列)。我喜欢这种方法,因为它直接且更易于理解,但请注意,有更好的方法来组织此代码,以便所有 UserGrid“列定义内容”都保存在同一个位置,而不是分散在不同的文件中。李>

    【讨论】:

    • 谢谢,这对我来说真的是高级的东西。我已将 def current_user 添加到 users_grid.rb 和 .merge 到用户控制器中的参数。将其添加到原始帖子中。我不太确定如何调整 users_grid.rb 的列部分(即如何实现动态列,如您所建议的)。因此,错误消息仍然相同。
    • 没问题,我上面加了一个例子。
    • 欣赏!我更新了原帖。删除了 def current_user 和新参数。将依赖于 current_user 的过滤器和列移至控制器。我收到一条新的错误消息(请参阅原始帖子)。
    • 啊,image_tag 的事情是因为通常不希望控制器使用视图助手。请参阅this other StackOverflow answer,尤其是您可能需要说view_context.image_tag(...) 而不仅仅是image_tag()
    • 谢谢托弗。这有帮助。用恐怕三个新的错误更新了原来的帖子。
    猜你喜欢
    • 1970-01-01
    • 2014-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-25
    • 2011-01-24
    相关资源
    最近更新 更多