设计确认令牌不能为空

时间:2016-04-15 22:29:44

标签: ruby-on-rails ruby devise

我正在尝试通过这些the developer's web site修改用户注册,但问题似乎潜伏在表单中,可能还有routes.rb。

要注册,用户输入他们的电子邮件。

确认电子邮件:

    <p>Welcome <%= @resource.email %>!</p>

    <p>You can confirm your account email through the link below:</p>

    <p><%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %></p>

的routes.rb

   as :user do
        patch '/users/confirmation' => 'confirmations#update', :via => :patch, :as => :update_user_confirmation
    end
    devise_for :users, :controllers => { :confirmations => "confirmations" }

confirmmations / show.html.erb:

    <div class="container">
      <h2> You're almost done! Now create a password to securely access your account.</h2>
        <%= form_for resource, :as => resource_name, :url => update_user_confirmation_path, :html => {:method => 'patch'} do |f| %>

          <%= devise_error_messages! %>

          <div class="form-group">
            <%= f.label :password %>
            <%= f.text_field :password %>
          </div>
          <div class="form-group">
            <%= f.label :password_confirmation %>
            <%= f.text_field :password_confirmation %>
            </div>
            <%= f.hidden_field :confirmation_token %>


            <div class="form-group">
              <%= f.submit "Confirm account", class: 'btn btn-success' %>
            </div>
            <% end %>

          </div>

confirmations_controller.rb

    # app/controllers/confirmations_controller.rb
    class ConfirmationsController < Devise::ConfirmationsController
      # Remove the first skip_before_filter (:require_no_authentication) if you
      # don't want to enable logged users to access the confirmation page.
      skip_before_filter :require_no_authentication
      skip_before_filter :authenticate_user!

      # PUT /resource/confirmation
      def update
        with_unconfirmed_confirmable do
          if @confirmable.has_no_password?
            @confirmable.attempt_set_password(params[:user])
            if @confirmable.valid? and @confirmable.password_match?
              do_confirm
            else
              do_show
              @confirmable.errors.clear #so that we wont render :new
            end
          else
            @confirmable.errors.add(:email, :password_already_set)
          end
        end

        if !@confirmable.errors.empty?
          self.resource = @confirmable
          render 'devise/confirmations/new' #Change this if you don't have the views on default path
        end
      end

      # GET /resource/confirmation?confirmation_token=abcdef
      def show
        with_unconfirmed_confirmable do
          if @confirmable.has_no_password?
            do_show
          else
            do_confirm
          end
        end

        unless @confirmable.errors.empty?
          self.resource = @confirmable
          render 'devise/confirmations/new' #Change this if you don't have the views on default path 
        end
      end


      def with_unconfirmed_confirmable
        original_token = params[:confirmation_token]
        confirmation_token = Devise.token_generator.digest(User, :confirmation_token, original_token)
        @confirmable = User.find_or_initialize_with_error_by(:confirmation_token, original_token)
        if !@confirmable.new_record?
          @confirmable.only_if_unconfirmed {yield}
        end

      end

      def do_show
        original_token = params[:confirmation_token]
        confirmation_token = Devise.token_generator.digest(User, :confirmation_token, original_token)
        @confirmable = User.find_or_initialize_with_error_by(:confirmation_token, original_token)
        @requires_password = true
        self.resource = @confirmable
        render 'confirmations/show' #Change this if you don't have the views on default path
      end

      def do_confirm
        @confirmable.confirm
        set_flash_message :notice, :confirmed
        sign_in_and_redirect(resource_name, @confirmable)
      end
    end

ConfirmationsController#更新

    started PATCH "/users/confirmation" for ::1 at 2016-04-15 16:20:42 -0600
    Processing by ConfirmationsController#update as HTML
      Parameters: {"utf8"=>"✓", "authenticity_token"=>"Vf94s47OKHJKJHU4eutpHnuwCqhZ78Qr/zIOb1qrkr2UnDxlmCtGrR3TNe5hgEIbAWhsntsV0QZZlGp1LozArw==", "user"=>{"password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "confirmation_token"=>"JNXxGzLsZjBTQ-9b-cGz"}, "commit"=>"Confirm account"}
      Rendered devise/shared/_links.html.erb (0.9ms)
      Rendered devise/confirmations/new.html.erb within layouts/application (13.4ms)
      Rendered searches/_form.html.erb (0.6ms)
      Rendered devise/sessions/_new.html.erb (2.9ms)
      Rendered devise/shared/_links.html.erb (0.4ms)

错误(使用binding.pry)

    From: app/controllers/confirmations_controller.rb @ line 28 ConfirmationsController#update:
     @messages={:confirmation_token=>["can't be blank"], :email=>[], :password=>[], :remember_me=>[]}>
    [2] pry(#<ConfirmationsController>)> 

用户可以访问可以输入密码的http://localhost:3000/users/confirmation?confirmation_token=JNXxGzLsZjBTQ-9b-cGz。隐藏字段确认令牌与通过确认电子邮件发送的令牌匹配,但似乎确认控制器未正确更新数据库。一旦他们选择确认表格,他们就会收到错误。有什么建议?

2 个答案:

答案 0 :(得分:0)

参数结构为:

{
   "user"=>{
       "password"=>"[FILTERED]", 
       "password_confirmation"=>"[FILTERED]",
       "confirmation_token"=>"JNXxGzLsZjBTQ-9b-cGz"
    }
}

因此,当您阅读confirmation_token参数时,您无法使用

params[:confirmation_token]

但是

params[:user][:confirmation_token]

答案 1 :(得分:0)

此解决方案位于Devise的指示范围内。

使用&#34;对于Rails 3/4&amp;设计3.1 +&#34;,必须使用更新和显示方法以及&#34; For Rails 3/4&amp;设计2.x-3.0&#34;让这个工作。

解决方案,结合&#34;对于Rails 3/4&amp;设计3.1 +&#34;和#34;对于Rails 3/4&amp;设计2.x-3.0&#34; ConfirmaitonsControllers

但为什么呢?

SELECT a.[Month / Year],        
    ROUND(SUM(a.[Gross Sales]),2) AS [Gross Sales],
    ROUND(SUM(a.[COGS]),2) AS [COGS],
    ROUND(SUM(a.[Sales Margin]),2) AS [Sales Margin],
    Round((Sum(a.[Sales Margin])/Sum([Gross Sales]))/100,2) AS [Profit Margin]    
FROM
    (
    SELECT
        Format(DatePart("m",sale_date),"00") & " / " & DatePart("yyyy",sale_date) AS [Month / Year], 
        Format(DatePart("m",s.sale_date),"00") AS [Sale Month], 
        DatePart("yyyy",s.sale_date) AS [Sale Year], 
        Nz(s.SELLING_PRICE * s.quantity,0) AS [Gross Sales], 
        Nz(i.VENDOR_ACTUAL_PRICE,0)*Nz(s.quantity,0) AS [COGS],
        Nz(s.SELLING_PRICE * s.quantity,0) - Nz(i.VENDOR_ACTUAL_PRICE * s.quantity,0) AS [Sales Margin]
    FROM 
        INVENTORY i
        INNER JOIN SALES_RECEIPT s ON i.INVENTORY_ID = s.INVENTORY_ID
    WHERE DatePart("m",sale_date) BETWEEN 1 AND 12
        AND DatePart("yyyy",sale_date) BETWEEN 2014 AND 2016
    ) a
GROUP BY a.[Sale Month], a.[Sale Year], a.[Month / Year]
ORDER BY a.[Sale Year], a.[Sale Month]