ምዕራፍ 14 ተጠቃሚዎችን መከተል

በዚህ ምዕራፍ ውስጥ ተጠቃሚዎች ሌሎች ተጠቃሚዎችን መከተል እና አለመከተል የሚያስችል አንድ ማህበራዊ ንጣፍን በማከል የሬይልስ ስልጠና ማሳያ አፕልኬሽኑን እናጠናቅቀዋለን፣ ይህም በእያንዳንዱ ተጠቃሚ የመነሻ ገጽ ላይ፣ አንድ የክትል ተጠቃሚዎች የአጪርጽሑፎች ሁኔታ ቀላቢን ያሳያል፡፡ በክፍል 14.1 ላይ በተጠቃሚዎች መካከል፣ ትስስርን እንዴት መቀረጽ እንደምንችል በመማር እንጀምር እና በክፍል 14.2 ላይ (እግረ መንገዳችንን ኤጃክስ (Ajax) ከተባለ ፕሮግራም ጋር መተዋወቅን ጨምሮ) ከዚሁ ጋር የሚዛመደውን የድር በይነገጽ እንገነባለን፡፡ ክፍል 14.3 ላይ አንድ የተሟላ አገልግሎት የሚሰጥ የሁኔታ ቀላቢ ግንባታን እንጨርሳለን፡፡

ይህ የመጨረሻ ምዕራፍ፣ ሁኔታ ቀላቢውን ለመስራት የተወሰኑ የሩቢ እና የተ.መ.ቋ ሽወዳን አካቶ፣ በዚህ ስልጠና ውስጥ በጣም ፈታኝ የሆኑ አንዳንድ ነገሮችን ያካትታል። በእነዚህ ምሳሌዎች አማካኝነትም፣ ሬይልስ የረቀቁ የውሂብ ቅርጸቶችን ሳይቀር እንኳ እንዴት አድርጎ ሊተገብር እንደሚችል ትመለከታላችሁ፤ ይህም ለወደፊት የተወሰኑ መስፈርቶች ያላቸው አፕልኬሽንኖችን ለመገንባት በምትፈልጉበት ጊዜ፣ በጥሩ ሁኔታ ሊያገለግላችሁ ይችላል። ከሰልጣኝ፣ ራሱን ወደ ቻለ አበልጻጊ ለመሽጋገር ያግዛችሁ ዘንድ፣ ክፍል 14.4 የተወሰኑ የላቁ የመረጃ ምንጮችን የሚጠቁም ምክርን ያቀርባል፡፡

በዚህ ምዕራፍ ውስጥ ያለው ነገር በጣም ፈታኝ ስለሆነ፣ አንድም ኮድ ከመጻፋችን በፊት ለአንዳፍታ ረጋ ብለን በይነገጹን እንቃኛለን፡፡ በቀደሙት ምዕራፎች እንደተጠቀምነው ሁሉ፣ አሁንም ገና በጅማሬው አንዳንድ ስእላዊ መግለጫወችን በመጠቀም፣ መጨረሻ ላይ እውን የምናደርጋቸውን የገጾች አምሳል እናያለን፡፡1 ሙሉ የገጹ ፍሰት እንደሚከተለው ይሄዳል:- አንድ ተጠቃሚ (ሳሙኤል ለኣከ) ከራሱ የመገለጫ ገጽ ይጀምራል (ምስል 14.1)፣ ቀጥሎም የሚከተለውን አንድ ተጠቃሚ ለመምረጥ ወደ ተጠቃሚዎች ገጽ ይሄዳል (ምስል 14.2)። ከዚያ በመቀጠል ሳሙኤል ወደ ሌላ ተጠቃሚ ማለት ወደ በላይነሽ ኪዳነ መገለጫ ገጽ ይሄድ እና (ምስል 14.3) እሷን ለመከተል የ “ተከተል” አዝራርን ጠቅ ያደርጋል፡፡ ይህ ሂደት የ “ተከተል” አዝራርን ወደ “አትከተል” አዝራር ይለውጠዋል፤ እንዲሁም የበላይነሽን የ“ተከታዮች” ቁጥርን በአንድ እንዲጨምር ያደርገዋል (ምስል 14.4)። ሳሙኤል ወደ ራሱ መነሻ ገጽ ሲዘዋወር፣ የ “ሚከተላቸው/ሏት” ቁጥር እንደጨመረ እና የበላይነሽን አጪርጽሑፎች በራሱ ሁኔታ ቀላቢ ላይ እንዳገኘ ይመለከታል (ምስል 14.5)፡፡ የተቀረው የዚህ ምዕራፍ ስራ፣ የዚህን ገጽ ፍሰት በትክክል እንዲሰራ ለማድረግ የተመደበ ይሆናል፡፡

images/figures/page_flow_profile_mockup_3rd_edition
ምስል 14.1: የአንድ አሁን ተጠቃሚ የመገለጫ ገጽ።
images/figures/page_flow_user_index_mockup_bootstrap
ምስል 14.2: አንድ የሚከተሉት ተጠቃሚን መፈለግ።
images/figures/page_flow_other_profile_follow_button_mockup_3rd_edition
ምስል 14.3: ለመከተል የተፈለገው አንድ ተጠቃሚ ከአንድ “ተከተል” አዝራር ጋር።
images/figures/page_flow_other_profile_unfollow_button_mockup_3rd_edition
ምስል 14.4: የተከታዮቹ ቁጥር የጨመረ እና የ “አትከተል” አዝራርን የያዘ አንድ የመገለጫ ገጽ።
images/figures/page_flow_home_page_feed_mockup_3rd_edition
ምስል 14.5: የመነሻ ገጹ ከሁኔታ ቀላቢ እና የሚከተላቸው/ሏት ቁጥር ጪማሬ ጋር።

14.1 የትስስር ቅርጸት

ተጠቃሚዎች መከተልን ተግባራዊ ለማድረግ፣ የመጀመሪያው ሂደታችን አንድ የውሂብ ቅርጸትን መገንባት ነው፣ ይህንን መገንባቱ እንደሚታሰበው ቀላል አይደለም፡፡ እንዲሁ በገርነት ስናየው፣ አንድ የ‘ብዙ_አለው (has_many) ትስስርን በመጠቀም የሚሰራ ይመስላል፤ ማለት አንድ ተጠቃሚ ብዙ ተከታዮች አሉት (has_many) ብዙ ተጠቃሚዎችንም ይከተላል (has_many) ብለን በገርነት ልንጠቀምበት እናስብ ይሆናል፡፡ በኋላ ላይ እንደምንመለከተው፣ በዚህ አቀራረብ ላይ አንድ የተወሰነ ችግር እንዳለ እና በ‘ብዙ_አለው በኩል (has_many :through) የተባለውን የመተሳሰር ዘዴን በመጠቀም ይህንን ችግር እንዴት ማስተካከል እንደሚቻል እንማራለን፡፡

የጊት ተጠቃሚዎች፣ እንደተለመደው አንድ አዲስ የርዕስ ቅርንጫፍን መፍጠር ይኖርባችኋል:-

$ git checkout -b ተጠቃሚዎችን-መከተል

14.1.1 በውሂብ ቅርጸቱ ላይ ያለ ችግር (እና መፍትሄው)

ተጠቃሚዎችን ለመከተል፣ አንድ የውሂብ ቅርጽን ለመስራት፣ እንደ አንድ የመጀመሪያ እርምጃ ይቆጠር ዘንድ፣ እስኪ አንድ የተለመደ ሁኔታን እንመልከት፡፡ እንበል አንድ ተጠቃሚ ሌላ ተጠቃሚን እንደሚከተል አድርጋችሁ በህሊናችሁ አስቡ፤ እንበል ለምሳሌ፣ ሳሙኤል በላይነሽን እየተከተላት ነው፣ በላይነሽ የሳሙኤል ክትል ናት፤ ስለዚህ ሳሙኤል ተከታይ (teketay)፡ በላይነሽ ደግሞ ክትል (ktl) ትሆናለች ማለት ነው፡፡ የሬይልስ የብዙነት ነባሪ አሰራርን ስንጠቀም፣ አንድ የተሰጠ ተጠቃሚን የሚከተሉት፣ የሁሉም ተጠቃሚዎች ስብስብ፣ የተጠቃሚው ተከታዮች (teketayoch) ናቸው ማለት ነው፤ ስለዚህ በላይነሽ.ተጠቃሚዎች (belaynesh.teketayoch) እነዚህን ተጠቃሚዎች የያዘ አንድ ድርድር ነው ማለት ነው፡፡ እንደ አጋጣሚ ሆኖ የተገላቢጦሹ ትክክል አይደለም፤ የሁሉም የክትል ተጠቃዎች ስብስብ ደግሞ በነባሪነት ክትሎች (ktls) መባል ነበረበት፣ ሆኖም ይህ ቃል ከሰዋሰው ስርዓት ውጪ የሆነ ጉዳይ ነው፡፡ ስለዚህ የትዊተርን አሰራር በመከተል፣ እነዚህን ሚከተላቸው (miketelachew) ብለን እንጠራቸዋለን (ልክ “50 ሚከተላቸው/ሏት፣ 75 ተከታዮች” እንደሚለው ማለት ነው)፣ ስለሆነም የተጠቃሚው ተዛማጅ ድርድር ሳሙኤል.ሚከተላቸው (samuel.miketelachew) ይሆናል ማለት ነው፡፡

ይህ ውይይት የተከታይ ተጠቃሚዎች ውሂብን ለመቅረጽ፣ በምስል 14.6 ላይ እንደሚታየው፣ አንድ ሚከተላቸው (miketelachew) የተባለ ሰንጠረዥን ከአንድ ብዙ_አለው (has_many) ማሕበር ጋር መጠቀም እንዳለብን ይጠቁማል። ተጠቃሚ.ሚከተላቸው (teteqami.miketelachew) (የሚለው ኮድ) አንድ የተጠቃሚዎች ክምችት መሆን ስላለበት፣ በክትል_መታወቂያ (ktl_id) እና በ‘ተከታይ_መታወቂያ (teketay_id) የሚታወቁት አምዶች አንድ ማሕበርን እንዲመሰርቱ፣ እያንዳንዱ የ‘ሚከተላቸው (miketelachew) ሰንጠረዥ ረድፍ አንድ ተጠቃሚ መሆን ይኖርበታል።2 ከዚህ በተጨማሪም፣ እያንዳንዱ ረድፍ የሚያመለክተው አንድ ተጠቃሚን ስለሆነ፣ የተጠቃሚውን ስም፣ የኤመልእክት አድራሻውን፣ መሕለፈቃሉን እና ወዘተረፈ ያሉ ባሕሪዎችን በሙሉ ማካተት ይኖርብናል ማለት ነው።

images/figures/naive_user_has_many_following
ምስል 14.6: በገርነት የተደረገው ሚከተላቸው (miketelachew) ትግበራ።

ምስል 14.6 ላይ የተመለከትነው የውሂብ ቅርጸት ትልቁ ችግር ድግግሞሹ መብዛቱ ነው፤ እያንዳንዱ ረድፍ የሚይዘው የተጠቃሚውን መታወቂያ ብቻ ሳይሆን በ‘ተጠቃሚዎች (teteqamis) ሰንጠረዥ ውስጥ ከድሮውም የተካተቱትን ሁሉንም መረጃዎች ነው። ከዚህ የከፋው ደግሞ፣ የተጠቃሚውን ተከታዮች ቅድን ለመቅረጽ አንድ ሌላ ድግግሞሽ የበዛበት የ‘ተከታዮች (teketayoch) ሰንጠረዥ ማዘጋጀት ማስፈለጉ ነው፡፡ ይህ የውሂብ ቅርጸት መረጃዎችን የማሻሻል ስራን እጅግ ከባድ ያደርጋል፤ ለምሳሌ፣ አንድ ተጠቃሚ ስሙን በቀየረ ቁጥር፣ በ‘ተጠቃሚዎች (teteqamis) ሰንጠረዥ ላይ ያለውን የተጠቃሚውን ስም፣ ብቻ ሳይሆን በ‘ሚከተላቸው (miketelachew) እና በ‘ተከታዮች (teketayoch) ሰንጠረዥ ውስጥ እያንዳንዱ ረድፍ ላይ የሚገኘውን ስም ሳይቀር ማዘመን ይኖርብናል ማለት ነው፡፡

እዚህ ላይ ያለው ችግር አንድ መሰረታዊ እንቆቅልሽን አለመፍታታችን ያሳያል፡፡ ትክክለኛውን ቅርጸት ለመቀረጽ አንዱ መንገድ፣ በአንድ ድር አፕልኬሽን ውስጥ የ‘ሚከተላቸው (miketelachew) ተግባርን እንዴት አድርገን እንደምንተገብር መገንዘብ ነው፡፡ በክፍል 7.1.2 ላይ እንደተመለከትነው፣ የው.ሁ.ማ መዋቅር የሚፈጠሩ እና የሚደመሰሱ ሃብቶችን እንደሚያሳትፍ አስታውሱ፡፡ ይህ ደግሞ ሁለት ጥያቄዎችን እንድንጠይቅ ያነሳሳናል፤ አንደኛው ጥያቄ፣ አንድ ተጠቃሚ ሌላኛውን እየተከተለ ከሆነ የሚፈጠረው ነግር ምንድን ነው? ሲሆን ሁለተኛው ጥያቄ ደግሞ፣ አንዱ ተጠቃሚ አንዱን ተከትሎት ቆይቶ እንደገና ባይከተለው የሚጠፋው ነገርስ ምንድን ነው? ማለት በዚህ ጊዜ የተደመሰሰው ነገር ምንድን ነው? የሚሉት ናቸው፣ እነዚህን ነገሮች በማነጻጸር ረገድ ስንመለከት፣ በእነዚህ ክስተቶች ምክንያት፣ አፕልኬሽኑ በሁለት ተጠቃሚዎች መካከል አንድ ትስስርን መፍጠር ወይም መሰረዝ እንደሚኖርበት እንገነዘባለን፡፡ ከዚያ በኋላ አንድ ተጠቃሚ ብዙ ትስስሮች ስለሚኖሩት፣ በእነዚህ ትስስሮች በኩል ብዙ ሚከተላቸው (miketelachew) (ወይም ተከታዮች (teketayoch)) እንደሚኖሩትም በሚገባ እንገነዘባለን፡፡

የአፕልኬሽናችንን የውሂብ ቅርጸትን በተመለከተ፣ አንድ ልናስተናግደው የሚገባ ተጨማሪ ነገር አለ፤ የፌስቡክ-አይነት ጓደኝነት ተመጣጣኝ ነው፣ ይህ ማለት አንድ ሰው ከሌላ ሰው ጋር ጓደኛ የሚሆነው ሁለቱም ከተስማሙ ብቻ ነው፣ ማለት ነው፤ ይህም ከትዊተር-አይነት ጓደኝነት ጋር ተቃራኒ ነው (ቢያንስ የውሂብ ቅዱን በተመለከተ)፣ የትዊተር የመከተል ትስስር ተመጣጣኝ አይደለም ሳሙኤል በላይነሽን ሳይከተላት በላይነሽ ሳሙኤልን ልትከተለው ትችላለች። በእነዚህ ሁለት ሁኔታወች መካከል ያለውን ልዩነት ለመለየት፣ ንቅ (nq) እና ያልተካፈለ (yaltekafele) ትስስሮች በማለት የራሳችን የሆኑ ስነአባባሎችን እንፈጥራለን። ሳሙኤል በላይነሽን ከተከተላት እና በላይነሽ ሳሙኤልን ካልተከተለችው፣ ሳሙኤል ከበላይነሽ ጋር አንድ ንቅ ትስስር ሲኖረው በላይነሽ ደግሞ ከሳሙኤል ጋር አንድ ያልተካፈለ ትስስር አላት ማለት ነው፡፡3

አሁን አንድ ሚከተላቸው (miketelachew) ተጠቃሚዎች ዝርዝርን ለማመንጨት፣ ንቁ ትስስሮችን በመጠቀም ላይ እናተኩራለን፤ በክፍል 14.1.5 ውስጥ ደግሞ ያልተካፈሉ (yaltekafele) ትስስሮችን እንመለከታለን፡፡ ምስል 14.6 እንዴት ተደርጎ መተግበር እንደሚገባው እንዲህ ሲል ይጠቁማል፤ እያንዳንዱ የሚከተል ተጠቃሚ በተለየ የ‘ክትል_መታወቂያ (ktl_id) ተለይቶ ስለሚታወቅ፣ ሚከተላቸው‘ን (miketelachew) ወደ አንድ ንቅ_ትስስሮች (nq_tssrs) ሰንጠረዥ መለወጥ እንደምንችል፤ የሚከተለውን ተጠቃሚ ከተጠቃሚዎች (teteqamis) ሰንጠረዥ ፈልገን ለማውጣት ክትል_መታወቂያ‘ውን (ktl_id) ስለምንጠቀም፣ የተጠቃሚውን ዝርዝር መረጃወች በ‘ንቅ_ትስስሮች (nq_tssrs) ሰንጠረዥ ውስጥ ከማስገባት እንደምንቆጠብ ይጠቁማል። የውሂብ ቅርጸት አቀራረጹ በምስል 14.7 ላይ ይታያል፡፡

images/figures/user_has_many_miketelachew_3rd_edition
ምስል 14.7: በንቅ ትስስሮች በኩል የሚሰራ አንድ የሚከተላቸው ተጠቃሚዎች ቅድ፡፡

ከአንድ ተዛማጅ ትስስር (Tssr) ቅርጸት ጋር፣ ለሁለቱም ማለት ለንቅ እና ለያልተካፈለ ትስስሮች አንድ የውሂበጎታ ሰንጠረዥን መጠቀማችን ስለማይቀር፣ ለሰንጠረዡ ስም ትስስር (tssr) የተባለ አጠቃላይ ስነቃልን እንጠቀማለን። ስለሆነም የትስስሩ የውሂብ ቅድ፣ በምስል 14.8 ላይ እንደሚታየው ይሆናል፡፡ ሁለቱንም ማለት የንቅ ትስስርን እና የያልተካፈለ ትስስር ቅርጸቶችን ለማስመሰል፣ የትስስር ቅርጸትን እንዴት መጠቀም እንደሚቻል በክፍል 14.1.4 ላይ ማየት እንጀምራለን፡፡

images/figures/relationship_model
ምስል 14.8: የትስስሩ የውሂብ ቅድ።

ትግበራውን ለመጀመር፣ በቅድሚያ ከምስል 14.8 ጋር የሚዛመድ አንድ ፍልሰትን እናመነጫለን:-

$ rails generate model Tssr teketay_id:integer ktl_id:integer

ትስስሮችን በ‘ተከታይ_መታወቂያ (teketay_id) እና በ‘ክትል_መታወቂያ‘ው (ktl_id) መሰረት ስለምንፈልግ፣ ለቅልጥፍና በዝርዝር 14.1 ውስጥ እንደታየው፣ በእያንዳንዱ አምድ ላይ አንድ የመረጃ-ጠቋሚን ማከል ይኖርብናል፡፡

ዝርዝር 14.1: ለትስስሮች ሰንጠረዥ የመረጃ-ጠቋሚዎችን ማከል። db/migrate/[ማህተመጊዜ]_create_tssrs.rb
class CreateTssrs < ActiveRecord::Migration[6.1]
  def change
    create_table :tssrs do |t|
      t.integer :teketay_id
      t.integer :ktl_id

      t.timestamps
    end
    add_index :tssrs, :teketay_id
    add_index :tssrs, :ktl_id
    add_index :tssrs, [:teketay_id, :ktl_id], unique: true
  end
end

ዝርዝር 14.1 አንድ ተጠቃሚ ሌላ ተጠቃሚን ከአንድ ጊዜ በላይ መከተል እንዳይችል (በ‘ተከታይ_መታወቂያ (teketay_id) እና በ‘ክትል_መታወቂያ (ktl_id)) ጥንድ ላይ ልዩነትን የሚያስፈጽም አንድ ባለብዙ ቁልፍ የመረጃ-ጠቋሚዎችንም ያካትታል፡፡ (ይህንን ከዝርዝር 6.29 የኤመልእክት ልዩ የመረጃ-ጠቋሚ እና ዝርዝር 13.3 ላይ ካለው፣ ባለብዙ የመረጃ-ጠቋሚዎች ጋር አነጻጽሩ፡፡) ስለሆነም ከክፍል 14.1.4 ጀምረን እንደምናየው፣ የእኛ የተጠቃሚ በይነገጽ ይህ ነገር እንዲከሰት አይፈቅድም፣ ነገር ግን አንድ ተጠቃሚ ለማንኛውም የተደጋገሙ ትስስሮችን (ለምሳሌ፣ እንደ ከርል (curl) ያለ የማዘዥያ መስመርን ተጠቅሞ) ለመፍጠር ቢሞክር፣ አንድ ልዩ የመረጃ-ጠቋሚን ከወዲሁ ማከላችን አንድ ስህተት እንዲነሳ ያዘጋጅልናል፡፡

የ‘ትስስሮች (tssrs) ሰንጠረዡን ለመፍጠር፣ እንደተለመደው ውሂበጎታውን እናፈልሳለን:-

$ rails db:migrate

መልመጃዎች

የሬይልስ ስልጠናን ለገዙ ሰወች በሙሉ የሁሉም የመልመጃ መልሶች እዚህ ላይ ይገኛሉ።

የሌሎች ሰዎች መልሶችን ለማየት እና የራሳችሁን ደግሞ ለመመዝገብ፣ በሬይልስ ስልጠና ወይም ሁሉንም በበቂ ተማር መድረሻ ጥቅል ላይ ተመዝገቡ፡፡

  1. ምስል 14.7 ላይ ለሚገኘው፣ የተጠቃሚ-መታወቂያው 1 ለሆነው ተጠቃሚ የዚህ:- teteqami.miketelachew.map(&:id) ዋጋ ምን ይሆናል? (የዚህን:- map(&:የዘዴ_ስም) አይነት ጥለትን በክፍል 4.3.2 ላይ እንደተመለከትን አስታውሱ፡፡ ይሄ የ teteqami.miketelachew.map(&:id) ዘዴ፣ አንድ መታወቂያዎችን (ids) የያዘ ድርድርን ይመልሳል።)
  2. አሁንም ምስል 14.7 ላይ ለሚገኘው፣ የተጠቃሚ-መታወቂያው 2 ለሆነው ተጠቃሚ፣ የሚከተለውን መታወቂያዎች ለማግኘት ይህንን:- teteqami.miketelachew ተጠቀሙ። የተጠቃሚው የዚህ teteqami.miketelachew.map(&:id) ዋጋስ ምንድነው?

14.1.2 የተጠቃሚ/የትስስር ማሕበር

ተጠቃሚ የሚከተላቸውን እና ተከታዮችን ከመተግበራችን በፊት፣ በቅድሚያ በተጠቃሚዎች እና በትስስሮች መካከል ያለውን ማሕበር መመስረት ይኖርብናል፡፡ አንድ ተጠቃሚ ብዙ (has_many) ትስስር ይኖሩታል፤ እናም (አንድ ትስስር ሁለት ተጠቃሚዎችን የሚያሳትፍ እንደመሆኑ መጠን) ትስስሩ የሁለቱም ማለት የአንድ የሚከተላቸው ተጠቃሚ እና የአንድ የተከታዮች ተጠቃሚ ነው (belongs_to) ማለት ነው።

ክፍል 13.1.3 ውስጥ፣ አጪርጽሑፎች ላይ እንዳደረግነው ሁሉ፣ እዚህ ላይም የተጠቃሚውን ማሕበር በመጠቀም፣ አንድ አዲስ ትስስርን በዚህ ዓይነት ኮድ እንፈጥራለን:-

teteqami.nq_tssrs.build(ktl_id: ...)

በአሁኑ ጊዜ፣ የአፕልኬሽኑ ኮድ፣ በክፍል 13.1.3 ካለው ኮድ ጋር ተመሳሳይነት ይኖረዋል ብላችሁ ትጠብቁ ይሆናል፣ ተመሳሳይ አይደለም፣ እዚህ ላይ ሁለት ትልቅ ልዩነቶች አሉ፡፡

