1

在我的 Rails 应用程序中,我有一些用户可以付费的活动。我需要能够根据当前用户更改活动价格。

*我知道已经有很多关于在模型中访问 c​​urrent_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作为参数之外,还有另一种解决方案吗?

4

3 回答 3

3

这是一个很好的问题,我很欣赏您关于不在模型中访问 c​​urrent_user 的意见。

实际上,Event 模型应该考虑的更少。模型的主要工作是存储数据并处理与自身相关的数据。定价是您的业务逻辑,而不是事件模型的关注点。一个事件是有代价的。就这样。不再。

看,你在定价上有很多事情要考虑。不仅是用户是否是高级用户。如果用户在您的应用程序中使用 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

好的?

于 2013-08-30T12:30:06.327 回答
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

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

于 2013-08-30T11:53:33.270 回答
0

如果您不想通过 current_user 那么您必须通过结帐和事件。方法只能在单个对象上调用。无论哪种方式,您都必须传递另一个对象。

于 2013-08-30T11:40:59.640 回答