Próbuję utworzyć aplikację w Rails 4. Próbowałem przez ostatnie 3 lata (z wyjątkiem 10 dni), aby przygotować się do pracy.Szyny 4 - Wymyśl Omniautha (wiele strategii)
Staram się śledzić ten tutorial: http://sourcey.com/rails-4-omniauth-using-devise-with-twitter-facebook-and-linkedin/
Proszę Niepolecane inną dokumentację tutoriale/GEM. Próbowałem co najmniej 30 innych samouczków, a dokumentacja z klejnotami zawiera mnóstwo błędów i składników, których nie rozumiem.
Mój obecny problem polega na tym, że po przejściu do etapu rejestracji w tym samouczku formularz poprosi mnie o podanie mojego adresu e-mail.
Kontroler użytkowników ma mety metody zapisywania jako:
def finish_signup
# authorize! :update, @user
if request.patch? && params[:user] #&& params[:user][:email]
if @user.update(user_params)
@user.skip_reconfirmation!
# sign_in(@user, :bypass => true)
# redirect_to root_path, notice: 'Your profile was successfully updated.'
# redirect_to [@user, @user.profile || @user.build_profile]
sign_in_and_redirect(@user, :bypass => true)
else
@show_errors = true
end
end
end
Kiedy próbuję to, otrzymuję ten błąd:
undefined method `match' for {:host=>"localhost", :port=>3000}:Hash
punktów błędach w tej linii:
<div class="intpol3"><%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %></div>
Moje środowisko programistyczne jest skonfigurowane tak, aby zawierało wszystkie szczegóły konfiguracji dla mojego nadawcy wiadomości e-mail.
Kiedy próbuję ten sam krok w trybie produkcyjnym, otrzymuję ten błąd:
ActionView::Template::Error (No route matches {:action=>"show", :controller=>"profiles", :id=>nil} missing required keys: [:id]):
on szuka identyfikatora profilu bo mam after_create działania w moim modelu użytkownika jako:
after_create :gen_profile
def gen_profile
Profile.create(user: self) # Associations must be defined correctly for this syntax, avoids using ID's directly.
# Profile.save
end
Innym problemem związanym z tym samouczkiem jest to, że pola w tabeli tożsamości nie są wypełniane.
Chciałbym znaleźć kogoś, kto pomyślnie wdrożył ten samouczek lub może zobaczyć, jak to zrobić.
Mój kod to:
gemfile
gem 'devise', '3.4.1'
gem 'devise_zxcvbn'
gem 'omniauth'
gem 'omniauth-oauth2', '1.3.1'
gem 'omniauth-google-oauth2'
gem 'omniauth-facebook'
gem 'omniauth-twitter'
gem 'omniauth-linkedin-oauth2'
gem 'google-api-client', require: 'google/api_client'
trasy
devise_for :users, #class_name: 'FormUser',
:controllers => {
:registrations => "users/registrations",
# :omniauth_callbacks => "users/authentications"
:omniauth_callbacks => 'users/omniauth_callbacks'
}
# get '/auth/:provider/callback' => 'users/authentications#create'
# get '/authentications/sign_out', :to => 'users/authentications#destroy'
# PER SOURCEY TUTORIAL ----------
match '/users/:id/finish_signup' => 'users#finish_signup', via: [:get, :patch], :as => :finish_signup
resources :users do
resources :profiles, only: [:new, :create]
end
user.rb
klasa User < ActiveRecord :: Base
TEMP_EMAIL_PREFIX = '[email protected]'
TEMP_EMAIL_REGEX = /\[email protected]/
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable,
:confirmable, :lockable,
# :zxcvbnable,
:omniauthable, :omniauth_providers => [:facebook, :linkedin, :twitter, :google_oauth2 ]
# --------------- associations
has_many :authentications, :dependent => :delete_all
has_one :profile
has_many :identities
# --------------- scopes
# --------------- validations
# validates_presence_of :first_name, :last_name
validates_uniqueness_of :email
# per sourcey tutorial - how do i confirm email registrations are unique?
# this is generating an error about the options in the without function -- cant figure out the solution
validates_format_of :email, :without => TEMP_EMAIL_REGEX, on: :update
# --------------- class methods
# sourcey tutorial
def self.find_for_oauth(auth, signed_in_resource = nil)
# Get the identity and user if they exist
identity = Identity.find_for_oauth(auth)
# If a signed_in_resource is provided it always overrides the existing user
# to prevent the identity being locked with accidentally created accounts.
# Note that this may leave zombie accounts (with no associated identity) which
# can be cleaned up at a later date.
user = signed_in_resource ? signed_in_resource : identity.user
# p '11111'
# Create the user if needed
if user.nil?
# p 22222
# Get the existing user by email if the provider gives us a verified email.
# If no verified email was provided we assign a temporary email and ask the
# user to verify it on the next step via UsersController.finish_signup
email_is_verified = auth.info.email && (auth.info.verified || auth.info.verified_email)
email = auth.info.email if email_is_verified # take out this if stmt for chin yi's solution
user = User.where(:email => email).first if email
# Create the user if it's a new registration
if user.nil?
# p 33333
user = User.new(
# at least one problem with this is that each provider uses different terms to desribe first name/last name/email. See notes on linkedin above
first_name: auth.info.first_name,
last_name: auth.info.last_name,
email: email ? email : "#{TEMP_EMAIL_PREFIX}-#{auth.uid}-#{auth.provider}.com",
#username: auth.info.nickname || auth.uid,
password: Devise.friendly_token[0,20])
# fallback for name fields - add nickname to user table
# debugger
# if email_is_verified
user.skip_confirmation!
# end
# user.skip_confirmation!
user.save!
end
end
# Associate the identity with the user if needed
if identity.user != user
identity.user = user
identity.save!
end
user
end
def email_verified?
self.email && TEMP_EMAIL_REGEX !~ self.email
end
użytkowników kontroler
class UsersController < ApplicationController
before_action :set_user, only: [:index, :show, :edit, :update, :finish_signup, :destroy]
# i added finish_signup to the set_user action (not shown in tutorial)
def index
# if params[:approved] == "false"
# @users = User.find_all_by_approved(false)
# else
@users = User.all
# end
end
# GET /users/:id.:format
def show
# authorize! :read, @user
end
# GET /users/:id/edit
def edit
# authorize! :update, @user
end
# PATCH/PUT /users/:id.:format
def update
# authorize! :update, @user
respond_to do |format|
if @user.update(user_params)
sign_in(@user == current_user ? @user : current_user, :bypass => true)
format.html { redirect_to @user, notice: 'Your profile was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: @user.errors, status: :unprocessable_entity }
end
end
end
# GET/PATCH /users/:id/finish_signup
def finish_signup
# authorize! :update, @user
if request.patch? && params[:user] #&& params[:user][:email]
if @user.update(user_params)
@user.skip_reconfirmation!
# sign_in(@user, :bypass => true)
# redirect_to root_path, notice: 'Your profile was successfully updated.'
# redirect_to [@user, @user.profile || @user.build_profile]
sign_in_and_redirect(@user, :bypass => true)
else
@show_errors = true
end
end
end
# DELETE /users/:id.:format
def destroy
# authorize! :delete, @user
@user.destroy
respond_to do |format|
format.html { redirect_to root_url }
format.json { head :no_content }
end
end
private
def set_user
@user = User.find(params[:id])
end
def user_params
# params.require(:user).permit(policy(@user).permitted_attributes)
accessible = [ :first_name, :last_name, :email, :avatar ] # extend with your own params
accessible << [ :password, :password_confirmation ] unless params[:user][:password].blank?
# accessible << [:approved] if user.admin
params.require(:user).permit(accessible)
end
end
omniauth callbacks Kontroler
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def self.provides_callback_for(provider)
class_eval %Q{
def #{provider}
@user = User.find_for_oauth(env["omniauth.auth"], current_user)
if @user.persisted?
sign_in_and_redirect @user, event: :authentication
set_flash_message(:notice, :success, kind: "#{provider}".capitalize) if is_navigational_format?
else
session["devise.#{provider}_data"] = env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
}
end
# , current_user has been deleted from the end of line 51
#come back to put current_user into fidn by oauth so i can link other accounts - i have added this back for the purpose of solving the current problem
# puts current_user.inspect
# sign_in_and_redirect [@user, @user.profile || @user.build_profile]
# sign_in_and_redirect_user(:user, event: :authentication)
[:twitter, :facebook, :linkedin, :google_oauth2].each do |provider|
provides_callback_for provider
end
def after_sign_in_path_for(resource)
if resource.email_verified?
super resource
else
finish_signup_path(resource)
end
end
end
rejestracje
class Users::RegistrationsController < Devise::RegistrationsController
protected
def after_sign_up_path_for(resource)
profile_path(resource)
end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password)
end
end
tożsamość.rb
kontrolerclass Identity < ActiveRecord::Base
belongs_to :user
validates_presence_of :uid, :provider
validates_uniqueness_of :uid, :scope => :provider
def self.find_for_oauth(auth)
find_or_create_by(uid: auth.uid, provider: auth.provider)
end
end
Tożsamości
class IdentitiesController < ApplicationController
before_action :set_identity, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!
# GET /identities
# GET /identities.json
def index
@identities = Identity.all
end
# GET /identities/1
# GET /identities/1.json
def show
end
# GET /identities/new
def new
@identity = Identity.new
end
# GET /identities/1/edit
def edit
end
# POST /identities
# POST /identities.json
def create
@identity = Identity.new(identity_params)
respond_to do |format|
if @identity.save
format.html { redirect_to @identity, notice: 'Identity was successfully created.' }
format.json { render :show, status: :created, location: @identity }
else
format.html { render :new }
format.json { render json: @identity.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /identities/1
# PATCH/PUT /identities/1.json
def update
respond_to do |format|
if @identity.update(identity_params)
format.html { redirect_to @identity, notice: 'Identity was successfully updated.' }
format.json { render :show, status: :ok, location: @identity }
else
format.html { render :edit }
format.json { render json: @identity.errors, status: :unprocessable_entity }
end
end
end
# DELETE /identities/1
# DELETE /identities/1.json
def destroy
@identity.destroy
respond_to do |format|
format.html { redirect_to identities_url, notice: 'Identity was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_identity
@identity = Identity.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def identity_params
params[:identity]
end
end
Devise Mailer - potwierdzenie
<div class="intpol3"><%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %></div>
STRESZCZENIE Aktualne problemy:
W trybie rozwoju: Jest problem z link do confi token rmacyjny. Nie mogę znaleźć żadnych materiałów, które wskazywałyby, dlaczego tak się mogło stać. Błąd: (ActionView :: Szablon :: Błąd (niezdefiniowana metoda "dopasuj" dla {: host => "localhost",: port => 3000}: Hash):
W trybie produkcyjnym istnieje błąd z użytkownikiem szukającym identyfikatora profilu. Komunikat o błędzie: ActionView :: Szablon :: Błąd (brak trasy odpowiada {: action => "show",: controller => "profiles",: id => nil} brakujące wymagane klucze [id]):
profilach trasy są:
resources :profiles, only: [:show, :edit, :update, :destroy]
resources :users do
resources :profiles, only: [:new, :create]
end
- Żaden z pola w model tożsamości jest wypełniany. Wszystkie są wyświetlane jako zero.
rzeczy zrobić inaczej niż jak pokazano w tutorialu:
pozwalam też e-mail zapisz się
dodam „finish_sign_up” do set_user zanim akcji w kontrolerze użytkowników
Dodaję strategię g + (co oznacza, że moje klejnoty są nieco inne)
Moja nowa metoda użytkownika nie używa surowych informacji. Używa informacji przetworzonych oauth.
Moje przekierowanie w metodzie rejestracji końcowej jest nieco inne, chociaż skomentowałem to i wróciłem do sposobu, w jaki zostało to określone w samouczku, aby spróbować działać (chociaż powyższe problemy się powtarzają).
Szaleję, próbując rozwiązać te problemy. Powiedziałbym, że 3 lata to o wiele za długo, aby utknąć w tym problemie. Jeśli ktokolwiek może pomóc, zapłaciłbym 10 razy, a potem kilka. Dziękuję Ci.
Zrobiłem to z powodzeniem. Czy potrafisz zweryfikować z poziomu konsoli szyn, czy rzeczywiście tworzone są twoje profile? Czy masz bardziej szczegółowe pytanie? – errata
Tak - profil jest tworzony dla użytkownika. Moje konkretne pytanie brzmi: jak mogę uzyskać tę konfigurację samouczka? Obecny błąd jest natychmiastowym wyzwaniem, więc jeśli istnieje sposób na rozwiązanie problemu, który może być przyczyną tego problemu, chciałbym zacząć od rozwiązania tego problemu. – Mel
Hi Errata - czy dodałeś jakiś przycisk gdzieś w kodzie, aby pozwolić użytkownikom (raz w sesji) na dodanie innych tożsamości użytkowników? Gdzie to zrobiłeś? Myślę, że gdy wszystkie bieżące problemy zostaną rozwiązane, prawdopodobnie ma to sens w metodzie rejestracji końcowej. Jak sobie z tym poradziłeś? – Mel