【问题标题】:Rails index action with a WHERE clause带有 WHERE 子句的 Rails 索引操作
【发布时间】:2019-09-21 17:09:16
【问题描述】:

我正在尝试学习 Rails,所以我知道我可能会遗漏一些简单的概念。

我有一份员工名单,每个人都属于一个给定的项目。登录系统的用户只能查看/管理属于其项目的人员(用户也附加到给定项目)。这意味着我在 User 和 Staff 模型中都有 project_id。

我希望 current_user 只能查看他/她自己项目的记录。 我已经在 Michael Hartl 的书中实现了身份验证系统,因此我已经定义了一个 current_user 方法并且可以正常工作。

这是我的索引操作:

def index
@staffs = Staff.where("current_user.project_id = ?", 'staff.project_id') 
end

但是,我得到一个错误:

no such column: current_user.project_id

我没有想法。我该如何实现?

【问题讨论】:

  • 使用Staff.where("project_id = ?", current_user.project_id)
  • 行得通!谢谢你。我怎样才能把它变成一个全局的 before_action 方法来在每个控制器中使用它?
  • 您可以创建一个可以返回查询的辅助方法。然后辅助方法将在整个控制器及其对应的视图中可用
  • 我添加了一个示例来展示如何使用它来为 添加选项

标签: ruby-on-rails


【解决方案1】:

你想做的事:

def index
    @staffs = Staff.where(project_id: current_user.project_id)
end

这将执行 sql 代码 select … from staff where staff.project_id = 123;,假设 current_user.project_id 的值为 123。发生这种情况是因为 where 方法负责将您提供的键 (project_id) 映射到值(current_user 的值)。 project_id)。

来自 where 方法的 sql 将是 select … from staff where current_user.project_id = "staff.project_id";。数据库列应该是 where 方法的第一部分,值是第二部分。

您可以将其添加到您的基本控制器 (ApplicationController) 以使其在任何地方都可用,例如:

class ApplicationController < ActionController::Base
    before_action :current_staff

    def index
    end

    def current_staff
        @staffs = Staff.where(project_id: current_user.project_id) if current_user # make sure user is signed in
    end
end

如果你想在选择中使用它,你可以添加一个这样的辅助方法:

module ApplicationHelper
    def options_for_staff_projects_select(selected = nil)
        project_ids = @staffs.collect(:project_id) # get list of project ids from staff
        options = Project.where(id: project_ids).map { |x| [x.name, x.id] }

        options_for_select options, selected
    end
end

# in your form call:
<%= f.select :project_id, options_for_staff_projects_select(model.project_id), include_blank: 'Choose Project' %>

【讨论】:

  • 也非常感谢@jonathan-bennet
  • 嗨,关于实现的一个问题:index 操作现在在current_staff 方法中实现后会变成什么?我应该恢复到@staffs=Staff.all吗?
  • 更新了答案。 index 操作仍然需要存在才能正常工作,但除非您在以后做更多工作,否则它将是空的。
【解决方案2】:
Staff.where("current_user.project_id = ?", 'staff.project_id')

这里current_user.project_id 不是人员模型的列。在活动记录中where 期望第一个参数是给定模型的列名。所以这里的模型是Staff,你必须检查的列名是project_id,条件值是current_user.project_id所以你必须使用如下条件。

Staff.where("project_id = ?", current_user.project_id)

【讨论】:

  • 非常感谢。我学到了很多东西。我可以在staffs/new 页面中将其进一步级联到collection_select,以仅列出与current_user 关联的项目吗?我正在尝试类似:&lt;%= form.select :project_id, options_for_select([["Choose Project", "0"]] + Project.all.collect {|x| [x.name, x.id] if Project.find_by_id(x.id) == current_user.project_id }), {}%&gt;。我只是得到一个空白选项
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-01
  • 1970-01-01
  • 2010-10-09
  • 1970-01-01
  • 1970-01-01
  • 2011-10-14
相关资源
最近更新 更多