【问题标题】:Rails Devise - How to add more data to current_userRails Devise - 如何向 current_user 添加更多数据
【发布时间】:2015-09-16 00:21:25
【问题描述】:

假设我有一个用户模型

user.rb

class User < ActiveRecord::Base
    ...
end

具有如下属性:名称、用户名、访问权限

access 是一个枚举,它告诉我用户是“员工”还是“客户”

要获取登录用户的姓名和用户名,我可以这样做:

current_user.name
current_user.username

假设我有一个 Staff 模型

staff.rb

class Staff < ActiveRecord::Base
    belongs_to :user
end

具有如下属性:薪水、电话号码

我还有一个客户模型

customer.rb

class Customer < ActiveRecord::Base
    belongs_to :user
end

具有如下属性:地址、电话号码


我希望能够在我员工的控制器上调用它:

current_user.staff.salary

这在我客户的控制器上:

current_user.customer.address

到目前为止我做了什么

我覆盖了 session_controller.rb

def create
  super
  model_name = current_user.access.capitalize.constantize
  spec = model_name.where(user_id: current_user.id).take
  session[:spec] = spec
end

所以我可以通过 session[:spec] 访问它,但不能通过 current_user。有什么想法吗?

【问题讨论】:

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


    【解决方案1】:

    首先,您的用户模型应该引用员工或客户,即使他们保持空白

    class User
    
      has_one :staff
      has_one :address
    

    只要这样做,您应该可以使用current_user.customer.address。不过……

    我建议你在 ApplicationController 或你包含的模块中添加一些方便的方法

    def staff_signed_in?
      @staff_signed_in ||= (user_signed_in? and current_user.access == :staff)
    end
    
    def current_staff
      @current_staff ||= (current_user.staff if staff_logged_in?)
    end
    
    # same for customer
    # Note that I use instance variables so any database queries are executed only once !
    

    那么你可以简单地调用

    <% if customer_signed_in? %>
      <h2>Logged in as customer</h2>
      <p>Address : <%= current_customer.address %>
    <% end %>
    

    编辑:关于您对数据库命中的担忧

    你举了 current_user.customer.cart.products 的例子

    这确实是一个相当嵌套的关联。我上面的建议已经将它降低了一个级别(即 current_customer == current_user.customer)。然后你必须通过购物车才能到达产品......在我看来这还不错。 如果您需要经常调用 (current_customercustomer.cart),您可以覆盖给定控制器的 current_customer 并立即加载您知道您将使用的资源。

    def UserShopController < ApplicationController
    # Let's assume current_customer is defined in ApplicationController like I showed above
    # UserShopController always uses the customer cart, so let's load it right at the beginning
    ...
    
    private
        # Override with eager loading
        def current_customer
          @current_customer ||= (current_user.customer.includes(:cart) if customer_logged_in?)
        end
    

    【讨论】:

    • 您向我展示了如何访问 current_customer.address。我还没试过。有没有办法像 current_user.customer.address 这样访问?
    • 只要添加has_one 语句,current_user.customer.address 也应该可以工作
    • 成功了!谢谢!不过,我想知道,你为什么提出这个建议。也许您说的是共享视图的情况?
    • 我正在使用一个类似的系统,用户可以同时以管理员、承包商、客户的身份登录。然后例如,在我看来,我只想向管理员显示“管理员”菜单,所以我使用了很多帮助程序,例如 administrator_signed_in? 而不是 user_signed_in? and user.administrator?,就像我给出的最后一个示例一样。
    • 查看我的编辑,你也可以谷歌“eager loading in rails”,你应该会发现有趣的结果。
    【解决方案2】:

    has_one :customer 添加到您的user.rb

    您的用户模型应如下所示以访问相关模型。

    class User < ActiveRecord::Base
        has_one :customer
    end
    

    【讨论】:

      猜你喜欢
      • 2013-08-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多