サインアップするためにDeviseルートを削除するにはどうすればよいですか?


147

Rails 3アプリでDeviseを使用していますが、この場合、ユーザーは既存のユーザーによって作成される必要があります。既存のユーザーは、自分が持つ権限を決定します。

このため、私は欲しい:

  • ユーザーがサインアップするためのルート削除するには
  • するために、自分のプロファイルを編集するユーザーをまだ許可(変更のメールアドレスとパスワード)の後、彼らはサインアップしています

これどうやってするの?

現在、私は前に次のものを配置することでこのルートを効果的に削除していますdevise_for :users

match 'users/sign_up' => redirect('/404.html')

それはうまくいきますが、もっと良い方法があると思いますよね?

更新

ブノワ・ギャレットが言ったように、私の場合の最善の解決策は、登録ルートをまとめて作成するのをスキップして、実際に必要なものだけを作成することです。

そのために、最初にを実行しrake routes、次に出力を使用して必要なものを再作成しました。最終結果はこれでした:

devise_for :users, :skip => [:registrations] 
as :user do
  get 'users/edit' => 'devise/registrations#edit', :as => 'edit_user_registration'
  put 'users' => 'devise/registrations#update', :as => 'user_registration'
end

ご了承ください:

  • 私はまだ:registerable私のUserモデルにいます
  • devise/registrations 電子メールとパスワードの更新を処理します
  • 他のユーザー属性(権限など)の更新は、別のコントローラーによって処理されます

実際の答え:

デフォルトのDeviseパスのルートを削除します。つまり:

devise_for :users, path_names: {
  sign_up: ''
}

4
実際のところ、元のソリューションははるかにシンプルで明確だったと思います。セキュリティに関して賢明な問題はありますか?
2014

何らかの理由で、更新されたソリューションで、IDが必要であるというエラーが表示され続けました。1時間の髪の引っ張りと多くの多くのサーバーの再起動の後、それはどういうわけかそれ自体を修正しました。わかりません...でも、誰かがそれを経験したら、挑戦し続けてください!
Erik Trautman

@counterbeing-私が知っている問題はありません、私は未使用のルートを持つことや注文に依存するのが好きではありませんでした。
Nathan Long

1
「実際の回答」は、デバイスコントローラ内からリダイレクトされた場合、ルートを強制終了できません。のようにGETルートを押すと、デフォルトの動作で引き続きサインアップパスにルーティングされますhttps://example.com/users/。以下の私の答えを参照してください。
lacostenycoder 2016

1
セキュリティ欠陥!表示される「実際の回答」は、サインアップフォームを取り除くだけであり、実際にユーザーを作成するPOSTルートを取り除くことはありません。
エリックテリー

回答:


54

私もこれをやろうとしましたが、devise googleグループのスレッドは、本当にクリーンなソリューションを探すことを思いとどまらせました。

JoséValim(Deviseのメンテナー)を引用します。

簡単なオプションはありません。パッチを提供するか、:skip =>:registerableを使用して、必要なルートのみを追加できます。

元の質問は:

Railsから特定のルート(ルートの削除)を削除する良い方法はありますか?


4
正解です。実際、私はパッチを提案し、彼は丁寧に断りました:「今日、コントローラー全体をスキップすることができます。それは使用の点で最適ではありませんが、コントローラー全体のルートを手動で設定することはかなり簡単です。ルートを除外すると私は信じています名前では、Railsヘルパー(リソース、リソース、友達など)を使用できないため、ルート生成コードが(以前よりも)複雑になります。」github.com/plataformatec/devise/issues/…–
ネイサンロング

2
この答えが最初に書かれたときにこれが当てはまったかどうかはわかりませんが、ホセからの引用のコードは間違っています。Devise 3.4.1では:skip => :registrationsそうではありません:skip => :registerable
GMA 2014年

89

あなたのモデルでこれを行うことができます

# typical devise setup in User.rb
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable

それを次のように変更します。

devise :database_authenticatable, :recoverable, :rememberable, :trackable, :validatable

