在Rails中实现“业务规则”的方法是什么?
让我们说我有一辆车,想卖掉它:
car = Cars.find(24)
car.sell
car.sell
方法会检查以下几点:
does current_user own the car?
check: car.user_id == current_user.id
is the car listed for sale in the sales catalog?
check: car.catalogs.ids.include? car.id
if all o.k. then car is marked as sold.
我正在考虑创建一个名为Rules的类:
class Rules
def initialize(user,car)
@user = user
@car = car
end
def can_sell_car?
@car.user_id == @user.id && @car.catalogs.ids.include? @car.id
end
end
并像这样使用它:
def Car
def sell
if Rules.new(current_user,self).can_sell_car
..sell the car...
else
@error_message = "Cannot sell this car"
nil
end
end
end
至于获取current_user
,我在考虑将其存储在全局变量中?
我认为无论何时调用控制器动作,它总是一个“新鲜”的呼叫对吗?如果是这样,那么将当前用户存储为全局变量不应该带来任何风险..(就像其他一些用户能够访问其他用户的详细信息一样)
任何见解都表示赞赏!
所以,全局变量路线已经出局了!感谢PeterWong指出全局变量仍然存在!
我现在想用这种方式:
class Rules
def self.can_sell_car?(current_user, car)
......checks....
end
end
然后从控制器操作中调用Rules.can_sell_car?(current_user,@car)
。
有关这种新方式的任何想法吗?
答案 0 :(得分:3)
我会使用下表:
买家和卖家:
人(ID:INT,名称:字符串)
class Person << ActiveRecord::Base
has_many :cars, :as => :owner
has_many :sales, :as => :seller, :class_name => 'Transfer'
has_many :purchases, :as => :buyer, :class_name => 'Transfer'
end
cars(id:int,owner_id:int,vin:string,year:int,make:string,model:string,listed_at:datetime)
listed_at是查看汽车是否可以出售的标志
class Car << ActiveRecord::Base
belongs_to :owner, :class_name => 'Person'
has_many :transfers
def for_sale?
not listed_at.nil?
end
end
传送(ID:INT,car_id:INT,seller_id:INT,buyer_id:INT)
class Transfer << ActiveRecord::Base
belongs_to :car
belongs_to :seller, :class_name => 'Person'
belongs_to :buyer, :class_name => 'Person
validates_with Transfer::Validator
def car_owned_by_seller?
seller_id == car.owner_id
end
end
然后您可以使用此自定义验证程序来设置规则。
class Transfer::Validator << ActiveModel::Validator
def validate(transfer)
transfer.errors[:base] = "Seller doesn't own car" unless transfer.car_owned_by_seller?
transfer.errors[:base] = "Car isn't for sale" unless transfer.car.for_sale?
end
end
答案 1 :(得分:1)
首先,标准的rails实践是将所有业务逻辑保留在模型中,而不是控制器中。看起来你正朝着这个方向前进,所以这很好 - 但是:要注意,从模型中找到current_user
没有一个很好的干净方法。
我不会制作新的规则模型(尽管如果你真的想这样做就可以),我只会涉及用户模型和汽车。所以,例如:
class User < ActiveRecord::Base
...
def sell_car( car )
if( car.user_id == self.id && car.for_sale? )
# sell car
end
end
...
end
class Car < ActiveRecord::Base
...
def for_sale?
!catalog_id.nil?
end
...
end
显然我正在假设你的目录是如何工作的,但是如果汽车是for_sale belong_to
一个目录,那么该方法就可以了 - 否则只需根据需要调整方法来检查汽车是否列在目录与否。老实说,在汽车模型本身上设置一个布尔值可能是一个好主意,这样用户可以根据需要随时切换待售的汽车或者不进行销售(通过标记汽车出售,或通过将汽车添加到目录等。)。
我希望这会给你一些方向!请随时提问。
编辑:另一种方法是在模型中使用方法:
user.buy_car( car )
car.transfer_to( user )
有很多方法可以将逻辑放在与之交互的对象中。
答案 2 :(得分:0)
我认为这将成为使用数据库的主要候选者,然后您可以使用Ruby来查询不同的表。
答案 3 :(得分:0)
您可以查看声明性授权gem - https://github.com/stffn/declarative_authorization
虽然它是为CRUD操作预先配置的,但您可以轻松添加自己的操作(购买,销售)并将其业务逻辑放在authorization_rules.rb配置文件中。然后,在您的控制器,视图甚至模型中,您可以轻松地询问allowed_to? :买,@ car
答案 4 :(得分:0)
我正在做与用户类似的事情以及他们可以用照片画廊做些什么。我正在使用设计用户和身份验证,然后我在用户模型中设置了几个方法,用于确定用户是否具有各种权限(用户拥有许多通过权限的图库)来操作该库。我认为你看到的最大问题是确定你当前的用户,使用Devise可以很容易地处理,然后你可以在用户模型中添加一个方法并检查current_user.can_sell?授权销售。