Mel*_*Mel 11 resources routes ruby-on-rails path
我试图整理这篇文章,所以对新来者来说似乎并不长.它包括由以下答案中的其他人提出的建议所导致的错误.
我正在尝试用Rails 4创建一个应用程序.
我使用设计和omniauth.
我有用户和个人资料的模型.用户有一个配置文件和配置文件属于用户.
我的目标是将用户模型用于用户并未真正触摸的所有内容.我将配置文件模型用于用户确实维护的内容.
创建新用户时,我希望将用户重定向到他们的配置文件页面,该页面应该部分填充在用户模型中创建的详细信息.
我遇到了麻烦.
我有:
User.rb
has_one :profile
Run Code Online (Sandbox Code Playgroud)
Profile.rb
belongs_to :user
Run Code Online (Sandbox Code Playgroud)
Omniauth_callbacks_controller.rb
if @user.persisted?
sign_in_and_redirect_user(:user, authentication.user.profile)
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
Run Code Online (Sandbox Code Playgroud)
我也尝试过回调重定向:
sign_in_and_redirect @user, event: :authentication
Run Code Online (Sandbox Code Playgroud)
型材/ show.html.erb
<div class="container-fluid">
<div class="row">
<div class="col-xs 8 col-xs-offset-1">
<%= @profile.user.formal_name %>
<%= @profile.occupation %>
<%= @profile.qualification.awards %>
<%= @profile.overview %>
<%= @profile.research_interests %>
</div>
<div class="col-xs 3">
<div class="geobox">
<%= render 'addresses/location' %>
<%= @profile.working_languages %>
<%= @profile.external_profile %>
</div>
</div>
</div>
<div class="row">
<div class="col-xs 10 col-xs-offset-1">
<%= render 'profiles/activity' %>
</div>
</div>
</div>
Run Code Online (Sandbox Code Playgroud)
_nav.html.erb
<% if user_signed_in? %>
Hi <%= link_to(current_user.first_name.titlecase, profile_path(current_user)) %></span>
Run Code Online (Sandbox Code Playgroud)
我也尝试过:
_nav.html.erb
<% if user_signed_in? %>
Hi <%= link_to(current_user.first_name.titlecase, user_profile_path(current_user.profile)) %></span>
Run Code Online (Sandbox Code Playgroud)
我需要做些什么来添加某种功能才能让新用户访问他们的个人资料页面?
目前,当我尝试登录并单击导航栏链接时,我想转到配置文件页面.相反,我转到一条错误消息,说我正在寻找的页面不存在.它寻找的路径从配置文件(而不是用户/配置文件)开始 - 不确定这是否是线索.
我的路线是:
简介:
profiles GET /profiles(.:format) profiles#index
POST /profiles(.:format) profiles#create
new_profile GET /profiles/new(.:format) profiles#new
edit_profile GET /profiles/:id/edit(.:format) profiles#edit
profile GET /profiles/:id(.:format) profiles#show
PATCH /profiles/:id(.:format) profiles#update
PUT /profiles/:id(.:format) profiles#update
DELETE /profiles/:id(.:format) profiles#destroy
Run Code Online (Sandbox Code Playgroud)
用户:
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) users/registrations#cancel
user_registration POST /users(.:format) users/registrations#create
new_user_registration GET /users/sign_up(.:format) users/registrations#new
edit_user_registration GET /users/edit(.:format) users/registrations#edit
PATCH /users(.:format) users/registrations#update
PUT /users(.:format) users/registrations#update
DELETE /users(.:format) users/registrations#destroy
user_confirmation POST /users/confirmation(.:format) devise/confirmations#create
new_user_confirmation GET /users/confirmation/new(.:format) devise/confirmations#new
GET /users/confirmation(.:format) devise/confirmations#show
user_unlock POST /users/unlock(.:format) devise/unlocks#create
new_user_unlock GET /users/unlock/new(.:format) devise/unlocks#new
GET /users/unlock(.:format) devise/unlocks#show
finish_signup GET|PATCH /users/:id/finish_signup(.:format) users#finish_signup
Run Code Online (Sandbox Code Playgroud)
新的尝试:根据下面的建议,我将资源嵌套为:
resources :users do
resources :profile
end
Run Code Online (Sandbox Code Playgroud)
我将重定向更改为:
def self.provides_callback_for(provider)
class_eval %Q{
def #{provider}
@user = User.find_for_oauth(env["omniauth.auth"])
if @user.persisted?
sign_in_and_redirect [current_user, current_user.profile || current_user.build_profile]
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
Run Code Online (Sandbox Code Playgroud)
我收到此错误:NoMethodError(nil的未定义方法`profile':NilClass):
下一步尝试:
我保留了以上所有内容,但尝试更换重定向,如下所示:
def self.provides_callback_for(provider)
class_eval %Q{
def #{provider}
@user = User.find_for_oauth(env["omniauth.auth"])
if @user.persisted?
sign_in_and_redirect [@user, @user.profile || @user.build_profile]
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
RuntimeError (Could not find a valid mapping for [#<User id: 1 ...
Run Code Online (Sandbox Code Playgroud)
然后它列出用户表中的所有属性,然后显示:
#<Profile id: nil, user_id: 1,
Run Code Online (Sandbox Code Playgroud)
后跟配置文件表中的所有属性.
一个新的尝试
我发现这篇文章:Rails尝试在创建用户后创建配置文件
我尝试添加:
after_create do
create_user_profile
end
Run Code Online (Sandbox Code Playgroud)
到我的用户模型.
我保持重定向与我一样(遵循阿列克谢的建议)并再次尝试.
我收到相同的错误消息:
RuntimeError (Could not find a valid mapping for [#<User id: 1
Run Code Online (Sandbox Code Playgroud)
谁能看到如何解决这个问题?
进一步尝试:
然后我发现这篇文章: Ruby on Rails - 在创建用户时创建配置文件
对于Rails 4(我使用的),我只需要这个回调:
after_create:create_profile
当我尝试这个时,我得到与上面相同的错误.
一个主意:
我为我的配置文件控制器使用了脚手架生成器.
我的创建方法是:
def create
@profile = Profile.new(profile_params)
respond_to do |format|
if @profile.save
format.html { redirect_to @profile }
format.json { render :show, status: :created, location: @profile }
else
format.html { render :new }
format.json { render json: @profile.errors, status: :unprocessable_entity }
end
end
end
Run Code Online (Sandbox Code Playgroud)
此错误是否与此方法中未特别引用的用户标识有关.我已在配置文件控制器的强参数中将user_id列入白名单.
一个新的尝试
本文建议使用build_profile而不是create_profile.
https://stackoverflow.com/questions/8337682/create-another-model-upon-user-new-registration-in-devise
Run Code Online (Sandbox Code Playgroud)
我将user.rb更改为
after_create :build_profile
Run Code Online (Sandbox Code Playgroud)
当我保存这个并尝试我得到相同的错误.
另一个尝试
Matt在这篇文章中的回答表明我必须将build_profile的定义包含为:
after_create :build_profile
def build_profile
Profile.create(user: self) # Associations must be defined correctly for this syntax, avoids using ID's directly.
end
Run Code Online (Sandbox Code Playgroud)
我将user.rb更改为:
after_create :build_profile
def build_profile
Profile.create(user: self) # Associations must be defined correctly for this syntax, avoids using ID's directly.
end
Run Code Online (Sandbox Code Playgroud)
当我保存并尝试这个时,我得到了类似的错误,但有更多信息.日志仍然显示:
RuntimeError (Could not find a valid mapping for [#<User id: 1,
Run Code Online (Sandbox Code Playgroud)
但在完成所有错误消息后,它会提供以下新信息:
SQL (2.9ms) INSERT INTO "profiles" ("user_id", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id" [["user_id", 1], ["created_at", "2015-12-18 21:58:49.993866"], ["updated_at", "2015-12-18 21:58:49.993866"]]
2015-12-18T21:58:49.966648+00:00 app[web.1]: Profile Load (1.5ms) SELECT "profiles".* FROM "profiles" WHERE "profiles"."user_id" = $1 LIMIT 1 [["user_id", 1]]
2015-12-18T21:58:50.007428+00:00 app[web.1]: Completed 500 Internal Server Error in 113ms (ActiveRecord: 21.8ms)
2015-12-18T21:58:49.941385+00:00 app[web.1]: User Load (1.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 1]]
Run Code Online (Sandbox Code Playgroud)
这是否能解决问题?
UPDATE
我再次尝试了这一点(没有对代码进行任何更改).现在我收到一个错误,但这次日志说:
RuntimeError (Could not find a valid mapping for [#<User id: 1, first_name: "Me", last_name: "Ma", email: "mema@gmail.com", encrypted_password: "$2a$jqQn..HSvlcNtfAH/28.DQoWetO...", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 16, current_sign_in_at: "2015-12-15 09:57:14", last_sign_in_at: "2015-12-15 09:27:07", current_sign_in_ip: #<IPAddr: IPv4:49.191.55>, last_sign_in_ip: #<IPAddr: IPv4:49.191.135.255.255>, confirmation_token: nil, confirmed_at: "2015-12-15 09:02:58", confirmation_sent_at: "2015-12-15 08:42:48", unconfirmed_email: nil, failed_attempts: 0, unlock_token: nil, locked_at: nil, created_at: "2015-12-09 23:53:20", updated_at: "2015-12-15 09:57:14", image: nil>, #<Profile id: 1, user_id: 1, title: nil, hero_image: nil, overview: nil, occupation: nil, external_profile: nil, working_languages: nil, created_at: "2015-12-18 21:58:49", updated_at: "2015-12-18 21:58:49">]):
Run Code Online (Sandbox Code Playgroud)
这次的不同之处在于配置文件的用户ID密钥为1.以前,这是零.
您已添加sing_in_and_redirect_user到回调控制器中。要编辑它重定向到的路径,您还应该覆盖并编辑
after_sign_in_path_for您的applications_controller.
class ApplicationController < ActionController::Base
def after_sign_in_path_for(resource)
request.env['omniauth.origin'] || stored_location_for(resource) || root_path
end
end
Run Code Online (Sandbox Code Playgroud)
您可以在此处编辑重定向到的实际路径。不确定 omniauth 部分,但您可以添加profile_path(resource.profile).
参考: https: //github.com/plataformatec/devise/wiki/How-To :-redirect-to-a-specific-page-on-successful-sign-in