[英]Rails: best practice to scope queries based on subdomain?
我正在開發一個Rails(目前是2.3.4)應用程序,該應用程序利用子域來隔離獨立的帳戶站點。 要明確的是,我的意思是foo.mysite.com應該顯示foo帳戶的內容,bar.mysite.com應該顯示欄的內容。
確保所有模型查詢都限定在當前子域的最佳方法是什么?
例如,我的一個控制器看起來像:
@page = @global_organization.pages.find_by_id(params[:id])
(注意@global_organization
是通過subdomain-fu在application_controller中設置的。)當我想要的是:
@page = Page.find_by_id(params[:id])
Page模型找到的位置自動限定在正確的組織中。 我嘗試過使用default_scope指令,如下所示:(在Page模型中)
class Page < ActiveRecord::Base
default_scope :conditions => "organization_id = #{Thread.current[:organization]}"
# yadda yadda
end
(再次,請注意,相同的application_controller將Thread.current [:organization]設置為組織的全局訪問ID。)此方法的問題是默認范圍在第一個請求上設置,並且永遠不會在后續請求中更改不同的子域名。
到目前為止有三種明顯的解
1為每個子域使用單獨的vhost,並且每個子域只運行應用程序的不同實例(使用mod_rails)。 此方法不適用於此應用。
2使用上面的原始控制器方法。 不幸的是,應用程序中有相當多的模型,許多模型都是從組織中刪除的一些連接,因此這種表示法很快變得很麻煩。 更糟糕的是,這主動要求開發人員記住並應用限制或冒重大安全問題。
3使用before_filter重置每個請求的模型的默認范圍。 不確定此處的性能或如何最好地選擇要更新的模型。
思考? 我還缺少其他任何解決方案嗎? 這似乎是一個普遍的問題,必須有一個最佳實踐。 感謝所有投入,謝謝!
您是否嘗試過將default_scope
定義為lambda
? 每次使用范圍時,都會評估定義選項的lambda
位。
class Page < ActiveRecord::Base
default_scope lambda do
{:conditions => "organization_id = #{Thread.current[:organization]}"}
end
# yadda yadda
end
它基本上是你的第三個選擇,通過與你之前的過濾魔法一起工作。 但它比那更具侵略性,可以使用Page模型中使用的每一個查找。
如果你想為所有模型使用這種行為,你可以將default_scope添加到ActiveRecord :: Base,但是你提到了一些是幾個連接。 因此,如果您使用此路線,則必須覆蓋這些模型中的默認范圍以解決連接問題。
這里要小心使用默認范圍,因為這會導致您產生錯誤的安全感,特別是在創建記錄時。
我總是用你的第一個例子來說明這一點:
@page = @go.pages.find(params[:id])
最大的原因是因為您還希望確保將此關聯應用於新記錄,因此您的新/創建操作將如下所示,確保它們適當地限定為父關聯:
# New
@page = @go.pages.new
# Create
@page = @go.pages.create(params[:page])
我發現acts_as_tenant gem [ github ]非常適合這個功能。 它以最小的額外努力為您確定范圍,並且還使繞過范圍很難。
這是關於它的最初博客文章: http : //www.rollcallapp.com/blog/2011/10/03/adding-multi-tenancy-to-your-rails-app-acts-as-tenant
我們在過去的兩年里一直在使用https://github.com/penguincoder/acts_as_restricted_subdomain ,但它只適用於Rails 2.3。
我們目前正在嘗試升級(和gemmify)插件以使用Rails 3.我很好奇你如何處理你的問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.