በመጀመሪያ፣ በተጠቃሚ/በአጪርጽሑፍ ማሕበር ሁኔታ ላይ ይህንን መጻፍ እንችል ነበር:-

class Teteqami < ApplicationRecord
  has_many :achrtshufs
  .
  .
  .
end

ይህ ይሰራ ነበር፣ ይህ የሆነበት ምክንያትም፣ ሬይልስ በተለምዶ ከአንድ አጪርጽሑፍ ቅርጸት ጋር የሚዛመድ አንድ የ‘:አጪርጽሑፎች (:achrtshufs) ወካይን ሰለሚመለከት ነው፡፡4 በአሁኑ ሁኔታ ላይ ግን ይህንን ኮድ መጻፍ ይጠበቅብናል:-

has_many :nq_tssrs

ምንም እንኳ ቅርጸቱ ከስር መሰረቱ ትስስር ተብሎ የሚታውቅ ቢሆንም፣ ሬይልስ ቅርጸቱን ይፈልግ ዘንድ፣ የቅርጸቱን የክፍል ስም ለሬይልስ መንገር ይኖርብናል፡፡

በመቀጠል፣ ይህንን ኮድ በአጪርጽሑፍ ቅርጸቱ ውስጥ ከመጻፋችን በፊት:-

class Achrtshuf < ApplicationRecord
  belongs_to :teteqami
  .
  .
  .
end

ይሰራ ነበር፤ ይህ የሆነበት ምክንያትም የአጪርጽሑፎች (achrtshufs) ሰንጠረዥ ተጠቃሚውን ለመለየት (ክፍል 13.1.1) አንድ የ‘ተጠቃሚ_መታወቂያ (teteqami_id) ባሕሪ ስላላው ነው፡፡ በዚህ ሁኔታ ላይ ሁለት የውሂበጎታ ሰንጠረዦችን ለማገናኘት የሚጠቅመው መታወቂያ (id) የውጪ ቁልፍ በመባል ይታወቃል፤ እናም ለአንድ የተጠቃሚ ቅርጸት ቁስ፣ የውጪ ቁልፉ የ‘ተጠቃሚ_መታወቂያ‘ው (teteqami_id) በሚሆንበት ጊዜ፣ ሬይልስ ባለው ሁኔታ ላይ በመመርኮዝ በራስሰር ማሕበሩን ያውቃል፣ ሬይልስ አንድ የውጪ ቁልፍን ለመስራት የዚህ <ክፍል>_መታወቂያ ዓይነት ቅጽን በነባሪ ይጠብቃል፡፡ ይህ ማለት የክፍል ስሙ እንደዚህ <class> በንዑስ ፊደል የተጻፈ መሆን ይገባዋል ማለት ነው፡፡5 በአሁኑ ሁኔታ ላይ፣ የተጠቃሚዎች ጉዳይ ላይ እየሰራን ቢሆንም፣ ሌላውን ተጠቃሚ የሚከተለው አንድ ተጠቃሚ፣ አሁን የሚለየው፣ ተከታይ-መታወቂያ (teketay_id) በተባለው የውጪ ቁልፍ ስለሆነ፣ ይህንንም ለሬይልስ መንገር ይኖርብናል፡፡

ከላይ የተወያየናቸውን የተጠቃሚ/የትስስር ማሕበርን ተግባራዊ የማድረጉ ውጤት፣ በዝርዝር 14.2 እና በዝርዝር 14.3 ውስጥ ይታያል፡፡ የነዚህ ዝርዝሮች የመግለጫ ጽሑፉ ላይ እንደተመለከተው፣ ሁለቱም ላይ ፈተናው በአሁኑ ጊዜ ቀይ ነው (ለምን?)፤6 ይህንን ችግር በክፍል 14.1.3 ላይ እናስተካክለዋለን፡፡

ዝርዝር 14.2: የንቁ ትስስሮች ላይ ብዙ ማሕበር አለውን (has_many) መተግበር፡፡ ቀይ app/models/teteqami.rb
class Teteqami < ApplicationRecord
  has_many :achrtshufs,   dependent: :destroy
  has_many :nq_tssrs,       class_name: "Tssr",
                            foreign_key: "teketay_id",
                            dependent:   :destroy
  .
  .
  .
end

(አንድ ተጠቃሚ ከውሂበጎታው በሚጠፋበት ወቅት፣ የተጠቃሚው ትስስሮች ሁሉ አብረውት ይጠፋ ዘንድ፣ ጥገኛ: :አጥፊን (dependent: :destroy) በማሕበሩ ውስጥ አክለናል።)

ዝርዝር 14.3: የተከታይ የባለቤትነት (belongs_to) ማህበርን በትስስር ቅርጸቱ ላይ ማከል።ቀይ app/models/tssr.rb
class Tssr < ApplicationRecord
  belongs_to :teketay, class_name: "Teteqami"
  belongs_to :ktl,     class_name: "Teteqami"
end

በውነቱ የ‘ክትል (ktl) ማሕበሩ እስከ ክፍል 14.1.4 ድረስ አይፈለግም፤ ይሁን እንጂ ትይዩው የክትል መዋቅር ግልጽ የሚሆነው፣ ሁለቱንም ሕብረቶች በአንድ ላይ መተግበሩ ላይ የተመሰረተ ስለሆነ፣ እኛም እንደዛው አድርገናል።

ሰንጠረዥ 14.1 ውስጥ እንደሚታየው፣ በዝርዝር 14.2 እና በዝርዝር 14.3 ውስጥ ያሉት ትስስሮች፣ በሰንጠረዥ 13.1 ውስጥ ካየናቸው ጋር ተመሳሳይነት ያላቸው ዘዴዎችን ይሰጡናል።

ዘዴ ጥቅም
nq_tssr.teketay ተከታይን መመለስ
nq_tssr.ktl ክትል ተጠቃሚን መመለስ
teteqami.nq_tssrs.create(ktl_id: lela_teteqami.id) ከተጠቃሚው (teteqami) ጋር የተዛመደ አንድ ንቁ ትስስርን መፍጠር
teteqami.nq_tssrs.create!(ktl_id: lela_teteqami.id) ከተጠቃሚው (teteqami) ጋር የተዛመደ አንድ ንቁ ትስስርን መፍጠር (በውድቀት ጊዜ ልዩነትን ያስነሳል)
teteqami.nq_tssrs.build(ktl_id: lela_teteqami.id) ከተጠቃሚው (teteqami) ጋር የተዛመደ አንድ አዲስ የትስስር ቁስን መመለስ
ሰንጠረዥ 14.1: የተጠቃሚ/የንቁ ትስስር ማሕበር ዘዴዎች አንድ ማጠቃለያ።

መልመጃዎች

የሬይልስ ስልጠናን ለገዙ ሰወች በሙሉ የሁሉም የመልመጃ መልሶች እዚህ ላይ ይገኛሉ።

የሌሎች ሰዎች መልሶችን ለማየት እና የራሳችሁን ደግሞ ለመመዝገብ፣ በሬይልስ ስልጠና ወይም ሁሉንም በበቂ ተማር መድረሻ ጥቅል ላይ ተመዝገቡ፡፡

  1. የ‘ፍጠር (create) ዘዴን ከሰንጠረዥ 14.1 በመጠቀም፣ በውሂበጎታው ውስጥ የሚገኘውን የመጀመሪያውን ተጠቃሚ፣ ሁለተኛው ተጠቃሚ እንደሚከተለው አድርጉ።
  2. የ‘ንቅ_ትስስር.ክትል (nq_tssr.ktl) እና የ‘ንቅ_ትስስር.ተከታይ (nq_tssr.teketay) ዋጋዎች ትክክል መሆናቸውን አረጋግጡ፡፡

14.1.3 የትስስር ማረጋገጫወች

ከመቀጠላችን በፊት ሁሉንም ነገር የተሟላ ለማድረግ፣ አንዳንድ የትስስር ቅርጸት ማረጋገጫወችን እናክላለን፡፡ በዝርዝር 14.4 ውስጥ ያሉት ፈተናወች እና በዝርዝር 14.5 ውስጥ ያሉት የአፕልኬሽኑ ኮዶች በግልጽ የተቀመጡ ናቸው፡፡ በዝርዝር 6.30 ውስጥ ለተጠቃሚ እንደመነጨው እቃ ሁሉ፣ ለትስስር የመነጨው እቃም እንዲሁ፣ በተዛማጁ ፍልሰት ላይ የተጣለውን የልዩነትን ግዴታ ይጥሳል (ዝርዝር 14.1)፡፡ የዚህ መፍትሄም ልክ በዝርዝር 6.31 ውስጥ እንደተደረገው፣ የእቃ ይዘቶቹን ማስወገድ ይሆናል፤ ይህም በዝርዝር 14.6 ላይ ተተግብሯል፡፡

ዝርዝር 14.4: የትስስር ቅርጸት ማረጋገጫዎችን መፈተን፡፡ ቀይ test/models/tssr_test.rb
require "test_helper"

class TssrTest < ActiveSupport::TestCase

  def setup
    @tssr = Tssr.new(teketay_id: teteqamis(:michael).id,
                         ktl_id: teteqamis(:ermias).id)
  end

  test "ብቁ መሆን አለበት" do
    assert @tssr.valid?
  end

  test "አንድ teketay_id ን ማስፈለግ አለበት" do
    @tssr.teketay_id = nil
    assert_not @tssr.valid?
  end

  test "አንድ ktl_id ን ማስፈለግ አለበት" do
    @tssr.ktl_id = nil
    assert_not @tssr.valid?
  end
end
ዝርዝር 14.5: የትስስር ቅርጸት ማረጋገጫዎችን ማከል፡፡ ቀይ app/models/tssr.rb
class Tssr < ApplicationRecord
  belongs_to :teketay, class_name: "Teteqami"
  belongs_to :ktl,     class_name: "Teteqami"
  validates  :teketay_id, presence: true
  validates  :ktl_id,     presence: true
end
ዝርዝር 14.6: የትስስር እቃ ይዞታዎችን ማስወገድ። አረንጓዴ test/fixtures/tssrs.yml
# ባዶ

በዚህ ወቅት የፈተና ስብስቡ አረንጓዴመሆን አለበት:-

ዝርዝር 14.7: አረንጓዴ
$ rails test

መልመጃዎች

የሬይልስ ስልጠናን ለገዙ ሰወች በሙሉ የሁሉም የመልመጃ መልሶች እዚህ ላይ ይገኛሉ።

የሌሎች ሰዎች መልሶችን ለማየት እና የራሳችሁን ደግሞ ለመመዝገብ፣ በሬይልስ ስልጠና ወይም ሁሉንም በበቂ ተማር መድረሻ ጥቅል ላይ ተመዝገቡ፡፡

  1. ዝርዝር 14.5 ውስጥ ያሉት ማረጋገጫዎች ላይ፣ አስተያየት በማድረግ አሁንም ፈተናዎቹ እንደሚያልፉ አረጋግጡ። (ይህ ለውጥ የተደረገው ከሬይልስ 5 ጀምሮ ሲሆን፣ በቀደምቶቹ የሬይልስ ስሪቶች ላይ ግን ማረጋገጫዎች ግዴታ ያስፈልጉ ነበር። በዚህ አጋጣሚ እኛ ለአይን እይታ የተሟሉ ይሆኑ ዘንድ፣ ባሉበት ቦታ ላይ ልንተዋቸው ወስነናል፣ ነገር ግን እነዚህን ማረጋገጫዎች፣ በሌሎች ሰወች ኮድ ላይ፣ ሳይጻፉ እንደሚቀሩ ልታዩ እንደምትችሉ ልብ ልትሉ ይገባል፡፡)

14.1.4 ክትል ተጠቃሚዎች

አሁን የትስስር ማሕበሮች ልብ ወደሆኑት፤ ወደ ሚከተላቸው (miketelachew) እና ወደ ተከታዮች (teketayoch) ትስስሮች መጥተናል፡፡ እዚህ ላይ በ‘ብዙ_አለው በኩል (has_many :through) የተባለውን የግንኙነት ዘዴ ለመጀመሪያ ጊዜ እንጠቀማለን፤ በምስል 14.7 ውስጥ በስእላዊ መግለጫ ላይ እንደተመለከተው፣ አንድ ተጠቃሚ በትስስሮች በኩል ብዙ የሚከተላቸው ይኖሩታል፡፡ አንድ የ‘ብዙ_አለው በኩል (has_many :through) ማሕበርን ስንጠቀም፣ ሬይልስ ከአንድ ነጠላ ስም ጋር የሚዛመድ አንድ የውጪ ቁልፍ ማሕበርን በነባሪ መመልከት ይጀምራል፡፡ በሌላ አማርኛ ይህንን ከመሰለ ኮድ ላይ:-

has_many :ktls, through: :nq_tssrs

ሬይልስ “ktls” የሚለውን ጽሑፍ ይመለከት እና የዚህን ነጠላ “ktl” ብሎ በመቀየር በ‘ትስስሮች (tssrs) ሰንጠረዥ ላይ ክትል_መታወቂያ‘ን (ktl_id) በመጠቀም፣ አንድ ክምችትን ይፈጥራል ማለት ነው፡፡ ነገር ግን በክፍል 14.1.1 ላይ እንደተጠቀሰው፣ ተጠቃሚ.ክትሎች (teteqami.ktls) የሚለውን፣ ለጆሮ ቀፋፊ የሆነውን ዘዴ ከመጠቀም ይልቅ፣ አንድ ተጠቃሚ.ሚከተላቸው (teteqami.miktelachew) የተባለ ዘዴን እራሳችን እንጽፋለን፡፡ ሬይልስ በተፈጥሮው፣ በዚህ ሁኔታ ላይ የ‘ምንጪ (source) ሰሚአሴትን በመጠቀም፣ (በዝርዝር 14.8 ላይ እንደሚታየው) ነባሪውን ስያሜ እንድናግድ ያስችለናል፣ ይህም ሬይልስን የ‘ሚከተላቸው (miketelachew) የድርድር ምንጪ፣ የ‘ክትል (ktl) መታወቂያዎች ክምችት መሆኑን በግልጽ/በቁምነገር ይነግረዋል፡፡

ዝርዝር 14.8: በተጠቃሚ ቅርጸቱ ውስጥ የ‘ሚከተላቸው (miketelachew) ማሕበርን ማከል። app/models/teteqami.rb
class Teteqami < ApplicationRecord
  has_many :achrtshufs,   dependent: :destroy
  has_many :nq_tssrs,       class_name: "Tssr",
                            foreign_key: "teketay_id",
                            dependent:   :destroy
  has_many :miketelachew, through: :nq_tssrs, source: :ktl
  .
  .
  .
end

ዝርዝር 14.8 ውስጥ የተበየነውን ማሕበር፣ ወደ አንድ ሃይለኛ የ‘ንቅ መዝገብ እና የድርድር አሰራርን ወደመሰለ፣ ጥምረት ወዳለው አመርቂ ባህሪ ያመራናል፡፡ ለምሳሌ፣ የ‘ያካትታልን? (include?) ዘዴን በመጠቀም፣ የተከታዮች ክምችት ሌላውን ተጠቃሚ እንደያዘ ለማረጋገጥ ወይም በማሕበሩ በኩል ቁሶቹን ለመፈለግ ያስችለናል (ክፍል 4.3.1)፡-

teteqami.miketelachew.include?(lela_teteqami)
teteqami.miketelachew.find(lela_teteqami)

ልክ እንደ ማንኛውም ድርድር፣ የፈለገውን አባል ማከልም ሆነ መሰረዝ እንችላለን:-

teteqami.miketelachew << lela_teteqami
teteqami.miketelachew.delete(lela_teteqami)

(ይሄ << የአካፋ ስሌት የተሰጠውን ነገር፣ በድርድሩ መጨረሻ ላይ እንደሚጨምር በክፍል 4.3.1 ላይ እንደተመለከትን አስታውሱ፡፡)

በብዙ ሁኔታዎች ውጤታማ በሆነ መንገድ ሚከተላቸው‘ን (miketelachew) እንደ አንድ ድርድር አድርገን ልንቆጥረው ብንችልም፣ ሬይልስ በስተጀርባ ነገሮችን እንዴት አድርጎ እንደሚያስተናግድ በጥሩ ሁኔታ ያውቃል። ለምሳሌ ይህንን የመሰለ ኮድ:-

miketelachew.include?(lela_teteqami)

እዚህ ላይ የ‘ያካትታልን? (include?) ዘዴን ለመተግበር፣ ሁሉንም ተከታዮች ከውሂበጎታ የሚጎትት/የሚያወጣ ዓይነት ሊመስል ይችላል፣ ነገር ግን በውነቱ፣ ለቅልጣፌ ሲባል ሬይልስ ንጽጽሩ በቀጥታ በውሂበጎታው ውስጥ እንዲከናወን ያዘጋጃል፡፡ (ይህንን ሁኔታ በክፍል 13.2.1 ውስጥ ካለው ኮድ ጋር ስናነጻጽር፣ በዚያ ክፍል ላይ ይህ ኮድ:-

teteqami.achrtshufs.count

ቆጠራውን በቀጥታ በውሂበጎታው ውስጥ እንደሚያከናውን እናያለን፡፡)

የሚከተላቸው ትስስሮችን ለማንቀሳቀስ ተከተል (teketel) እና አትከተል (atketel) የተባሉ ሁለት መገልገያ (Utility) ዘዴወችን እናስተዋውቃለን፤7 ስለሆነም እንደዚህ አድርገን:- ተጠቃሚ.ተከተል(ሌላ_ተጠቃሚ) (teteqami.teketel(lela_teteqami)) መጻፍ እንችላለን ማለት ነው፡፡ አንድ ተጠቃሚ ሌላውን እየተከተለ መሆኑን ለማረጋገጥ፣ አንድ ይከተላቸዋልን? (miketelachew?) የተባለ ተዛማጅ የቡልየን ዘዴንም እናክላለን፡፡8

በመጀመሪያ የተወሰኑ ፈተናዎችን ለመጻፍ የምፈልግበት ትክክላኛ ሁኔታ ይሄ ነው፡፡ ምክንያቱም በአንድ የሚሰራ የድር በይነገጽ ላይ የሚከተላቸው ተጠቃሚዎችን ለማስገባት ገና ብዙ ጊዜ ስለሚቀረን እና እኛ ያበለጸግነው ኮድን ያለ አንድ ተገልጋይ (client) (በአሳሽ በኩል የሚገለገል ተጠቃሚ) ማካሄዱም ከባድ ስለሆነ ነው። በዚህ ሁኔታ ላይ፣ ተጠቃሚው የሌላውን ተጠቃሚ አለመከተሉን ለማረጋገጥ ይከተላቸዋልን? ‘ን (miketelachew?) በመጠቀም፣ ሌላ ተጠቃሚን ለመከተል ተከተል‘ን (teketel) በመጠቀም፣ ክንዋኔው የተሳካ መሆኑን ለማረጋገጥ ይከተላቸዋልን?‘ን (miketelachew?) በመጠቀም እና በመጨረሻም አለመከተል (atketel) እና እሱራሱ እንደሰራ የሚያረግጥ አንድ አጪር ፈተናን ለተጠቃሚ ቅርጸቱ መጻፉ ግን ቀላል ነው፡፡ ይህንን በተግባር ላይ በማዋል የተገኘው ውጤት፣ በዝርዝር 14.9 ውስጥ ይታያል። 9

ዝርዝር 14.9: አንዳንድ የ‘ሚከተላቸው “miketelachew” መገልገያ ዘዴዎችን መፈተኛዎች። ቀይ test/models/teteqami_test.rb
require 'test_helper'

class TeteqamiTest < ActiveSupport::TestCase
  .
  .
  .
  test "አንድ ተጠቃሚን መከተል እና አለመከተል አለበት" do
    michael = teteqamis(:michael)
    ermias  = teteqamis(:ermias)
    assert_not michael.miketelachew?(ermias)
    michael.teketel(ermias)
    assert michael.miketelachew?(ermias)
    michael.atketel(ermias)
    assert_not michael.miketelachew?(ermias)
    # ተጠቃሚዎች እራሳቸውን መከተል አይችሉም፡፡
    michael.teketel(michael)
    assert_not michael.miketelachew?(michael)
  end
end

የ‘ሚከተላቸው (miketelachew) ማሕበርን ልክ እንደ አንድ ድርድር አድርገን በመቁጠር፣ ተከተል (teketel) ፣ አትከተል (atketel) እና ይከተላቸዋልን?‘ን (miketelachew?) የተባሉ የመገልገያ ዘዴወችን በዝርዝር 14.10 ላይ እንደሚታየው አድርገን መጻፍ እንችላለን፡፡ (በተጠቃሚ ቅርጸቱ ውስጥ የሚገኘውን የ‘ራሥ (self) ተለዋዋጪን ማስወገድ አመች በሆነ ቁጥር እሱን ለማስወገድ ወደኋላ እንደማንል አስተውሉ።)

ዝርዝር 14.10: ለሚከተላቸው የመገልገያ ዘዴዎችን ማከል፡፡ አረንጓዴ app/models/teteqami.rb
class  Teteqami < ApplicationRecord
  .
  .
  .
  def qelabi
    .
    .
    .
  end

  # አንድ ተጠቃሚን ይከተላል።
  def teketel(lela_teteqami)
    miketelachew << lela_teteqami unless self == lela_teteqami
  end

  # አንድ ተጠቃሚን አይከተልም።
  def atketel(lela_teteqami)
    miketelachew.delete(lela_teteqami)
  end

  # የአሁን ተጠቃሚ ሌላ ተጠቃሚን የሚከለው ከሆነ እውነትን ይመለሳል።
  def miketelachew?(lela_teteqami)
    miketelachew.include?(lela_teteqami)
  end

  private
  .
  .
  .
end

ዝርዝር 14.10 ውስጥ ካለው ኮድ ጋር፣ ፈተናው አረንጓዴመሆን አለበት:-

ዝርዝር 14.11: አረንጓዴ
$ rails test

መልመጃዎች

የሬይልስ ስልጠናን ለገዙ ሰወች በሙሉ የሁሉም የመልመጃ መልሶች እዚህ ላይ ይገኛሉ።

የሌሎች ሰዎች መልሶችን ለማየት እና የራሳችሁን ደግሞ ለመመዝገብ፣ በሬይልስ ስልጠና ወይም ሁሉንም በበቂ ተማር መድረሻ ጥቅል ላይ ተመዝገቡ፡፡

  1. ዝርዝር 14.9 ውስጥ የተዘረዘሩትን ቅደም ተከተሎች በመከተል፣ ፈተናወቹን በሰሌዳችሁ ውስጥ እንደገና አረጋግጡ፡፡
  2. በላይኛው መልመጃ ላይ፣ ከያንዳንዱ የተ.መ.ቋ ትእዛዝ የተገኘው ውጤት ምንድን ነው?

14.1.5 ተከታዮች

የትስስሮች ስራን ለመቋጨት የመጨረሻ ተግባር የሚሆነው፣ ከ‘ተጠቃሚ.ሚከተላቸው (teteqami.miketelachew) ዘዴ ጋር አብሮ የሚሄድ፣ አንድ ተጠቃሚ.ተከታዮች (teteqami.teketayoch) የተባለ ዘዴን ማከል ብቻ ነው፡፡ አንድ የተከታዮች ድርድን ለማውጣት የሚያስፈልጉ መረጃዎች በሙሉ፣ ቀድሞውኑ በ‘ትስስሮች (tssrs) ሰንጠረዥ ውስጥ እንደሚገኙ ከምስል 14.7 አስተውላችሁ ይሆናል። (ይህንንም በዝርዝር 14.2 ውስጥ ባለው ኮድ በኩል ልክ እንደ ንቅ_ትስስሮች (nq_tssrs) ሰንጠረዥ አድርገን ተመልክተነው ነበር)፡፡ በእርግጥ የ‘ተከታይ_መታወቂያ (teketay_id) ሚናን በ‘ክትል_መታወቂያ (ktl_id) ሚና ከመቀየር እና በ‘ንቅ_ትስስሮች (nq_tssrs) ቦታ ያልተካፈለ_ትስስሮች‘ን (yaltekafele_tssrs) ከመተካት በስተቀር፤ አሰራሩ ከሚከተላቸው ተጠቃሚዎች አሰራር ጋር ፍጹም አንድ አይነት ነው። ስለሆነም የውሂብ ቅዱ በዝርዝር 14.9 ላይ እንደሚታየው ይሆናል ማለት ነው፡፡

