【问题标题】:Pass instance variable between controllers using a helper使用助手在控制器之间传递实例变量
【发布时间】:2017-04-26 01:34:35
【问题描述】:

我有三个实体:用户、联系人和参与度。 user 那个has_many: contacts。联系belongs_to: user。用户与联系人进行互动。我也有订婚belongs_to: contact。 在我的views/contacts/show.html.erb 中,我想显示特定联系人的页面,并让用户通过填写​​参与表格来注册与联系人的参与。我希望在联系人页面上创建的参与与该特定联系人相关联。 所以我显示一个联系人:

resources :contacts
resources :engagements, only: [:create, :edit, :destroy]

class ContactsController < ApplicationController
      include ApplicationHelper
       def show
        @contact = Contact.find(params[:id])
        set_current_contact @contact.id  #pass the particular id to helper
      end
    end

在助手中定义方法:

module ApplicationHelper
  def set_current_contact(contact_id)
    @current_contact = Contact.find_by(id: contact_id) 
  end

  def the_current_contact
    @current_contact   #create instance variable for the other helper
  end
end

我想要做的关键事情是让参与控制器“知道”用户正在注册参与的联系人。即通过@contactEngagementsController

class EngagementsController < ApplicationController
  def create
    @engagement = the_current_contact.engagements.build(engagement_params) 
  end
end

我得到错误:

undefined method `set_current_contact' for #<EngagementsController:0x007f2c2c24f360>

第一个问题是我不明白为什么控制器不能从ApplicationHelper 访问方法? 我并不是要问两个不同的问题,但第二个问题是以这种方式使用帮助程序是否是正确的方法。我知道 HTTP 是一种无状态协议,在这种情况下,帮助程序对于传递实例变量很有用。我搜索了类似的帖子并找到了相关的Rails: Set a common instance variable across several controller actions,但虽然它推荐了帮助器作为解决方案,但它并没有特别说明如何使用帮助器。

编辑:我在EngagementsController 中添加了缺少的include ApplicationHelper。现在的错误是:

wrong number of arguments (given 0, expected 1)
Extracted source (around line #13):

  end

  13 def set_current_contact(contact_id)
  14   @current_contact = Contact.find_by(id: contact_id)
  15 end

【问题讨论】:

  • 您忘记在 EngagementsController 中输入 include ApplicationHelper。即使你解决了这个问题,你的假设是正确的,它不会像你期望的那样工作:)

标签: ruby-on-rails


【解决方案1】:

您不能使用实例变量在两个请求之间共享数据,甚至在对同一个控制器的两个请求之间也不能。导轨creates a new controller instance for every request。即便如此,您的应用程序可能位于负载均衡器之后,没有人可以保证第二个请求甚至由同一台服务器提供服务。

实现您想要的最佳方式是将contact_id 作为参数传递给EngagementsController#create 操作。或者使用会话数据。

【讨论】:

  • @lulian 是的,能够将contact_id 传递给EngagementsController 会很有帮助。我可以在EngagementsController 中传递Contact.allContact.first 等等,但我如何获得特定的Contact.find([params: id])。 EngagementsController 如何访问该 ID?联系人控制器可以通过get 'contacts/:id' 访问它,这在contacts#showdestroy 等中很容易使用。参与控制器如何知道当前页面是例如contacts/23 从而将订婚附加到 id 23 的联系人?
  • @lulian 您还建议使用会话数据。由于用户登录,这可以通过session[:user_id] 获取当前用户ID。但是联系人不登录。我可以在会话中存储联系人ID吗?如果用户永久登录并创建 cookie,那么它不是会话,而是 cookies.signed[:user_id],并且可能必须以不同方式捕获 id。
【解决方案2】:

我找到了一种使contact_id 可访问EngagementsController 的方法,而无需通过助手将变量从ContactsController 传递给EngagementsController。嵌套资源:

  resources :contacts do
    resources :engagements 
  end

生成路径:

POST   /contacts/:contact_id/engagements(.:format)  engagements#create

因此,EngagementsController 可以访问参与的contact_id:

def create
    @contact = Contact.find(params[:contact_id])
    @engagement = @contact.engagements.build(engagement_params)
end

【讨论】:

    猜你喜欢
    • 2016-03-04
    • 1970-01-01
    • 2015-07-22
    • 2012-07-19
    • 2011-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多