2014-10-07 4 views
5

我有一個檔案模型,它有許多屬性,如電子郵件,圖像,年齡,地址等。 最終用戶可以使某些屬性爲私人,以便其他用戶無法查看。 我加入到表private_attr列解決了這個問題,並序列化它來存儲一個散列,如: -設置個人檔案模型的某些屬性的最佳方式是公開(可見)還是私人(不可見)給其他用戶?

{email: true, address: true, age: false } 

這裏屬性的關鍵有值true被認爲是私人和沒有顯示出比人,其它用戶這些屬於。

我想知道這是解決這個問題的最好方法,還是有其他方法。 在此先感謝。

回答

5

我想你可以只序列化用戶想要在數組中私有的字段(而不是散列)。像[:email, :address](使用你的例子)

然後,當你要呈現視圖時,只需檢查該字段是否存在於該列中。類似於

<%= user.email unless user.private_fields.include?(:email) %> 

您甚至可以將該邏輯提取到視圖幫助程序以避免重複。

<%= show_if_allowed(user, :email) %> 

然後創建一個這樣

def show_if_allowed(user, field) 
    user[field] unless user.private_fields.include?(field) 
end 
+1

謝謝我以後也想到了這個方法。 – 2014-10-13 04:15:58

+1

結合Presenter模式(在視圖上實例化類,具有如何顯示屬性的方法等),這將是 - 在我看來 - 最好的方法。 +1 – MrYoshiji 2014-10-15 14:58:34

+0

@MrYoshiji然後請加你回答。 – 2014-10-16 04:04:01

2

您問是否有其他方法。當然。一個人是否更好取決於你。

地段列

的你可以爲每個屬性創建額外的列。 email_protected:true/false(等)。如果你只有3列,那還不算太壞,但如果你保護了很多屬性,就不會很好地擴展。

多對多的關係

你可以有一個額外的模型,如ProtectedAttribute。配置文件has_many ProtectedAttributes並將數據存儲在單獨的表中而不是序列化。這消除了序列化數據到單個列中。

其他細節遵循的要求

# I'm using User instead of Profile as Profile is a protected word in Rails 
class User < ActiveRecord::Base 
    has_many :profile_protected_attributes 
    has_many :protected_attributes, through: :profile_protected_attributes 

    def protect_attribute?(name) 
    protected_attributes.where(name: name).present? 
    end 

    def show_attribute?(name) 
    !protect_attribute(name) 
    end 

    def protect_attribute(name) 
    return if self.protect_attribute?(name) 
    protected_attributes << ProtectedAttribute.find_by_name(name) 
    end 

    def unprotect_attribute(name) 
    protected_attributes.delete(ProtectedAttribute.find_by_name(name)) 
    end 
end 

class ProtectedAttribute < ActiveRecord::Base 
    has_many :profile_protected_attributes 
    has_many :users, through: :profile_protected_attributes 
end 

# The join model 
class ProfileProtectedAttribute < ActiveRecord::Base 
    belongs_to :user 
    belongs_to :protected_attribute 
end 

的遷移(你需要調整,如果你堅持使用配置文件):

class CreateProtectedAttributes < ActiveRecord::Migration 
    def change 
    create_table :protected_attributes do |t| 
     t.string :name 
     t.timestamps 
    end 
    end 
end 

class CreateProfileProtectedAttributes < ActiveRecord::Migration 
    def change 
    create_table :profile_protected_attributes do |t| 
     t.integer :user_id 
     t.integer :protected_attribute_id 
     t.timestamps 
    end 
    end 
end 
+0

您能否用'ProtectedAttribute'模型解釋可能的解決方案? – 2014-10-13 04:26:15

+0

當然。當我有時間寫下細節時,我會更新我的答案。 – JPrevost 2014-10-13 16:26:45

+0

我已經用Class關係和一些示例幫助器方法更新了我的答案。 – JPrevost 2014-10-14 18:09:54

1

你可以使用一個名爲cancan寶石處理您在紅寶石文件中定義的不同類型用戶的權利(ability.rb)。然後,我建議你爲一個資源使用不同的序列化程序,每個序列化程序專用於特定的用戶角色,這很容易使用active-model-serializer

2

其實一個幫手,那就是如果我不得不處理8到10個屬性,我會做什麼。但是,如果模型類的屬性太多,並且在用戶的組,公共,共享等基礎上顯示這些屬性的複雜邏輯,那麼我建議您將其移至單獨的模型類,我們假設:「ProfileConfigurationProfileSetting」,它將在行級別維護每個屬性,或者您可以將這些設置移動到Redis,其結構如下所示:user_id: {attribute_name: true, type: 'type_name'}但有一個缺點是您將依賴Redis服務器的可用性。現在

,你的情況:

serialize :profile_preferences, Hash 

,然後你維護它(正如你所說,只是在爲他們的任務相反的方式):

{email: false, address: false, age: true } 

但是,你可以去然後創建一些方便的方法,您可以調用您的配置文件對象:

after_initialize :load_profile_preferences 

private 

def load_profile_preferences 
    profile_preferences.each do |attr, value| 
    self.class.send(:define_method, "show_#{attr.to_s}?") { value } 
    end 
end 

現在,您將得到方便的m方法如:show_email?,show_address?show_age?Profile類的對象,你可以delegateUser類的實例。因此,您現在可以在您的視圖中執行類似操作,例如:

<%= "Email: {user.email}" if user.show_email? %> 
<%= "Address: {user.address}" if user.show_address? %> 
<%= "Age: {user.age}" if user.show_age? %> 
+0

謝謝,我是有興趣知道更多關於第一種方法,即使用'ProfileConfiguration'模型,你可以詳細說明一個,如何管理多個用戶屬性。 – 2014-10-13 04:24:48

+0

當然,我很樂意詳細說明,請允許我一些時間。 – Surya 2014-10-13 06:22:32

相關問題