在我的User类中获取`current_user`

时间:2009-11-15 21:41:43

标签: ruby-on-rails ruby

奇怪的是,大部分内容都是按照它编写的方式进行的,但是我不确定如何评估current_user是否有徽章,(所有的关系都是正确的,我只是遇到了麻烦)我的类中的方法(应该部分地移动到lib或其他东西),无论如何,问题特别是1)检查当前用户是否有记录,2)如果没有创建相应的新记录。

如果有更简单或更好的方法,请分享。以下是我所拥有的:

# Recipe Controller
class RecipesController < ApplicationController
  def create
  # do something
  if @recipe.save
    current_user.check_if_badges_earned(current_user)
  end
end

因此,它肯定看起来很混乱,我希望它只是check_if_badges_earned而不必将current_user传递给方法,但可能需要因为它可能不会始终是启动此方法的当前用户。

# User model
class User < ActiveRecord::Base

  def check_if_badges_earned(user)
    if user.recipes.count > 10
      award_badge(1, user)
    end
    if user.recipes.count > 20
      award_badge(2, user)
    end
  end

  def award_badge(badge_id, user)
    #see if user already has this badge, if not, give it to them!
    unless user.badgings.any? { |b| b[:badge_id] == badge_id}
      @badging = Badging.new(:badge_id => badge_id, :user_id => user)
      @badging.save
    end
  end

end

因此,虽然第一种方法(check_if_badges_earned)看起来很好,并且只在满足条件时才提供运行award_badge(),但问题发生在award_badge()方法本身的表达式{{ 1}}总是评估为真,所以即使用户已经拥有相同的徽章(通过badge_id),也会给予用户徽章,其次问题是它始终将unless user.badgings.any? { |b| b[:badge_id] == badge_id}保存为1。

关于如何进行调试的任何想法都会很棒!

2 个答案:

答案 0 :(得分:2)

无论您是否需要上述current_user行为,award_badge应该只是作用于self的常规实例方法,而不是对传递的user参数执行操作(相同)转到check_if_badges_earned)。在award_badge方法中,尝试find_or_create_by_...而不是您目前拥有的逻辑。例如,试试这个:

class User < ActiveRecord::Base
  # ...

  def award_badge(badge_id)
    badgings.find_or_create_by_badge_id(badge_id)
  end
end

要访问模型类中的current_user,我有时希望使用线程局部变量。它确实模糊了MVC的分离,但有时这种耦合在应用程序中是必需的。

在ApplicationController中,将current_user存储在线程局部变量中:

class ApplicationController < ActionController::Base
  before_filter :set_thread_locals

  private

  # Store thread-local variables so models can access them (Hackish, but useful)
  def set_thread_locals
    Thread.current[:current_user] = current_user
  end
end

向ActiveRecord模型添加一个新的类方法以返回current_user(您还可以扩展ActiveRecord :: Base以使其可用于所有模型):

class User < ActiveRecord::Base
  def self.current_user
    Thread.current[:current_user]
  end
end

然后,您将能够使用User访问self.class.current_user模型的实例方法中的当前用户。

答案 1 :(得分:1)

首先需要做的是使这些方法成为类方法(自我调用),这样可以避免不必要地传递用户引用。

然后,在您的award_badge方法中,您应该将徽章添加到用户的徽章列表中,例如:user.badgings << Badging.new(:badge_id => badge_id)