在Rails中访问另一个控制器中的一个控制器变量

时间:2013-12-15 03:57:35

标签: ruby-on-rails ruby

我有一个C编程背景,我正在学习侧面项目的Ruby / Rails。目前,我正在努力了解变量的范围是如何工作的。这是我遇到的问题的一个例子。我有一个用户和一个产品型号。在Product DB中,我存储了不同的产品,其中一个字段是userid字段,该字段与存储在User表中的用户ID相匹配。在用户登录后 - 我显示用户的姓名,电子邮件等(这存储在@current_user中),然后有一个链接显示用户拥有的不同产品。我通过users / show.html.erb中的以下代码执行此操作,如下所示:     ...     

     命名:      <%= @ current_user.name%>     

    ...     <%= link_to" Products",products_path,id:" products" %GT;

到目前为止一切顺利。当我点击"产品"链接它带我到products / index.html.erb并执行以下代码(我想过滤此显示只显示@ current_user.userid拥有的产品。我该怎么做?以下代码给我一个运行时错误因为@current_user评估为nil我相信。如果我删除了" if"子句,那么所有产品都显示出来并不是我想要的。非常感谢任何提示。

<tbody>
<% @products.each do |product| %>
  <tr>
    <td><%= product.userid if product.userid == @current_user.userid %></td>
    <td><%= product.productName if product.userid == @current_user.userid %></td>
    <td><%= product.productLink if product.userid == @current_user.userid %></td>

谢谢,

3 个答案:

答案 0 :(得分:13)

我打算将此作为评论,但我认为值得回答。要理解的不仅仅是rails,而是整个互联网, HTTP是无状态的。这意味着在您的控制器中,您可以获取用户的信息,使用数据库中的所有内容构建一个网页,然后将其发送给他们。然后他们在页面上执行某些操作并发送请求以获取另一页或更多数据,并且您的rails应用程序就像“哦,你!你是谁?”因为所有那些填充了很好信息的变量都已消失了。每次你的应用程序收到请求时,它都会创建一个正在使用的控制器的全新实例,然后将其中的所有内容与其中的所有内容一起删除。这一点非常重要,因为目前可能会有数千或数百万人登录您的终极飞盘联盟网站,试图找出周六谁在哪里比赛。并且您希望向合适的人提供正确的信息,您不能认为您上次向其发送信息的人是同一个人,要求您提供新信息。

因此,我们需要使用session,每次发送页面时都会传递给客户端浏览器的一些信息,浏览器会在每次请求时将其发送给您。您在会话中放置了足够的信息,以便在收到响应时可以使用它来重建服务器所需的内容。我将使这个变得非常简单,然后引导您到Rails Security Guide,在那里您可以获得更重要的信息。实际上,我只会使用他们的例子:

您可以通过这种方式将用户ID添加到会话中:

session[:user_id] = @current_user.id

然后以这种方式取回它:

@current_user = User.find(session[:user_id])

然后使用您的用户模型(在本例中)从数据库中获取所需的特定信息。这是Rails指南的另一个链接,因为它非常好,我将它链接两次:http://guides.rubyonrails.org/security.html#what-are-sessions-questionmark

如果您正在做一些需要密码的事情,您可以使用像deviseinstructions here这样的宝石,但要注意,它会完全劫持您的用户模型,会话控制器,一些视图,基本上所有与登录和身份相关的事情。它不容易定制,但它使所有这些东西和事情变得更加复杂,实现起来非常简单。如果您不需要任何用户名或密码,并且您正在做一些非常简单的事情,请跳过特殊的宝石并自己使用会话。

答案 1 :(得分:0)

您必须在每个请求上初始化@current_user,而不仅仅是在用户登录之后。控制器实例变量不会在请求之间保持不变。

以下是执行此操作的常用方法:

  1. 将用户ID存储在会话中。
  2. ApplicationController中创建一个“之前”过滤器,用于从会话中检索用户ID并初始化实例变量。

答案 2 :(得分:0)

在一个操作中设置的实例变量无法在另一个操作中访问。如上所述,您需要将user_id存储在会话哈希中。在处理用户sign_in的控制器中,您必须执行以下操作:

#in SessionsController(for example)

def create
  user = User.find_by(email: params[:session][:email].downcase)
  if user && user.authenticate # logic for authentication
    session[:user_id] = user.id
    redirect_to root_path, notice: "Successful sign in."
  else
    flash.now[:error] = "Invalid email/password combination"
    render :new
  end
end

记下将user_id分配给会话密钥:会话哈希中的user_id。现在,在application_helper或sessions_helper中定义current_user,以便所有视图都可以访问它:

def current_user
  User.find(session[:user_id]) if session[:user_id]
end

现在迭代所有用户的产品:

<tbody>
<% current_user.products.each do |product| %>
  <tr>
    <td><%= product.userid %></td>
    <td><%= product.product_name %></td>
    <td><%= product.product_link %></td>

只要您在用户和产品模型中有has_many :products关联belongs_to :user,您就可以通过上述user.products来调用所有用户的产品。另请注意,我使用'snake_case'作为产品的方法/属性。 Ruby中的惯例是将snake_case用于方法名称和变量。如果您将列命名为productName和productLink,则必须重命名它们才能使用'snake_case'。在Ruby中,CamelCase用于Class和ModuleNames。

希望有所帮助!