#ruby-on-rails #ruby #arrays #block
#ruby-on-rails #ruby #массивы #блок
Вопрос:
У меня есть три модели: Isbn, продажа и канал.
Цель: получить список в представлении isbns show.html.erb, который выглядит примерно так:
Isbn: myisbn
Общий объем продаж для myisbn: 100
Продажи Myisbn для канала 1: 50
Продажи Myisbn для канала 2: 25
Продажи Myisbn для канала 3: 25
Вот мои модели. Модель Isbn.rb
has_many :sales
has_many :channels, :through => :sales
Модель Sale.rb (имеет атрибуты sales_channel_id, isbn_id, количество)
has_many :channels
belongs_to :isbn
Модель Channel.rb:
belongs_to :sale
Я работал в контроллере isbns, в методе show, просто чтобы заставить что-то работать. Я подумал, что проведу рефакторинг позже — совет о том, следует ли включать что-либо из этого в модель, был бы весьма кстати.
Пока у меня есть это:
@channelisbn = Sale.where("sales_channel_id =?',1).where("isbn_id=?",3)
@channelsalesisbn = 0
@channelisbn.each {|y| @channelsalesisbn = y.quantity}
Это успешно возвращает все продажи, где идентификатор канала равен 1, а идентификатор ISBN равен 3. Но от этого мало толку, поскольку идентификаторы жестко закодированы. Итак, я получил идентификаторы каналов в массив:
@channellist = Channel.all
@channel = 0
@channelarray = @channellist.map {|z| @channel = z.id}
что дает мне прекрасный массив [1,2,3,4]
Но я не могу понять, как передать 1, затем 2, затем 3, а затем 4 в блок, который можно использовать для поиска продаж ISBN, которые имеют этот идентификатор канала продаж. Это то, что я пробовал (все еще жестко кодируя идентификатор ISBN — думал, что буду решать по одной проблеме за раз), который вернул пустой массив:
@channelarray.each do |channel|
@channelisbn = []
@channelisbn = Sale.where("sales_channel_id = ?", channel).where("isbn_id = ?",3)
@channelsalesisbn = 0
@result = []
@result << @channelisbn.each {|a| @channelsalesisbn = a.quantity}
end
Затем я собирался просуммировать содержимое массива.
Любая помощь будет принята с благодарностью. Это мой первый пост, поэтому мой нулевой коэффициент принятия скоро изменится!
Обновить
Просто чтобы закончить этот вопрос, вот к чему я пришел, что здорово и готово к доработке: массив, красиво сгруппированный, обеспечивающий мне продажи по isbn по каналам. Спасибо за подсказку group_by!
#in the show action in the isbns controller:
@isbn = Isbn.find(params[:id])
@channelarray = Channel.select(:id).all
@channelarray.group_by {|i| Sale.where("channel_id = ?",i).where("isbn_id =?", @isbn)}
В консоли для наглядности добавлены разрывы строк:
(прежде всего, незаметно установите @isbn = 3, поскольку в консоли вы не можете передавать параметры из представления, поэтому экземпляр @isbn, определенный в контроллере, равен нулю в консоли)
ruby-1.9.2-p180 :067 > @channelarray.group_by {|i| Sale.where("channel_id = ?",i).where("isbn_id =?", @isbn)}
=> {[#<Sale id: 1, isbn_id: 3, quantity: 10000, value: 12000, currency: "GBP", total_quantity: nil, created_at: "2011-05-06 12:30:35", updated_at: "2011-05-07 17:43:13", customer: "Waterstone's", retail_price: nil, discount: nil, invoice_date: "2011-05-24">, #<Sale id: 2, isbn_id: 3, quantity: 1000, value: 500, currency: "GBP", total_quantity: nil, created_at: "2011-05-07 09:37:53", updated_at: "2011-05-07 19:14:52", customer: "Borders", retail_price: nil, discount: nil, invoice_date: "2011-02-05">]=>[#<Channel id: 1>],
[#<Sale id: 3, isbn_id: 3, quantity: 500, value: 1500, currency: "", total_quantity: nil, created_at: "2011-05-07 09:38:11", updated_at: "2011-05-07 19:15:07", customer: "Borders", retail_price: nil, discount: nil, invoice_date: "2011-12-05">, #<Sale id: 4, isbn_id: 3, quantity: 45, value: 300, currency: "", total_quantity: nil, created_at: "2011-05-07 09:38:38", updated_at: "2011-05-07 19:15:36", customer: "Borders", retail_price: nil, discount: nil, invoice_date: "2011-06-05">]=>[#<Channel id: 2>],
[]=>[#<Channel id: 3>],
[]=>[#<Channel id: 4>]}
ОБНОВЛЕНИЕ 2
Ха, в хэше, который я сгенерировал, пары ключ-значение были неправильно расположены. Массив, содержащий данные о продажах, был ключом — он должен был быть значением. Rubydocs спас положение:
@salesbychannel = @salesbychannelwrong.invert
invert
Метод переключает пары ключ-значение. Мило.
Ответ №1:
То, что вы ищете, это передача массива в ARel#where(), вот так:
Sale.where(:sales_channel_id => @channelarray)
Это должно выполнить запрос IN . Если это не работает, вы всегда можете передать массив в ActiveRecord#find, вот так:
Sale.find(@channelarray)
Надеюсь, это поможет
Комментарии:
1. Привет, Срджан, большое тебе спасибо за помощь. Вы прояснили мою мысль, потому что это возвращает массив, содержащий все продажи, поскольку массив каналов содержит все идентификаторы каналов. Что мне нужно, так это иметь возможность передавать идентификаторы каналов по одному и получать один набор данных на isbn / канал. Возможно, мне нужно вернуться к идее создания массива идентификаторов каналов в первую очередь.
2. @snowangel, читая более внимательно, я вижу, что это более сложная проблема. Что вам нужно, так это ARel#group для агрегирования. Кроме того, вместо выполнения перечисляемого#map , вы можете просто выбрать идентификатор из модели канала, выполнив Channel.select(:id).all
3. О, трещина. Большое спасибо! Когда у меня будет достаточная репутация, я вас поддержу. Очень признателен.