Last active
December 20, 2015 04:08
-
-
Save DmytroVasin/6068248 to your computer and use it in GitHub Desktop.
Anadea
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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