シンボル:registerableが削除されたことに注意してください

それだけです。他に何も必要ありません。登録ページへのすべてのルートとリンクも魔法のように削除されます。


21
残念ながら、これによりへのルートも削除されedit_user_registrationます。私が言ったように、「彼らはまだ彼らのプロフィールを編集することができるはずです。」
Nathan Long

1
ああ、そうか、まあ、私は通常、これを回避するためにrails_admin gemをインストールします。これによりlocalhost:3000/admin、抵抗可能なオブジェクトが削除されていても、ユーザーは自分のアカウントを編集できる場所に移動できます。それが実行可能なソリューションでない場合は、CanCanを見てください。リソースにアクセスできるユーザーとアクセスできないユーザーを指定できます。私は「管理者」や「モデレーター」などの役割を追加し、他のすべてのユーザーをサインアップページからロックする傾向があります。
スティーブンマードック

28
ユーザーが自分のプロファイルを編集する方法を提供するために管理セクション(任意のレコードの編集を可能にするために構築されている)を使用することは、私が長い間聞いた中で最悪の考えです。誰もこれを行わないでください
ジェレミー

sign_in本番環境で無効にする方法は?
WM

30

同様の問題が、作成新規のdevise_invitableパスを削除しようとしました

前:

 devise_for :users

熊手ルート

accept_user_invitation GET    /users/invitation/accept(.:format)           devise/invitations#edit
       user_invitation POST   /users/invitation(.:format)                  devise/invitations#create
   new_user_invitation GET    /users/invitation/new(.:format)              devise/invitations#new
                       PUT    /users/invitation(.:format)                  devise/invitations#update

devise_for :users , :skip => 'invitation'
devise_scope :user do
  get "/users/invitation/accept", :to => "devise/invitations#edit",   :as => 'accept_user_invitation'
  put "/users/invitation",        :to => "devise/invitations#update", :as => nil
end

熊手ルート

accept_user_invitation GET    /users/invitation/accept(.:format)                 devise/invitations#edit
                       PUT    /users/invitation(.:format)                        devise/invitations#update

注1デバイススコープhttps://github.com/plataformatec/devise#configuring-routes

注2私はdevise_invitableに適用していますが、devise * able機能で動作します

重要な注意: devise_scopeがユーザーではなくユーザーにあることを確認してください。それは正しいです、これに注意してください!それはあなたにこの問題を与える多くの痛みを引き起こす可能性があります:

Started GET "/users/invitation/accept?invitation_token=xxxxxxx" for 127.0.0.1 
Processing by Devise::InvitationsController#edit as HTML
  Parameters: {"invitation_token"=>"6Fy5CgFHtjWfjsCyr3hG"}
 [Devise] Could not find devise mapping for path "/users/invitation/accept?  invitation_token=6Fy5CgFHtjWfjsCyr3hG".
This may happen for two reasons:

1) You forgot to wrap your route inside the scope block. For example:

  devise_scope :user do
     match "/some/route" => "some_devise_controller"
  end

 2) You are testing a Devise controller bypassing the router.
   If so, you can explicitly tell Devise which mapping to use:

    @request.env["devise.mapping"] = Devise.mappings[:user]

まさに私が探していたものに感謝します。このソリューションを使用する他の人のために、私は/:idをプットルート定義に追加する必要がありました。
ジョン

21

私はこれに似た別の投稿を見つけ、@ chrisnicolaからの回答を共有したいと思いました。投稿では、本番中はユーザーのサインアップのみをブロックしようとしていました。

登録コントローラーを変更することもできます。次のようなものを使用できます。

では「アプリ/コントローラ/ registrations_controller.rb」

class RegistrationsController < Devise::RegistrationsController
  def new
    flash[:info] = 'Registrations are not open.'
    redirect_to root_path
  end

  def create
    flash[:info] = 'Registrations are not open.'
    redirect_to root_path
  end
end

これはdeviseのコントローラーをオーバーライドし、代わりに上記のメソッドを使用します。彼らは、誰かが何らかの理由でsign_upページにアクセスした場合に備えて、フラッシュメッセージを追加しました。リダイレクトを任意のパスに変更することもできます。

