【问题标题】:Rails Sorcery update attributes of model without passwordRails Sorcery 在没有密码的情况下更新模型的属性
【发布时间】:2018-06-20 22:09:37
【问题描述】:

我在 rails 4.1 应用程序中使用巫术进行用户身份验证。一切正常。但是当我尝试更新用户模型的特定属性(通过巫术认证)时,我收到一个错误,提示密码为空且太短。

这是来自控制台的 sn-p

> user = User.last  
=> # I get the user  
> user.update(about_me: "I'm a user")  
=> false  
> user.update(about_me: "I'm a user", password: "secret")  
=> true

这是我的型号代码
app/models/user.rb

class User < ActiveRecord::Base  
  authenticates_with_sorcery!  
  validates :password, presence: true, length: { minimum: 6 }  
  .....
end  

我的控制器代码
app/controllers/users_controller.rb

class UsersController < ApplicationController
  .....
  def edit
    @user = User.find(params[:id])
  end

  def update
    @user = User.find(params[:id])
    if @user.update(user_params)
        redirect_to @user
        flash[:notice] = "Profile successfully updated"
    else
        render 'edit'
    end
  end

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

end

还有我的更新表单
app/views/users/edit.html.erb

<%= form_for @user, method: :put do |f| %>
  <% if @user.errors.any? %>
    <div class="alert">
      <p><%= pluralize(@user.errors.count, 'error') %></p>
      <ul>
        <% @user.errors.full_messages.each do |msg| %>
          <li><%= msg %></li>
        <% end %>
      </ul>
    </div>
  <% end %>
  <%= f.text_field :username, placeholder: 'Username' %>
  <%= f.text_field :name, placeholder: 'Name' %>
  <%= f.email_field :email, placeholder: 'Email' %>
  <%= f.text_area :about_me, placeholder: 'About me' %>
  <%= f.password_field :password, placeholder: 'Password' %>
  <%= f.submit 'Save Changes', class: 'button' %>
<% end %>

如果我从表单中删除密码字段,我会收到关于密码为空以及密码长度的错误。 这是与巫术有关还是我与rails本身缺少的东西? 有没有更好的方法来更新让我们只说电子邮件字段而不影响其他任何内容?

【问题讨论】:

  • update :发现我们可以在模型中使用 allow_blank: true 。由于这也将允许用户在没有密码的情况下注册,所以捕获可能在用户控制器的创建操作中使用条件。如果我得到它的工作将发布答案。无论如何,我认为这不是正确的做法。
  • 标记 allow_blank true 不是正确的方法。相反,您可以在用户模型中进行条件验证。就像在什么条件下将检查验证以及何时应该跳过验证。看起来,如果它是您尝试编辑的现有用户,那么只需通过带有条件的验证:它是现有用户。检查我下面的答案,这将消除您的疑问。

标签: ruby-on-rails sorcery


【解决方案1】:
class User < ActiveRecord::Base  
  authenticates_with_sorcery!  
  validates :password, presence: true, length: { minimum: 6 }, if: :new_user?

  private
  def new_user?
    new_record?
  end
end  

只有当它是一个 new_record 时才会检查验证,我们为此添加了我们自己的私有验证方法 new_user?。此函数将在您的正常注册/注册期间返回 true。因此,在这些注册中,只需要密码验证。

在编辑期间,用户当然会是现有用户/new_record?将返回假。因此,将跳过密码验证。

第二种方式:

class User < ActiveRecord::Base 
  attr_accessor :skip_password
  validates :password, presence: true, length: { minimum: 6 }, unless: :skip_password
end

 #users_controller.rb 
def update
  @user = User.find(params[:id])
  @user.skip_password = true 
  if @user.update(user_params)
     redirect_to @user
  else
     render 'edit'
  end
end

这里我们添加了我们自己的自定义 attr_accessor skip_password。如果 skip_password 值设置为 true,则在编辑/更新期间将跳过密码验证。

我希望这两种方法都能帮助到你:)

【讨论】:

  • 你的两种方法都很有效。第二种方式需要一个冒号(除非::skip_password,除非:skip_password)。我更喜欢使用第一种方式,因为逻辑在模型中。我怀疑在用户更新他/她的属性后密码被更新为空字符串,但事实证明它没有。谢谢!
  • 是的,第一个更可取,因为逻辑仅在模型中累积。感谢您指出错字(在除非::skip_password)。更新了那个。
【解决方案2】:

如果以后有人找这个话题,可以用changes ActiveRecord模型的map:

class User < ActiveRecord::Base  
  authenticates_with_sorcery!  
  validates :password, presence: true, length: { minimum: 6 }, if: -> {new_record? || changes[:crypted_password]}
  .....
end

其中:crypted_passwordsorcery_config.crypted_password_attribute_name 的值。

目前Simple Password Authentication sorcery wiki 文章中也指出了这种验证条件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-29
    • 2011-03-01
    • 2013-03-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多