我刚刚开始使用 Devise 和 Rails3。我已完成身份验证并正在工作并了解基础知识。
截至目前,在代表我的主页/首页的主控制器中,我有两个链接,一个链接到“注册”=>“sign_up”,另一个链接根据登录/注销=>“sign_in/sign_out”而变化。
但是我不想将我的用户重定向到登录页面。相反,我想在我的首页上显示我的登录表单。所以我将
devise/session/new
模板 int 分离为视图和 _form.html.erb 部分。
现在在我的主视图中,我将登录表单呈现如下:
<% if user_signed_in? %>
Welcome: <b><%= current_user.username %> (<%= current_user.group.name %>)</b>
<%= link_to "Logout", destroy_user_session_path, :method => 'delete' %>
<% else %>
<%= render 'devise/sessions/form' %> // Rendering the partial here
<%= link_to "Login", new_user_session_path %>
<% end %>
<hr>
这是部分代码:
<%= form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| %>
<div><%= f.label :email %><br />
<%= f.email_field :email, :autofocus => true %></div>
<div><%= f.label :password %><br />
<%= f.password_field :password %></div>
<% if devise_mapping.rememberable? -%>
<div><%= f.check_box :remember_me %> <%= f.label :remember_me %></div>
<% end -%>
<div><%= f.submit "Sign in" %></div>
<% end %>
我的错误如下:
NameError in Home#index
Showing devise/sessions/_form.html.erb where line #1 raised:
undefined local variable or method `resource' for #<#<Class:0x614ec68>:0x6157ff8>
Extracted source (around line #1):
1: <%= form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| %>
2: <div><%= f.label :email %><br />
3: <%= f.email_field :email, :autofocus => true %></div>
4:
我明白为什么会发生错误。这是因为该部分没有被赋予资源属性。我使用了
dump(resource)
,结果发现它是一个用户模型/对象所以我在它之前添加了以下内容:
<% if @user %>
<% resource = @user %>
<% end %>
并将以下内容添加到我的家庭控制器索引方法中:
def index
@user = User.new
end
但是之后我得到了resource_name错误,结果只是
:user
,如果我设置了它,那么我会遇到问题,因为devise_mapping.rememberable?
我不知道如何提供。
我想正确地做到这一点,所以我想避免我开始的混乱和不合逻辑的方法。
看看这个问题的答案:在不同的控制器中设计表单
您尝试使用 Home 控制器呈现的表单依赖于 Devise 定义的助手,而非 Devise 控制器无法访问这些助手。
向您的 home_helper.rb 添加必要的助手应该可以解决您的问题:
def resource_name
:user
end
def resource
@resource ||= User.new
end
def devise_mapping
@devise_mapping ||= Devise.mappings[:user]
end
我正在使用 Devise 3.5.1,我还必须添加资源类才能使登录表单在不同的控制器上工作。
我将其添加到 application_helper.rb,以便它适用于我的所有控制器。
def resource_name
:user
end
def resource
@resource ||= User.new
end
def devise_mapping
@devise_mapping ||= Devise.mappings[:user]
end
def resource_class
devise_mapping.to
end
由于低代表,我无法对已接受的答案发表评论,但我刚刚发现了这种方法的一个棘手的错误(Rails 7.1.3 和 Devise 4.9.3)。如果您定义
resource
就像 application_helper.rb 中的答案状态一样,它将隐藏 Devise 的实现
def resource
instance_variable_get(:"@#{resource_name}")
end
在大多数情况下这仍然有效。在我的用例中,它在用户注册时产生了一个主要错误,因为流程创建了一个新的用户实例,但没有将其存储在 DeviseController 都依赖的实例变量 (
self.resource
) 中。
这很可能会在前端显示“电子邮件不能为空”或“密码不能为空”错误,即使您可以在 Devise 尝试之前看到您的参数已正确传入并过滤
build_resource(sign_up_params)
然后非常奇怪的是 resource
在结构上存在,但它的所有字段都是空的。
删除资源帮助器定义解决了这个问题。实际上,我删除了所有助手,除了
def devise_mapping
@devise_mapping ||= Devise.mappings[:member]
end
Devise 代码中使用的
@devise_mapping ||= request.env["devise.mapping"]
在 DeviseController 之外也不适用于我,所以我坚持使用静态硬编码方法。
我花了两天时间才弄清楚这个问题。
但是,现在你可能遇到另一个问题。假设您的部分登录表单(例如登陆页面上的导航栏,这是一种非常常见的设计模式)不是由 DeviseController 呈现的。如果你的帮助器中没有
resource
,这将在 erb 语法中出错。
就我而言,我通过在该部分表单中“硬编码”我的
resource
和 resource_name
解决了这个问题,因为我无法对主站点控制器使用 DeviseController 继承。