13

私は Railscast を通じて Devise と OmniAuth の実装に取り​​組んでいます (Devise のドキュメントと共に)。

ただし、OmniAuth 経由でサインアップしたユーザーがプロファイルを編集しようとすると、問題が発生します。Devise は、ユーザーがプロファイルに変更を送信するときにユーザーの現在のパスワードを探しますが、facebook でログインしているユーザーは自分のパスワードを知りません (ユーザー モデルで自動的に設定されます)。

  def self.find_for_facebook_oauth(auth, signed_in_resource=nil)
    user = User.where(:provider => auth.provider, :uid => auth.uid).first
    unless user
      user = User.create(first_name:auth.extra.raw_info.first_name,
                         last_name:auth.extra.raw_info.last_name,
                           provider:auth.provider,
                           uid:auth.uid,
                           email:auth.info.email,
                           password:Devise.friendly_token[0,20]
                           )
    end
    user
  end

ユーザーが自分の情報を編集するときに、OmniAuth を使用してアカウントを設定した場合、アプリはパスワードの確認を要求しないようにする必要があります。チュートリアルでは、便利な password_required? メソッドは、この結果を達成するのに役立ちます。具体的には、このメソッドをユーザー モデルに追加すると、ユーザーが OmniAuth を介してサインアップしなかった場合にのみ true を返す必要があることを意味します (その場合、プロバイダー属性は nil になります)。

def password_required?
  super && provider.blank?
end

したがって、次のようなコードです。

<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %>
  <%= devise_error_messages! %>
    <%= render :partial => "essential_user_info_inputs", :locals => { :f => f } %>
    <%= render :partial => "inessential_user_info_inputs", :locals => { :f => f } %>
    <% if f.object.password_required? %> 
        <%= render :partial => "password_inputs", :locals => { :f => f } %>
        <%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
        <%= f.password_field :current_password %>
    <% end %>
  <%= f.submit "Update" %>
<% end %>

理論的には、必要な場合にのみパスワード入力を表示します。また、Devise には、OmniAuth ユーザーが自分のアカウントを編集するためにパスワードを使用する必要がないというロジックが組み込まれていることも示唆しています。これが本当かどうかはわかりませんが、チュートリアルのようなものはそのように見えます. しかし、OmniAuth ユーザーが自分のアカウントを編集しようとすると、「Current password can't be blank.」というメッセージが表示されます。非 OmniAuth ユーザーの場合も同じです (これらのユーザーの編集ページにもパスワード フィールドが表示されないため、これは理にかなっています)。

ちょっと調べてみると、password_required? メソッドは、ユーザーが OmniAuth を介してサインアップしたときと、サイトの通常のユーザー サインアップを介してサインアップしたときの両方で、false を返しています。単純にスーパークラス メソッドを実行するように変更しても、false が返されます。

password_required メソッドで何が起こっているかについてのアイデアはありますか? それについてはどこにも何も見つかりませんが、それが今、物事をつまずかせているように感じます.

アップデート:

これは現在機能していますが、requires_password? に依存する Railscast で概説されている方法を使用していません。メソッド、私がまだ何も知らないトピック。代わりに、ここで提案されているように、ここで概説されているソリューションを実装しました。そのため、OmniAuth 以外のアカウントをコードで更新するためにパスワードのみを要求するようになりました。

class Users::RegistrationsController < Devise::RegistrationsController
def update
    @user = User.find(current_user.id)
    email_changed = @user.email != params[:user][:email]
    is_facebook_account = !@user.provider.blank?

    successfully_updated = if !is_facebook_account
      @user.update_with_password(params[:user])
    else
      @user.update_without_password(params[:user])
    end

    if successfully_updated
      # Sign in the user bypassing validation in case his password changed
      sign_in @user, :bypass => true
      redirect_to root_path
    else
      render "edit"
    end
  end
end
4

3 に答える 3

22

最も簡単な方法は、 の update_resource メソッドを上書きすることRegistrationsControllerです。これは、コントローラーの独自の実装でdeviseによって推奨されています。

  # By default we want to require a password checks on update.
  # You can overwrite this method in your own RegistrationsController.
  def update_resource(resource, params)
    resource.update_with_password(params)
  end

したがって、解決策は、次のように独自のコントローラーでこのメソッドを上書きすることです。

class Users::RegistrationsController < Devise::RegistrationsController

  # Overwrite update_resource to let users to update their user without giving their password
  def update_resource(resource, params)
    if current_user.provider == "facebook"
      params.delete("current_password")
      resource.update_without_password(params)
    else
      resource.update_with_password(params)
    end
  end

end
于 2013-12-23T05:55:08.917 に答える
1

以下のリンクに、Devise/OmniAuth のユーザー プロファイル/パスワードの変更の問題に対する解決策を含む更新を追加し、いくつかの役立つリンクを収集しました。

stackoverflow - デバイスにパスワードを保存せずにユーザーがアカウントを編集できるようにする

于 2013-03-11T19:17:33.070 に答える
0

これが使われているのをどこかで見ました。


def update
    params[:user].delete(:current_password)
    params[:user].delete(:password)
    params[:user].delete(:password_confirmation)
    if current_user.update_without_password(params[:user])
      redirect_to somewhere_wicked_path, notice => "You rock"
    else
      render 'edit', :alert => 'you roll'
    end
end

コントローラーの update メソッドでこのようなものを使用します。そのメソッドがDeviseにもあることを確認してください。

于 2012-11-18T00:31:52.997 に答える