また、「config / routes.rb」に次のように追加できます。

devise_for :users, :controllers => { :registrations => "registrations" }

このままにしておくと、標準のデバイスを使用してプロファイルを編集できます。必要に応じて、次のコードを含めることで、プロファイル編集オプションをオーバーライドできます。

  def update
  end

「アプリ/コントローラ/ registrations_controller.rb」


13

これは古い質問ですが、最近同じ問題を解決して、次の方法よりもはるかにエレガントな解決策を考え出しました。

devise_for :users, :skip => [:registrations] 
as :user do
  get 'users/edit' => 'devise/registrations#edit', :as => 'edit_user_registration'
  put 'users' => 'devise/registrations#update', :as => 'user_registration'
end

そして、cancel_user_registration過度に冗長になることなく、名前付きルートのデフォルト名(など)を提供します。

devise_for :users, skip: [:registrations]

# Recreates the Devise registrations routes
# They act on a singular user (the signed in user)
# Add the actions you want in 'only:'
resource :users,
    only: [:edit, :update, :destroy],
    controller: 'devise/registrations',
    as: :user_registration do
  get 'cancel'
end

rake routes デフォルトのdeviseモジュールでの出力:

                  Prefix Verb   URI Pattern                    Controller#Action
        new_user_session GET    /users/sign_in(.:format)       devise/sessions#new
            user_session POST   /users/sign_in(.:format)       devise/sessions#create
    destroy_user_session DELETE /users/sign_out(.:format)      devise/sessions#destroy
           user_password POST   /users/password(.:format)      devise/passwords#create
       new_user_password GET    /users/password/new(.:format)  devise/passwords#new
      edit_user_password GET    /users/password/edit(.:format) devise/passwords#edit
                         PATCH  /users/password(.:format)      devise/passwords#update
                         PUT    /users/password(.:format)      devise/passwords#update
cancel_user_registration GET    /users/cancel(.:format)        devise/registrations#cancel
  edit_user_registration GET    /users/edit(.:format)          devise/registrations#edit
       user_registration PATCH  /users(.:format)               devise/registrations#update
                         PUT    /users(.:format)               devise/registrations#update
                         DELETE /users(.:format)               devise/registrations#destroy

12

「devise_for」の前に配置することで、「devise_scope」をオーバーライドできます。

devise_scope :user do
  get "/users/sign_up",  :to => "sites#index"
end

devise_for :users

これが最善の方法かどうかはわかりませんが、現在の解決策は、サインインページにリダイレクトされるだけです。


1
私は同様のアプローチをとりましたが、URLも変更したかったので、 `get" / users / sign_up "、:to => redirect(" / ")`を使用しました
dinjas

とてもシンプルで簡単な解決法。しかし、この解決には1分の問題があります。住所は残ります。入力/users/sign_upすると、sites#indexnot not sign_upアドレスにアクセスできます/users/sign_up
ペンギン

5

私は@maxの答えが好きでしたが、それを使用しようとすると、devise_mappingnilであるためエラーが発生しました。

私は彼の解決策を、問題に対処しているように少し修正しました。resource内部への呼び出しをラップする必要がありましたdevise_scope

devise_for :users, skip: [:registrations]

devise_scope :user do
  resource :users,
           only: [:edit, :update, :destroy],
           controller: 'devise/registrations',
           as: :user_registration do
    get 'cancel'
  end
end

devise_scopeは単数を期待するの:userに対しresource、複数を期待することに注意してください:users


4

route.rbでこれを行う

devise_for :users, :controllers => {:registrations => "registrations"}, :skip => [:registrations]
  as :user do
    get 'users/edit' => 'devise/registrations#edit', :as => 'edit_user_registration'
    put 'users' => 'devise/registrations#update', :as => 'user_registration'
end

  devise_scope :user do
    get "/sign_in",  :to => "devise/sessions#new"
    get "/sign_up",  :to => "devise/registrations#new"
  end