images/figures/user_has_many_followers_3rd_edition
ምስል 14.9: የተጠቃሚ ተከታዮች፣ በያልተካፈለ ትስስሮች በኩል የሆነ አንድ ቅድ፡፡

ዝርዝር 14.12 ላይ እንደተመለከተው፣ የዝርዝር 14.9 የውሂብ ቅርጸት ትግበራ፣ ከዝርዝር 14.12 የውሂብ ቅርጸት ትግበራ ጋር በትክክል ትይዩ ነው፡፡

ዝርዝር 14.12: ያልተካፈለ ትስስሮችን በመጠቀም ተጠቃሚ.ተከታዮች‘ን (teteqami.teketayoch) መተግበር። app/models/teteqami.rb
class Teteqami < ApplicationRecord
  has_many :achrtshufs,   dependent:   :destroy
  has_many :nq_tssrs,       class_name:  "Tssr",
                            foreign_key: "teketay_id",
                            dependent:   :destroy
  has_many :miketelachew, through: :nq_tssrs, source: :ktl
  has_many :yaltekafele_tssrs, class_name:  "Tssr",
                               foreign_key: "ktl_id",
                               dependent:   :destroy
  has_many :teketayoch, through: :yaltekafele_tssrs, source: :teketay
  .
  .
  .
end

ዝርዝር 14.13 ውስጥ እንደሚታየው፣ የ‘ተከታዮች.ያካትታልን? (teketayoch.include?) ዘዴን በመጠቀም፣ ከዚህ በላይ ያለውን የውሂብ ቅርጸት በሚመች ሁኔታ መፈተን እንችላለን፡፡ (ዝርዝር 14.13 ከ‘ይከተላቸዋልን? (miketelachew?) ዘዴ ጋር የሚሄድ አንድ ተከትሏል_በ? (teketluwal_be?) የተባለ ዘዴን ሊጠቀም ይችል ነበር፣ ነገር ግን ይህ ዘዴ በአፕልኬሽናችን ውስጥ የማያስፈልግ ሆኖ ተገኝቷል፡፡)

ዝርዝር 14.13: ተከታዮች‘ን (teketayoch) መፈተን። አረንጓዴ test/models/teteqami_test.rb
require 'test_helper'

class TeteqamiTest < ActiveSupport::TestCase
  .
  .
  .
  test "አንድ ተጠቃሚን መከተል እና አለመከተል አለበት" do
    michael  = teteqamis(:michael)
    ermias   = teteqamis(:ermias)
    assert_not michael.miketelachew?(ermias)
    michael.teketel(ermias)
    assert michael.miketelachew?(ermias)
    assert ermias.teketayoch.include?(michael)
    michael.atketel(ermias)
    assert_not michael.miketelachew?(ermias)
  end
end

ዝርዝር 14.13ዝርዝር 14.9 ፈተናዎች ላይ አንድ መስመር ፈተናን ብቻ አክሏል፤ ነገር ግን በዝርዝር 14.12 ውስጥ ያለው ኮድ በቀላሉ የሚበላሽ ኮድ ስለሆነ፣ ፈተናው እንዲያልፍ ብዙ ነገሮች በትክክል መሰራት ይኖርባቸዋል፡፡

በዚህ ጊዜ የፈተና ስብስቡ በሙሉ አረንጓዴመሆን አለበት፡-

$ rails test

መልመጃዎች

የሬይልስ ስልጠናን ለገዙ ሰወች በሙሉ የሁሉም የመልመጃ መልሶች እዚህ ላይ ይገኛሉ።

የሌሎች ሰዎች መልሶችን ለማየት እና የራሳችሁን ደግሞ ለመመዝገብ፣ በሬይልስ ስልጠና ወይም ሁሉንም በበቂ ተማር መድረሻ ጥቅል ላይ ተመዝገቡ፡፡

  1. በሰሌዳችሁ ውስጥ፣ ውሂበጎታው ውስጥ ላለው፣ ለመጀመሪያው ተጠቃሚ፣ ሁለት ተጠቃሚዎች እንደሚከተሉት አድርጉ (የመጀመሪያውን ተጠቃሚ “ተጠቃሚ” ብላችሁ መሰየም ይኖርባችኋል)። የዚህ ተጠቃሚ.teketayoch.map(&:id) ዋጋ ምንድንነው?
  2. የተጠቃሚ.ተከታዮች.ቁጠር (ተጠቃሚ.teketayoch.count) ብዛት፣ እናንተ ከዚህ በላይ ከፈጠራችኋቸው ተከታዮች ብዛት ጋር እኩል መሆኑን አረጋግጡ፡፡
  3. ይህንን:- ተጠቃሚ.teketayoch.count ለመጠቀም የተደረገው ተ.መ.ቋ ይሄን:- ተጠቃሚ.teketayoch.to_a.count ለመጠቀም ከተደረገው ተ.መ.ቋ በምን ይለያል? ጠቃሚ ምንጪ:- ተጠቃሚው አንድ ሚሊየን ተከታዮች አሉት እንበል፡፡

14.2 ለተጠቃሚዎች መከተያ፣ አንድ የድር በይነገጽ።

ክፍል 14.1 ውስጥ የውሂብ ቅርጸት አቀራረጽ ክህሎታችንን የሚፈትኑ አንዳንድ ከባድ ምስፈርቶችን ጠይቆ ነበረ፣ እናም እነሱን በድንብ ለመረዳት፣ ትንሽ ጊዜ ወስዶባችሁ ከሆነ፣ ያ ጥሩ ምክንያት እንደሆነ ከወዲሁ ልትገነዘቡት ይገባል። በእርግጥ፣ ማሕበሮችን ለመረዳት ከሚረዱት ምርጥ መንገዶች ውስጥ አንዱ፣ በድር በይነገጽ ውስጥ እነሱን መጠቀም ነው፡፡

በዚህ ምዕራፍ መግቢያ ላይ አንድ ተጠቃሚ ሚከተላቸው የገጽ ፍሰት ቅድመዕይታን ተመልክተናል፡፡ በዚህ ክፍል ውስጥ፣ በእነዛ ስእላዊ መግለጫዎች ላይ ከተመለከቱት ውስጥ፣ ማለት መሰረታዊ የሆነ በይነገጽን፣ የሚከተላቸው እና የተከታዮች ተግባሮችን እንተገብራለን። ተጠቃሚ ሚከተላቸው እና የተጠቃሚ ተከታዮች ድርድሮችን ለማሳየት የሚያገለግሉ ሁለት የተለያዩ ገጾችንም እንሰራለን፡፡ በክፍል 14.3 ውስጥ፣ በማሳያ አፕልኬሽኑ ላይ የተጠቃሚ ሁኔታ ቀላቢውን በማከል፣ የማሳያ አፕልኬሽኑን ሙሉ በሙሉ እናጠናቅቃለን።

14.2.1 የሚከተላቸው የውሂብ ናሙና

እንደቀድሞዎቹ ምዕራፎች ሁሉ፣ ውሂበጎታውን በናሙና ትስስሮች ለመሙላት፣ የ‘ሬይልስ ውሂብጎታ:ዝራ (rails db:seed) ትእዛዝን መጠቀሙን፣ አሁንም ምቹ ሆኖ እናገኘዋለን፡፡ ይህ ከፊት ያለውን የድር ገጻችንን እይታ እና ስሜታ ለመንደፍ ያስችለናል፣ የደጀኑን አተገባበር ደግሞ በዚህ ክፍል መጨረሻ ላይ እንመለከታለን፡፡

የሚከተላቸው ትስስሮችን የሚዘራው ኮድ፣ በዝርዝር 14.14 ውስጥ ይታያል፡፡ የመጀመሪያውን ተጠቃሚ፣ ከሶስተኛው (3) እስከ ሃምሳ አንደኛው ያሉ ተጠቃሚወችን እንዲከተል ስናደርግ፣ እሱን ደግሞ ከአራተኛው (4) እስከ አርባ አንደኛው (41) ያሉ ተጠቃሚወች እንዲከተሉት አድርገናል፡፡ ከዚህ የሚገኙት ትስስሮች የአፕልኬሽኑን በይነገጽ ለማበልጸግ በቂ ይሆናሉ፡፡

ዝርዝር 14.14: በናሙና ውሂቡ ውስጥ የሚከተላቸው እና የተከታዮች ትስስሮችን ማከል። db/seeds.rb
# አንድ ዋና የናሙና ተጠቃሚን መፍጠር።
Teteqami.create!(sim:  "Abnetawi Teteqami",
             emelekt: "example@railstutorial.org",
             password:              "kebekasa",
             password_confirmation: "kebekasa",
             astedadari: true,
             nq: true,
             nq_at: Time.zone.now)
# መአት ተጠቃሚዎችን ማመንጨት።
99.times do |n|
  sim  = Faker::Name.name
  emelekt = "msalie-#{n+1}@railstutorial.org"
  password = "mehlefeqal"
  Teteqami.create!(sim:  sim,
               emelekt: emelekt,
               password:              password,
               password_confirmation: password,
               nq: true,
               nq_at: Time.zone.now)
end

# ለክፍለንዑስ ተጠቃሚዎች አጪርጽሑፎችን ያመነጫል።
teteqamis = Teteqami.order(:created_at).take(6)
50.times do
  yizet = Faker::Lorem.sentence(word_count: 5)
  teteqamis.each { |teteqami| teteqami.achrtshufs.create!(yizet: yizet) }
end

# የመከተል ትስስሮችን ይፈጥራል።
teteqamis = Teteqami.all
teteqami  = teteqamis.first
miketelachew = teteqamis[2..50]
teketayoch = teteqamis[3..40]
miketelachew.each { |ktl| teteqami.teketel(ktl) }
teketayoch.each { |teketay| teketay.teketel(teteqami) }

ዝርዝር 14.14 ውስጥ ያለውን ኮድ ለማስፈጸም፣ እንደተለመደው ውሂበጎታውን በድጋሜ እናስጀምር እና በድጋሜ እንዘራዋለን:-

$ rails db:migrate:reset
$ rails db:seed

መልመጃዎች

የሬይልስ ስልጠናን ለገዙ ሰወች በሙሉ የሁሉም የመልመጃ መልሶች እዚህ ላይ ይገኛሉ።

የሌሎች ሰዎች መልሶችን ለማየት እና የራሳችሁን ደግሞ ለመመዝገብ፣ በሬይልስ ስልጠና ወይም ሁሉንም በበቂ ተማር መድረሻ ጥቅል ላይ ተመዝገቡ፡፡

  1. ሰሌዳችሁን በመጠቀም፣ የዚህ:- Teteqami.first.teketayoch.count ውጤት በዝርዝር 14.14 ከሚጠበቀው ዋጋ ጋር መዛመዱን አረጋግጡ፡፡
  2. ይህ:- Teteqami.first.miketelachew.count ትክክል መሆኑንም አረጋግጡ፡፡

14.2.2 አሃዛዊ-መረጃ እና አንድ የመከተያ ቅጽ

አሁን የናሙና ተጠቃሚዎቻችን፣ ተጠቃሚዎችን በማስከተል እና በመከተል ላይ ስለሚገኙ፣ ይህንን ለማንጸባረቅ፣ የመገለጫ እና የመነሻ ገጹን ማዘመን ይኖርብናል፡፡ በመገለጫ እና በመነሻ ገጹ ላይ፣ የሚከተላቸው እና የተከታዮች አሃዛዊ-መረጃዎችን ለማሳየት የሚያገለግ አንድ ከፊልን በመስራት እንጀምራለን፡፡ በመቀጠል አንድ የተከተል/አትከተል ቅጽን እናክል እና ከዚያ፣ “ሚከተላቸው/ሏት” እና “ተከታዮች” ‘ን ለማሳየት የተመደቡ ሁለት ገጾችን እንሰራለን፡፡

ክፍል 14.1.1 ላይ እንደተገለጸው፣ የትዊተር ደንብን በመከተል፣ አንድ ተጠቃሚ የሚከተላቸውን ተጠቃሚዎች “ሚከተላቸው/ሏት” የሚለውን ቃል እንደ አንድ መሰየሚያ አድርገን እንጠቀማለን፡፡ ለምሳሌ “50 ሚከተላቸው/ሏት” ስንል ተጠቃሚው ሌሎች 50 ተጠቃሚዎችን እየተከተለ ነው ማለት ነው፡፡ አጠቃቀሙ ከዝርዝር 14.1 ጀምሮ በተርታ በተዘረዘሩት ስእላዊ መግለጫወች ላይ ሲታይ፣ አሁን ደግሞ በቅርበት ጎልቶ፣ በዝርዝር 14.10 ላይ ይታያል፡፡

stats_partial_mockupaz
ምስል 14.10: አንድ የአሃዛዊ-መረጃ ከፊልን የሚያሳይ ስእላዊ መግለጫ።

ዝርዝር 14.10 ላይ ያሉት የአሃዛዊ-መረጃዎች፣ የአሁኑ ተጠቃሚ የሚከተላቸው እና የተከታዮቹን ተጠቃሚዎች የቁጥር ብዛትን የያዙ ሲሆን፤ እያንዳንዳቸውም ወደ ሚመለከታቸው ማሳያ ገጽ የተመደበ አንድ አገናኝ መሆን ይኖርባቸዋል፡፡ በምዕራፍ 5 ላይ እነዚህን አገናኞች በ  '#' ምልክት ቆርጠናቸው ነበር፣ በዛን ጊዜ እንደዛ ያደረግነው ስለ ማዘዋወርያዎች ጠለቅ ያለ ዕውቀት እና ልምድ ባልነበረን ወቅት ነበር፡፡ በዚህ ጊዜ፣ ለዚህ ስራ የሚያስፈልጉትን ትክክለኛ ገጾች የመስራቱን ሂደት ወደ ክፍል 14.2.3 ያስተላለፍን ቢሆንም፣ በዝርዝር 14.15 ላይ እንደሚታየው፣ ማዘዋወርዎቹን ግን አሁን እንሰራለን፡፡ ይህ ኮድ አንድ የ‘ሃብቶች (resources) ጥምር ውስጥ የ‘:አባል (:member) ዘዴን ይጠቀማል፣ ይህን ኮድ ከዚህ በፊት አላየነውም፣ እስኪ ግን ምን እንደሚሰራ መገመት ትችሉ ከሆነ ሞክሩ፡፡

ዝርዝር 14.15: በተጠቃሚዎች መቆጣጠርያ ውስጥ የ‘ሚከተላቸው (miketelachew) እና የ‘ተከታዮች (teketayoch) ተግባሮችን ማከል። config/routes.rb
Rails.application.routes.draw do
  root   'quami_getss#menesha'
  get    '/erdata',     to: 'quami_getss#erdata'
  get    '/silegna',    to: 'quami_getss#silegna'
  get    '/agignun',    to: 'quami_getss#agignun'
  get    '/temezgeb',   to: 'teteqamis#new'
  get    '/gba',        to: 'sessions#new'
  post   '/gba',        to: 'sessions#create'
  delete '/wta',        to: 'sessions#destroy'
  resources :teteqamis do
    member do
      get :miketelachew, :teketayoch
    end
  end
  resources :meleya_magberyas, only: [:edit]
  resources :meda_masjemers,   only: [:new, :create, :edit, :update]
  resources :achrtshufs,       only: [:create, :destroy]
end

ዓ.አ.ሃ.አው ለሚከተላቸው እና ለተከታዮች /ተጠቃሚዎች/1/ሚከተላቸው‘ን (/teteqamis/1/miketelachew) እና /ተጠቃሚዎች/1/ተከታዮች‘ን (/teteqamis/1/teketayoch) ሊመስል እንደሚችል ልትገምቱት ችላላችሁ፣ በዝርዝር 14.15 ላይ ያለው ኮድ በትክክል የሚያዘጋጀውም ይህንኑ ነው፡፡ ሁለቱም ገጾች ውሂብን ስለሚያሳዩ ትክክለኛው የሃ.ጽ.ማ.ስ ግስ አንድ የ‘ዓግኝ (GET) መጠይቅ ነው፣ ስለሆነም ዓ.አ.ሃ.አወቹ ተገቢውን ምላሽ እንዲሰጡ ለማዘጋጀት የ‘አግኝ (get) ዘዴን ተጠቅመናል። ይህ በእንዲህ እንዳለ፣ የ‘አባል (member) ዘዴ የተጠቃሚውን መታወቂያ የያዙ ዓ.አ.ሃ.አች ላይ ምላሽ እንዲሰጡ ማዘዋወርያዎቹን ያዘጋጃል። ሌላኛው ያለ መታወቂያ የሚሰራው አማራጪ ስብስብ (collection) ነው፤ ስለሆነም ይሄ:-

resources :teteqamis do
  collection do
    get :walya
  end
end

የሚመልሰው የ‘/ተጠቃሚዎች/ዋልያ (/teteqamis/walya) ዓ.አ.ሃ.አን ይሆናል (በዚህ ምሳሌ መሰረት፣ አፕልኬሽኑ ውስጥ ያሉትን ሁሉንም ዋልያወች ያሳየናል ማለት ነው፡፡)10

ዝርዝር 14.15 አማካኝነት የመነጩት ማዘዋወሪያወች፣ በሰንጠረዥ 14.2 ላይ ይታያሉ፡፡ የሚከተላቸው እና የተከታዮች ተጠቃሚ ገጾችን ለማቅረብ በቅርቡ ስራ ላይ የምናውላቸውን፣ ስዩም ማዘዋወሪያወችን እንደያዙ በደንብ ተገንዝባችሁ ይሆናል።

የሃ.ጽ.ማ.ስ መጠይቅ ዓ.አ.ሃ.አ ጥቅም ስዩም ማዘዋወሪያ
GET /teteqamis/1/miketelachew miketelachew miketelachew_teteqami_path(1)
GET /teteqamis/1/teketayoch teketayoch teketayoch_teteqami_path(1)
ሰንጠረዥ 14.2: ዝርዝር 14.15 ውስጥ ባሉት ብጁ የሃብት ህጎች የተሰጡ ሙሉየው.ሁ.ማ ማዘዋወሪያወች።

የሚያስፈልጉትን ማዘዋወሪያወች በይነናል፣ አሁን የአሃዛዊ-መረጃዎች ከፊልን ለመበየን የሚያስችል አንድ አቋም ላይ እንገኛለን፣ ይህም በዝርዝር 14.16 ላይ እንደሚታየው፣ ሁለት አገናኞችን በአንድ የሃ.ጽ.መ.ቋ ክፍሊት ውስጥ ማድረግን ያሳትፋል፡፡

ዝርዝር 14.16: አንድ የተከተዮች አሃዛዊ-መረጃዎችን የሚያሳይ ከፊል። app/views/gru/_ahazawimerejawech.html.erb
<% @teteqami ||= ahun_teteqami %>
<div class="አሃዛዊመረጃዎች">
  <a href="<%= miketelachew_teteqami_path(@teteqami) %>">
    <strong id="ሚከተላቸው" class="አሃዛዊመረጃ">
      <%= @teteqami.miketelachew.count %>
    </strong>
    ሚከተላቸው/ሏት
  </a>
  <a href="<%= teketayoch_teteqami_path(@teteqami) %>">
    <strong id="ተከታዮች" class="አሃዛዊመረጃ">
      <%= @teteqami.teketayoch.count %>
    </strong>
    ተከታዮች
  </a>
</div>

በተጠቃሚ ማሳያ እና በመነሻ ገጹ ላይ፣ አሃዛዊ-መረጃዎችን የምናካትት ስለሆነ፣ በዝርዝር 14.16 ላይ ያለው የመጀመሪያው መስመር ይህንን በመጠቀም:-

<% @teteqami ||= ahun_teteqami %>

ትክክለኛውን ገጽ ይመርጣል፡፡ በሳጥን 8.1 እንደተብራራው፣ @ተጠቃሚ (@teteqami) (በመገለጫ ገጹ ላይ እንዳለው) ምንም (nil) በማይሆንበት ጊዜ ምንም አያደርግም፤ ግን (በመነሻ ገጹ ላይ እንዳለው) በሚሆንበት ጊዜ @ተጠቃሚ‘ን (@teteqami) ለአሁኑ ተጠቃሚ ያዘጋጀዋል፡፡ እንዲሁም የሚከተላቸው/የተከታዮች ቆጠራዎች በማሕበሩ በኩል:-

@teteqami.miketelachew.count

እና

@teteqami.teketayoch.count

‘ን በመጠቀም እንደሚሰሉ አስተውሉ፡፡ እነዚህን በዝርዝር 13.24 ውስጥ የአጪርጽሑፎች ብዛትን እንዲቆጥርልን እንደዚህ ብለን:-

@teteqami.achrtshufs.count

ከጻፍነው ኮድ ጋር አነጻጽሩ፡፡ በአጪርጽሑፎቹ ሁኔታ ላይ፣ ሬይልስ ለቅልጥፍና ቆጠራውን በቀጥታ በውሂበጎታው ውስጥ ያከናውናል፡፡

አንድ መጨረሻ ላይ ልብ ሊባል የሚገባው ዝርዝር፣ በአንዳንድ አባል ላይ የቅ.ቋ መታወቂያዎች መኖራቸው ነው፣ እንደዚህኛው ማለት ነው:-

<strong id="ሚከተላቸው" class="አሃዛዊመረጃ">
...
</strong>

ይህ በክፍል 14.2.5 ውስጥ ለኤጃክስ (Ajax) መተግበሪያ ጥቅም ላይ የሚውል ሲሆን፣ ይህም ልዩ መታወቂያቸውን በመጠቀም በገጹ ላይ የሚገኙትን አባላት ይደርሳል።

ከፊሉን ከሰነቁ በኋላ፣ በዝርዝር 14.17 ላይ እንደተመለከተው፣ አሃዛዊ-መረጃዎቹን በመነሻ ገጹ ላይ ማካተቱ ቀላል ነው፡፡

ዝርዝር 14.17: የተከታዮች አሃዛዊ-መረጃዎችን በመነሻ ገጹ ላይ ማከል። app/views/quami_getss/menesha.html.erb
<% if gebtual? %>
  <div class="row">
    <aside class="col-md-4">
      <section class="የተጠቃሚ_መረጃ">
        <%= render 'gru/teteqami_mereja' %>
      </section>
      <section class="አሃዛዊመረጃዎች">
        <%= render 'gru/ahazawimerejawech' %>
      </section>
      <section class="የአጪርጽሑፍ_ቅጽ">
        <%= render 'gru/achrtshuf_qts' %>
      </section>
    </aside>
    <div class="col-md-8">
      <h3>አጪርጽሑፍ ቀላቢ</h3>
      <%= render 'gru/qelabi' %>
    </div>
  </div>
<% else %>
  .
  .
  .
<% end %>

ዝርዝር 14.18 ላይ እንደሚታየው፣ አሃዛዊ-መረጃዎችን ቅጥ ለማስያዝ፣ የተወሰኑ ዓ.ቆ.ሉ.ቅን እናክላለን (ይህ ዝርዝር፣ በዚህ ምዕራፍ ውስጥ የሚያስፈልጉትን ማለት ሁሉንም የቅጠሉህ ኮዶችን የያዘ ነው)። የተገኘው የመነሻ ገጽ ውጤት በምስል 14.11 ላይ ይታያል።

ዝርዝር 14.18: ለመነሻ ገጹ የጎን-አሞሌ አንዳንድ ዓ.ቆ.ሉ.ቅን ማከል፡፡ app/assets/stylesheets/bju.scss
.
.
.
/* ጎን-አሞሌ */
.
.
.
.አምሳያ {
  float: left;
  margin-right: 10px;
}

.አምሳያ_እርምት {
  margin-top: 15px;
}

