Пета задача

  1. Има пета задача! Срокът е до първи декември, включително.

    Препоръчваме ви да я решите преди теста, тъй като задачата не е сложна и ще си направите една полезна подготовка за него. Освен това, ако предадете решение уикенда, има реален шанс да получите коментари от нас :)

    Още нещо - тъй като задачата е лесна и вече знаете как се пишат тестове - споделянето на тестове е забранено.

    Ако имате въпроси по условието - пишете тук.

  2. Благодаря, а още едно въпросче имах относно това как да интерпретирам нещата от условието. Дадено е: class User < DataModel attributes :name, :email data_store ArrayStore.new end

    На User като на таблица със записи ли трябва да гледам или с каква аналогия да го свържа от базите данни?

  3. Ако при извикване на DataStore#update подадем атрибути, които не са дефинирани преди това, трябва ли да бъде върната грешка DataModel::UnknownAttributeError или записа трябва да бъде ъпдейтнат с новите атрибути?

    Също, по какъв начин трябва да изглеждат хешовете в HashStore - например {1: {id:1, first_name: "name"}, 2: {id:2, first_name: "name2"}} или {1: {first_name: "name"}, 2: {first_name: "name2"}}?

  4. Супер, благодаря.

    Още един въпрос: Всички методи тук приемат прости хешове, не инстанции на DataModel. и #update - Приема ID на обекта, който искаме да обновим, и хеш с атрибутите, които искаме да презапишем. Това означава ли, че данните записани в DataStore задължително трябва да имат атрибут id? Как ще се подава id-то на DataStore#update - например update(1, ...) или update(id: 1, ...)

  5. @Иван, винаги трябва да има атрибут id. Подава се като позиционен параметър.

    @Лазар, използвал си класова променлива (@@var). Казва ти да използваш инстанционна (@var). За класовите не сме ви казвали все още и по принцип не се използват - имат доста подводни камъни. Тъй като и класовете са обекти, и те си имат инстанционни променливи. Виж този отговор в StackOverflow.

  6. Имам въпрос относно класовия метод attributes. В условието пише Записва нов масив с атрибути за модела. Това означава ли, че можем да запишем нови атрибути вместо стари? Тоест може ли да имаме една инстанция с едни атрибути, след това да сменим атрибутите и като си създадем нова инстанция, тя да има само новите атрибути и съответните ми сетъри и гетъри?

  7. Масивът (или хешът) трябва да се пазят като инстанционни променливи. Ключовете на хеша трябва да бъдат id-тата на съответните записи.

    { 1: {id:1, first_name: "name"}, 2: {id:2, first_name: "name2"}, 3: {id:3, first_name: "name3"}, 4: {id:1, price: 12} 5: {id:1, book: "rom"} },където първите 3 записа са от един модул ,после 4ти и 5ти от други.Това ли трябва да представлява записването в HashStore.

    [{id:1, first_name: "name"}, {id:2, first_name: "name2"},{id:3, first_name: "name3"},{id:1, price: 12},{id:1, book: "rom"}] - a това ArrayStore?

  8. Голям пример:

    class User < DataModel
      attributes :name, :email
      data_store HashStore.new
    end
    
    pesho = User.new(name: 'Pesho', email: 'pesho@gmail.com')
    pesho.id #=> nil
    
    User.where(name: 'Pesho') #=> []
    
    pesho.save
    pesho.id #=> 1
    
    pesho_again = User.where(name: 'Pesho').first
    pesho_again == pesho     #=> true
    pesho_again.id           #=> 1
    pesho_again.equal? pesho #=> false
    
    pesho_again.name = 'Pesho 1'
    pesho_again.save
    
    User.where(name: 'Pesho') #=> []
    
    gosho = User.new(name: 'Gosho')
    gosho.id #=> nil
    

    :)

  9. "При записване на нов обект, id-то му се сетва на най-малкото положително цяло число (започва се от 1), което не е било използвано досега в хранилището на модела." От теста, който сте дали, обаче, се вижда, че очаквате да можем да задаваме id-то ръчно, когато създаваме нов модел. Може ли разяснение по въпроса?

    "Ако бъде подадено поле, които не съществува за модела, трябва да се хвърли грешка DataModel::UnknownAttributeError със съобщение Unknown attribute <attribute_name>." Ако има повече от едно полéта, които не са в списъка с атрибути какво да правим? Защото предвид, че получаваме полетата за търсене в хеш, нямаме гаранция за реда им.

  10. @Михаил,

    • За този тест ли говориш?

      user = {id: 2, name: 'Pesho'}
      store.create(user)
      
      expect(store.find(id: 2)).to eq [user]
      

      Това е за хранилището. create приема хеш с атрибутите и стойностите на записа. id-то е атрибут на записа => се предава и тук. Това id по какъв начин е генерирано метода create не го интересува.

    • Хвърляш грешка за първото. Напротив - имаш гаранция за реда им - хешовете в Ruby запазват реда на ключовете си - виж някоя от първите лекции. :)

  11. "Масивът (или хешът) трябва да се пазят като инстанционни променливи. Ключовете на хеша трябва да бъдат id-тата на съответните записи.".

    Да предположим, че искам да запаметя три обекта с id 6, 9 и 15.

    Доколкото разбрах, ArrayStore трябва да изглежда така:

    [ {id: 6, country: 'Bulgaria', capital: 'Sofia'}, {id: 9, country: 'Greece', capital: 'Athens'}, {id: 15, country: 'Romania', capital: 'Bucharest'} ]

    Правилно ли е това? И мога ли да направя такъв HashStore?

    {6 => {country: 'Bulgaria', capital: 'Sofia'}, 9 => {country: 'Greece', capital: 'Athens'}, 15 => {country: 'Romania', capital: 'Bucharest'} }

  12. Да. Ако го има вътре кодът ти ще е много по-прост, защото няма да се налага постоянно да вадиш и слагаш обратно id-то. Плюс това намаляваш "специалността" на определения атрибут - винаги е добре да имаш колкото се може по-малко специални неща.

  13. Забележка: В горното върнатите обекти не са същите инстанции на класа, но имат същите стойности за атрибутите си. Новите и старите инстанции представят един и същ запис от хранилището.

    Когато извлечем даден обект от нашия store чрез метода where(от масива,който връща) и после чрез него променим дадена стойност на даден атрибут и го запишем отново в store-a => ще се update-не записа,то тогава оригиналния обект,който всъщност е създал този запис в store-a ще си остане с непроменен атрибут,така ли?

    class B < DataModel
      attributes :name, :name1
      data_store HashStore.new
    end
    
    test = B.new({name: "kaka"})
    test.save
    
    new_test = B.where(name: "kaka")[0]
    new_test.name = "baba"
    new_test.save
    => test = name:"kaka",name1: nil, id=1
    => new_test = name:"baba",name1: nil, id=1
    

    Това ли трябва да е?

  14. @Стамен - да. Ако се чудиш, така е и в ActiveRecord. Там проблема се решава с метод #reload, който презарежда стойностите на атрибутите от базата.

    Постовете тук използват Markdown - разгледай линка и го използвай. Цъкни на "Редактирай" на поста си и виж как съм ти го форматирал, така че да се чете.

  15. first_user = User.new({name: "Todor"})
    second_user = User.new({name: "Kaloqn"})
    
    first_user.save.id #=> 1
    second_user.save.id #=> 2
    
    first_user.delete
    second_user.delete
    
    third_user = User.new
    
    third_user.save.id #=> 1 или 3 ?
    first_user.save.id #=> ?
    second_user.id #=> 2 или nil?
    

    Последните три реда какво трябва да върнат?

  16. @Мариян,

    При записване на нов обект, id-то му се сетва на най-малкото положително цяло число (започва се от 1), което **не е било използвано досега в хранилището** на модела.

    1 и 2 вече са били използвани. Това, че са изтрити няма значение.

    Представи си следната ситуация в някой форум (или StackOverflow):

    1. Някой си прави тема във форума. Тази тема си има id
    2. На друго място поства линкове към тази тема. Линкът е по ID
    3. Някой модератор изтрива темата
    4. Ако се преизползват id-та - следващата тема ще има id-то на предната
    5. Всички линкове към старата тема вече водят към новата

    Още, ако не се зачистват правилно връзките в базата от данни - всички отговори на старата тема вече ще са се пренесли на новата.

    Очевидно това е лошо - затова никоя база от данни не преизползва id-та. Ако създадеш 10000 записа и ги изтриеш, базата ще е празна, но следващото id ще е 10001.

Трябва да сте влезли в системата, за да може да отговаряте на теми.