それを修正するために、サインインページにアクセスしているときにエラーが発生します。この変更を行う:app / views / devise / shared / _links.erb

<% if  request.path != "/sign_in" %>
    <%- if devise_mapping.registerable? && controller_name != 'registrations' %>
        <%= link_to "Sign up", new_registration_path(resource_name) %><br />
    <% end -%>
<% end %>

これは私にとってはうまくいき(私はdevise_forasブロックのみを使用しました):registerable、モデルから削除する必要がありました。
dusan 2014

3

これは、ルートをいじったり、アプリケーションコントローラーメソッドを追加したりせずにうまく機能することがわかりました。私のアプローチはdeviseメソッドをオーバーライドすることです。これを追加してapp/controllers/devise/registrations_controller.rb 、簡潔にするために他のメソッドを省略しました。

class Devise::RegistrationsController < DeviseController
  ...
  # GET /resource/sign_up
  def new
    redirect_to root_path
  end
  ....
end

また、他のビューからもこのパスに到達できるという錯覚を取り除くには、このコードを削除することもできます。 app/views/devise/shared/_links.erb

<%- if devise_mapping.registerable? && controller_name != 'registrations' %>
  <%= link_to "Sign up", new_registration_path(resource_name) %><br />
<% end -%>

2

私の場合、他の人のために。
devise (3.5.2)
次のコードを使用して、サインアップへのルートを正常に削除しましたが、プロファイルを編集するためのルートは保持しました。

#routes.rb
devise_for :users, skip: [:registrations]
as :user do
  get 'users/edit' => 'devise/registrations#edit', :as => 'edit_user_registration'
  put '/users(.:format)' => 'devise/registrations#update', as: 'user_registration'
  patch '/users(.:format)' => 'devise/registrations#update'
end

1

ここに私が行った少し異なるルートがあります。devise/shared/_links.html.erbビューを上書きする必要がないようにします。

app/models/user.rb

devise :database_authenticatable, :recoverable, :rememberable, :trackable, :validatable

config/routes.rb

devise_for :users
devise_scope :user do
  put 'users' => 'devise/registrations#update', as: 'user_registration'
  get 'users/edit' => 'devise/registrations#edit', as: 'edit_user_registration'
  delete 'users' => 'devise/registrations#destroy', as: 'registration'
end

前:

$ rake routes | grep devise
           new_user_session GET    /users/sign_in(.:format)                    devise/sessions#new
               user_session POST   /users/sign_in(.:format)                    devise/sessions#create
       destroy_user_session DELETE /users/sign_out(.:format)                   devise/sessions#destroy
              user_password POST   /users/password(.:format)                   devise/passwords#create
          new_user_password GET    /users/password/new(.:format)               devise/passwords#new
         edit_user_password GET    /users/password/edit(.:format)              devise/passwords#edit
                            PATCH  /users/password(.:format)                   devise/passwords#update
                            PUT    /users/password(.:format)                   devise/passwords#update
   cancel_user_registration GET    /users/cancel(.:format)                     devise/registrations#cancel
          user_registration POST   /users(.:format)                            devise/registrations#create
      new_user_registration GET    /users/sign_up(.:format)                    devise/registrations#new
     edit_user_registration GET    /users/edit(.:format)                       devise/registrations#edit
                            PATCH  /users(.:format)                            devise/registrations#update
                            PUT    /users(.:format)                            devise/registrations#update
                            DELETE /users(.:format)                            devise/registrations#destroy

後:

$ rake routes | grep devise
           new_user_session GET    /users/sign_in(.:format)                    devise/sessions#new
               user_session POST   /users/sign_in(.:format)                    devise/sessions#create
       destroy_user_session DELETE /users/sign_out(.:format)                   devise/sessions#destroy
              user_password POST   /users/password(.:format)                   devise/passwords#create
          new_user_password GET    /users/password/new(.:format)               devise/passwords#new
         edit_user_password GET    /users/password/edit(.:format)              devise/passwords#edit
                            PATCH  /users/password(.:format)                   devise/passwords#update
                            PUT    /users/password(.:format)                   devise/passwords#update
          user_registration PUT    /users(.:format)                            devise/registrations#update
     edit_user_registration GET    /users/edit(.:format)                       devise/registrations#edit
               registration DELETE /users(.:format)                            devise/registrations#destroy