.አሃዛዊመረጃዎች {
  overflow: auto;
  margin-top: 0;
  padding: 0;
  a {
    float: left;
    padding: 0 10px;
    border-left: 1px solid $gray-lighter;
    color: gray;
    &:first-child {
      padding-left: 0;
      border: 0;
    }
    &:hover {
      text-decoration: none;
      color: blue;
    }
  }
  strong {
    display: block;
  }
}

.የተጠቃሚ_አምሳያወች {
  overflow: auto;
  margin-top: 10px;
  .አምሳያ {
    margin: 1px 1px;
  }
  a {
    padding: 0;
  }
}

.ተጠቃሚዎች.ተከተል {
  padding: 0;
}

/* ቅጾች */
.
.
.
images/figures/home_page_follow_stats
ምስል 14.11: የመነሻ ገጹ ከተከተል አሃዛዊ-መረጃዎች ጋር።

በመገለጫ ገጹ ላይ፣ አሃዛዊ-መረጃዎችን ማቅረቡን በአጪር ጊዜ ውስጥ እንመለስበታለን፣ ነገር ግን በቅድሚያ በዝርዝር 14.19 ላይ እንደሚታየው፣ ለተከተል እና ለአትከተል አዝራር የሚሆን አንድ ከፊልን እንሰራለን፡፡

ዝርዝር 14.19: ለተከተል/አትከተል ቅጽ የሚሆን አንድ ከፊል። app/views/teteqamis/_teketel_qts.html.erb
<% unless ahun_teteqami?(@teteqami) %>
  <div id="የተከተል_ቅጽ">
  <% if ahun_teteqami.miketelachew?(@teteqami) %>
    <%= render 'atketel' %>
  <% else %>
    <%= render 'teketel' %>
  <% end %>
  </div>
<% end %>

ይህ ትክክለኛውን ስራ ወደ ተከተል (teketel) እና አትከተል (atketel) ከፊሎች ከማመላከት በስተቀር ሌላ ምንም ነገር አያደርግም፣ ይህም በዝርዝር 14.20 ውስጥ እንደሚታየው፣ የአጪርጽሑፎች ሃብት ምሳሌን (ዝርዝር 13.30) የሚከተል፣ አዲስ የትስስሮች ሃብት ማዘዋወርያዎችን ይፈልጋል።

ዝርዝር 14.20: ለተጠቃሚ ትስስሮች የሚያገለግሉ ማዘዋወርያዎችን ማከል፡፡ config/routes.rb
Rails.application.routes.draw do
  root   'quami_getss#menesha'
  get    '/erdata',     to: 'quami_getss#erdata'
  get    '/silegna',    to: 'quami_getss#silegna'
  get    '/agignun',    to: 'quami_getss#agignun'
  get    '/temezgeb',   to: 'teteqamis#new'
  get    '/gba',        to: 'sessions#new'
  post   '/gba',        to: 'sessions#create'
  delete '/wta',        to: 'sessions#destroy'
  resources :teteqamis do
    member do
      get :miketelachew, :teketayoch
    end
  end
  resources :meleya_magberyas, only: [:edit]
  resources :meda_masjemers,   only: [:new, :create, :edit, :update]
  resources :achrtshufs,       only: [:create, :destroy]
  resources :tssrs,            only: [:create, :destroy]
end

የተከተል/አትከተል ከፊሎቹ በዝርዝር 14.21 እና በዝርዝር 14.22 ላይ ይታያሉ፡፡

ዝርዝር 14.21: አንድ ተጠቃሚን መከተያ ቅጽ። app/views/teteqamis/_teketel.html.erb
<%= form_with(model: ahun_teteqami.nq_tssrs.build, local: true) do || %>
  <div><%= hidden_field_tag :ktl_id, @teteqami.id %></div>
  <%= .submit "ተከተል", class: "btn btn-primary" %>
<% end %>
ዝርዝር 14.22: አንድ ተጠቃሚን ያለመከተያ ቅጽ። app/views/teteqamis/_atketel.html.erb
<%= form_with(model: ahun_teteqami.nq_tssrs.find_by(ktl_id: @teteqami.id),
             html: { method: :delete }, local: true) do || %>
  <%= .submit "አትከተል", class: "btn" %>
<% end %>

እነዚህ ሁለት ቅጾች፣ የአንድ ትስስር ቅርጸት ቁስን ለማንቀሳቀስ፣ ሁለቱም ቅጽ_ጋር‘ን (form_with) ይጠቀማሉ፤ በሁለቱ መካከል ያለው ዋና ልዩነት፣ ዝርዝር 14.21 አንድ አዲስ ትስስርን መገንባቱ ሲሆን፣ ዝርዝር 14.22 ደግሞ አሁን ያለውን ትስስር መፈሉጉ ነው፡፡ በተፈጥሮ የመጀመሪያው፣ አንድ አዲስ ግንኙነትን ለመፍጠር (create) ለትስስሮች መቆጣጠርያው፣ አንድ የ‘ዓስቀምጥ (POST) መጠይቅን የሚልክ ሲሆን፤ ሁለተኛው ግን ትስስሩን ለመሠረዝ አንድ የ‘ሠርዝ (DELETE) መጠይቅን ለ‘አጥፋ (destroy) ይልካል፡፡ (እነዚህን ተግባሮች በክፍል 14.2.4 ላይ እንጽፋቸዋለን።) በመጨረሻም፣ የመከተል ቅጽ ካለ አንድ አዝራር በስተቀር ሌላ ምንም አይነት ይዘት እንደለለው አስተውላችሁ ይሆናል፣ ይሁን እንጅ አሁንም የ‘ክትል_መታወቂያ‘ውን (ktl_id) ወደ መቆጣጠሪያው መስደድ ይፈልጋል፡፡ ይህንን ለማከናወን በዝርዝር 14.21 ውስጥ አንድ የ‘ተደበቀ_መስክ_መለያ (hidden_field_tag) ዘዴን ተጠቅመናል፤ ይህ ዘዴም የሚከተለውን የሃ.ጽ.መ.ቋ ቅጽን ይሰራል:-

<input id="ktl_id" name="ktl_id" type="hidden" value="3" />

ክፍል 12.3 ውስጥ እንዳየነው (ዝርዝር 12.14)፣ የተደበቀው የ‘ግብዓት (input) መለያ በቅጹ ውስጥ የገባውን ዋጋ በአሳሹ ላይ ሳያሳይ፣ በገጹ ውስጥ ተገቢውን መረጃ ይይዛል፡፡

ዝርዝር 14.23 ውስጥ እንደሚታየው፣ አሁን ከፊሎችን በማቅረብ፣ የተከተል ቅጹን እና የተከታይ አሃዛዊ-መረጃወቹን፣ በተጠቃሚው መገለጫ ገጽ ላይ በቀላሉ ማካተት እንችላለን። የ “ተከተል” እና የ “አትከተል” አዝራሮች ያሏቸው የመገለጫ ገጾች በምስል 14.12 እና በምስል 14.13 ላይ በቅደም ተከተል ይታያሉ፡፡

ዝርዝር 14.23: በተጠቃሚ መገለጫ ገጽ ላይ የተከታይ ቅጽን እና የተከታዮች አሃዛዊ መረጃዎችን ማከል። app/views/teteqamis/show.html.erb
<% provide(:title, @teteqami.sim) %>
<div class="row">
  <aside class="col-md-4">
    <section class="የተጠቃሚ_መረጃ">
      <h1>
        <%= amsaya_le @teteqami %>
        <%= @teteqami.sim %>
      </h1>
    </section>
    <section class="አሃዛዊመረጃዎች">
      <%= render 'gru/ahazawimerejawech' %>
    </section>
  </aside>
  <div class="col-md-8">
    <%= render 'teketel_qts' if gebtual? %>
    <% if @teteqami.achrtshufs.any? %>
      <h3>(<%= @teteqami.achrtshufs.count %>) አጪርጽሑፎች</h3>
      <ol class="አጪርጽሑፎች">
        <%= render @achrtshufs %>
      </ol>
      <%= will_paginate @achrtshufs, :previous_label => "ቀዳሚ",
                                          :next_label => "ቀጣይ" %>

    <% end %>
  </div>
</div>
images/figures/profile_follow_button
ምስል 14.12: አንድ የተጠቃሚ መገለጫ ከአንድ “ተከተል” አዝራር ጋር (/teteqamis/2)።
images/figures/profile_unfollow_button
ምስል 14.13: አንድ የተጠቃሚ መገለጫ ከአንድ “አትከተል” አዝራር ጋር (/teteqamis/5)።

በቅርብ ጊዜ ውስጥ እነዚህ አዝራሮች መስራት እንዲጀምሩ እናደርጋቸዋለን፣ በርግጥ፣ በሁለት ዓይነት መንገድ እንደሚሰሩም እናደርጋቸዋለን፣ አንደኛው በመደበኛው መንገድ ሲሆን (ክፍል 14.2.4)፣ ሁለተኛው ደግሞ ኤጃክስን በመጠቀም ይሆናል (ክፍል 14.2.5)፣ በመጀመሪያ ግን የሃ.ጽ.መ.ቋ በይነገጹን በሚከተሉት እና በተከታዮች ገጽ ላይ ሰርተን መጨረስ ይኖርብናል።

መልመጃዎች

የሬይልስ ስልጠናን ለገዙ ሰወች በሙሉ የሁሉም የመልመጃ መልሶች እዚህ ላይ ይገኛሉ።

የሌሎች ሰዎች መልሶችን ለማየት እና የራሳችሁን ደግሞ ለመመዝገብ፣ በሬይልስ ስልጠና ወይም ሁሉንም በበቂ ተማር መድረሻ ጥቅል ላይ ተመዝገቡ፡፡

  1. የሁለተኛው ተጠቃሚ (/teteqamis/2) አንድ የተከተል ቅጽ እና አምስተኛው (ተጠቃሚ /teteqamis/5) ደግሞ አንድ የአተከተል ቅጽ እንዳለው አረጋግጡ፡፡ የመጀመሪያው ተጠቃሚ (/teteqamis/1) አንድ የተከተል ቅጽ አለውን?
  2. በመነሻ እና በመገለጫ ገጹ ላይ አሃዛዊ-መረጃዎቹ በትክክል መታየታቸውን በአሳሹ ውስጥ አረጋግጡ።
  3. በመነሻ ገጹ ላይ ለሚገኙት፣ የአሃዛዊ-መረጃዎች አንዳንድ ፈተናዎችን ጻፉ። ጠቃሚ ምክር ፈተናወቹን በዝርዝር 13.28 ውስጥ አክሉ፡፡ ለምንድን ነው በተጠቃሚው መገለጫ ገጽ ላይ የሚገኙትን አሃዛዊ-መረጃዎችን መፈተኑ ያላስፈለገው?

14.2.3 የሚከተሉ እና የተከታዮች ገጾች

የሚከተሉ እና ተከታዮችን ለማሳየት የምንጠቀምበት ገጽ፣ ከተጠቃሚ መገለጫ፣ ከተጠቃሚዎች ማውጫ ገጽ (ክፍል 10.3.1)፣ ከአንድ የተጠቃሚ መረጃ የጎን-አሞሌ (የሚከተሉት የአሃዛዊ-መረጃወችን ጨምሮ) እና ከተጠቃሚዎች ዝርዝር ጋር የተዳቀለ አንድ ገጽን ይመስላል። በተጨማሪም፣ በጎን-አሞሌው ውስጥ አንድ መጠኑ ያነሰ፣ አነስተኛ የተጠቃሚ መገለጫ ምስል አገናኝን እናካትታለን፡፡ እነዚህን መስፈርቶች የሚያሟሉ ስእላዊ መግለጫወች፣ በምስል 14.14 (የሚከተሉ) እና በምስል 14.15 ላይ (የተከታዮች) ይታያሉ፡፡

images/figures/following_mockup_bootstrap
ምስል 14.14: አንድ ተጠቃሚ የሚከተላቸው ገጽ ስእላዊ መግለጫ።
images/figures/followers_mockup_bootstrap
ምስል 14.15: አንድ የተጠቃሚ ተከታዮች ገጽ፣ ስእላዊ መግለጫ።

የመጀመሪያ ሂደታችን የሚከተላቸው/ሏት እና የተከታዮች አገናኞችን እንዲሰሩ ማድረግ ይሆናል፡፡ የትዊተርን የአሰራር ስልት በመከተል፣ ሁለቱንም ገጾች የተጠቃሚ መግባትን እንዲፈልጉ እናደርጋቸዋለን። ልክ እንደ አብዛኛዎቹ ቀደምት የመዳረሻ ቁጥጥር ምሳሌዎች ላይ እንዳደረግነው ሁሉ፣ አሁንም በዝርዝር 14.24 ላይ እንደሚታየው፣ ለነሱ አንዳንድ ፈተናዎችን በመጻፍ እንጀምራለን፡፡ ዝርዝር 14.24ሰንጠረዥ 14.2 ላይ የሚገኙትን ስዩም ማዘዋወሪያወችን እንደሚጠቀም አስተውሉ፡፡

ዝርዝር 14.24: ለሚከተሉ እና ለተከታዮች ገጾች የሚሆኑ የፈቃድ ፈተናዎች። ቀይ test/controllers/teteqamis_controller_test.rb
require 'test_helper'

class TeteqamisControllerTest < ActionDispatch::IntegrationTest

  def setup
    @teteqami = teteqamis(:michael)
    @lela_teteqami  = teteqamis(:ermias)
  end
  .
  .
  .
  test "ባልተገባ ጊዜ ሚከተላቸው ማዟዟር አለበት" do
    get miketelachew_teteqami_path(@teteqami)
    assert_redirected_to gba_url
  end

  test "ባልተገባ ጊዜ ተከታዮች ማዟዟር አለበት" do
    get teketayoch_teteqami_path(@teteqami)
    assert_redirected_to gba_url
  end
end

የአተገባበሩ ብቸኛው አስቸጋሪ ክፍል፣ በተጠቃሚዎች መቆጣጠሪያው ውስጥ ሁለት አዲስ ተግባሮችን ማከል እንዳለብን መገንዘቡ ነው። በዝርዝር 14.15 ላይ በተበየኑት ማዘዋወሪያወች ላይ በመመርኮዝ፣ ሚከተላቸው (miketelachew) እና ተከታዮች (teketayoch) ብለን ልንጠራቸው ይገባል፡፡ እያንዳንዱ ተግባር፣ አንድ ርዕስ ማዘጋጀት፣ ተጠቃሚውን መፈለግ፣ እና ወይ በ‘@ተጠቃሚ.ሚከተላቸው (@teteqami.miketelachew) አለበለዚያ ደግሞ በ‘@ተጠቃሚ.ተከታዮች (@teteqami.teketayoch) ፈልጎ (ማለት ከገጸቁጥር ጋር) በማውጣት ገጹን ማቅረብ አለበት። ውጤቱም በዝርዝር 14.25 ይታያል፡፡

ዝርዝር 14.25: የ‘ሚከተላቸው (miketelachew) እና የ‘ተከታዮች (teketayoch) ተግባራትን ማከል። ቀይ app/controllers/teteqamis_controller.rb
class TeteqamisController < ApplicationController
  before_action :gb_teteqami, only: [:index, :edit, :update, :destroy,
                                     :miketelachew, :teketayoch]
  .
  .
  .
  def miketelachew
    @title = "ሚከተላቸው/ሏት"
    @teteqami = Teteqami.find(params[:id])
    @teteqamis = @teteqami.miketelachew.paginate(page: params[:page])
    render 'teketay_asay'
  end

  def teketayoch
    @title = "ተከታዮች"
    @teteqami = Teteqami.find(params[:id])
    @teteqamis = @teteqami.teketayoch.paginate(page: params[:page])
    render 'teketay_asay'
  end

  private
  .
  .
  .
end

በዚህ ስልጠና ሁሉ እንደተመለከትነው፣ የተለመደው የሬይልስ አሰራር፣ አንድ ከተግባሩ ጋር የሚዛመድ ዝግጁገጽታን በግልጽ (implicitly) ማቅረብ ነው፤ ለምሳሌ፣ የ‘አሳይ (show) ተግባር ልክ መጨረሻ ላይ አሳይ.ሃጽመቋ.ክሩ‘ን (show.html.erb) እንዲቀርብ ያደርጋል፡፡11 በተቃራኒው፣ በዝርዝር 14.25 ውስጥ ያሉ ሁለቱም ተግባሮች ተከታይ_አሳይ (teketay_asay) የተባለ ትይታን ለማቅረብ፣ ለ‘ዓቅርብ (render) ዘዴ፣ አንድ ያልተገለጸ (Explicit) ጥሪን ያደርጋሉ፣ ይህንን ትይታም ግዴታ መፍጠር ይኖርብናል። የጋራ የሆነ አንድ ትይታ የሚጠቀሙበት ምክንያት ደግሞ፣ በሁለቱም ሁኔታ ላይ ክትሩቢው በጣም ተመሳሳይ ስለሆነ ነው፣ እናም ዝርዝር 14.26 ሁለቱንም ይሸፍንልናል፡፡

ዝርዝር 14.26: የሚከተላቸው እና ተከታዮችን ለማቅረብ የሚጠቅም የ‘ተከታይ_አሳይ (teketay_asay) ትይታ። አረንጓዴ app/views/teteqamis/teketay_asay.html.erb
<% provide(:title, @title) %>
<div class="row">
  <aside class="col-md-4">
    <section class="የተጠቃሚ_መረጃ">
      <%= amsaya_le @teteqami %>
      <h1><%= @teteqami.sim %></h1>
      <span><%= link_to "መገለጫዎን ይመልከቱ", @teteqami %></span>
      <span><b>አጪርጽሑፎች:</b> <%= @teteqami.achrtshufs.count %></span>
    </section>
    <section class="አሃዛዊመረጃዎች">
      <%= render 'gru/ahazawimerejawech' %>
      <% if @teteqamis.any? %>
        <div class="የተጠቃሚ_አምሳያወች">
          <% @teteqamis.each do |teteqami| %>
            <%= link_to amsaya_le(teteqami, meten: 30), teteqami %>
          <% end %>
        </div>
      <% end %>
    </section>
  </aside>
  <div class="col-md-8">
    <h3><%= @title %></h3>
    <% if @teteqamis.any? %>
      <ul class="ተጠቃሚዎች ተከተል">
        <%= render @teteqamis %>
      </ul>
      <%= will_paginate :previous_label => "ቀዳሚ", :next_label => "ቀጣይ" %>
    <% end %>
  </div>
</div>

ዝርዝር 14.25 ውስጥ ያሉት ተግባሮች በዝርዝር 14.26 ውስጥ ባሉት ሁለት ሁኔታዎች ላይ በመርኮዝ ሁለት ትይታወችን ያቀርባሉ፡፡ ምስል 14.16 የ “ሚከተላቸው/ሏት” ትይታን ሲያቀርብ፣ ምስል 14.17 ደግሞ የ “ተከታዮች” ትይታን ያቀርባል፡፡ ከላይ ያለው ኮድ፣ ማናቸውም ቦታ ላይ፣ የአሁን ተጠቃሚን እንዳልተጠቀመ አስተውሉ፤ ስለሆነም በምስል 14.18 ላይ እንደሚታየው፣ እነዚሁ አገናኞች ለሌሎች ተጠቃሚዎችም ይሰራሉ፡፡

images/figures/user_following
ምስል 14.16: ለአንድ ተጠቃሚ የሚከተላቸውን/ሏትን ማሳየት።
images/figures/user_followers
ምስል 14.17: ለአንድ ተጠቃሚ ተከታዮቹን ማሳየት።
images/figures/diferent_user_followers
ምስል 14.18: የሌላ ተጠቃሚ ተከታዮችን ማሳየት።

በዚህ ጊዜ፣ በዝርዝር 14.25 ውስጥ ባለው በቅድመአጣሪው ምክንያት በዝርዝር 14.24 ውስጥ ያሉ ፈተናወች አረንጓዴ መሆን አለባቸው:-

ዝርዝር 14.27: አረንጓዴ
$ rails test

የ‘ተከታይ_አሳይ (teketay_asay) አቅርቦትን ለመፈተን፣ ማለት የሚሰሩ የሚከተላቸው እና የተከታዮች ገጾች መኖራቸውን ለማረጋገጥ፣ አንዳንድ አጪር የውህደት ፈተናወችን እንጽፋለን። ፈተናወቹም እውነታን ለማጣራት የተነደፉ እንጂ፣ የተሟላ ፈተናን እንዲያደርጉ የተነደፉ አይደሉም፤ በእርግጥ በክፍል 5.3.4 ላይ እንደተብራራው፣ እንደ ሃ.ጽ.መ.ቋ አወቃቀር ያሉ ነገሮች ላይ አጠቃላይ የሆነ ፈተናን ማድረጉ፣ በቀላሉ ሊበላሽ ወደሚችል ሁኔታ ሊያመራ እና የልታሰበ ውጤትን ሊያስከትል ይችላል፡፡ በሚከተላቸው እና በተከታዮች ገጾች ላይ እቅዳችን፣ ቁጥራቸው በትክክል መታየቱን እና አገናኞቹ ከትክክለኛ ዓ.አ.ሃ.አ‘ዎች ጋር በገጹ ላይ እንደሚታዩ ማረጋገጥ ነው፡፡

ስራችንን ለመጀመር እንደተለመደው፣ አንድ የውህደት ፈተናን እናመነጫለን፡-

$ rails generate integration_test miketelachew
      invoke  test_unit
      create    test/integration/miketelachew_test.rb

በመቀጠልም፣ የተወሰኑ የፈተና ውሂቦችን ማሰባሰብ ይኖርብናል፣ ይህንንም የሚከተሉት እና የተከታዮች ትስስሮችን ለመፍጠር አንዳንድ የትስስሮች እቃዎችን በማከል ማከናወን እንችላለን፡፡ ከአንድ የተሰጠ ተጠቃሚ ጋር አንድ አጪርጽሑፍን ለማገናኘት እንደዚህ:-

weba:
  yizet: "ወባ ፊት የነሳው ሰውየ ቡዳ እንዳይበላኝ አለ።"
  created_at: <%= 10.minutes.ago %>
  teteqami: michael

ያለ ኮድን መጠቀም እንደምንችል በክፍል 13.2.3 ላይ እንደተማርን አስታውሱ፡፡ በተለይ ደግሞ ይህን ከመጻፍ:-

teteqami: michael

ይልቅ ይህንን:-

teteqami_id: 1

መጻፍ እንደምንችልም ተገንዝባችሁ ይሆናል፡፡ ይህንን ሃሳብ በትስስሮች እቃዎች ላይ መተግበሩ፣ በዝርዝር 14.28 ውስጥ የሚገኘውን ማሕበር ይሰጣል፡፡

ዝርዝር 14.28: በሚከተሉት እና በተከታዮች ፈተናወች ጥቅም ላይ የሚውሉ የትስስሮች እቃዎች። test/fixtures/tssrs.yml
and:
  teketay: michael
  ktl: gerie

hulet:
  teketay: michael
  ktl: abeba

sost:
  teketay: gerie
  ktl: michael

arat:
  teketay: ermias
  ktl: michael

ዝርዝር 14.28 ውስጥ ያሉት የመጀመሪያዎቹ እቃዎች፣ ማይክልን፣ ገሬን እና አበባን እንዲከተል ያዘጋጃሉ፣ ከዚያ ማይክልን፣ ገሬ እና ኤርምያስ እንዲከተሉት ያዘጋጃሉ፡፡ ትክክለኛውን ቆጠራ ለማረጋገጥ፣ በተጠቃሚ የመገለጫ ገጽ ላይ የአጪርጽሑፎች ብዛት መታየቱን ለመፈተሽ፣ በዝርዝር 13.28 ውስጥ የተጠቀምንበትን የ‘አቻነት_አረጋግጥ (assert_match) ዘዴን መጠቀም እንችላለን፡፡ ለትክክለኞቹ አገናኞች፣ ማረጋገጫዎችን ማከሉ፣ በዝርዝር 14.29 ውስጥ የተመለከቱትን ፈተናወች ያስገኛል፡፡

