Rails控制器参数条件 - 如何干净地执行此操作

时间:2015-06-26 00:03:02

标签: ruby-on-rails ruby ruby-on-rails-3 redirect

我需要在控制器方法中检查一堆条件。 1)这是一团糟2)它甚至没有击中正确的重定向。

def password_set_submit
  password_check = /^(?=.*[a-z]{1,})(?=.*[A-Z]{1,})(?=.*\d{1,}){8,}.+$/

  @user = User.find(session[:id])
    if params[:password] && params[:password_confirmation] && params[:username] && params[:old_password]
        if params[:password] == params[:password_confirmation] && params[:password] =~ password_check

          # do some api stuff here

        if @user.save
          flash[:success] = 'Password updated.'
          redirect_to login_path and return
        end
      end
      if params[:password] != params[:password_confirmation]
        flash[:error] = 'Passwords did not match.'
        redirect_to password_set_path and return
      end
      if params[:password] == params[:password_confirmation] && params[:password] !~ password_check
        flash[:error] = 'Passwords did not match password criteria.'
        redirect_to password_set_path and return
      end
    end
  else
    flash[:error] = 'Please fill all inputs.'
    redirect_to password_set_path and return
  end
end

这需要执行以下操作:

1)如果提交的参数少于4个,则重定向并显示“填写所有输入”

2)如果密码和密码确认彼此不匹配,请重定向并显示“密码不匹配”

3)如果密码和密码确认相互匹配但与条件不符,则重定向并显示“密码与条件不匹配”

4)如果密码和密码确认相互匹配且符合条件,请进行api呼叫并重定向登录

我没有if / else想法,我希望清理它会帮助我正确地修改重定向。

2 个答案:

答案 0 :(得分:2)

Rails的方法是使用模型验证。

class User < ActiveRecord::Base
  validates :password, confirmation: true, presence: true# password must match password_confirmation
  validates :password_confirmation, presence: true # a password confirmation must be set
end

如果我们尝试创建或更新没有匹配pw / pw确认的用户,操作将失败。

irb(main):006:0> @user = User.create(password: 'foo')
   (1.5ms)  begin transaction
   (0.2ms)  rollback transaction
=> #<User id: nil, password: "foo", password_confirmation: nil, created_at: nil, updated_at: nil>
irb(main):007:0> @user.errors.full_messages
=> ["Password confirmation can't be blank"]
irb(main):008:0> 

然而

在处理用户密码时,你应该永远不会以纯文本形式将它们存储在数据库中!

由于大多数用户重复使用通用密码,您可能还会损害他们的电子邮件,银行帐户等。您可能会在财务上和法律上承担责任,这可能会破坏您的职业生涯。

答案是使用加密密码。由于这非常容易出错,Rails有一些名为has_secure_password的东西可以加密和验证密码。

您要做的第一件事就是从password数据库中删除password_confirmationusers列。

添加password_digest列。然后将has_secure_password添加到您的模型中。

class User < ActiveRecord::Base
  PASSWORD_CHECK = /^(?=.*[a-z]{1,})(?=.*[A-Z]{1,})(?=.*\d{1,}){8,}.+$/
  has_secure_password
  validates :password, format: PASSWORD_CHECK
end

这会自动为passwordpassword_confirmation的密码,确认以及获取者和设置者添加验证。

要检查旧密码是否正确,我们会这样做:

@user = User.find(session[:id]).authenticate(params[:old_password])
# user or nil

这是Rails方式的一个例子:

class UsersController

  # We setup a callback that redirects to the login if the user is not logged in
  before_action :authenticate_user!, only: [ :password_set_submit ]

  def password_set_submit
    # We don't want assign the the old_password to user.
    unless @user.authenticate(params[:old_password])
      # And we don't want to validate on the model level here
      # so we add an error manually:
      @user.errors.add(:old_password, 'The current password is not correct.')
    end
    if @user.update(update_password_params)
      redirect_to login_path, notice: 'Password updated.'
    else
      # The user failed to update, so we want to render the form again.
      render :password_set, alert: 'Password could not be updated.'
    end
  end

  private 

  # Normally you would put this in your ApplicationController 
  def authenticate_user!
    @user = User.find(session[:id])
    unless @user
      flash.alert('You must be signed in to perform this action.')
      redirect_to login_path
    end
  end

  # http://guides.rubyonrails.org/action_controller_overview.html#strong-parameters
  def update_password_params
    params.require(:user).permit(:password, :password_confirmation)
  end
end

请注意我们行动中的逻辑如何简单得多?用户已更新,我们重定向或无效,我们重新呈现表单。

我们不会在每个错误中创建一条Flash消息,而是在表单上显示错误:

<%= form_for(@user, url: { action: :password_set_submit}, method: :patch) do |f| %>

  <% if @user.errors.any? %>
    <div id="error_explanation">
      <h2>Your password could not be updated:</h2>
      <ul>
      <% @user.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>
  <div class="row">
    <%= f.label :password, 'New password' %>
    <%= f.password_field_tag :password %>
  </div>
  <div class="row">
    <%= f.label :password_confirmation %>
    <%= f.password_field_tag :password_confirmation %>
  </div>
  <div class="row">
    <p>Please provide your current password for confirmation</p>
    <%= f.label :old_password, 'Current password' %>
    <%= f.password_field_tag :old_password %>
  </div>
  <%= f.submit 'Update password' %>
<% end %>

答案 1 :(得分:0)

我会从控制器中删除与此密码重置相关的所有代码,并将其放入自己的模型//Changables var playerMoves = 0 var solidNumbers =[ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "and So on"] //Functions func checkForPlayerMovesEqual12() { //What a very long function name XD if playerMoves / 12 == solidNumbers { //Do this } else { //Do this if else } 中:

User::PasswordReset

这样可以将控制器的方法更改为更简单的方法:

# in app/models/user/password_reset.rb
class User::PasswordReset
  attr_reader :user, :error

  PASSWORD_REGEXP = /^(?=.*[a-z]{1,})(?=.*[A-Z]{1,})(?=.*\d{1,}){8,}.+$/

  def initialize(user_id)
    @user  = User.find(user_id)
  end

  def update(parameters)
    if parameters_valid?(parameters)
      # do some api stuff here with `user` and `parameters[:password]`
    else
      false
    end
  end

private

  def valid?
    error.blank?
  end

  def parameters_valid?(parameters)
    parameter_list_valid(parameters.keys) &&
      password_valid(params[:password], params[:password_confirmation])
  end

  def parameter_list_valid(keys)
    mandatory_keys = [:password, :password_confirmation, :username, :old_password]

    unless mandatory_keys.all? { |key| keys.include?(key) }
      @error = 'Please fill all inputs.'
    end

    valid?
  end

  def password_valid(password, confirmation)
    if password != confirmation
      @error = 'Passwords did not match.'
    elsif password !~ PASSWORD_REGEXP
      @error = 'Passwords did not match password criteria.'
    end

    valid?
  end

end

完成此重构后,您可以更轻松地在条件中查找问题并扩展代码。