为什么 ruby​​ 返回数组类型而不是属性

发布于 2024-11-06 12:15:50 字数 471 浏览 0 评论 0原文

我的视图中有这段代码

<% @items.each do |i| %>
  <tr>
    <td><%= i.name %></td>
  </tr>
<%end%>

,控制器中有这段代码

  @categories = Category.find_by_sql("SELECT * FROM categories WHERE users_id =#{session[:user_id]}")
  @categories.each do |c|
    @items << (Item.where(:categorys_id => c.id))
  end

,当我运行它时,该代码会生成一个如下所示的页面: “您的用户名是一个物品物品” 而不是 “您的用户名是数字堡垒海洋十一定居者”

I have this code in my view

<% @items.each do |i| %>
  <tr>
    <td><%= i.name %></td>
  </tr>
<%end%>

and this code in my controller

  @categories = Category.find_by_sql("SELECT * FROM categories WHERE users_id =#{session[:user_id]}")
  @categories.each do |c|
    @items << (Item.where(:categorys_id => c.id))
  end

and when I run it, the code generates a page looking like this:
"Your username is a Item Item Item"
instead of
"Your username is a Digital Fortress Oceans Eleven Settlers"

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

两相知 2024-11-13 12:15:50

您想要实现的目标可以这样完成:

Item.where(:categorys_id => c.id).第一个

Item.where 返回一个范围,它实际上并不构造或运行查询。

方法 firstlast 将使用 LIMITORDER BY 运行查询,并返回元素。

eachall 等方法构造并运行查询并返回结果数组。

代码审查

您的控制器代码容易受到 SQL 注入,如果 session[:user_id] 中存在恶意内容,请想象一下。 "#{stuff}" 在 Ruby 中不会对 stuff 进行任何转义。

要摆脱注入问题:

ruby
@categories = Category.where(:users_id => session[:user_id]) # 您确定该列不是 user_id 而是 users_id 吗?

我们应该做的第二件事是避免进行 N + 1 查询,其中 N 是结果类别的数量。

一个好的方法是使用 SQL IN 运算符。
红宝石
@items = Item.where(:categorys_id => @categories.map(&:id)) #

What you are trying to achieve can be done like this:

Item.where(:categorys_id => c.id).first

Item.where returns a scope, it doesn't actually construct or run the query.

Methods first and last will run the query with LIMIT and ORDER BY and will return the element.

Methods like each and all construct and run the query and return the array of results.

Code review

Your controller code is prone to SQL injection, image if something evil was in session[:user_id]. "#{stuff}" does not do any escaping of stuff in Ruby.

To get rid of the injection problem:

ruby
@categories = Category.where(:users_id => session[:user_id]) # Are you sure the column is not user_id but users_id?

The second thing we should do is to avoid doing N + 1 query where N is the number of resulting categories.

An OK way to do this is by using the SQL IN operator.
ruby
@items = Item.where(:categorys_id => @categories.map(&:id)) #

秋日私语 2024-11-13 12:15:50

我将重写您的控制器代码如下:

@categories = Category.find_all_by_user_id(session[:user_id], :include => :items)
@items      = @categories.map(&:items).flatten

现在在您看来:

<% @items.each do |item| %>
  <tr>
    <td><%= item.name %></td>
  </tr>
<%end%>

I would rewrite your controller code as follows:

@categories = Category.find_all_by_user_id(session[:user_id], :include => :items)
@items      = @categories.map(&:items).flatten

Now in your view:

<% @items.each do |item| %>
  <tr>
    <td><%= item.name %></td>
  </tr>
<%end%>
静谧 2024-11-13 12:15:50

Item.where(:categorys_id => c.id) 将为您提供一个 ActiveRecord 对象,而不是单个属性。因此,当您迭代这些时,i 是一个 Item 对象,而不是属性。

假设您确实想输出项目的 name 字段,那么您可以这样做:

<% @items.each do |i| %>
  <tr>
    <td><%= i.name %></td>
  </tr>
<%end%>

Item.where(:categorys_id => c.id) will give you an ActiveRecord object, not an individual attributes. So when you iterate over these, i is an Item object, not an attribute.

Let's say you really wanted to output the item's name field, then you would do this:

<% @items.each do |i| %>
  <tr>
    <td><%= i.name %></td>
  </tr>
<%end%>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文