ዝርዝር 14.29: የሚከተላቸው እና የተከታዮች ገጾችን መፈተን። አረንጓዴ test/integration/miketelachew_test.rb
require "test_helper"

class MiketelachewTest < ActionDispatch::IntegrationTest

  def setup
    @teteqami = teteqamis(:michael)
    gba_ende(@teteqami)
  end

  test "የሚከተሉ ገጽ" do
    get miketelachew_teteqami_path(@teteqami)
    assert_not @teteqami.miketelachew.empty?
    assert_match @teteqami.miketelachew.count.to_s, response.body
    @teteqami.miketelachew.each do |teteqami|
      assert_select "a[href=?]", teteqami_path(teteqami)
    end
  end

  test "የተከታዮች ገጽ" do
    get teketayoch_teteqami_path(@teteqami)
    assert_not @teteqami.teketayoch.empty?
    assert_match @teteqami.teketayoch.count.to_s, response.body
    @teteqami.teketayoch.each do |teteqami|
      assert_select "a[href=?]", teteqami_path(teteqami)
    end
  end
end

ዝርዝር 14.29 ውስጥ ይህንን ማረጋገጫ ማካተታችንን አስታውሱ:-

assert_not @teteqami.miketelachew.empty?

ይህም ይሄ:-

@teteqami.miketelachew.each do |teteqami|
  assert_select "a[href=?]", teteqami_path(teteqami)
end

በትክክል እውነት ያልሆነ መሆኑን ለማረጋገጥ የተካተተ ነው (ለ‘ተከታዮች‘ም (teketayoch) እንደዛው ነው)፡፡ በሌላ አማርኛ፣ @ተጠቃሚ.ሚከተላቸው.የለለነውን? (@teteqami.miketelachew.empty?) እውነት ቢሆን፣ አንድም የ‘መለያ_አረጋግጥ (assert_select) ማረጋገጫ በምልልሱ ውስጥ አይከናወንም ማለት ነው፤ ይህም ፈተናወቹ እንዲያልፉ እና በዚህም እኛን ከእውነት የራቀ የመተማመን ስሜት እንዲኖረን ያደርጋል፡፡

የፈተና ስብስቡ አሁን አረንጓዴመሆን አለበት:-

ዝርዝር 14.30: አረንጓዴ
$ rails test

መልመጃዎች

የሬይልስ ስልጠናን ለገዙ ሰወች በሙሉ የሁሉም የመልመጃ መልሶች እዚህ ላይ ይገኛሉ።

የሌሎች ሰዎች መልሶችን ለማየት እና የራሳችሁን ደግሞ ለመመዝገብ፣ በሬይልስ ስልጠና ወይም ሁሉንም በበቂ ተማር መድረሻ ጥቅል ላይ ተመዝገቡ፡፡

  1. በአንድ አሳሽ ውስጥ /ተጠቃሚዎች/1/ተከታዮች (/teteqamis/1/teketayoch) እና /ተጠቃሚዎች/1/ሚከተላቸው (/teteqamis/1/miketelachew) እንደሚሰሩ አረጋግጡ፡፡ በጎን-አሞሌው ውስጥ ያሉት የምስል አገናኞች እንዲሁ ይሰራሉን?
  2. ዝርዝር 14.29 ውስጥ የሚገኘው፣ የ‘መለያ_አረጋግጥ (assert_select) ማረጋገጫ የሚፈትነውን የአፕልኬሽኑ ኮድ ላይ አንድ አስተያየትን በማደረግ ፈተናውን ወደ ቀይ በመቀየር፣ ፈተናው ትክክለኛውን ነገር እየፈተነ መሆኑን አረጋግጡ፡፡

14.2.4 በመደበኛው መንገድ የሚሰራ የተከተል አዝራር

አሁን ትይታዎቻችን ቅደም ተከተላቸውን የጠበቁ ስለሆኑ፣ የሚከተላቸው እና የተከታዮች አዝራሮች እንዲሰሩ የማድረጉ ጊዜ አሁን ነው፡፡ መከተል እና አለመከተል፣ ትስስሮችን መፍጠርን እና ማጥፋትን የሚያሳትፍ ስለሆነ፣ ይህንኑ ተግባር ለመፈጸም እንደተለመደው አድርገን የምናመነጨው አንድ የትስስሮች መቆጣጠሪያ እንፈልጋለን:-

$ rails generate controller Tssrs

ዝርዝር 14.32 ላይ እንደምናየው፣ በትስስሮች መቆጣጠሪያ ተግባሮች ላይ የመዳረሻ ቁጥጥርን ማስገደዱ ብዙም ፋይዳ አይኖረውም፣ ነገር ግን የጥብቅ ቅርጸታችንን በተቻለ መጠን በቶሎ ለማስገደድ፣ አሁንም የቀድሞ ልምዳችንን እንከተላለን፡፡ በተለይም ደግሞ፣ በዝርዝር 14.31 ላይ እንደሚታየው፣ በትስስሮች መቆጣጠሪያ ውስጥ ያሉ ተግባሮችን ለመድረስ የሚደረጉ ሙከራዎች፣ አንድ የገባ ተጠቃሚን የሚጠይቁ መሆናቸውን እናረጋግጣለን፣ እንዲሁም፣ የትስስር ብዛቱ አለመቀየሩንም እናረጋግጣለን (እናም በሂደቱ ተጠቃሚው ወደ መነሻ ገጹ ይዟዟራል)።

ዝርዝር 14.31: ለትስስሮች የሚሆኑ መሰረታዊ የመዳረሻ ቁጥጥር ፈተናዎች፡፡ ቀይ test/controllers/tssrs_controller_test.rb
require "test_helper"

class TssrsControllerTest < ActionDispatch::IntegrationTest

  test "መፍጠር የገባ ተጠቃሚ ሊፈልግ ይገባል" do
    assert_no_difference 'Tssr.count' do
      post tssrs_path
    end
    assert_redirected_to gba_url
  end

  test "መሰረዝ የገባ ተጠቃሚ ሊፈልግ ይገባል" do
    assert_no_difference 'Tssr.count' do
      delete tssr_path(tssrs(:and))
    end
    assert_redirected_to gba_url
  end
end

የ‘ግብ_ተጠቃሚ (gb_teteqami) ቅድመአጣሪን በዝርዝር 14.32 ውስጥ በማከል፣ ዝርዝር 14.31 ውስጥ ያሉ ፈተናወችን እንዲያልፉ ማድረግ እንችላለን።

ዝርዝር 14.32: ለትስስሮች የሚሆን የመዳረሻ ቁጥጥር። አረንጓዴ app/controllers/tssrs_controller.rb
class TssrsController < ApplicationController
  before_action :gb_teteqami

  def create
  end

  def destroy
  end
end

የተከተል እና የአትከተል አዝራሮችን ለማሰራት ማድረግ ያለብን ነግር፣ በተጓዳኙ ቅጽ (ማለትም ዝርዝር 14.21 ወይም ዝርዝር 14.22) ውስጥ ከ‘ክትል_መታወቂያ‘ው (ktl_id) ጋር የተዛመደውን ተጠቃሚ መፈለግ እና ከዚያ፣ ከዝርዝር 14.10 ተገቢውን የ‘ተከተል (teketel) ወይም የ‘አትከተል (atketel) ዘዴን መጠቀም ነው፡፡ ሙሉ አተገባበሩ በዝርዝር 14.33 ውስጥ ይታያል፡፡

ዝርዝር 14.33: የትስስሮች መቆጣጠሪያው። አረንጓዴ app/controllers/tssrs_controller.rb
class TssrsController < ApplicationController
  before_action :gb_teteqami

  def create
    teteqami = Teteqami.find(params[:ktl_id])
    ahun_teteqami.teketel(teteqami)
    redirect_to teteqami
  end

  def destroy
    teteqami = Tssr.find(params[:id]).ktl
    ahun_teteqami.atketel(teteqami)
    redirect_to teteqami
  end
end

ዝርዝር 14.33 ‘ን በመመልከት ቀድሞ የጠቀስነው የጥብቃ ችግር ያን ያህል የተጋነነ አለመሆኑን ማወቅ እንችላለን፤ አንድ ያልገባ ተጠቃሚ፣ ሁለቱንም ተግባሮች ለመጠቀም ቢሞክር (ለምሳሌ፣ እንደ ከርል (curl) ያለ አንድ የማዘዥያ መስመር መሳርያን ቢጠቀም)፣ የ‘ዓሁን_ተጠቃሚ (ahun_teteqami) ዋጋ ምንም (nil) ይሆናል፤ ስለሆነም በሁለቱም ሁኔታዎች ላይ የተግባሮቹ ሁለተኛው መስመር አንድ ልዩነትን ያስነሳል፣ ይህም በአፕልኬሽኑ ወይም በውሂቡ ላይ ምንም ዓይነት ጉዳትን ሳያደርስ አንድ ስህተት ብቻ እንዲታይ ያደርጋል። ሆኖም ግን በዚያ ላይ መተማመኑ ጥሩ ስላልሆነ፣ ተጨማሪ እርምጃውን በመውሰድ፣ አንድ ተጨማሪ የጥበቃ ንጣፍን አክለናል።

በዚያ፣ ዋናው የተከተል እና የአትከተል ትግበራ ይጠናቀቃል፤ ስለዚህ ማንኛውም ተጠቃሚ ሌላ ተጠቃሚን መከተልም ሆነ አለመከተል ይችላል፣ ይህንንም አሳሻችሁን በመጠቀም፣ ከምትፈልጉት ተግባር ጋር የሚዛመደውን አዝራር ጠቅ በማድረግ ማረጋገጥ ትችላላችሁ። (በክፍል 14.2.6 ውስጥ እነዚህን ባህሪዎች የሚያረጋግጡ የውህደት ፈተናወችን እንጽፋለን) ሁለተኛውን #2 ተጠቃሚ የመከተል ውጤትም በምስል 14.19 እና በምስል 14.20 ላይ ይታያል፡፡

images/figures/unfollowed_user
ምስል 14.19: አንድ ያልተከተሉት ተጠቃሚ።
images/figures/followed_user
ምስል 14.20: አንድ ያልተከተሉትን ተጠቃሚ የመከተል ውጤት።

መልመጃዎች

የሬይልስ ስልጠናን ለገዙ ሰወች በሙሉ የሁሉም የመልመጃ መልሶች እዚህ ላይ ይገኛሉ።

የሌሎች ሰዎች መልሶችን ለማየት እና የራሳችሁን ደግሞ ለመመዝገብ፣ በሬይልስ ስልጠና ወይም ሁሉንም በበቂ ተማር መድረሻ ጥቅል ላይ ተመዝገቡ፡፡

  1. አሳሻችሁን በመጠቀም፣ /ተጠቃሚ/2‘ን (/teteqamis/2) ተከተሉ እና ከዚያ አትከተሉ። ይሰራልን?
  2. በአገልጋይ ዘጋቢው መሰረት፣ በእያንዳንዱ ሁኔታ ላይ፣ የትኞቹ ዝግጁገጽታዎች ቀረቡ?

14.2.5 በኤጃክስ የሚሰራ አንድ የተከተል አዝራር

ምንም እንኳን የተጠቃሚ መከተያ ትግበራችን አሁን ባለበት ደረጃ የተጠናቀቀ ቢሆንም፣ የሁኔታ ቀላቢው ላይ ስራ ከመጀመራችን በፊት፣ በትግበራችን ላይ የቀረንን አንድ የማስዋብ ስራ እናክላለን። በትስስሮች መቆጣጠሪያ ውስጥ ያሉት፣ ሁለቱም የ‘ፍጠር (create) እና የ‘አጥፋ (destroy) ተግባሮች በቀላሉ ወደ ዋናው መገለጫ መልሰው እንደሚያዟዙሩ በክፍል 14.2.4 ላይ አስተውላችሁ ይሆናል፡፡ በሌላ አማርኛ፣ አንድ ተጠቃሚ፣ ሌላ ተጠቃሚን ለመከተል በሌላ መገለጫ ገጽ ላይ ይጀምራል፣ ያንኑ ተጠቃሚ ለመከተል፣ “ተከተል” አዝራርን ጠቅ በማድረግ ይከተለዋል፣ ከዚያም ተጠቃሚው ወዲያውኑ መጀመሪያ ወደ ነበረበት አድራሻ ይዟዟራል። “ከመጀመሪያውስ ተጠቃሚው ያንን ገጽ በጪራሽ እንዲተው ለምን አስፈለገ?” የሚለውን ጥያቄ መጠየቅ ምክንያታዊ ይሆናል፡፡

ለእንደዚህ አይነቱ ጥያቄ ትክክለኛው ምላሽ ደግሞ አጃክስን መጠቀም ነው፣ ይህም የድር ገጾችን፣ ከገጹ ሳይለቁ/ሳይወጡ፣ ባልተመሳሰለ መልኩ (asynchronously) ማለት በአንድ ጊዜ ከአንድ በላይ የሆነ ሂደትን በማካሄድ12 መጠይቆችን ወደ አገልጋዩ እንዲልኩ ያስችላቸዋል፡፡13 ኤጃክስን በድር ቅጾች ላይ ማከሉ አንድ የተለመደ ተግባር ስለሆነ፣ ሬይልስም ኤጃክስን መተግበሩን ቀላል ያደርገዋል፡፡ በእርግጥ፣ የተከተል/አትከተል ቅጽ ከፊልን ማዘመኑ ራሱ እጅግ በጣም ቀላል ነው። ይህንን:-

form_with(model: ..., local: true)

ወደዚህ:-

form_with(model: ..., local: false)

መለወጥ ብቻ ነው፤ እናም ሬይልስ በራስምትሃት (Automagically) ኤጃክስን ይጠቀማል። (በእውነቱ፣ የ‘ቅጽ-ጋር (form_with) ተፈጥሯዊ ባህሪ፣ የሩቅ ርክቦችን ማድረግ ነው፣ ስለሆነም ሰፈር፡ ሃሰት‘ን (local: false) ልንተወው እንችላለን፣ ነገር ግን ቢያንስ በመጀመሪያ ላይ ሁኔታውን ግልጽ ለማድረግ በማሰብ፣ እሱን በግልጽ ማከሉን መርጫለሁ፡፡) የዘመኑት ከፊሎች፣ በዝርዝር 14.34 እና በዝርዝር 14.35 ውስጥ ይታያሉ፡፡

ዝርዝር 14.34: አንድ ኤጃክስን በመጠቀም የሚሰራ የተጠቃሚ መከተያ ቅጽ። app/views/teteqamis/_teketel.html.erb
<%= form_with(model:  ahun_teteqami.nq_tssrs.build, local: false) do || %>
  <div><%= hidden_field_tag :ktl_id, @teteqami.id %></div>
  <%= .submit "ተከተል", class: "btn btn-primary" %>
<% end %>
ዝርዝር 14.35: አንድ ኤጃክስን በመጠቀም የሚሰራ ተጠቃሚን አለመከተያ ቅጽ። app/views/teteqamis/_atketel.html.erb
<%= form_with(model: ahun_teteqami.nq_tssrs.find_by(ktl_id: @teteqami.id),
             html: { method: :delete }, local: false) do || %>
  <%= .submit "አትከተል", class: "btn" %>
<% end %>

በዚህ ክ.ሩ ስለመነጨው ትክክለኛው/ጥሬው ሃ.ጽ.መ.ቋ ማወቁ ያን ያህል አስፈላጊ አይደለም፣ ነገር ግን ለማወቅ ከፈለጋችሁ፣ ከንድፉዊ ትይታው የተቀነጨበው ይዘት ይህንን ይመስላል (ዝርዝሩ ሊለያይ ይችል ይሆናል):-

<form action="/tssrs/117" class="edit_tssr" data-remote="true"
      id="edit_tssr_117" method="post">
  .
  .
  .
</form>

እዚህ ላይ በቅጹ መለያ ውስጥ፣ የ‘ሩቅ-ውሂብ (data-remote) ተለዋዋጩን የ‘እውነት ("true") ዋጋን እንዲይዝ ያዘጋጃል፣ ይህም ቅጹ በጃቫስክሪፕት ይስተናገድ ዘንድ፣ ሬይልስን እንዲፈቅድ ይነግረዋል፡፡ ሬይልስ ሙሉ የጃቫስክሪፕት ኮድን ድሩ ላይ ከማስገባት ይልቅ፣ አንድ ቀለል ያለ የሃ.ጽ.መ.ቋ ባሕሪን ለመጠቀም (እንደቀድሞዎቹ የሬይልስ ስሪቶች ሁሉ)፣ የማይታወቅ ጃቫስክሪፕት (unobtrusive JavaScript) የተባለ ፍልስፍናን ይከተላል፡፡

ቅጹን ካዘመንን በኋላ፣ የትስስሮች መቆጣጠሪያ ለኤጃክስ መጠይቆች ምላሽ ይሰጥ ዝንድ፣ እሱን ማዘጋጀት ይኖርብናል፡፡ ይህንንም በመጠይቁ መሰረት፣ ተገቢውን ምላሽ ለመስጠት፣ የ‘ምላሽ_ስጥ (respond_to) ዘዴን በመጠቀም፣ ማዘጋጀት እንችላለን፡፡ አጠቃላይ ጥለቱም ይህን ይመስላል፡-

respond_to do |format|
  format.html { redirect_to teteqami }
  format.js
end

አገባቡ ግራ የሚያጋባነው፣ እናም ከላይ ባለው ኮድ ውስጥ አንዱ መስመር ብቻ እንደሚፈጸም መረዳቱም አስፈላጊ ነው፡፡ (በዚህ አንጻር ሲታይ፣ የ‘ምላሽ_ስጥ (respond_to) አሰራር፣ የአንድ የከሆነ-ከዚያ-ካልሆነ ዓረፍተሐሳብ አሰራርን ከመከተል ይልቅ፣ አንድ ቅደም ተከተሉን የያዘ አሰራርን የሚፈጽም ይመስላል፡፡) የትስስሮች መቆጣጠሪያ ለኤጃክስ ምላሽ እንዲሰጥ ለማድረግ፣ ከላይ የሚታየውን የ‘ምላሽ_ስጥ (respond_to) ዘዴን፣ በዝርዝር 14.33 የ‘ፍጠር (create) እና የ‘አጥፋ (destroy) ተግባሮች ውስጥ ማከልን ያሳትፋል፡፡ ውጤቱም በዝርዝር 14.36 ውስጥ ይታያል፡፡ ተጠቃሚ (teteqami) የተባለውን የሰፈር ተለዋዋጪ ወደ አንድ @ተጠቃሚ (@teteqami) የተባለ ቅርፀ ተለዋዋጪ እንደቀየርነው አስተውሉ፣ በዝርዝር 14.33 ውስጥ ቅርፀ ተለዋዋጪ አያስፈልገንም ነበር፤ አሁን ግን እንደዚህ አይነቱ ቅርፀ ተለዋዋጪን በዝርዝር 14.34 ውስጥ እና በዝርዝር 14.35 ውስጥ ለመጠቀም አስፈላጊ ነው፡፡

ዝርዝር 14.36: በትስስሮች መቆጣጠሪያ ውስጥ ለአጃክስ መጠይቆች ምላሽ መስጠት፡፡ app/controllers/tssrs_controller.rb
class TssrsController < ApplicationController
  before_action :gb_teteqami

  def create
    @teteqami = Teteqami.find(params[:ktl_id])
    ahun_teteqami.teketel(@teteqami)
    respond_to do |format|
      format.html { redirect_to @teteqami }
      format.js
    end
  end

  def destroy
    @teteqami = Tssr.find(params[:id]).ktl
    ahun_teteqami.atketel(@teteqami)
    respond_to do |format|
      format.html { redirect_to @teteqami }
      format.js
    end
  end
end

ዝርዝር 14.36 ውስጥ የተዘረዘሩት ተግባሮች ደረጃ በደረጃ እየወረዱ ይሰራሉ፣ ይህ ማለት ጃቫስክሪፕት እንዳይነቃ በተደረጉ አሳሾች ላይ (በዝርዝር 14.37 ላይ እንደሚታየው፣ አንድ አነስተኛ የሆነ መዋቅርን ማከሉ አስፈላጊ ቢሆንም)፣ አሳሾቹ ያለምንም ችግር እንደድሮው እንዲሰሩ ያደርጋሉ ማለት ነው፡፡

ዝርዝር 14.37: ቅጽን ደረጃ በደረጃ ለማስረከብ የሚያስፈልግ መዋቅር። config/application.rb
require_relative 'boot'
.
.
.
module SampleApp
  class Application < Rails::Application
    .
    .
    .
    # በርቀት ቅጾች ላይ የፍቃደኝነት ይስሙላን ያካትታል።
    config.action_view.embed_authenticity_token_in_remote_forms = true
  end
end

በሌላ በኩል ጃቫስክሪፕት ሲነቃ ደግሞ፣ በትክክል ምላሽ መስጠት አለብን፡፡ የአንድ ኤጃክስ መጠይቅን ስንመለከት፣ ሬይልስ ከ‘ፍጠር.ጀኤስ.ክሩ (create.js.erb) ወይም ከ‘አጥፋ.ጀኤስ.ክሩ (destroy.js.erb) ተግባር ጋር አንድ አይነት ስም ያለውን፣ አንድ የ‘ጃቫስክሪፕት.ክሩ (.js.erb) ፋይልን በራስሰር ይጠራል (.ጀኤስ.ክሩቢ (.js.erb) ማለት የጃቫስክሪፕት ክትሩቢ ማለት ነው)፡፡ እንደምትገምቱት እንደዚህ ያሉ ፋይሎች፣ በአሁኑ ገጽ ላይ አስፈላጊ የሆኑ እርምጃዎችን እንፈጽም ዘንድ፣ ጃቫስክሪፕትን እና ክት ሩቢን እንድንቀላቀል ያስችሉናል፡፡ በመከተል ወይም ባለመከተል ጊዜ፣ የአንድ ተጠቃሚ መገለጫ ገጽን ለማዘመን ያገለግሉን ዘንድ፣ መፍጠር እና አርትዕ ማድረግ ያለብን ፋይሎች ናቸው፡፡

ሬይልስ በአንድ የጄኤስ-ኢአርቢ (JS-ERb) ፋይል ውስጥ፣ የሰነድ ቁስ ቅርጸትን (ሰ.ቁ.ቅ) (Document Object Model (DOM)) በመጠቀም፣ ገጹን ለማንቀሳቀስ የጀኴይሪ (jQuery) ጃቫስክሪፕት ረጅዎችን በራስሰር ይሰጣል፡፡ የጀኴይሪ ቤተኮድ (በአጪሩ በክፍል 13.4.2 ውስጥ እንደተመለከትነው) ሰ.ቁ.ቅን ለማንቀሳቀስ በርካታ ዘዴዎችን ይሰጣል፣ ነገር ግን እዚህ ላይ ሁለት ዘዴዎች ብቻ ያስፈልጉናል፡፡ በቅድሚያ፣ ልዩ በሆነው የቅ.ቋ መታወቂያ ላይ በመመርኮዝ የሰ.ቁ.ቅ አባልን ለመድረስ ስለሚያገለግለው የዶላር ምልክት አገባብ ማወቅ ይኖርብናል። ለምሳሌ የተከተል_ቅጽ አባልን ለማንቀሳቀስ፣ የሚከተለውን አገባብ እንጠቀማለን:-

$("#የተከተል_ቅጽ")

(ዝርዝር 14.19 ላይ ካስተዋላችሁ፣ ክፍሊት (div) ቅጹን አቅፎ የሚይዝ አንድ ክፍሊት እንጅ ቅጹ ራሱ አይደለም።) ይህ አገባብ በቅ.ቋ ላይ የተመረኮዘ ነው፤ አንድ የቅ.ቋ መታወቂያን ለማመልከት፣ የ # ስርዓተ-ምልክትን ይጠቀማል፡፡ እንደምትገምቱት ጀኴይሪም ልክ እንደ ቅ.ቋ፣ የቅ.ቋ ክፍሎችን ለማንቀሳቀስ አንድ ነጥብን . ይጠቀማል፡፡ እናም እንዚህ የዘረዘርናቸው ነገሮች ከሚያስፈልጉን ነገሮች የመጀመሪያዎቹ ይሆናሉ ማለት ነው፡፡

