Почему ruby возвращает тип массива вместо атрибута

#ruby-on-rails #ruby #view #controller

#ruby-on-rails #рубин #Вид #контроллер #ruby

Вопрос:

На мой взгляд, у меня есть этот код

 <% @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
  

и когда я запускаю его, код генерирует страницу, выглядящую следующим образом:
«Ваше имя пользователя — это элемент Item Item»
вместо
«Ваше имя пользователя — Digital Fortress Oceans Eleven Settlers»

Комментарии:

1. В вашем / console, когда вы запускаете код вашего контроллера, какой массив возвращается? Также вы не могли бы сделать @categories = Category.find(:all, :conditions => ["user_id = ?", session[:user_id]])

Ответ №1:

То, чего вы пытаетесь достичь, может быть сделано следующим образом:

Item.where(:categorys_id => c.id ).сначала

Item.where возвращает область видимости, на самом деле она не создает и не запускает запрос.

Методы first и last выполнят запрос с помощью LIMIT и ORDER BY и вернут элемент.

Такие методы, как each и all , создают и запускают запрос и возвращают массив результатов.

Обзор кода

Код вашего контроллера подвержен SQL-инъекции, представьте, что в нем было что-то злое session[:user_id] . "#{stuff}" не выполняет никакого экранирования stuff в Ruby.

Чтобы избавиться от проблемы с внедрением:

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(amp;:id)) #

Комментарии:

1. Это просто дает мне нулевой объект. У меня есть таблица Users, которая имеет много типов, в которой много элементов. Я хочу показать все элементы всех типов, которыми владеет текущий пользователь.

Ответ №2:

Я бы переписал код вашего контроллера следующим образом:

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

Теперь, на ваш взгляд:

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

Ответ №3:

Item.where(:categorys_id => c.id) даст вам объект ActiveRecord, а не отдельные атрибуты. Итак, когда вы перебираете их, i это Item объект, а не атрибут.

Допустим, вы действительно хотели вывести name поле элемента, тогда вы бы сделали это:

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

Комментарии:

1. Это то, что я уже сделал (я пропустил .name, копируя его, и сейчас отредактировал его)

2. Не будет Item.where возвращать массив, когда аргумент является хэшем? Что означало бы @items << добавление массива, а не элемента