[英]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.