あなたは冗長なルートを持ってしたくない場合は、すべてのデフォルトルートを飛ばし、すなわちdevise_for :users, skip: :all
elquimista

0

同じ問題があり、ユーザーを登録ページからリダイレクトするのは少し悪い習慣であることがわかりました。だから私の解決策は基本的にまったく使用:registrableしていません。

私がしたことは、次のようなユーザー詳細の編集のような同様のページを作成することでした:

<%= form_tag(update_user_update_path, method: :post) do %>  
    <br>
    <%= label_tag(:currPassword, 'Current password:') %> <%= password_field_tag(:currPassword) %> <br>
    <%= label_tag(:newPassword, 'New password:') %> <%= password_field_tag(:newPassword) %> <br>
    <%= label_tag(:newPasswordConfirm, 'Confirm new password:') %> <%= password_field_tag(:newPasswordConfirm) %> <br>
    <%= submit_tag('Update') %>
<% end %>

したがって、このフォームは、次のようなパスワードを更新する新しいポストエンドポイントに送信します。

  def update
    currPass = params['currPassword']
    newPass1 = params['newPassword']
    newPass2 = params['newPasswordConfirm']
    currentUserParams = Hash.new()
    currentUserParams[:current_password] = currPass
    currentUserParams[:password] = newPass1
    currentUserParams[:password_confirmation] = newPass2
    @result = current_user.update_with_password(currentUserParams)
  end

後で@resultビューでを使用して、パスワードが更新されたかどうかをユーザーに通知できます。


0

ルートを変更することで、それに伴う他の問題がたくさんあります。私が見つけた最も簡単な方法は、次のことです。

ApplicationController < ActionController::Base
  before_action :dont_allow_user_self_registration

  private

  def dont_allow_user_self_registration
    if ['devise/registrations','devise_invitable/registrations'].include?(params[:controller]) && ['new','create'].include?(params[:action])
      redirect_to root_path
    end
  end
end

機能しますが、すべてのアクションでこのメソッドを実行しますか?
lacostenycoder 2016

-7

devise宝石自体を変更できます。まず、次のコマンドを実行して、インストールされている場所を使用します。

gem which devise

パスが次のとおりだとします。 /usr/local/lib/ruby/gems/1.9.1/gems/devise-1.4.2/lib/devise

次に行きます

/usr/local/lib/ruby/gems/1.9.1/gems/devise-1.4.2/lib/devise/lib/devise/railsroutes.rbそのディレクトリで編集します。def devise_registration(mapping, controllers)新しいアクションを取り除くために変更できると呼ばれるメソッドがあります。のマッピングを完全に削除することもできますdevise_registration


別の提案では+1しますが、宝石をフォークすることは、ルートに厄介なコードを入れるよりも私には望ましくないようです。
ネイサンロング

4
一般的には、これは非常に大きな問題です。彼らがそうであるように、あなたが変更にちょうどモンキーパッチ彼らに何か必要がある場合には、宝石を維持する必要があります
equivalent8

この場合はあなたに同意しますが、一般的に、さまざまな場所でサルのパッチコードの代わりに使用するライブラリや宝石に変更を加えることをためらわないでください。ライブラリをニーズに合わせて作成する機能は、オープンソースコードIMOを使用する大きな利点の1つです。
Ankit Soni

gemを変更する場合は、少なくともフォークして、Gemfileに(たとえばgithub上の)サルのパッチを当てたgemを指定します。私はこれをいくつかの機会に行いました。プロセスは次のとおりです。gemをフォークし、ローカルにフォークを複製し、ローカルバージョンにモンキーパッチを適用し、リモートリポジトリにpushして、Gemfileにそれを指定します。(つまりgem 'devise', github: 'yourusername/devise', branch: "master"
lacostenycoder 2016
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.