ሁለተኛው የሚያስፈልገን ዘዴ ደግሞ፣ ሃጽመቋ (html) ይሆናል፣ ይህም በሃ.ጽ.መ.ቋ ውስጥ ያለውን አባል፣ በሚመለከተው ማለት በነጋሪአሴቱ ይዘቶች ያዘምናል፡፡ ለምሳሌ፣ ሙሉውን የተከተል_ቅጽ ይዘትን እንዳለ "ኤደን አግቢኝ" በሚል ጽሑፍ ለመተካት ብንፈልግ እንዲህ ብለን መጻፍ እንችላለን:-

$("#የተከተል_ቅጽ").html("ኤደን አግቢኝ")

ከተለመዱት ጥሬ የጃቫስክሪፕት ፋይሎች በተለየ መልኩ፣ የ‘ጀኤስ-ክትሩቢ (JS-ERb) ፋይሎች እንዲሁ ክት ሩቢን መጠቀምን ይፈቅዳሉ፣ ይህንንም፣ የተከተል ቅጹን በ‘አትከተል (atketel) ከፊል ለማዘመን እና እንዲሁም የተከታዮችን ቆጠራ ለማዘመን በ‘ፍጠር.ጀኤስ.ክሩ (create.js.erb) ፋይል ውስጥ እንተገብረዋለን (ከአንድ ውጤታማ መከተል በኋላ መታየት ያለበትም ይህ ነው)። ይህ ሃ.ጽ.መ.ቋን በአንድ የጃቫስክሪፕት ፋይል ውስጥ በማስገባት ጊዜ፣ ውጤቱን ለማስመለጥ የሚያስፈልገውን የጃቫስክሪፕት_አስመልጥ (escape_javascript) ዘዴን ይጠቀማል፡፡ ውጤቱም በዝርዝር 14.38 ላይ ይታያል።

ዝርዝር 14.38: አንድ የመከተል ትስስርን የሚፈጥር የጃቫስክሪፕት ክት ሩቢ። app/views/tssrs/create.js.erb
$("#የተከተል_ቅጽ").html("<%= escape_javascript(render('teteqamis/atketel')) %>");
$("#ተከታዮች").html('<%= @teteqami.teketayoch.count %>');

ከላይ ያለው ኮድ እያንዳንዱ መስመር በድርብ ሰረዝ ; እንደሚያልቅ አስተውሉ፤ ይህም አልጎር ከተባለው ቋንቋ የመጣ አገባብ ያላቸው ቋንቋዎች መለያ ባህሪ ነው፡፡

የ‘አጥፋ.ጀኤስ.ክሩ (destroy.js.erb) ፋይሉ ከ‘ፍጠር.ጀኤስ.ክሩ (create.js.erb) ፋይል ጋር ተመሳሳይ ነው (ዝርዝር 14.39)

ዝርዝር 14.39: አንድ የመከተል ትስስርን የሚያጠፋ የሩቢ ጃቫስክሪፕት (RJS)፡፡ app/views/tssrs/destroy.js.erb
$("#የተከተል_ቅጽ").html("<%= escape_javascript(render('teteqamis/teketel')) %>");
$("#ተከታዮች").html('<%= @teteqami.teketayoch.count %>');

በዚያ፣ ወደ አንድ የተጠቃሚ መገለጫ ገጽ በመሄድ፣ ገጹን ሳታድሱ፣ ተጠቃሚውን መከተል እና አለመከተል መቻላችሁን ማረጋገጥ ይኗርባችኋል።

መልመጃዎች

የሬይልስ ስልጠናን ለገዙ ሰወች በሙሉ የሁሉም የመልመጃ መልሶች እዚህ ላይ ይገኛሉ።

የሌሎች ሰዎች መልሶችን ለማየት እና የራሳችሁን ደግሞ ለመመዝገብ፣ በሬይልስ ስልጠና ወይም ሁሉንም በበቂ ተማር መድረሻ ጥቅል ላይ ተመዝገቡ፡፡

  1. አሳሻችሁን በመጠቀም፣ /ተጠቃሚ/2 ‘ን (/teteqamis/2) ተከተሉ እና ከዚያ አትከተሉ። ይሰራልን?
  2. በአገልጋይ ዘጋቢው መሰረት፣ በእያንዳንዱ ሁኔታ ላይ፣ የትኞቹ ዝግጁገጽታዎች ቀረቡ?

14.2.6 የመከተል ፈተናዎች

አሁን የመከተያ አዝራሮቹ እየሰሩ ነው፣ ስለዚህ ምልሰቶችን ለመከላከል፣ አንዳንድ ቀላል ፈተናወችን እንጽፋለን፡፡ አንድ ተጠቃሚን ለመከተል፣ ተጠቃሚውን በትስስሮች መንገድ ላይ ዕናስቀምጥ እና ከዚያ የተከተሉት ተጠቃሚዎች ቁጥር በ 1 እንደጨመረ እናረጋግጣለን:-

assert_difference '@teteqami.miketelachew.count', 1 do
  post tssrs_path, params: { ktl_id: @lela.id }
end

ይህ መደበኛ ትግበራውን ይፈትናል፣ ይሁን እንጅ በኤጃክስ የተሰራውን ትግበራ መፈተኑ ከዚሁ ጋር ፍጹም ተመሳሳይ ነው፤ አንድ ብቸኛ ልዩነት ቢኖር፣ አንድ ተጨማሪ የ‘:ኤክስኤችአር እውነት (xhr: true) አማራጪ መኖሩ ነው:-

assert_difference '@teteqami.miketelachew.count', 1 do
  post tssrs_path, params: { ktl_id: @lela.id }, xhr: true
end

እዚህ ላይ፣ የ‘ኤክስኤችአር (xhr) አማራጪን በ‘እውነት (true) ማቀናበሩ፣ በፈተናው ውስጥ አንድ የኤጃክስ መጠይቅ እንዲያቀርብ ያደርጋል፣ ይህም በዝርዝር 14.36 ውስጥ ያለውን የ‘ምላሽ_ስጥ (respond_to) ጥምርን ትክክለኛውን የጃቫስክሪፕት ዘዴን እንዲፈጽም ያደርገዋል (xhr የኤክሰኤምሌል ሃ.ጽ.ማ.ስ መጠይቅ (XmlHttpRequest) ማለት ነው)፡፡14

የ‘አስቀምጥ (post) ዘዴን ቦታ በ‘ሰርዝ (delete) ዘዴ በመተካት፣ ተጠቃሚወችን ላለመከተል፣ ተመሳሳይ ትይዩ መዋቅርን ተግባር ላይ ማዋል ይቻላል፡፡ እዚህ ጋር፣ የተከታዮቹ ተጠቃሚዎች ብዛት በ 1 እንደቀነሰ፣ እና እንዲሁም ትስስሩ እና የክትሉ መታወቂያ እንደተካተተ እናረጋግጣለን:-

assert_difference '@teteqami.miketelachew.count', -1 do
  delete tssr_path(tssr)
end

እንዲሁም በኤጃክስ እንደሚከተለው አድርገን እናረጋግጣለን:-

assert_difference '@teteqami.miketelachew.count', -1 do
  delete tssr_path(tssr), xhr: true
end

ሁለቱን ሁኔታዎች በአንድ ላይ በማስቀመጥ፣ በዝርዝር 14.40 ውስጥ ያሉትን ፈተናወች እናገኛለን፡፡

ዝርዝር 14.40: የመከተል እና የአለመከተል አዝራሮችን መፈተን። አረንጓዴ test/integration/miketelachew_test.rb
require "test_helper"

class MiketelachewTest < ActionDispatch::IntegrationTest

  def setup
    @teteqami = teteqamis(:michael)
    @lela = teteqamis(:ermias)
    gba_ende(@teteqami)
  end
  .
  .
  .
  test "አንድ ተጠቃሚን በመደበኛው መንገድ መከተል አለበት" do
    assert_difference '@teteqami.miketelachew.count', 1 do
      post tssrs_path, params: { ktl_id: @lela.id }
    end
  end

  test "አንድ ተጠቃሚን በኤጃክስ መከተል አለበት" do
    assert_difference '@teteqami.miketelachew.count', 1 do
      post tssrs_path, xhr: true, params: { ktl_id: @lela.id }
    end
  end

  test "አንድ ተጠቃሚን በመደበኛው መንገድ አለመከተል አለበት" do
    @teteqami.teketel(@lela)
    tssr = @teteqami.nq_tssrs.find_by(ktl_id: @lela.id)
    assert_difference '@teteqami.miketelachew.count', -1 do
      delete tssr_path(tssr)
    end
  end

  test "አንድ ተጠቃሚን በኤጃክስ አለመከተል አለበት" do
    @teteqami.teketel(@lela)
    tssr = @teteqami.nq_tssrs.find_by(ktl_id: @lela.id)
    assert_difference '@teteqami.miketelachew.count', -1 do
      delete tssr_path(tssr), xhr: true
    end
  end
end

በዚህ ጊዜ ፈተናወቹ አረንጓዴመሆን አለባቸው:-

ዝርዝር 14.41: አረንጓዴ
$ rails test

መልመጃዎች

የሬይልስ ስልጠናን ለገዙ ሰወች በሙሉ የሁሉም የመልመጃ መልሶች እዚህ ላይ ይገኛሉ።

የሌሎች ሰዎች መልሶችን ለማየት እና የራሳችሁን ደግሞ ለመመዝገብ፣ በሬይልስ ስልጠና ወይም ሁሉንም በበቂ ተማር መድረሻ ጥቅል ላይ ተመዝገቡ፡፡

  1. የ‘ምላሽ_ስጥ (respond_to) ጥምር ስር ያሉ ሁለት መስመሮች ላይ (ዝርዝር 14.36)፣ ማለት በእያንዳንዳቸው ላይ አስተያየት በማድረግ እና ባለማድረግ፣ ፈተናወቹ መፈተን የሚገባቸውን ነገር መፈተናቸውን አረጋግጡ፡፡ በያንዳዱ ሁኔታ ላይ የትኛው ፈተና ወደቀ?
  2. ዝርዝር 14.40 ውስጥ ካሉት አንዱን ማለት ይህንን:- xhr: true ብታስወግዱት ምን ይሆናል? ይህ ምን አይነት ችግር እንደሚያስከትል አብራሩ? ከዚህ በፊት የነበረው መልመጃ ላይ ያለው አሰራር ለምን ችግሩን እንዳልያዘው አብራሩ?

14.3 የሁኔታ ቀላቢ

አሁን የማሳያ አፕልኬሽናችን ጉልላት ወደሆነው፤ የአጪርጽሑፎች የሁኔታ ቀላቢው ላይ ደርሰናል። ይህ ክፍል በዚህ ስልጠና ውስጥ ካሉት ነገሮች ሁሉ በጣም ላቅ ያሉ አንዳንድ ነገሮችን በሚገባ ያካትታል። ሙሉው የሁኔታ ቀላቢው የሚገነባው፣ በክፍል 13.3.3 ቀደምት-ቀላቢ ላይ ነው፤ የሚገነባውም በአሁኑ ተጠቃሚ፣ አጪርጽሑፎች እና እሱ ከሚከተላቸው ተጠቃሚዎች አጪርጽሑፎች ጋር በተሰባሰበ አንድ ድርድር ይሆናል። በዚህ ክፍል ውስጥ፣ ከጊዜ ወደ ጊዜ ርቀቱ/ውስብስብነቱ እየጨመረ የሚሄደውን የሁኔታ ቀላቢ አተገባበር ሂደትን በማከታተል ጉዞዋችንን እንቀጥላለን። ይህንን ለማከናወን፣ በተወሰነ ደረጃ የላቀ የሬይልስ፣ የሩቢ እና እንዲሁም የተ.መ.ቋ ፕሮግራም ስልቶችን እንፈልጋለን፡፡

ከፊለፊታችን አንድ ከባድ ስራ ስለሚጠብቀን፣ ከወዲሁ ስራውን መገምገሙ በጣም ጠቃሚ ነገር ይሆናል፡፡ ስለሆነም፣ በምስል 14.5 ላይ ታይቶ የነበረው የመጨረሻው የሁኔታ ቀላቢ፣ አጠቃላይ መግለጫ አሁንም በድጋሚ በምስል 14.21 ላይ ቀርቧል፡፡

images/figures/page_flow_home_page_feed_mockup_bootstrap
ምስል 14.21: አንድ የሁኔታ ቀላቢ ያለው፣ አንድ የተጠቃሚ መነሻ ገጽ ስእላዊ መግለጫ።

14.3.1 መንስኤ እና ስልት

ከቀላቢው ጀርባ ያለው መሰረታዊ ሃሳብ ግልጽ ነው፡፡ ምስል 14.22 አንድ የ‘አጪርጽሑፎች (achrtshufs) ናሙና ውሂበጎታ ሰንጠረዥን እና የተገኘውን የቀላቢ ውጤት ያሳያል፡፡ የአንድ ቀላቢ ዋና ዓላማው፣ ስእሉ ላይ ባሉ ቀስቶች እንደተመለከተው፣ የተጠቃሚዎቹ መታወቂያ፣ የአሁን ተጠቃሚ ከሚከተላቸው ተጠቃሚዎች ጋር የሚዛመዱ አጪርጽሑፎችን ጎትቶ ማውጣት ነው (የአሁን ተጠቃሚው አጪርጽሑፎችንም ይጨምራል)፡፡

images/figures/user_feed
ምስል 14.22: የመጀመሪያው ተጠቃሚ አንድ ቀላቢ፤ የመለያቁጥራቸው 2 ፣ 7 ፣ 8 እና 10 የሆኑ ተጠቃሚዎችን ተከትሎ።

ምንም እንኳን ቀላቢውን እንዴት መተግበር እንዳለበት ገና ባናውቅም፣ ፈተናወቹን መጻፉ ግን በአንጻሩ በጣም ቀላል ነው፤ ስለሆነም (በሳጥን 3.3 ውስጥ ያሉትን መመሪያዎች በመከተል) በመጀመሪያ ፈተናወቹን እንጽፋለን። ዋናው ነገር እነዚህን ሶስት የቀላቢ መስፈርቶችን ማረጋገጥ ነው፤ በቀላቢው ውስጥ የተከታይ እና የተከታዮች አጪርጽሑፎች መካተት ሲኖርባቸው፣ ከአንድ የማይከተሉት ተጠቃሚ የመጣ አንድ አጪርጽሑፍን ግን ማካተት የለበትም፡፡

ዝርዝር 14.28 ላይ እንደምናየው፣ ማይክል ገሬን እንጅ ኤርምያስን እንደማይከተል አድርገን እናዘጋጀዋለን፤ በዝርዝር 10.47 እና በዝርዝር 13.55 ውስጥ ባሉት እቃዎች መሰረት፣ ይህ ማለት፣ ማይክል የገሬን እና የራሱን አጪርጽሑፎች ማየት ሲኖርበት፣ የኤርምያስን አጪርጽሑፎች ግን ማየት የለበትም ማለት ነው፡፡ እንዲሁም ሁሉም ተጠቃሚዎች የራሳቸውን አጪርጽሑፎች (ከሁለቱም ከተከታዮቻቸው እና ከማይከተላቸው ጋር) ማየታቸውን ማረጋገጥ እንፈልጋለን፡፡ እነዚህን መስፈርቶች ወደ ማረጋገጫዎች መለወጥ እና ቀላቢ‘ው (qelabi) በተጠቃሚ ቅርጸቱ (ዝርዝር 13.46) ውስጥ እንዳለ ማስታወሱ፣ በዝርዝር 14.42 ውስጥ የተመለከተውን የተሻሻለውን የተጠቃሚ ቅርጸት ፈተናን ይሰጣል፡፡

ዝርዝር 14.42: አንድ የሁኔታ ቀላቢ ፈተና። ቀይ test/models/teteqami_test.rb
require 'test_helper'

class TeteqamiTest < ActiveSupport::TestCase
  .
  .
  .
  test "ቀላቢ ትክክለኛ ቅምጦች ሊኖሩት ይገባል" do
    michael = teteqamis(:michael)
    ermias  = teteqamis(:ermias)
    gerie   = teteqamis(:gerie)
    # ከተከተሉት ተጠቃሚ የተለጠፉ ቅምጦች
    gerie.achrtshufs.each do |keteketelut_qmt|
      assert michael.qelabi.include?(keteketelut_qmt)
    end
    # በራስ የተቀመጡ ቅምጦች ከተከታዮች ጋር
    michael.achrtshufs.each do |yeras_qmt|
      assert michael.qelabi.include?(yeras_qmt)
    end
    # ምንም ተከታዮች ከለለው ተጠቃሚ የተቀመጡ ቅምጦች
    ermias.achrtshufs.each do |yeras_qmt|
      assert ermias.qelabi.include?(yeras_qmt)
    end
    # ከማይከተሉት ተጠቃሚ የተቀመጡ ቅምጦች
    ermias.achrtshufs.each do |kemiketelut_qmt|
      assert_not michael.qelabi.include?(kemiketelut_qmt)
    end
  end
end

በእርግጥ፣ አሁን ያለው አተገባበር፣ አንድ ቀደምት-ቀላቢን መተግበር ብቻ ስለሆነ፣ አዲሱ ፈተና በመጀመሪያ ቀይሊሆን ይገባዋል:-

ዝርዝር 14.43: ቀይ
$ rails test

መልመጃዎች

የሬይልስ ስልጠናን ለገዙ ሰወች በሙሉ የሁሉም የመልመጃ መልሶች እዚህ ላይ ይገኛሉ።

የሌሎች ሰዎች መልሶችን ለማየት እና የራሳችሁን ደግሞ ለመመዝገብ፣ በሬይልስ ስልጠና ወይም ሁሉንም በበቂ ተማር መድረሻ ጥቅል ላይ ተመዝገቡ፡፡

  1. የአጪርጽሑፎቹ የመታወቂያዎች ቅደም ተከተል፣ ከፍተኛው ቁጥር በቅርብ ጊዜ የተጻፈው አጪርጽሑፍ መሆኑን በመገመት፣ ምስል 14.22 ላይ ለሚታየው ቀላቢ ይሄ teteqami.qelabi.map(&:id) ምንን ይመልሳል? ጠቃሚ ምክር:- ክፍል 13.1.4 ላይ የተማርነውን ነባሪ ክልሉን አስታውሱ፡፡

14.3.2 የመጀመሪያው የቀላቢ አተገባበር

ዝርዝር 14.42 ፈተና ውስጥ ከተገኙት፣ የሁኔታ ቀላቢ ንድፍ መስፈርቶች ጋር፣ አሁን ቀላቢውን መጻፍ ለመጀመር ዝግጁ ነን። የመጨረሻው የቀላቢ አተገባበር በጣም የተወሳሰበ ስለሆነ፣ በአንድ ጊዜ አንድ ትንሽ ክፍልን በማስተዋወቅ፣ በትንሽ በትንሹ እንገነባዋለን። የመጀመሪያው ሂደት የምንፈልገው መጠይቅ ምን ዓይነት መሆኑን ማሰብ ነው፡፡ አንድ የተሰጠ ተጠቃሚ (ወይም ተጠቃሚው ራሱ) ከሚከተላቸው ተጠቃሚዎች መታወቂያዎች ጋር የሚዛመዱ አጪርጽሑፎችን (ማለት የሚከትላቸው ተጠቃሚወች የመታወቂያዎች ክምችትን) በሙሉ ከአጪርጽሑፎች (achrtshufs) ሰንጠረዥ ውስጥ መምረጥ ይኖርብናል፡፡ ይህንን በንድፋዊ መልኩ እንደሚከተለው ልንጽፍ እንችላለን:-

SELECT * FROM achrtshufs
WHERE teteqami_id IN (<የመታወቂያ ዝርዝሮች>) OR teteqami_id = <teteqami id>

ይህንን ኮድ ስንጽፍ፣ ተ.መ.ቋ (SQL) የስብስብ መካተትን ለመሞከር የሚያስችለንን አንድ የውስጥ (IN) ቁልፈቃልን እንደሚደግፍ ገምተን ነበር፡፡ ደስ ሲል! ያሰብነው ተሳክቷል፤ ማለት ይህንኑ ቁልፈቃል መጠቀም እንችላለን ማለት ነው፡፡

ዝርዝር 13.46 ላይ እንደተብራራው፣ በክፍል 13.3.3 ውስጥ በቀደምት-ቀላቢ ላይ፣ ንቅ መዝገብ ከላይ የተመለከተውን ዓይነት ምርጫ ለማከናወን፣ የ‘የት (where) ዘዴን እንደሚጠቀም አስታውሱ፡፡ እዚያ ላይ ምርጫችን በጣም ቀላል ነበር፤ ያደረግነውም ከአሁን ተጠቃሚው መታወቂያ ጋር የሚዛመዱትን አጪርጽሑፎችን በሙሉ መርጦ ማውጣት ብቻ ነበር:-

Achrtshuf.where("teteqami_id = ?", id)

እዚህ ላይ ግን እንደበፊቱ ቀላል ሳይሆን በጣም የተወሳሰበ ምርጫን እንፈልጋለን፣ ማለትም ይህን የመሰለ:-

Achrtshuf.where("teteqami_id IN (?) OR teteqami_id = ?",
                                      miketelachew_ids, id)

ከእነዚህ ሁኔታዎች በመነሳት፣ መታወቂያቸው ከሚከተሉት ተጠቃሚዎች ጋር የሚዛመድ፣ መታወቂያዎችን የያዘ አንድ ድርድር እንደሚያስፈልገን እንገነዘባለን። ይህንን ስራ ተግባራዊ ለማድረግ አንዱ መንገድ፣ የሩቢ ካርታ (map) ዘዴን መጠቀም ነው፤ ይህም በሩቢ ፕሮግራም ውስጥ በማንኛውም “ተቆጣሪ (Enumerable)” ቁሶች ላይ ይገኛል፤ ማለትም፣ አንድ የአባላቶች ክምችት፣ ባካተተ ማንኛውም ቁስ (ማለት እንደ ድርድር ወይም ተርታ ባሉ) ላይ ይገኛል/ይሰራል ማለት ነው።15ክፍል 4.3.2 ላይ የዚህን ዘዴ አሰራር ለመማር አንድ ምሳሌን ተመልክተን ነበር፤ እንደ አንድ ተጨማሪ ምሳሌ ይሆናችሁ ዘንድ፣ አንድ የቁጥሮች ድርድርን ወደ አንድ ሃረጎች ድርድር ለመቀየር የ‘ካርታ (map) ዘዴን እንጠቀማለን:-

$ rails console
>> [1, 2, 3, 4].map { |i| i.to_s }
=> ["1", "2", "3", "4"]

ከላይ እንደተብራራው አይነት ምሳሌ ሁኔታ ላይ፣ በአንድ ክምችት ውስጥ በእያንዳንዱ አባል ላይ አንድ ዓይነት ዘዴን መጥራት የተለመደ አሰራር ስለሆነ፣ ለዛም አንድ አጪር የአጻጻፍ ስርዓተ-ምልክት አለው (በክፍል 4.3.2 ላይ በግልጽ ታይቷል)፤ ያም አንድ እናን (&) እና ከዘዴው ጋር የሚዛመድ አንድ ወካይን ይጠቀማል:-

>> [1, 2, 3, 4].map(&:to_s)
=> ["1", "2", "3", "4"]

የ‘አገጣጥም (join) ዘዴን በመጠቀም (ክፍል 4.3.1)፣ በነጠላሰረዝ-ክፍትቦታ በተገጣጠሙ መታወቂያዎች የተዋቀረ አንድ ሃረግን መፍጠር እንችላለን:-

>> [1, 2, 3, 4].map(&:to_s).join(', ')
=> "1, 2, 3, 4"

በ‘ተጠቃሚ.ሚከተላቸው (teteqami.miketelachew) ስብስብ ውስጥ፣ በእያንዳንዱ አባል ላይ መታወቂያ‘ን ( id) በመጥራት አስፈላጊውን የተጠቃሚ ተከታዮች ድርድርን ለመገንባት፣ ከላይ የተጠቀሰውን ዘዴ መጠቀም እንችላለን፡፡ ለምሳሌ፣ በውሂበጎታው ውስጥ ላለው የመጀመሪያው ተጠቃሚ፣ የተከታዮች የመታወቂያዎች ድርድር እንደሚከተለው ሁኖ ይታያል ማለት ነው:-

