[英]How to implement “business rules” in Rails?
在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)
。 对这种新方式有什么想法吗?
我将使用以下表格:
对于买卖双方:
人(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
汽车(id:int,owner_id:int,vin:string,year:int,make:string,model:string,listed_at:datetime)
listing_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:整数)
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
首先,标准的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
属于目录,那么该方法将起作用-否则,根据需要调整方法,以检查汽车是否在目录中列出。 坦率地说,在Car模型本身上设置布尔值可能是个好主意,这样用户就可以在需要时直接切换要出售或不出售的汽车(通过标记要出售的汽车或将汽车添加到目录等)。
我希望这会给您一些指导! 请随时提问。
编辑:另一种方法是在模型中使用如下方法:
user.buy_car( car )
car.transfer_to( user )
有很多方法可以将逻辑放入与其交互的对象中。
我认为这将是使用数据库的主要候选人,然后您可以使用Ruby查询不同的表。
您可以看一下声明式授权gem- https://github.com/stffn/declarative_authorization
尽管已为CRUD操作预先配置了该操作,但您可以轻松添加自己的操作(购买,出售),并将其业务逻辑放入authorization_rules.rb配置文件中。 然后,在您的控制器,视图甚至模型中!,您可以轻松地问allowed_to? :买,@车
我正在与用户做类似的事情,以及他们可以对照相馆做些什么。 我将devise用于用户和身份验证,然后在用户模型中设置了几种方法,以确定用户是否具有对该画廊采取行动的各种权限(用户通过权限拥有许多画廊)。 我认为您面临的最大问题是确定当前用户,这可以通过Devise轻松处理,然后可以向用户模型添加方法并检查current_user.can_sell? 授权销售。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.