我在视图中有这段代码
<% @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
当我运行它时,代码生成一个如下所示的页面: “您的用户名是项目项目项” 代替 “您的用户名是Digital Fortress Oceans Eleven Settlers”
答案 0 :(得分:2)
你想要实现的目标可以这样做:
Item.where(:categorys_id =&gt; c.id)。 first
Item.where
返回一个范围,它实际上并不构造或运行查询。
方法first
和last
将使用LIMIT
和ORDER BY
运行查询并返回元素。
each
和all
之类的方法构造并运行查询并返回结果数组。
代码审核
您的控制器代码很容易进行SQL注入,如果session[:user_id]
中存在邪恶,则会显示图像。 "#{stuff}"
不会在Ruby中对stuff
进行任何转义。
摆脱注射问题:
ruby
@categories = Category.where(:users_id => session[:user_id]) # Are you sure the column is not user_id but users_id?
我们应该做的第二件事是避免进行N + 1查询,其中N是结果类别的数量。
执行此操作的正常方法是使用SQL IN
运算符。
ruby
@items = Item.where(:categorys_id => @categories.map(&:id)) #
答案 1 :(得分:1)
我会按如下方式重写您的控制器代码:
@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%>
答案 2 :(得分:0)
Item.where(:categorys_id => c.id)
将为您提供ActiveRecord对象,而不是单个属性。因此,当您迭代这些时,i
是Item
对象,而不是属性。
假设你真的想要输出项目的name
字段,那么你会这样做:
<% @items.each do |i| %>
<tr>
<td><%= i.name %></td>
</tr>
<%end%>