前提・実現したいこと
deviseで作成されるパスワードを別(管理者側)で作成してそれをユーザーがログインする際(sessions/new)のパスワードに割り当てたい。deviseのragistrations/newは使用しない。
ここに質問の内容を詳しく書いてください。
今回、ユーザーの登録は管理者側で行いたい。アドレスやパスワードはdeviseのコントローラーを使わずに管理者のコントローラーでユーザーを作成する。その作成したパスワードとemailでログインできる様にしたい。
該当のソースコード
schea.rb create_table "shops", force: :cascade do |t| t.string "email", default: "", null: false t.string "encrypted_password", default: "", null: false t.string "reset_password_token" t.datetime "reset_password_sent_at" t.datetime "remember_created_at" t.string "name", null: false t.string "phonenumber", null: false t.string "address", null: false t.string "shop_image_id" t.string "postal_code", null: false t.string "open_time", null: false t.string "close_time", null: false t.string "lunch_limit" t.string "dinner_limit" t.float "latitude" t.float "longitude" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.string "password_digest" t.index ["email"], name: "index_shops_on_email", unique: true t.index ["reset_password_token"], name: "index_shops_on_reset_password_token", unique: true end
app/models/shop.rb class Shop < ApplicationRecord # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable has_many :informations, dependent: :destroy has_many :reviews, dependent: :destroy has_many :favorites, dependent: :destroy has_many :inquiries, dependent: :destroy has_many :courses, dependent: :destroy has_many :messages, dependent: :destroy has_many :rooms, dependent: :destroy has_many :genres, dependent: :destroy has_many :shop_genres, through: :genres attr_accessor :shop_genre_ids has_secure_password attachment :shop_image end
controllers/admins/shops_controller.rb def new @shop = Shop.new @genres = Genre.all end def create @shop = Shop.new(shop_params) @shop_genres = Shop.all binding.pry if @shop.save shop_params[:shop_genre_ids].each_with_index do | genre, i | if i == 0 next end genre = Genre.new(shop_genre_id: genre.to_i) genre.shop_id = @shop.id genre.save end redirect_to admins_shops_path(@shop) else render 'new' end end
view/admins/shops/new.html.erb <%= form_for(@shop, url:admins_shops_path(@shop),method: :post) do |f| %> <div class = "food"> <div class="field"> <%= attachment_image_tag @shop, :shop_image, src: "", id:"img_prev", size: "200x200", alt:"Image preview", class: "item_prev", fallback: "no_image.jpg" %> </div> <div class="field"> <%= f.label :shop_image,"image change" ,class: "btn btn-warning btn-lg" ,for:"post_img"%> <%= f.attachment_field :shop_image, id:"post_img", class: "image", style:"display:none;" %> </div> <div class="field"> <%= f.label :email, "ショップ名" %><br /> <%= f.text_field :email %> </div> <div class="field"> <%= f.label :email, "メールアドレス" %><br /> <%= f.text_field :email %> </div> <div class="field"> <%= f.label :password_digest, "パスワード" %><br /> <%= f.text_field :password_digest %> </div> <div class="field"> <%= f.label :phonenumber, "電話番号" %><br /> <%= f.telephone_field :phonenumber %> </div> <div class="field"> <%= f.label :postal_code, "郵便番号" %><br /> <%= f.number_field :postal_code %><span class="unit"></span> </div> <div class="field"> <%= f.label :address, "住所"%><br /> <%= f.text_field :address %> </div> <div class="field"> <%= f.label :open_time, "開店時間" %><br /> <%= f.text_field :open_time %> </div> <div class="field"> <%= f.label :close_time, "閉店時間" %><br /> <%= f.text_field :close_time %> </div> <div class="field"> <%= f.label :lunch_limit, "ランチラストオーダー" %><br /> <%= f.text_field :lunch_limit %> </div> <div class="field"> <%= f.label :dinner_limit, "ディナーラストオーダー" %><br /> <%= f.text_field :dinner_limit %> </div> <div class="form-group"> <%= f.label :shop_genres, class:'control-label' %> <div class="checkbox"> <%= collection_check_boxes(:shop, :shop_genre_ids, ShopGenre.all, :id, :name) do |f| %> <%= f.label {f.check_box + f.text} %> <% end %> </div> </div> <div class="field"> <%= f.submit "shop create", class: "new-btn" %> </div> </div> <% end %>
routes.rb devise_for :shops, controllers: { sessions: 'shops/sessions', }
controllers/shops/sessions_controller.rb # frozen_string_literal: true class Shops::SessionsController < Devise::SessionsController prepend_before_action :require_no_authentication, only: [:new, :create] prepend_before_action :allow_params_authentication!, only: :create prepend_before_action :verify_signed_out_shop, only: :destroy prepend_before_action(only: [:create, :destroy]) { request.env["devise.skip_timeout"] = true } # GET /resource/sign_in def new self.resource = resource_class.new(sign_in_params) clean_up_passwords(resource) yield resource if block_given? respond_with(resource, serialize_options(resource)) end # POST /resource/sign_in def create #元の認証ロジック #self.resource = warden.authenticate!(auth_options) #emailだけでログインできるように変更 self.resource = Shop.where(:name => params[:shop]['email']).first set_flash_message(:notice, :signed_in) if is_flashing_format? sign_in(resource_name, resource) yield resource if block_given? respond_with resource, :location => after_sign_in_path_for(resource) end # DELETE /resource/sign_out def destroy signed_out = (Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name)) set_flash_message! :notice, :signed_out if signed_out yield if block_given? respond_to_on_destroy end protected def sign_in_params devise_parameter_sanitizer.sanitize(:sign_in) end def serialize_options(resource) methods = resource_class.authentication_keys.dup methods = methods.keys if methods.is_a?(Hash) methods << :password if resource.respond_to?(:password) { methods: methods, only: [:password] } end def auth_options { scope: resource_name, recall: "#{controller_path}#new" } end def translation_scope 'devise.sessions' end private # Check if there is no signed in user before doing the sign out. # # If there is no signed in user, it will set the flash message and redirect # to the after_sign_out path. def verify_signed_out_shop if all_signed_out? set_flash_message! :notice, :already_signed_out respond_to_on_destroy end end def all_signed_out? shops = Devise.mappings.keys.map { |s| warden.shop(scope: s, run_callbacks: false) } shops.all?(&:blank?) end def respond_to_on_destroy # We actually need to hardcode this as Rails default responder doesn't # support returning empty response on GET request respond_to do |format| format.all { head :no_content } format.any(*navigational_formats) { redirect_to after_sign_out_path_for(resource_name) } end end end
試したこと
パスワードを暗号化して保存できる様にpassword_digestというカラムをshopに持たせ、対象のモデルファイル(shop.rb)にhas_secure_passwordと記述。
暗号化のためのbcryptというGemを追加。
あとはdeviseのパスワードなしでログインさせるというqiitaの記事を参考にdeviseのルートを変更し任意のコントローラーを指定しその記述をemailだけでログインできる様に変更。
そこから管理者側で作成したpassword_digestと組み合わせてログインできる様にしたいが、どうすれば実装できるのか分からず、いろいろな記事を見て見ましたがdeviseに関しての理解が乏しくわかりませんでした。
分からなすぎて不安で眠れず、、、何かヒントが欲しいと思い質問させていただきました。
学習を初めて間も無く、初の質問でわかりにくい説明で申し訳ありませんがよろしくお願い申し上げます。
補足情報(FW/ツールのバージョンなど)
ここにより詳細な情報を記載してください。