>> Teteqami.first.miketelachew.map(&:id)
=> [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
42, 43, 44, 45, 46, 47, 48, 49, 50, 51]

በእርግጥ፣ የዚህ ዓይነቱ ግንባታ በጣም ጠቃሚ በመሆኑ የተነሳ፣ ንቅ መዝገብ ይህን አሰራር በነባሪነት ያቀርባል:-

>> Teteqami.first.miketelachew_ids
=> [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
42, 43, 44, 45, 46, 47, 48, 49, 50, 51]

እዚህ ላይ የ‘ሚከተላቸው_መታወቂያዎች (miketelachew_ids) ዘዴ በ‘ብዙ_ሚከተላቸው አሉት (has_many :miketelachew) ማሕበር መሰረት በ‘ንቅ መዝገብ የተቀናጀ ነው (ዝርዝር 14.8)፤ ስለዚህ ከ‘ተጠቃሚ.ሚከተላቸው (teteqami.miketelachew) ክምችት ጋር የሚዛመዱ መታወቂያዎችን ለማግኘት፣ የማሕበሩ ስም ላይ _መታወቂያዎች ‘ን (_ids) ብቻ ማያያዝ ይኖርብናል ማለት ነው። ከዚያ የአንድ የተከታይ ተጠቃሚ መታወቂያዎች ሃረግ እንደሚከተለው ሁኖ ይታያል:-

>> Teteqami.first.miketelachew_ids.join(', ')
=> "3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
42, 43, 44, 45, 46, 47, 48, 49, 50, 51"

አንድ የተ.መ.ቋ ሃረግን በመጠይቅ ውስጥ በምታስገቡበት ጊዜ፣ የሃረግ ውስጠገምትን መጠቀም አያስፈልጋችሁም፤ የ ? ውስጠገምት በናንተ ስም እሱን ያደርግላችኋል (እናም በእውነቱ፣ አንዳንድ በውሂበጎታ ላይ ጥገኛ የሆኑ ነገሮች ላይ የሚከሰቱ አለመጣጣሞችንም ያስወግዳል)፡፡ ይህ ማለት ሚከተላቸው_መታወቂያዎች‘ን (miketelachew_ids) ራሱን መጠቀም እንችላለን ማለት ነው። በዚህ ምክንያትም ይህ:-

Achrtshuf.where("teteqami_id IN (?) OR teteqami_id = ?",
                                      miketelachew_ids, id)

የመጀመሪያው ግምት ይሆናል፣ የመጀመሪያው ግምታችንም በትክክል ይሰራል! ውጤቱም በዝርዝር 14.44 ውስጥ ይታያል።

ዝርዝር 14.44: የመጀመሪያው የሚሰራ ቀላቢ። አረንጓዴ app/models/teteqami.rb
class Teteqami < ApplicationRecord
  .
  .
  .
  # አንድ የመሕለፈቃል ዳግምማስጀመሪያ ጊዜው ካበቃ እውነትን ይመለሳል።
  def mehlefeqal_damasjemerya_abqtualn?
    masjemer_tesedede_at < 2.hours.ago
  end

  # የአንድ ተጠቃሚ ሁኔታ ቀላቢን ይመልሳል።
  def qelabi
    Achrtshuf.where("teteqami_id IN (?) OR teteqami_id = ?",
                                          miketelachew_ids, id)
  end

  # አንድ ተጠቃሚን ይከተላል።
  def teketel(lela_teteqami)
    miketelachew << lela_teteqami unless self == lela_teteqami
  end
  .
  .
  .
end

የፈተና ስብስቡ አረንጓዴመሆን አለበት:-

ዝርዝር 14.45: አረንጓዴ
$ rails test

በአንዳንድ አፕልኬሽኖች ላይ፣ ይህ የመጀመሪያ አተገባበር ለአብዛኞቹ ተግባራዊ ዓላማዎች በቂ ሊሆን ይችላል፣ ይሁን እንጂ፣ ዝርዝር 14.44 የመጨረሻው አተገባበር አይደለም፤ ወደ ቀጣዩ ክፍል ከመቀጠላችሁ በፊት፣ ለምን እምብዛ በቂ እንዳልሆነ መገመት ትችላላችሁን? (ጠቃሚ ምክር:- አንድ ተጠቃሚ 5000 ተጠቃሚዎችን የሚከተል ከሆነ ውሂበጎታው ላይ ምን ይፈጥራል?)

መልመጃዎች

የሬይልስ ስልጠናን ለገዙ ሰወች በሙሉ የሁሉም የመልመጃ መልሶች እዚህ ላይ ይገኛሉ።

የሌሎች ሰዎች መልሶችን ለማየት እና የራሳችሁን ደግሞ ለመመዝገብ፣ በሬይልስ ስልጠና ወይም ሁሉንም በበቂ ተማር መድረሻ ጥቅል ላይ ተመዝገቡ፡፡

  1. ዝርዝር 14.44 ውስጥ፣ የተጠቃሚውን ማለት የራሱን አጪርጽሑፎች የሚፈልገውን የመጠይቅ ክፍልን አስወግዱ፡፡ በዝርዝር 14.42 ውስጥ ካሉት ፈተናወች ውስጥ የትኛው ፈተና ተሰበረ/ወደቀ?
  2. ዝርዝር 14.44 ውስጥ የተከታይ ተጠቃሚዎች አጪርጽሑፎች የሚፈልገውን የመጠይቅ ክፍል አስወግዱ፡፡ በዝርዝር 14.42 ካሉት ፈተናወች ውስጥ የትኛው ፈተና ተሰበረ/ወደቀ?
  3. ዝርዝር 14.44 ውስጥ ያለው ቀላቢ በስህተት ላልተከተሉት ተጠቃሚ አጪርጽሑፎችን መልሶ፣ በዝርዝር 14.42 ላይ ያለው፣ ሶስተኛው ፈተና ይወድቅ ዘንድ፣ አንድ የተ.መ.ቋ መጠይቅን ጻፉ፡፡ ጠቃሚ ምክር:- ሁሉንም አጪርጽሑፎች መመለሱ ለዚህ መፍትሄ ይሆናል፡፡

14.3.3 ንዑስምርጫ እና በጉጉት ጫኝ

በመጨረሻው ክፍል ላይ በተሰጠው ፍንጪ እና ብዙውን ጊዜ እንደሚያጋጥመው፣ ለምሳሌ እንበል አንድ ተጠቃሚ 5000 ተጠቃሚዎችን ቢከተል እናም ይህንን ተጠቃሚ ለማስተናገድ ብንሞክር፣ በክፍል 14.3.2 ውስጥ ያለው የቀላቢ አተገባበር፣ ለቀላቢው ቁጥር ስፍር የሌለው አጪርጽሑፎችን ስለሚጠይቅ በደንብ አይመዝንም (Scale) (መመዘን (Scale) ማለት ቅልጣፌ ማለት ነው)፡፡ በዚህ ክፍል ውስጥ የሁኔታ ቀላቢውን፣ ከተከታይ ተጠቃሚዎች ብዛት ጋር በተሻለ መልኩ እንዲመዝን አድርገን እንዳዲስ እንተገብረዋለን፡፡

ክፍል 14.3.2 ውስጥ ያለው ኮድ የመጀመሪያ ችግሩ፣ የ‘ሚከተላቸው_መታወቂያወች (miketelachew_ids) ሁሉንም የተከታይ ተጠቃሚዎች መታወቂያዎችን በማህደረ-ትውስታው ላይ ጎትቶ የሚጪን መሆኑ ነው፣ ይህም ሁሉንም ተከታይ ተጠቃሚዎች የያዘ አንድ ድርድርን ይፈጥራል። በዝርዝር 14.44 ውስጥ ያለው ሁኔታ የሚያረጋግጠው፣ የተፈለገው ነገር በአንድ ስብስብ ውስጥ መካተቱን ነው፣ በእውነቱ ይህን ለማድረግ፣ ከዚያ የተሻለ አንድ ቀልጣፋ መንገድ መኖር አለበት፣ እናም በእርግጥ ተ.መ.ቋ ለእንዲዚህ ዓይነቶቹ የስብስብ ተግባሮች የተባ ነው። መፍትሄውም አንድ ንዑስምርጫ የተባለ አሰራርን በመጠቀም የተከታይ ተጠቃሚዎች መታወቂያዎችን የመፈለግ ስራውን ወደ ውሂበጎታው ማሸጋገርን ያሳትፋል፡፡

ዝርዝር 14.46 ውስጥ በጥቂቱ በተሻሻለው ኮድ፣ ቀላቢውን በማጣራት እንጀምራለን።

ዝርዝር 14.46: በቀላቢው የት (where) ዘዴ ውስጥ የቁልፍ እና የዋጋ ጥንዶችን መጠቀም፡፡ አረንጓዴ app/models/teteqami.rb
class Teteqami < ApplicationRecord
  .
  .
  .
  # የአንድ ተጠቃሚ ሁኔታ ቀላቢን ይመልሳል።
  def qelabi
    Achrtshuf.where("teteqami_id IN (:miketelachew_ids) OR
                  teteqami_id = :teteqami_id", miketelachew_ids:
                  miketelachew_ids, teteqami_id: id)
  end
  .
  .
  .
end

ወደ ሚቀጥለው ደረጃ ለማለፍ ይህንን፡-

Achrtshuf.where("teteqami_id IN (?) OR teteqami_id = ?",
                                      miketelachew_ids, id)

በዚህ ቀይረናል:-

Achrtshuf.where("teteqami_id IN (:miketelachew_ids) OR
              teteqami_id = :teteqami_id", miketelachew_ids:
              miketelachew_ids, teteqami_id: id)

የጥያቄ ምልክቱ አገባብ በጣም ጥሩ ነው፣ ነገር ግን አንድ ተለዋዋጪን ከአንድ ወይም ከዚያ በላይ በሆነ ቦታ ላይ ማስገባት ከፈለግን፣ ሁለተኛው አገባብ የበለጠ አመች ይሆናል፡፡

ከዚህ በላይ ያለው ውይይት የሚያሳየው በተ.መ.ቋ መጠይቁ ላይ አንድ ሁለተኛ የ‘ተጠቃሚ_መታወቂያ (teteqami_id) ተለዋዋጪን ማከል እንዳለብን ነው፡፡ እኛም እዚህ ላይ የሩቢ ኮዱን:-

miketelachew_nous_mrcha

በዚህኛው የተ.መ.ቋ ቁርጥራጪ (snippet)16 መተካት እንችላለን:-

miketelachew_nous_mrcha = "SELECT ktl_id FROM tssrs
                          WHERE  teketay_id = :teteqami_id"

ይህ ኮድ የተ.መ.ቋ ንዑስክፍልን የያዘ ነው፣ እናም ለ ( 1) ቁጥር ተጠቃሚ ሁሉንም ክትሎች ከውሂበጎታው ለመሰብሰብ የምንጠቀምበት ኮድ ይህንን ይመስላል:-

SELECT * FROM achrtshufs
WHERE teteqami_id IN (SELECT ktl_id FROM tssrs
                  WHERE  teketay_id = 1)
      OR teteqami_id = 1

ይህ ንዑስክፍል ሁሉንም ጫና ወደ ውሂበጎታው ይልካል፡ ይህም ስራውን በጣም ቀልጣፋ ያደርገዋል።

ከዚህ በላይ ካገኘነው መሰረት ጋር፣ አንድ ይበልጥ ቀልጣፋ የሆነ፡ የቀላቢ ትግበራን ለመስራት ዝግጁ ነን፡፡ በዝርዝር 14.47 ላይ እንደሚታየው፣ አሁን እዚህ ላይ የምንጠቀመው ጥሬ ተ.መ.ቋን ስለሆነ፣ የ‘ሚከተላቸው_ንዑስ_ምርጫ (miketelachew_nous_mrcha) ሃረጉ ከመዘለል ይልቅ ውስጠገምት መደረጉን ልታስተውሉ ይገባል፡፡

