模型方法取决于rails中的current_user

时间:2013-08-30 11:35:52

标签: ruby-on-rails ruby

在我的rails应用程序中,我有一些用户可以支付的事件。我需要能够根据当前用户更改事件价格。

*我知道有很多关于在模型中访问current_user的主题,但它不是我想要的。*

我有以下2个型号(非常简化)。 Checkout正在管理与事件相关的所有付款事项(我在单独的模型中需要它,就像真实应用程序中它与事件具有多态关联一样)。

class Event < ActiveRecord::Base
  attr_accessible :ticket_price, :checkout
  has_one :checkout

  checkout_price
    # Here I'd like to be able to use the current_user to change price accordingly
    # Example: user.premium? ? ticket_price/2 : ticket_price
    ticket_price
  end
end

class Checkout < ActiveRecord::Base
  attr_accessible :event
  belongs_to :event

  def total
    event.checkout_price
  end

  def free?
    total == 0
  end
end

我显然可以定义checkout_price(user),但我必须在每个地方传递它(例如event.checkout_price(current_user)checkout.total(current_user)checkout.free?(current_user))。

我知道从模型中访问current_user是一种不好的做法(我绝对不想这样做)但是在我的情况下还有另一种解决方案,而不是将current_user作为参数传递一直都在吗?

3 个答案:

答案 0 :(得分:3)

这是一个很好的问题,感谢您对不访问模型中的current_user的看法。

实际上,事件模型应该考虑更少。模型的主要工作是存储与自身相关的数据和过程数据。定价是您的业务逻辑,而不是事件模型的关注点。活动有价格。就这样。不再。

请注意,您在定价方面需要考虑很多事项。不仅用户是否是优质的。如果用户在您的应用中使用了6个月,那么折扣怎么样?在应用程序生日那天推广怎么样?因为你喝醉了,买卖怎么样?如果您使用事件模型来处理它们,那么所有这些都将非常复杂。即使您现在不需要所有这些功能,最好留出一些扩展空间。

那么在哪里应该考虑定价逻辑?显然,控制器也不是一个好地方。我们来试试服务对象。

class PricingService

  def initialize(event, user)
    @user = user
    @event = event
    @price = event.price
  end

  def get_price
    # The place for your easily adding rules. Or use some meta programming.
    # say go through all instance methods starting with "pricing_"
    pricing_premium_user
    pricing_app_birthday
    pricing_old_event
    @price
  end

  def pricing_premium_user
    @price -= 10 if user.premium?
  end

  def pricing_app_birthday
    @price = @price*0.9 if Time.current.today == APP_BIRTHDAY
  end

  def pricing_old_event
    @price = @price*0.9 if event.created_at < (Time.current - 1.week)
  end

end

然后在控制器中使用它

# Checkout 
def new
  @event = method_to_find_event
  pricing = PricingService.new(@event, current_user)
  @event.price = pricing.get_price
  # blah blah
end

尼斯?

答案 1 :(得分:1)

更好的设计是将用户设置为关联或实例变量,而不是将其设置在不同对象的多个位置。当您考虑它时,每个结帐确实属于用户,不是吗?

就像那样:

class Checkout < ActiveRecord::Base
  attr_accessible :event
  belongs_to :event
  belongs_to :user

  def total
    event.checkout_price(user)
  end

  def free?
    total == 0
  end
end

您只需确保在创建结帐记录时设置用户。

答案 2 :(得分:0)

如果你不想传递current_user,那么你必须通过结账&amp;事件。方法只能在单个对象上调用。不管怎样,你必须传递另一个对象。