在其他控制器中设计表单


128

我正在将一个devise gem用于sign_in / sign_out过程。

我使用以下方法从devise生成了视图文件 rails g devise views

我看到有一个devise / sessions / new.html.erb文件,其中包含sign_in的表单。

我创建了另一个文件devise / sessions / _form.html.erb,并<%= render 'form' %>在new.html.erb文件中进行了工作,效果很好。

现在,我想包含来自其他控制器的此表单。因此,在名为“ main”的控制器(特别是在视图页面内)中的“ mains / index.html.erb”中,我包含了<%= render 'devise/sessions/form' %>文件。似乎包含工作正常,但出现以下错误。

NameError in Mains#index

Showing /home/administrator/Ruby/site_v4_ruby/app/views/devise/sessions/_form.html.erb where line #1 raised:

undefined local variable or method `resource' for #<#<Class:0x007f1aa042d530>:0x007f1aa042b870>
Extracted source (around line #1):

1: <%= form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| %>
2:   <p><%= f.label :email %><br />
3:   <%= f.text_field :email %></p>
4: 

似乎form_for(resource,...)部分引起了问题(如果我在原始的dev_sign_in页面上,此方法很好...如何以Rails方式解决此问题?

我个人更喜欢使用“渲染”功能来包含表单,而不是内联编写html代码。

我是否必须在“主”控制器中指定某些内容(资源)?

感谢您的帮助。谢谢。


有什么解决方案吗...?截至11月16日,我还没有真正使用render的解决方案。.虽然如果我只是键入内联代码,它似乎可以正常工作
。–

您为此找到了解决方案吗?
neebz 2011年

是的,我选择了可​​以解决我的问题的答案。这比我想象的要简单。
2011年

Answers:


240

如Andres所说,该表单调用由Devise指定的助手,因此当您从非Devise控制器访问Devise表单时,该助手将不存在。

要解决此问题,您需要将以下方法添加到希望在其下显示表单的控制器的帮助器类中。或者,您可以将它们添加到应用程序帮助程序中以使它们在任何地方都可用。

  def resource_name
    :user
  end

  def resource
    @resource ||= User.new
  end

  def devise_mapping
    @devise_mapping ||= Devise.mappings[:user]
  end

来源:http//pupeno.com/blog/show-a-devise-log-in-form-in-another-page/


6
优秀的。确保它在帮助器中,而不在控制器中。另外,如果您有其他资源(例如也可以登录的公司)并且想要加载其表单,则可能会导致巨大的问题。确保重新定义名称,路由也可能会成为问题。
Michael Schmitz

1
这种解决方案的坏处在于它会中断inherited_resources
jrhorn424

6
为了限制这些方法的范围(例如,避免名称空间与其他gem冲突),请尝试将上述方法与控制器本身一起添加helper_method :resource_name, :resource_class, :resource, :devise_mapping:resource_class在较新的Devise版本中似乎是必需的)。
2014年

1
如果我们的设计模型很少,应该怎么解决?
yozzz 2014年

我有两个Devise模型,并且都需要在主页上登录。任何想法如何做类似于您的答案?
DR_

8

也可以尝试...检查此问题

资源

<%= form_for("user", :url => user_session_path) do |f| %>
  <%= f.text_field :email %>
  <%= f.password_field :password %>
  <%= f.check_box :remember_me %>
  <%= f.label :remember_me %>
  <%= f.submit 'Sign in' %>
  <%= link_to "Forgot your password?", new_password_path('user') %>
<% end %> 

这不是所有答案中的最佳做法吗?
allegutta 2014年

4

您创建的表单在从Devise控制器呈现时可以工作,因为“资源”是通过Devise定义的。看一下Devise SessionsController的实现-据我了解,您正在尝试复制“新”操作。您可能正在寻找方法“ build_resource”。

监狱长的宝石是这里的“资源”对象的来源。如果您想深入研究,那就去找吧。


我只是在mains_controller中调用了“ build_resource”,但它会出现[未定义的局部变量或方法“ build_resource”]错误。我尝试通过在'mains_controller'的顶部插入'include Devise :: Controllers :: InternalHelpers'来包括devise内部帮助程序,但它也引起了AbstractAbstract :: ActionNotFound错误
user482594

3

为了完善可接受的答案,我们使用此帮助程序来允许不同类型的资源:

def resource_name
  @resource_name ||= if admin_controller?
    :admin_user
  else
    :user
  end
end

def resource
  @resource ||= resource_name.to_s.classify.constantize.new
end

def devise_mapping
  @devise_mapping ||= Devise.mappings[resource_name]
end

admin_controller?我们之前ApplicationController处理登录重定向的地方是什么?

def admin_controller?
  !devise_controller? and request.path =~ /^\/admin/
end
helper_method :admin_controller?

2

undefined local variable or method "resource"从一个控制器中收到与您描述的错误相同的错误,因为我的控制器基类缺少以下内容(Rails-API ActionController :: API有错误):

include ActionController::Helpers

因此,无法在视图中解析Devise的辅助方法。

为了使Devise与Rails-API一起使用,我需要包括:

class ApplicationController < ActionController::API

  include AbstractController::Rendering
  include AbstractController::Layouts
  include ActionController::MimeResponds
  include AbstractController::Translation
  include ActionController::ImplicitRender
  include ActionController::Helpers
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.