ዝርዝር 14.47: ለመጨረሻ የተቃረበው የቀላቢ ትግበራ። አረንጓዴ app/models/teteqami.rb
class Teteqami < ApplicationRecord
  .
  .
  .
  # የአንድ ተጠቃሚ ሁኔታ ቀላቢን ይመልሳል።
  def qelabi
    miketelachew_nous_mrcha = "SELECT ktl_id FROM tssrs
                              WHERE  teketay_id = :teteqami_id"
    Achrtshuf.where("teteqami_id IN (#{miketelachew_nous_mrcha})
                  OR teteqami_id = :teteqami_id", teteqami_id: id)
  end
  .
  .
  .
end

እንደተለመደው፣ የፈተና ስብስቡን በማስኬድ፣ ኮዱ እንደሚሰራ ማረጋገጥ እንችላለን:-

ዝርዝር 14.48: አረንጓዴ
$ rails test

ሁለተኛው ችግር፣ በዝርዝር 14.47 ውስጥ ይበልጥ ቀልጣፋ የሆነው ኮድ እንኳን፣ ተዛማጅ ተጠቃሚዎችን (ወይም አባሪዎችን) ሳይጨምር፣ የቀላቢውን አጪርጽሑፎች ብቻ መጎተቱ ነው፡፡ በዚህ ምክንያትም አጪርጽሑፍ ከፊልን (ዝርዝር 13.72) የሚጠራው የቀላቢው ከፊል (ዝርዝር 13.51)፣ ከእያንዳንዱ አጪርጽሑፍ ጋር የሚዛመደውን ተጠቃሚ ለመፈለግ፣ አንድ ተጨማሪ የውሂበጎታ ምትን ያመነጫል፡፡ \( ሀ \) ‘ን ያህል ብዛት ያላቸው አጪርጽሑፎች ካሉ፣ ዝርዝር 14.47 አጪርጽሑፎቹን ለመጎተት \( 1 \) መጠይቅን ብቻ እንደሚጠቀም ሳይታለም የተፈታ ሃቅ ነው፤ ነገር ግን የቀላቢ ትይታው ራሱ፣ እያንዳንዱን የአጪርጽሑፍ ተጠቃሚ ለመፈለግ፣ ተጨማሪ \( ሀ \) መጠይቆችን ያመነጫል፣ ማለት በድምሩ \( ሀ+1 \) መጠይቆችን ያመነጫል ማለት ነው። (\( ሀ \) ‘ን ያህል ለተያያዙ ምስሎችም፣ ያንኑ ያህል ነጋሪአሴትን ይተገብራል፤ ስለሆነም በዚህ ሁኔታ፣ የመጠይቆቹ ብዛት ከ \( 2ሀ+1 \) በላይ ሊበልጥ ይችል ይሆናል።) የ \( ሀ+1 \) መጠይቅ ችግር ተብየው፣ የውሂበጎታው መጠን እያደገ ሲሄድ፣ የአንድ አፕልኬሽን አፈጻጸምን ቀስ በቀስ ወደታች ሊያወርድ ይችላል።

የዚህ ችግር መፍትሄ፣ አንድ በጉጉት ጫኝ (Eager Loading) ተብሎ የሚታወቅ ዘዴን ማሳተፍን ይጠይቃል፡፡ በኬቪን ጊልፒን፣ በለርን ኢነፍ ብሎግ አጪርጽሑፍ “በጉጉት ጫኝ እና የ \( ሀ+1 \) መጠይቅ ችግር” ላይ በበለጠ በዝርዝር እንደተብራራው፣ በጉጉት ጫኝ፣ ተጠቃሚዎችን (እና ምስሎችን) ልክ እንደ አንድ ነጠላ የአጪርጽሑፍ መጠይቅ አካል አድርጎ ያካትታቸዋል፣ ስለሆነም ለቀላቢው የሚያስፈልጉ ነገሮች ሁሉ፣ በአንድ ጊዜ ይጎትታል፣ በዚህም ውሂበጎታውን አንድ ጊዜ ብቻ እንዲመታ ያደርጋል፡፡ ከዚህ ስልት የሚገኘው ቅልጣፌም ከፍተኛ ሊሆን ይችላል፡፡

በሬይልስ ውስጥ በጉጉት ጫኝን የመጠቀም መንገዱ፣ አንድ አክል (includes) በተባለ ዘዴ በኩል ነው፡፡ አሁን ባለው ሁኔታ ላይ፣ አክልን (includes) ከ‘አጪርጽሑፍ.የት (Achrtshuf.where) ጋር በማስተሳሰር ሁለቱንም ማለት የአጪርጽሑፍ ተጠቃሚውን እና የምስል አባሪውን (ካለ) ማካተት እንችላለን:-

Achrtshuf.where("teteqami_id IN (#{miketelachew_nous_mrcha})
                  OR teteqami_id = :teteqami_id", teteqami_id: id)
           .includes(:teteqami, msl_attachment: :blob)

ይህንን ኮድ በዝርዝር 14.47 ላይ ማከሉ፣ በዝርዝር 14.49 ውስጥ የሚታየውን ቀላቢ (qelabi) ያስገኛል፡፡

ዝርዝር 14.49: የቀላቢው የመጨረሻ ትግበራ ከጉጉት ጫኝ ጋር። አረንጓዴ app/models/teteqami.rb
class Teteqami < ApplicationRecord
  .
  .
  .
  # የአንድ ተጠቃሚ ሁኔታ ቀላቢን ይመልሳል።
  def qelabi
    miketelachew_nous_mrcha = "SELECT ktl_id FROM tssrs
                              WHERE  teketay_id = :teteqami_id"
    Achrtshuf.where("teteqami_id IN (#{miketelachew_nous_mrcha})
                  OR teteqami_id = :teteqami_id", teteqami_id: id)
           .includes(:teteqami, msl_attachment: :blob)
  end
  .
  .
  .
end

አንድ የመጨረሻ የፈተና ስብስብ ማስኬዱ፣ በዝርዝር 14.49 ውስጥ ያለው ቀላቢ እንደተፈለገው እንደሚሰራ ያረጋግጣል:-

ዝርዝር 14.50: አረንጓዴ
$ rails test

በአፕልኬሽናችን ውስጥ ማንኛውንም ምልሰት መያዝ እንድንችል፣ በጉጉት ጫኝን በቀጥታ መፈተኑም ጥሩ በሆነ ነበረ። ይህን ማድረጉም አንዳንድ የላቁ የፈተና ስልቶችን ይጠይቃል፣ እንደዛ ይሁን እንጅ በእርግጠኝነት መፈተንም ይቻላል፤ እንዴት እሱን መፈተን እንደሚቻል አንዳንድ ዝርዝሮችን ለመመልከት “በጉጉት ጫኝ እና የ \( ሀ+1 \) መጠይቅ ችግር” ላይ ተመልከቱ።

በእርግጥ፣ ንዑስምርጫው እና በጉጉት ጫኙ ለዘልዓለም የሚመዝኑ (የሚቀለጥፋ) አይደሉም፡፡ አንድ በጣም ብዙ ተጠቃሚዎችን ሊያስተናግድ የሚችል ጣቢያን ለመገንባት የምትፈልጉ ከሆነ፣ ቀላቢውን ባልተመሳሰለ መልኩ (Asynchronously) ለማመንጨት (ማለት በአንድ ጊዜ ከአንድ በላይ የሆነ ቀላቢን ለማመንጨት) የመሳሰሉትን ነገሮች ለማድረግ አንድ የዳራ ስራ ( Background Job) የተባለ አሰራርን መጠቀም ይኖርባችኋል። እንደዚህ ዓይነቶቹን ረቂቅ የሚዛን (የመቀልጠፍ) ሳንካዎች፣ ተግባራዊ የማድረጉ ጉዳይ፣ ሙሉ በሙሉ ከዚህ ስልጠና ወሰን ውጪ ነው፤ ነገር ግን እናንተ ካዳበራችሁት ሙያዊ ክህሎት ጋር፣ የሚቀጥለውን እርምጃ ለመውሰድ በጣም ጥሩ የሆነ አቋም ላይ ናችሁ።

ዝርዝር 14.49 ላይ ካለው ኮድ ጋር፣ የሁኔታ ቀላቢያችን አሁን ተጠናቋል፡፡ (ይህንን ለማሻሻል የተደረገውን አንድ ጪማሬ ለማየት በክፍል 14.3.3.1 ውስጥ ያሉትን መልመጃዎች ተመልከቱ፡፡) ክፍል 13.3.3 ላይ የመነሻ ገጹ፣ ቀድሞውኑ ቀላቢውን ያካተተ እንደነበር አስታውሱ። በምዕራፍ 13 ላይ ውጤቱ አንድ ቀደምት-ቀላቢ (አጪርጽሑፎችን በዝርዝር ማሳየት) ብቻ ነበር (ምስል 13.14)፣ በምስል 14.23 ላይ እንደሚታየው፣ ግን በዝርዝር 14.49 ትግበራ ምክንያት የመነሻ ገጹ አሁን የተሟላውን ቀላቢ ያሳያል፡፡

images/figures/home_page_with_feed
ምስል 14.23: የመነሻ ገጹ ከአንድ የሚሰራ የሁኔታ ቀላቢ ጋር።

በዚህ ጊዜ ለውጦቻችንን ወደ ዋናው ቅርንጫፍ ለማዋሃድ ዝግጁ ነን:-

$ rails test
$ git add -A
$ git commit -m "የተጠቃሚ መከተያን ማከል"
$ git checkout main
$ git merge ተጠቃሚዎችን-መከተል

ከዚያም ኮዱን ወደ ሩቁ ማከማቻ በመግፋት አፕልኬሽኑን ወደ ምርት ማሰማራት እንችላለን:-

$ git push
$ git push heroku
$ heroku pg:reset DATABASE
$ heroku run rails db:migrate
$ heroku run rails db:seed

የተገኘው ውጤት፣ በቀጥታ ድር ላይ የሚሰራ አንድ የሁኔታ ቀላቢ ነው (ምስል 14.24)፡፡ (አንድ ብጁ ግዝአትን በመጠቀም፣ ጣቢያችሁን በሃረኩ ድር ላይ እንዴት ማስተናገድ እንደምትችሉ ለማወቅ፣ ማለት ስለዚህ ጉዳይ የነጻ ትምህርት ለማግኘት፣ በብጁ ግዝአት ላይ መሰረታዊ እውቀትን ለማግኘት የሚያስፈልገውን ተማርን ጎብኙ፡፡)

images/figures/live_status_feed
ምስል 14.24: አንድ በቀጥታ ድር ላይ የሚሰራ የሁኔታ ቀላቢ።

መልመጃዎች

የሬይልስ ስልጠናን ለገዙ ሰወች በሙሉ የሁሉም የመልመጃ መልሶች እዚህ ላይ ይገኛሉ።

የሌሎች ሰዎች መልሶችን ለማየት እና የራሳችሁን ደግሞ ለመመዝገብ፣ በሬይልስ ስልጠና ወይም ሁሉንም በበቂ ተማር መድረሻ ጥቅል ላይ ተመዝገቡ፡፡

  1. የቀላቢው የመጀመሪያ ገጽ፣ እንደሚገባ በመነሻ ገጹ ላይ መታየቱን ለማረጋገጥ፣ አንድ የውህደት ፈተና ጻፉ፡፡ ለዚህ ስራ የሚያገለግል አንድ አብነት፣ በዝርዝር 14.51 ውስጥ ቀርቧል። እንደተለመደው ይህን_ሙሉ በሚለው ምትክ፣ የራሳችሁን ኮድ ማስገባት ይጠበቅባችኋል፡፡
  2. ዝርዝር 14.51 የ‘ሲጅሲ.አምልጥሃ.ጽ.መ.ቋ (CGI.escapeHTML) ዘዴን በመጠቀም፣ ከተጠበቀው ሃ.ጽ.መ.ቋ እንዳመለጠ ልብ ልትሉ ይገባል( ይህም በክፍል 11.2.3 ውስጥ ዓ.አ.ሃ.አዎችን ለማስመለጥ ከተጠቀምንበት ከ‘ሲጅሲ.አምልጥ (CGI.escape) ዘዴ ጋር በጣም የተዛመደ ነው።) እዚህ ላይ ሃ.ጽ.መ.ቋውን ማስመለጥ ለምን አስፈለገ? ጠቃሚ ምክር:- ማስመለጫውን ከፈተናው አስወግዱ እና ከዚያ የማይዛመደውን የአጪርጽሑፍ ይዘት በገጹ ምንጪ ላይ በጥንቃቄ ለመመርመር ሞክሩ፡፡ የመናኸሪያ ቀፎ ላይ ቃላትን የመፈለጊያ ገጸባህሪን ማለት “ተቆር-ኤፍን (Ctrl-F)” ወይም “ትእዝ-ኤፍን (Cmd-F)” በመጠቀም፣ “sorry” የሚለውን ቃል መፈለጉ በጣም ጠቃሚ ሊሆን ይችላል።
  3. ዝርዝር 14.47 ውስጥ ያለው ኮድ፣ በሬይልስ የግራ ውጫዊ ዓገናኝ (left outer join) ተብየውን፣ የ‘የግራ ውጫዊ ዓገናኝ (left_outer_joins) ዘዴን በመጠቀም፣ ይህንን በሬይልስ ውስጥ በቀጥታ መግለጽ ይችላል፡፡ ፈተናዎቹን በማስኬድ፣ በዝርዝር 14.52 ውስጥ ያለው ኮድ፣ አንድ የሚያልፍ ቀላቢን እንደሚመልስ አረጋግጡ።17 አለመታደል ሆኖ፣ እውነተኛው ቀላቢ፣ የተጠቃሚውን ማለት የራሱ የሆኑ የተባዙ የአጪርጽሑፎች ቅጂዎችን ይይዛል (ምስል 14.25)፤18 ስለሆነም ይህንን ስህተት ለመያዝ፣ (በአንድ ክምችት ውስጥ፣ የተለዩ አባላቶችን የሚመልሰውን የ‘የተለየ (distinct) ዘዴን ለመጠቀም) በዝርዝር 14.53 ውስጥ የሚገኘውን ፈተና ተጠቀሙ። ከዚያ የ‘የተለየ (distinct) ዘዴን (ዝርዝር 14.54) በመጠይቁ ላይ መጨመሩ፣ አንድ አረንጓዴ ፈተናን እንደሚያስገኝ አሳዩ፡፡ በዚህ የመነጨውን ተ.መ.ቋ በቀጥታ በመመርመር፣ የተለየ (DISTINCT) የሚለው ቃል፣ በራሱ ማለት በመጠይቁ ውስጥ መገኘቱን አረጋግጡ፤ ይህም የተለዩት አባላቶች፣ ከአፕልኬሽናችን ማህደረ-ትውስታ ላይ ከመመረጣቸው ይልቅ፣ በውሂበጎታው ውስጥ ብቃታዊ በሆነ መንገድ የተመረጡ መሆናቸውን ያመለክታል። (ጠቃሚ ምክር:- ተ.መ.ቋውን ለማግኘት ተጠቃሚ.አንደኛ.ቀላቢ‘ን (Teteqami.first.qelabi) በሬይልስ ሰሌዳ ውስጥ አስኪዱ።)
ዝርዝር 14.51: የቀላቢውን ሃ.ጽ.መ.ቋ መፈተን። አረንጓዴ test/integration/miketelachew_test.rb
require "test_helper"

class MiketelachewTest < ActionDispatch::IntegrationTest

  def setup
    @teteqami = teteqamis(:michael)
    @lela = teteqamis(:ermias)
    gba_ende(@teteqami)
  end
  .
  .
  .
  test "የቀላቢው የመጀመሪያ ገጽ በመነሻ ገጹ ላይ መታየት አለበት" do
    get root_path
    @teteqami.qelabi.paginate(page: 1).each do |achrtshuf|
      assert_match CGI.escapeHTML(ይህን_ሙሉ), ይህን_ሙሉ
    end
  end
end
ዝርዝር 14.52: አንድ ቀላቢን ለመስራት አንድ የ‘ዓገናኝ (join) ዘዴን መጠቀም፡፡ app/models/teteqami.rb
class Teteqami < ApplicationRecord
  .
  .
  .
  # የአንድ ተጠቃሚ ሁኔታ ቀላቢን ይመልሳል።
  def qelabi
    yeqelabi_kfl = "tssrs.teketay_id = :id or achrtshufs.teteqami_id = :id"
    Achrtshuf.left_outer_joins(teteqami: :teketayoch)
               .where(yeqelabi_kfl, { id: id })
               .includes(:teteqami, msl_attachment: :blob)
  end
  .
  .
  .
end
images/figures/repeated_feed_items
ምስል 14.25: በቀላቢው ውስጥ የተደጋገሙ አጪርጽሑፎች።
ዝርዝር 14.53: የተደጋገሙ የቀላቢ አጪርጽሑፎችን ለመያዝ፣ አንድ ፈተናን መጻፍ። ቀይ app/tests/teteqami_test.rb
require 'test_helper'

class TeteqamiTest < ActiveSupport::TestCase
  .
  .
  .
  test "ቀላቢ ትክክለኛ ቅምጦች ሊኖሩት ይገባል" do
    michael = teteqamis(:michael)
    ermias  = teteqamis(:ermias)
    gerie   = teteqamis(:gerie)
    # ከተከተሉት ተጠቃሚ የተቀመጡ ቅምጦች
    gerie.achrtshufs.each do |keteketelut_qmt|
      assert michael.qelabi.include?(keteketelut_qmt)
    end
    # በራስ የተቀመጡ ቅምጦች ከተከታዮች ጋር
    michael.achrtshufs.each do |yeras_qmt|
      assert michael.qelabi.include?(yeras_qmt)
      assert_equal michael.qelabi.distinct, michael.qelabi
    end
    # ምንም ተከታዮች ከለለው ተጠቃሚ የተቀመጡ ቅምጦች
    ermias.achrtshufs.each do |yeras_qmt|
      assert ermias.qelabi.include?(yeras_qmt)
    end
    # ከማይከተሉት ተጠቃሚ የተቀመጡ ቅምጦች
    ermias.achrtshufs.each do |kemiketelut_qmt|
      assert_not michael.qelabi.include?(kemiketelut_qmt)
    end
  end
end
ዝርዝር 14.54: ድግግሞሹ የተወገደ የሁኔታ ቀላቢ። አረንጓዴ app/models/teteqami.rb
class Teteqami < ApplicationRecord
  .
  .
  .
  # የአንድ ተጠቃሚ ሁኔታ ቀላቢን ይመልሳል።
  def qelabi
    yeqelabi_kfl = "tssrs.teketay_id = :id or achrtshufs.teteqami_id = :id"
    Achrtshuf.left_outer_joins(teteqami: :teketayoch)
           .where(yeqelabi_kfl, { id: id }).distinct
           .includes(:teteqami, msl_attachment: :blob)
  end
  .
  .
  .
end

14.4 ማጠቃለያ

የሁኔታ ቀላቢውን በማከል፣ የሩቢ ኦን ሬይልስ ስልጠና የማሳያ አፕልኬሽንን እዚህ ላይ አጠናቀናል፡፡ ይህ አፕልኬሽን ሁሉንም የሬይልስ መሰረታዊ ባህርያት ማለት የቅርጸቶች፣ የትይታዎች፣ የመቆጣጠሪያዎች፣ የዝግጁገጽታዎች፣ የከፊሎች፣ የማጣሪያወች፣ የማረጋገጫወች፣ የመልሰጥሪዎች፣ የ‘ብዙ_አለው (has_many) / ባለቤት_ነው (belongs_to) እና የ‘ብዙ_አለው በኩል (has_many :through) ማሕበሮች፣ የጥበቃ፣ የመፈተን እና የማሰማራት ምሳሌዎችን ያካተቱ ባህርያት አሉበት፡፡

ከእነዚህ አስደናቂ ዝርዝሮች ባሻገር፣ አሁንም ስለ ድር ብልጸጋ ብዙ መማር የሚያስፈልጉ ነገሮች አሉ፡፡ በዚህ ሂደት ውስጥ ልክ እንደ አንድ የመጀመሪያ እርምጃ ይቆጠር ዘንድ፣ ይህ ክፍል በዚሁ አምድ ላይ ተጨማሪ ትምህርትን ለመማር የሚያግዙ በርካታ መንገዶችን ይጠቁማል፡፡

14.4.1 የሬይልስ ዕውቀትን የሚያሰፉ ተጨማሪ ምንጮች

በመጽሐፍት ቤቶች እና በድር ላይ፣ ብዙ የሬይልስ መማሪያ ምንጮች አሉ፤ በእርግጥ፣ እጅግ ከመብዛታቸው የተነሳ ለመምረጥ ግራ ያጋባሉ። መልካሙ ዜና ግን፣ እናንተ ይህንን ያህል ከተማራችሁ በኋላ፣ እዛ ለምታገኙዋቸው ነገሮች ሁሉ፣ እናንተ ቀድሞውኑ ብቁ መሆናችሁ ነው፡፡ ከዚህ ቀጥሎ አንዳንድ ተጨማሪ ትምህርትን ለመማር የሚያግዙ ጥቆማዎችን ጀባ እላችኋለሁ:-

  • የሁሉም የበቂ ተማር መዳረሻ ጥቅል:- የሩቢ ኦን ሬይልስ ስልጠና ላይ በመመርኮዝ፣ ይህንኑ ስልጠና የበለጠ ግልጽ የሚደርግ፣ ማለት በተለያዩ ስልቶች የተሞላ፣ ከ 15 ሰዓት በላይ የሚሆን የቪዲዮ ትምህርትን የያዘ፣ እና አንድ መጽሐፍን በማንበብ ልታገኟቸው የማትችሏቸውን ጠቃሚ ምክሮችን እና ነገሮች እንዴት መሰራት እንዳለባቸው በቀጥታ የሚያሳይ ሂደትን ያካተተ፣ የተወሰነ ገንዘብ በማስከፈል አገልግሎት የሚሰጥ ድርጅት ነው፡፡ በቂ ተማር ለተባሉት ስልጠናዎችም፣ በጽሑፍ እና በቪድዮ የተደገፉ ትምህርቶችንም ይሰጣል። የነጻ ትምህርት ዕድልንም ይሰጣል።
  • ላውንች ትምህርት ቤት:- ከቅርብ ዓመታት ወዲህ በመስመር ላይ ብቻ ሳይሆን፣ በአካል ሳይቀር ብዙ የጦር-ሰፈር (Bootcamp) አበልጻጊወች ብቅ ብለዋል፤19 ስለዚህ በምትኖሩበት አካባቢ አንድ የጦር-ሰፈር እንድትፈልጉ እና እንድትሰለጥኑ እመክራለሁ፤ የላውንች ትምህርት ቤት ስልጠና በመስመር ላይ ብቻ የሚሰጥ ስልጠና ነው፤ ስለሆነም የትም ቦታ ሆኖ ሊወሰድ ይችላል። በተለይ በአንድ በተዋቀረ የትምህርት መርሃግብር አንጻር፣ የአስተማሪ ግብረመልስን የምትፈልጉ ከሆነ፣ ላውንች ትምህርት ቤት፣ በጣም ጥሩ አማራጪ ይሆናል።
  • ተሪንግ የሶፍትዌር እና ዲዛይን ትምህርት ቤት:- በዴንቨር ኮሎራዶ ውስጥ፣ በየቀኑ ለ 27 ሳምንት የሩቢ፣ የሬይልስ እና የጃቫስክሪፕት ስልጠናወችን የሚሰጥ ድርጅት ነው። አብዛኛዎቹ ተማሪዎቻቸው ምንም ዓይነት ፕሮግራም የማድረግ ልምድ የሌላቸው ቢሆኑም፣ የሚሰጣቸውን ስልጠና በትክክል ለመከታተል ቁርጥ ውሳኔ እንዲኖራቸው ግን ይጠይቃል፡፡ ስለሆነም፣ የተሪንግ ትምህርት ቤት፣ ተማሪዎቹ ከተመረቁ በኋላ ስራ እንደሚያስቀጥራቸው እና ስራ ካላስቀጠራቸው ደግሞ ለመማር የከፈለቱን ገንዘብ እንደሚመልስላቸው ሙሉ ዋስትናን ይሰጣቸዋል።
  • ብሎክ:- ከአንድ የተዋቀረ የትምህርት መርሃግብር ጋር የግል አማካሪወችን የሚያቀርብ እና ተጨባጪ በሆኑ ፕሮጄክቶች ላይ በመማር የሚያተኩሩ ስልጠናወችን የሚሰጥ፣ የመስመር ላይ የጦር-ሰፈር ነው፡፡ ከምዝገባ ክፍያ $500 ዶላር ቅናሽ ታገኙ ዘንድ፣ ይህንን BLOCLOVESHARTL ኩፖን እንድትጠቀሙ እመክራችኋለሁ።
  • ቲንክፉል:- አንድ ፕሮጀክት ላይ የተመሰረተ ትምህርትን በምትማሩበት ወቅት፣ እናንተን ከአንድ ባለሞያ መሐንዲስ ጋር በመስመር ላይ በማገናኘት አገልግሎት የሚሰጥ ድርጅት ነው፡፡ የሚሰጣቸው ትምህርቶችም ሩቢ ኦንሬይልስ፣ የግንባር-ገጽ ብልጸጋ፣ የድር ነደፋን እና የውሂብ ሳይንስን ያጠቃልላል።
  • ፕራግማቲክ ስቱዲዮ:- በማይክ እና በኒኮል ክላርክ የተዘጋጀ የሩቢ ኦንሬይልስ ስልጠናወችን በመስመር ላይ የሚሰጥ ድርጅት ነው፡፡
  • ሬይልስአፕስ:- አስተማሪ የሆኑ የሬይልስ አፕልኬሽኖችን በጽሑፍ እና በቪድዮ የሚያቀርብ ድርጅት ነው፡፡
  • ላምዳ ትምህርት ቤት:- አንድ ሰው ከፍተኛ ደሞዝ የሚያስከፍል ስራ ካገኘ ብቻ የተማረበትን ክፍያ የሚያስከፍል፣ ሙሉ-ቀን የላቀ ፕሮግራምን በመስመር ላይ የሚያስተምር ድርጅት ነው፡፡

14.4.2 በዚህ ምዕራፍ ውስጥ የተማርናቸው ነገሮች:-

  • የሬይልስ ብዙ_አለው በኩል (has_many :through) የተወሳሰቡ የውሂብ ትስስሮችን መቅረጽን እንደሚፈቅድ፣
  • የ‘ብዙ_አለው (has_many) ዘዴ የቁሱን የክፍል ስም እና የውጪ ቁልፉን ጨምሮ፣ በርካታ የነጋሪአሴት አማራጮችን እንደሚወስድ፣
  • በትክክል ከተመረጡ ከክፍል ስም እና ከውጪ ቁልፎች ጋር፣ ብዙ_አለው‘ን (has_many) እና ብዙ_አለው በኩል‘ን (has_many :through) በመጠቀም፣ የንቅ (የሚከተላቸው) እና የያልተካፈለ (የተከታዮች) ትስስሮችን መቅረጽ እንደምንችል፣
  • የሬይልስ ማዘዋወሪያ እቅፍቅፍ ማዘዋወሪያወችን እንደሚደግፍ፣
  • የ‘የት (where) ዘዴ የውሂበጎታ መጠይቆችን ለመፍጠር እንደልብ የሚገራ እና ሃይለኛ መንገድ መሆኑን፣
  • አስፈላጊ ሆኖ ከተገኘ፣ ሬይልስ በጣም ውስብስብ ያልሆኑ የተ.መ.ቋ መጠይቆችን መስጠትን እንደሚደግፍ፣
  • በሬይልስ ውስጥ በጉጉት ጫኝን ለመተግበር የ‘አክል (includes) ዘዴን በመጠቀም፣ የ \( ሀ+1 \) መጠይቅ ችግርን መፍታት እንደምንችል እና
  • በዚህ መጽሐፍ ውስጥ የተማርናቸውን ነገሮች ሁሉ ተግባር ላይ በማዋል፣ ተጠቃሚ የሚከተላቸውን፣ ከአንድ የተከታይ ተጠቃሚዎች የአጪርጽሑፎች ቀላቢ ጋር በተሳካ ሁኔታ ተግባራዊ ማድረጋችንን ተምረናል።
1. የሰውየው ምስል በ 2021-06-19 ከ https://www.facebook.com/photo?fbid=135172889876395set=pob.100001510558046 በወንድሙ ፍቃድ የተወሰደ ነው፡፡ በጆን ለስቲን የ 2008 የቅጂ መብት © እና የጋራ የፈጠራ አጠቃላይ ዋለዮ 2.0 ፈቃድ መሰረት ስእሉ ላይ ለውጥ አልተደረገም። የሴትዮዋ ምስል ከ 2021-06-19 ከ https://www.facebook.com/profile.php?id=100009633824167 በባለቤቷ ፍቃድ የተወሰደ ነው፡፡ በሬኔ ሜሰን የ 2013 የቅጂ መብት © እና የጋራ የፈጠራ አጠቃላይ ዋለዮ 2.0 ፈቃድ መሰረት ስእሉ ላይ ለውጥ አልተደረገም።
2. ነገሮችን ቀለል ለማድረግ ሲባል ምስል 14.6 የ‘ሚከተላቸው (miketelachew) ሰንጠረዥ የ‘መታወቂያ (id) አምዱን አጥፍቶታል፡፡
3. ይህንን ሃሳብ ላካፈሉት ክቡር አንባቢ ፖል ፊዮራቫንቲን ከልብ አመሰግናለሁ፡፡
4. በቴክኒካዊ መልኩ ሲታይ፣ ሬይልስ መዳቢ (classify) የተባለውን ዘዴ በመጠቀም፣ የ‘ብዙ_አለው (has_many) ነጋሪአሴትን ወደ አንድ የክፍል ስም ይቀይረዋል፤ ይህ ማለት "tedi_mihretn" ‘ን ወደ "TediMihret" ይቀይረዋል ማለት ነው፡፡
5. በቴክኒካዊ መልኩ ሲታይ፣ ሬይልስ የክፍል ስሙን ወደ መታወቂያ (id) ለመቀየር የታች-ሰረዝ (underscore) ዘዴን ይጠቀማል፤ ለምሳሌ የዚህ:- "MentaKeremela".underscore መታወቂያ (id) ይሄ:- menta_keremela_id ነው። ስለዚህ የ MentaKeremela ቁስ፣ የውጪ ቁልፍ menta_keremela_id ይሆናል ማለት ነው፡፡
6. መልሱ፣ በዝርዝር 6.30 ውስጥ የመነጩት እቃወች ማረጋገጫውን ስለማያሟሉ ሲሆን፣ ይህም ፈተናዎቹ እንዳይሳኩ ያደርጋቸዋል፡፡
7. መገልገያ (Utility) ዘዴ ማለት፣ መደበኛ የፕሮግራም ስራዎችን ለማከናወን ጠቃሚ የሆነ፣ በተደጋጋሚ የሚደረግ የፕሮግራም ስራን ለመፈጸም የሚያስችል፣ በድጋሜ ሊጠቀሙበት የሚችሉ ዘዴ/ፕሮግራም ማለት ነው
8. አንድ ጊዜ፣ አንዳንድ ትልሞችን በመቅረጽ ብዙ ተሞክሮ ካገኛችሁ፣ እንደዚህ ዓይነት የመገልገያ ዘዴወችን መስራት እንደሚኖርባችሁ፣ ቀደም ብላችሁ መገመት ትችላላችሁ፤ መገመት ባችሉም እንኳ፣ ፈተናዎችን የበለጠ ንጹህ ለማድግ ብዙውን ጊዜ እነደነዚህ ዓይነት የመገልገያ ዘዴወችን እንድትጽፉ ያደርጋችኋል። በዚህ ሁኔታ ላይ እናንተ እነዚህን ነገሮች መገመት ካልቻላችሁ፣ ምንም ችግር የለውም፡፡ ሶፍትዌርን የማበልጸግ ስራ፣ ብዙውን ጊዜ ተደጋጋሚ የሆነ ሂደት ነው፣ ኮዱ አስቀያሚ እስኪሆን ድረስ ኮዱን ትጽፋላችሁ፣ ከዚያ ታጣሩታላችሁ፣ ነገር ግን ስራውን ቀለል ለማድረግ የስልጠናው አቀራረብ ትንሽ የተጣራ ነው።
9. ተጠቃሚዎች እራሳቸውን መከተል መቻል እንደሌለባቸው በመጠቆማቸው ክቡር አንባቢ ሱዳይ አቸ ኤዞይሎ‘ን ከልብ አመሰግናለሁ።
10. በእንደነዚህ ያሉ ማዘዋወሪያወች ላይ ተጨማሪ መረጃዎችን ለማግኘት “የሬይልስ ከውጪ ወደ ውስጥ ማዛወሪያ” የሚለውን የሬይልስ መመሪያ መጣጥፍን ተመልከቱ፡፡
11. በፕሮግሚንግ ውስጥ፣ ግልጽ (Implicit) ማለት፣ እናንተ ሳታዩት ለናንተ ጥቅም እንዲሰጥ ተብሎ የተጻፈ ኮድ፣ ማለት ሲሆን፤ ያልተገለጸ (Explicit) ማለት ደግሞ፣ ለናንተ የተጻፈውን ኮድ፣ እናንተ በምትፈልጉት መልክ መቀየር እና መጠቀም ማለት ነው)።
12. ያልተመሳሰለ (asynchronous) ማለት በአንድ ጊዜ ከአንድ በላይ የሆነ ሂደትን ማካሄድ ማለት ሲሆን፡ የተመሳሰለ (synchronous) ማለት ደግሞ በአንጻሩ በአንድ ጊዜ አንድ ሂደትን ማካሄድ ማለት ነው
13. ምንም እንኳ ዋናው የኤጃክስ መጣጥፍ ላይ፣ ከግር እስከራሱ “Ajax” ብሎ ቢጽፈውም፣ Ajax የ asynchronous JavaScript and XML እና የ XML የቃል መነሻ ስብስብ ስለሆነ፣ አንዳንድ ጊዜ “AJAX” ተብሎ በተሳሳተ መንገድ ሲጻፍ ይስተዋላል።
14. ኤክሰኤምሌል ሃ.ጽ.ማ.ስ፣ (xhr XmlHttpRequest) ዘዴዎቹ በድር አሳሽ እና በድር አገልጋይ መካከል፣ ውሂቦችን ልክ እንደ አንድ ቁስ የሚያስተላልፉበት አንድ አ.ፕ.በ ነው፡፡
15. ዋናው መስፈርት ተቆጣሪ ቁሶች በክምችቱ በኩል ለመደጋገም አንድ የ‘እያንዳንዳቸው (each) ዘዴን መተግበር ይኖርባቸዋል፡፡
16. (ቁርጥራጪ (snippet) ማለት፤ ትንሽ ቦታ ላይ በተደጋጋሚ ሊያገለግል የሚችል ኮድ ማለት ነው)
17. ይህንን ሃሳብ ላካፈሉት ክቡር አንባቢ አና እና በመጀመሪያው ተ.መ.ቋ ላይ የለ አንድ ስህተትን ስለጠቆሙኝ፣ ክቡር አንባቢ አንድሪው ሜድን ከልብ አመሰግናለሁ፡፡
18. ይህንን ችግር ፈልገው በማግኘት እና የችግሩንም መፍትሄ በማበርከታቸው፣ ክቡር ብሪታኒ ሉቪዬርን ከልብ ላመሰግናቸው እወዳለሁ፡፡
19. የጦር-ሰፈር (Bootcamp) ማለት ውትድርናን በተመለከተ፣ የተለያዩ ዓይነት ሙያዎችን መማርያ ሰፈር ማለት ሲሆን፤ እዚህ ላይ ያለው የቃሉ ይዞታ በኮምፕዩተር ሳይንስ ላይ የተደገፉ ሙያዎችን ያንጸባርቃል።