Skip to content

Instantly share code, notes, and snippets.

@DmytroVasin
Last active December 20, 2015 04:08
Show Gist options
  • Save DmytroVasin/6068248 to your computer and use it in GitHub Desktop.
Save DmytroVasin/6068248 to your computer and use it in GitHub Desktop.
Anadea
# ActiveRecord
1)
В фрагменте кода показано два класса: Listing и Category
У Listing есть много Category ( в обратку должно быть belongs_to - но тут вроде как не обязательно)
Listing содержит поля "published", "name" ( не очень понял зачем поле name )
Category содержит поля "top_rated", "title" и должно содержать "listing_id" ( но можно и без него )
Метод класса "categories":
1. создает два пустых массива ( с их помощью, в дальнейшем, делается сортировка по полю top_rated )
2. выбирает все обьекты Listing ( все строки из таблици Listing ), у которых поле 'published' равно
true (хотя такая запись scope работать не будет - надо явно указать "{ }" - обертку для скоупа)
3. для каждого обьекта таблици ( для каждой записи ) находит все категории.
4. у каждой категории смотрит на поле top_rated - и в зависимости от него записует категорию в
первый или во второй массив ( пункт 1 ) - сделано для простой сортировки
5. В каждом массиве находит уникальные значения. ( но в данном случае uniq не должно срабатывать -
у каждого уникальный id)
6. Сортирует в каждом массиве записи по полю "title", ( первый массив содержит записи у который
поле "top_rated" true, второй массив - false )
7. Складываем два массив - и на выходе получаем обьект класса Array.
Итого:
Сделать выборку всех уникальных Categories, которые есть в опубликованных Listing. И
отсортировать выбранные категории по полю "top_rated" ( c начала все категории со значением
true, потом все со значение - false) и все категории со значением true отсортировать по полю
"title" в алфавитном порядке, тоже самое для категорий со значение "false"
3)
Переделал:
1. Добавить belongs_to в category - так как выборка будет производиться относительно Category
2. Добавить scope-ы:
2.1 published_category_only - находит все категории, которые есть в опубликоанных
Listing-ах ( используем join - так как выводить на экран на listings не надо ).
2.2 abc_order - задает правельный порядок ( сперва по колонке top_rated, а потом
по колонке title)
3. uniq_by(&:title) - если нужны categories с уникальным 'title' или сделать
выборку по какому-то конкретному полю: "select(:title).uniq"
class Category < ActiveRecord::Base
belongs_to :listing
scope :published_category_only, -> { joins(:listing).where(listings: { published: true }) }
scope :abc_order, -> { order("top_rated DESC, title ASC") }
end
Запрос:
# => Category.published_category_only.abc_order.uniq_by(&:title)
4)
# RSpec тесты на scope-ы и на сравнение выходных данных сделанных при помощи scope,
и self.categories метода ( рефакторинга большого в тестах не делал )
describe Category do
describe 'one part of scopes' do
before :each do
published = Listing.create(name: 'jQuery', published: true)
unpublished = Listing.create(name: 'Get Real', published: false)
@first_cat = published.categories.create(title: 'JavaScript', top_rated: false)
@second_cat = unpublished.categories.create(title: 'Another', top_rated: true)
end
it 'should return category which was the published' do
expect(Category.all).to eq([@first_cat, @second_cat])
Category.published_category_only.should have_exactly(1).items
Category.published_category_only.should include(@first_cat)
end
it 'should return category order by top_rated field' do
expect(Category.all).to eq([@first_cat, @second_cat])
expect(Category.abc_order).to eq([@second_cat, @first_cat])
end
it 'should return category order by title field' do
expect(Category.all).to eq([@first_cat, @second_cat])
expect(Category.abc_order).to eq([@second_cat, @first_cat])
end
it 'should return category ordered by top_rated and title field' do
@third_cat = @first_cat.listing.categories.create(title: 'Atom', top_rated: false)
@four_cat = @first_cat.listing.categories.create(title: 'Anam', top_rated: true)
expect(Category.all).to eq([@first_cat, @second_cat, @third_cat, @four_cat ])
expect(Category.abc_order).to eq([@four_cat, @second_cat, @third_cat, @first_cat])
end
end
describe 'general testing for' do
describe 'full scoped chain' do
before :each do
first_published = Listing.create(name: 'jQuery', published: true)
second_published = Listing.create(name: 'JavaScript', published: true)
unpublished = Listing.create(name: 'Get Real', published: false)
@bbb = first_published.categories.create(title: 'bbb', top_rated: true)
@ccc = first_published.categories.create(title: 'ccc', top_rated: true)
@fff = first_published.categories.create(title: 'fff', top_rated: false)
@ddd = second_published.categories.create(title: 'ddd', top_rated: false)
@aaa = second_published.categories.create(title: 'aaa', top_rated: true)
@bbbbbb = second_published.categories.create(title: 'bbb', top_rated: true)
@five = unpublished.categories.create(title: 'five', top_rated: false)
end
it 'should work correctly' do
all_category = Category.all
all_category.should have(7).items
all_category.should include(@five)
scoped_category = Category.published_category_only.abc_order
scoped_category.should have(6).items
scoped_category.should_not include(@five)
expect(all_category).to eq([@bbb, @ccc, @fff, @ddd, @aaa, @bbbbbb, @five])
expect(scoped_category).to eq([@aaa, @bbb, @bbbbbb, @ccc, @ddd, @fff])
end
it 'should should include only uniq' do
scoped_category = Category.published_category_only.abc_order
scoped_category.should have(6).items
scoped_uniq_category = Category.published_category_only.abc_order.uniq_by(&:title)
scoped_uniq_category.should have(5).items
end
it 'should work same as not refactored method' do
Listing.categories.should eq Category.published_category_only.abc_order
end
end
end
end
3) фрагмент кода в окружении простых Руби-объектов
Не совсем понял как сделать с помощью простых Руби-объектов. Но вроде работать должно.
class Listing < Struct.new(:name, :categories, :published)
def self.published
# some method that returns an array of listings, e.g.
LISTINGS.select {|l| l.published? }
end
def self.categories
all_ctegories = []
self.published.each do |listing|
listing.categories.each do |category|
all_ctegories << category
end
end
all_ctegories.group_by(&:top_rated?).values.each(&:sorting).flatten.uniq_by(&:title)
end
end
class Array
def sorting
uniq.sort!{|a,b| a.title <=> b.title}
end
end
class Category < Struct.new(:title, :top_rated)
alias top_rated? top_rated
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment