在我的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
作为参数传递一直都在吗?
答案 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;事件。方法只能在单个对象上调用。不管怎样,你必须传递另一个对象。