2017-08-24 32 views
2

我想要一個User模型創建/驗證/更新具有以下屬性的系統:Rails&ActiveRecord - 對於on::create和on :: update的不同驗證?

要求1

User首次創建時,:name:email:password屬性都應該存在否則創建保存應該失敗。

要求2

User被更新,這三個屬性可以單獨更新,所以更新保存可以繼續,如果其中一個或兩個是空白的。

簡單,普通的要求對嗎?我不確定。最明顯的方式,以滿足第一個要求是在User模型validationspresence: true所有三個:

user.rb

validates :name,  length: {maximum: 50},   presence: true 
validates :email, uniqueness: {case_sensitive: false}, presence: true 
validates :password, length: {minimum: 6},   presence: true 
從這裏

那麼,我們如何滿足第二個要求?

嘗試1

添加on: :create的驗證:

validates :name,  length: {maximum: 50},   presence: true, on: :create 
validates :email, uniqueness: {case_sensitive: false}, presence: true, on: :create 
validates :password, length: {minimum: 6},   presence: true, on: :create 

這是災難性的。如果用戶試圖通過用新name但空白emailpassword領域,name的確會被更新,但emailpassword屬性也將更新爲空值提交更新的形式來更新只是他name - "" - 因爲驗證將不會運行。

嘗試2

添加allow_nil: true的驗證:

validates :name,  length: {maximum: 50},   presence: true, allow_nil: true 
validates :email, uniqueness: {case_sensitive: false}, presence: true, allow_nil: true 
validates :password, length: {minimum: 6},   presence: true, allow_nil: true 

同樣是災難性的。您可以使用空白屬性創建和更新用戶。

嘗試3

只有驗證,如果它是一個新的記錄或字段不爲空:

validates :email, uniqueness: {case_sensitive: false}, presence: true, if: :should_validate? 

def should_validate? 
    new_record? || email.present? 
end 

這已被接受爲別處#2正確的解決方案,但如果我指正錯了,是不是也是災難性的?如果您使用空白email字段更新模型,should_validate?將返回false,則電子郵件驗證將不會運行,並且數據庫將更新爲空白email

請糾正我,如果我錯了,但這個「解決方案」將工作如果沒有驗證也意味着不更新,但事實並非如此呢?如果你不運行驗證,該屬性仍然會保存到數據庫中嗎?

嘗試4

在控制器中,從除去了params屬性,如果它是空白:

user.rb

validates :name,  length: {maximum: 50},   presence: true 
validates :email, uniqueness: {case_sensitive: false}, presence: true 
validates :password, length: {minimum: 6},   presence: true 

users_controller.rb

def update 
    params[:user].delete(:name)  if params[:user][:name].blank? 
    params[:user].delete(:email) if params[:user][:email].blank? 
    params[:user].delete(:password) if params[:user][:password].blank? 

    if @user.update_attributes(update_user_params) 
    flash[:success] = "Edit Successful." 
    redirect_to @user 
    else 
    @title = "Edit user" 
    render 'edit' 
    end 
end 

def update_user_params 
    params.require(:user).permit(:name, :email, :password) 
end 

由於驗證中的presence: true,這不起作用。如果params中沒有任何屬性,驗證將失敗,並且記錄不會更新。

同樣,這已被接受爲Stackoverflow其他地方的正確解決方案,所以我很確定我在某處丟失了某些東西,請告訴我在哪裏?

嘗試5

params刪除屬性,如果是空白的,並從驗證刪除presence: true

user.rb

validates :name,  length: {maximum: 50} 
validates :email, uniqueness: {case_sensitive: false} 
validates :password, length: {minimum: 6} 

users_controller.rb

def update 
    params[:user].delete(:name)  if params[:user][:name].blank? 
    params[:user].delete(:email) if params[:user][:email].blank? 
    params[:user].delete(:password) if params[:user][:password].blank? 

    if @user.update_attributes(update_user_params) 
    flash[:success] = "Edit Successful." 
    redirect_to @user 
    else 
    @title = "Edit user" 
    render 'edit' 
    end 
end 

這不起作用。我們已經達到了要求2,但銷燬了要求1.使用此「解決方案」,您確實可以更新記錄的個別屬性,但您也可以使用空白屬性創建新記錄。

嘗試6

唯一可能的解決方案,我可以看到的是,以具有不同的驗證爲on: :createon: :update。如果您要創建記錄,則堅持要求presence: true,但如果要更新記錄,請刪除presence: true。您還需要在控制器中的空屬性去除:

user.rb

validates :name,  length: {maximum: 50},   presence: true, on: :create 
validates :email, uniqueness: {case_sensitive: false}, presence: true, on: :create 
validates :password, length: {minimum: 6},   presence: true, on: :create 

validates :name,  length: {maximum: 50},   on: :update 
validates :email, uniqueness: {case_sensitive: false}, on: :update 
validates :password, length: {minimum: 6},   on: :update 

users_controller.rb

def update 
    params[:user].delete(:name)  if params[:user][:name].blank? 
    params[:user].delete(:email) if params[:user][:email].blank? 
    params[:user].delete(:password) if params[:user][:password].blank? 

    if @user.update_attributes(update_user_params) 
    flash[:success] = "Edit Successful." 
    redirect_to @user 
    else 
    @title = "Edit user" 
    render 'edit' 
    end 
end 

這是允許的?它會工作嗎?我完全錯過了解決這個問題的正確方法嗎?

+0

待辦事項你想保存名稱,電子郵件爲零更新?我認爲沒有必要單獨更新名稱和電子郵件。您只需在名稱或電子郵件地址等字段中進行更改,不要讓其他提交的空白變得簡單。 –

+0

絕對不是。姓名和電子郵件永遠不應更新爲零。 – Bazley

+0

剛剛發佈的解決方案看看 –

回答

0

是否要保存名稱,電子郵件爲零更新?我認爲沒有必要單獨更新名稱和電子郵件。您只需在名稱或電子郵件地址等字段中進行更改,不要讓其他提交的空白變得簡單。

如果你想要的用戶名,電子郵件更新只是單獨下創建用戶模型的setter方法是這樣的:

def name=(val) 
    val = name if val.blank? 
    self.write_attribute(name: val) 
end 

def email=(val) 
    val = email if val.blank? 
    self.write_attribute(email: val) 
end 

沒有需要寫更新用戶單獨的驗證。

validates :name,  length: {maximum: 50},   presence: true 
validates :email, uniqueness: {case_sensitive: false}, presence: true 
validates :password, length: {minimum: 6},   presence: true 

您在更新記錄時沒有允許用戶參數。你可能會得到異常的這個,如果你使用的是軌道4.請確保您允許PARAMS之前創建或更新users_controller這樣的記錄:

def user_params 
    params.require(:user).permit(:name, :email, :password) 
end 

所以你更新的動作將是:

def update 
    if @user.update_attributes(user_params) 
    flash[:success] = "Edit Successful." 
    redirect_to @user 
    else 
    @title = "Edit user" 
    render 'edit' 
    end 
end 
+0

對不起,我的意思是在問題中有很強的參數 - 我已經糾正它。 – Bazley

+0

你是說第四次嘗試會奏效嗎?據我可以告訴你的解決方案是嘗試4.驗證中不會出現「存在:真」,防止這種情況發生。 – Bazley

+0

如果你想解決方案4的工作,你需要添加電子郵件,名稱和密碼setter方法來處理空白值。如果價值不存在,那麼它只會採取舊的價值 –