ምዕራፍ 13 የተጠቃሚ አጪርጽሑፎች

ዋናውን የማሳያ አፕልኬሽን በማበልጸግ ሂደት ውስጥ፣ እስከ አሁን ድረስ አራት ሃብቶችን ማለት የተጠቃሚዎች፣ የክፍለጊዜዎች፣ የመለያ ማግበርያዎች እና የመሕለፈቃል ዳግም ማስጀመርያዎች ሃብቶችን አግኝተናል፣ ነገር ግን ከእነዚህ ሁሉ የመጀመሪያው ብቻ አንድ በንቅ መዝገብ ቅርጸት የተደገፈ አንድ የውሂበጎታ ሰንጠረዥ አለው። አሁን ከመጀመሪያው ሃብት ጋር አንድ አይነት የሆነ አንድ ሃብትን ወደ አፕልኬሽናችን የምናክልበት የመጨረሻው ጊዜ መጥቷል፤ እሱም የተጠቃሚ አጪርጽሑፎች ይባላል፣ እነዚህ የተጠቃሚ፣ አጪርጽሑፎችም፣ ከአንድ የተወሰነ ተጠቃሚ ጋር የተዛመዱ አጫጪር መልዕክቶች ናቸው።1 ለመጀመሪያ ጊዜ በምዕራፍ 2 ውስጥ አጪርጽሑፎችን ገና እንጪጪ እያሉ የተመለከትን ሲሆን፣ በዚህ ምዕራፍ ውስጥ ግን የአጪርጽሑፍ የውሂብ ቅድን በመገንባት፣ ብዙ_አለው (has_many) እና ባለቤት_ነው (belongs_to) ነው የተባሉ ዘዴወችን ተጠቅመን፣ ከተጠቃሚ ቅርጸቱ ጋር በማዛመድ በክፍል 2.3 ላይ የተነደፉትን እንጪጪ አጪርጽሑፎች ወደ ተሟላ ንድፍ እንቀይራቸዋለን፣ ከዚያ ውጤቶቹን ለማንቀሳቀስ እና ለማሳየት የሚያስፈልጉትን ቅጾች እና ከፊሎች እንሰራለን (እንዲሁም በክፍል 13.4 ላይ የምስሎች ሰቀላን እናካትታለን)፡፡ በምዕራፍ 14 ላይ፣ የነሱን አንድ የአጪርጽሑፎች ቀላቢ ይቀበሉ ዘንድ፣ ተጠቃሚዎችን የመከተል ሃሳብን በማከል ትንሿን የትዊተር መንትያችንን እናጠናቅቃለን።

13.1 የአጪርጽሑፍ ቅርጸት

የአጪርጽሑፎችን አስፈላጊ ባህሪያት የሚይዝ አንድ የአጪርጽሑፍ ቅርጸትን በመፍጠር፣ የአጪርጽሑፎች ሃብትን እንጀምራለን፡፡ ልክ በክፍል 2.3 ላይ እንደገነባነው ቅርጸት፣ አዲሱ የአጪርጽሑፍ ቅርጸታችን የውሂብ ማረጋገጫዎችን እና ከተጠቃሚ ቅርጸቱ ጋር ህብረትን የሚፈጥር አንድ ማሕበርን ያካትታል፡፡ ከእዚያ ቅርጸት በተለየ መልኩ፣ የአሁኑ የአጪርጽሑፍ ቅርጸት ሙሉ በሙሉ የፈተናል፤ እንዲሁም አንድ ነባሪ ቅደም ተከተል እና የነሱ ወላጅ ተጠቃሚ ከተደመሰሰ፣ የቲሞቹን በራስሰር የሚያጠፋ ባህሪ ይኖረዋል።

ጊትን ለስሪት ቁጥጥር እየተጠቀማችሁ ከሆነ፣ በዚህ ጊዜ አንድ የርእስ ቅርንጫፍ እንድትፈጥሩ ሃሳቤን አቀርባለሁ:-

$ git checkout -b የተጠቃሚ-አጪርጽሑፎች

13.1.1 መሰረታዊው ቅርጸት

የአጪርጽሑፍ ቅርጸቱ ሁለት ባሕሪያዎችን ብቻ ይፈልጋል፣ እነሱም የአጪርጽሑፍ ይዘቱን የሚይዝ አንድ ይዘት (yizet) የተባለ ባሕሪ እና አንድ አጪርጽሑፍን ከአንድ የተወሰነ ተጠቃሚ ጋር ለማገናኘት የሚያገለግል አንድ የ‘ተጠቃሚ_መታወቂያ (teteqami_id) የተባለ ባሕሪዎች ናቸው። ይህን በአንድ ላይ የመቋጨቱ ውጤት በምስል 13.1 ላይ የሚታየውን አንድ የአጪርጽሑፍ ቅርጸትን ከመዋቅሩ ጋር ይሰጣል፡፡

images/figures/micropost_model
ምስል 13.1: የአጪርጽሑፍ የውሂብ ቅድ።

ምስል 13.1 ውስጥ ያለው የውሂብ ቅርጸት ለአጪርጽሑፍ ይዞታ በ‘ሃረግ (string) ፈንታ የ‘ጽሑፍ (text) የውሂብ ዓይነትን እንደሚጠቀም ማስተዋሉ ተገቢ ነው፣ ይህም ወሰን የለሽ ጽሑፍን ማከማቸት ይችላል፡፡ ምንም እንኳ የአጪርጽሑፍ ይዘቱ ከ 140 ሆሄወች ያነሰ እንዲሆን ቢደረግም (ክፍል 13.1.2) እናም 255 ሆሄወችን በሚይዘው የ‘ሃረግ (string) ውሂብ ውስጥ ማከማቸት ቢቻልም፣ የ‘ጽሑፍ (text) የውሂብ ዓይነትን መጠቀሙ ግን የአጪርጽሑፎችን ባህሪ በተሻለ ሁኔታ ይገልጻል፣ አጪርጽሑፎቹም በተፈጥሮ ልክ እንደ ጽሑፍ ጥምሮች ተደርገው ይታሰባሉ። በእርግጥ፣ በክፍል 13.3.2 ውስጥ አጪርጽሑፎችን ለማስረከብ ከአንድ መስክ ይልቅ አንድ የጽሑፍ ቦታን እንጠቀማለን፡፡ በተጨማሪም፣ የ‘ጽሑፍ (text) የውሂብ ዓይነትን መጠቀሙ፣ ለወደፊቱ የአጪርጽሑፉን የእርዝመት ገደብ መጨመር ብንፈልግ፣ ልባችን የፈቀደውን እንድናደርግ እድሉን ይሰጠናል (ለምሳሌ:- ይህንኑ አፕልኬሽን የተለያዩ ቛንቛወችን እንዲደግፍ ከተፈለገ እንዲሁ ማድረግ ይቻላል)። በመጨረሻም፣ በምርት ወቅት በአፕልኬሽናችን ላይ የጽሑፍ (text) የውሂብ ዓይነትን መጠቀሙ፣ በአፕልኬሽናችን አሰራር ላይ ምንም ልዩነት አያመጣም፣ ስለሆነም እሱን እዚህ ላይ በመጠቀማችን ምክንያት ምንም የምንከስረው ነገር የለም ማለት ነው፡፡2

ልክ የተጠቃሚ ቅርጸትን (ዝርዝር 6.1) ለማመንጨት የቅርጸት-አመንጪ (generate model) ትእዛዝን እንደተጠቀምን ሁሉ፣ የአጪርጽሑፍ ቅርጸቱን ለማመንጨትም ይህንኑ ትእዛዝ እንጠቀማለን (ዝርዝር 13.1)።

ዝርዝር 13.1: የአጪርጽሑፍ ቅርጸቱን ማመንጨት።
$ rails generate model Achrtshuf yizet:text teteqami:references

ይህ ፍልሰት በዝርዝር 13.2 ላይ ለተመለከተው የአጪርጽሑፍ ቅርጸት መፈጠር ምክንያት ሆኗል፡፡ እንደተለመደው ከ‘አፕልኬሽንመዝገብ (ApplicationRecord) ውርስ በተጨማሪ (ክፍል 6.1.2)፣ የመነጨው ቅርጸት፣ ተጠቃሚው የአጪርጽሑፉ ባለቤት መሆኑን የሚያመለክት አንድ ባለቤት_ነው (belongs_to) የተባለ ዘዴን ያካትታል፣ ይህም በዝርዝር 13.1 ውስጥ ባለው በ‘ተጠቃሚን:ያጣቅሳል (teteqami:references) ነጋሪአሴት ምክንያት የተካተተ ነው፡፡ የዚህን ኮድ አንድምታ በክፍል 13.1.3 ላይ እንቃኛለን፡፡

ዝርዝር 13.2: የመነጨው የአጪርጽሑፍ ቅርጸት፡፡ app/models/achrtshuf.rb
class Achrtshuf < ApplicationRecord
  belongs_to :teteqami
end

ዝርዝር 13.1 ውስጥ ያለው የ‘አመንጪ (generate) ትእዛዝ በውሂበጎታው ውስጥ አንድ የ‘አጪርጽሑፎች (achrtshufs) ሰንጠረዥን ለመፍጠር የሚያገለግል አንድ ፍልሰትን ይፈጥራል (ዝርዝር 13.3)፤ ይህንን ዝርዝር 6.2 ላይ ካለው የ‘ተጠቃሚዎች (teteqamis) ሰንጠረዥ ፍልሰት ጋር ብናነጻጽር አንድ የምናየው ትልቅ ልዩነት የ‘ማጣቀሻወች (references) ዘዴ አጠቃቀም ላይ ነው፤ ይህም በተጠቃሚ እና በአጪርጽሑፍ ማህበር ውስጥ ጥቅም ላይ የሚውል አንድ የ‘ተጠቃሚ-መታወቂያ (teteqami_id) ረድፍን (ከአንድ መረጃ-ጠቋሚ እና ከአንድ የውጪ ቁልፍ ማጣቀሻ3 ጋር) በውሂበጎታው ላይ በራስሰር ማከሉ ነው። ልክ እንደ Teteqami ቅርጸት ፍልሰት፣ የአጪርጽሑፎች (Achrtshufs) ቅርጸት ፍልሰትም (በክፍል 6.1.1 እንደተጠቀሰው) በምስል 13.1 ላይ የሚታየውን የተፈጠረ_በ (created_at) እና የተዘመነ_በ (updated_at) አስማታዊ ረድፎችን የሚያክለውን የሰንጠረዥ.ማህተመጊዜ (t.timestamps) ኮድን በራስሰር ያካትታል፡፡ (በክፍል 13.1.4 ላይ የ‘ተፈጠረ_በ (created_at) ረድፍን በስራ ላይ እናውለዋለን፡፡)

ዝርዝር 13.3: የአጪርጽሑፍ ፍልሰቱ ከታከለው የመረጃ-ጠቋሚ ጋር። db/migrate/[ማህተመጊዜ]_create_achrtshufs.rb
class CreateAchrtshufs < ActiveRecord::Migration[6.1]
  def change
    create_table :achrtshufs do |t|
      t.text :yizet
      t.references :teteqami, null: false, foreign_key: true

      t.timestamps
    end
    add_index :achrtshufs, [:teteqami_id, :created_at]
  end
end

ከአንድ ከተሰጠ የተጠቃሚ-መታወቂያ ጋር የተዛመዱትን ሁሉንም አጪርጽሑፎች በተገላቢጦሽ ቅደም ተከተል ፈልገን እናወጣለን ብለን ስለምንጠብቅ፣ ዝርዝር 13.3 በ‘ተጠቃሚ-መታወቂያ (teteqami_id) እና ተፈጠረ_በ (created_at) መስኮች ላይ አንድ የመረጃ-ጠቋሚን አክሏል (ሳጥን 6.2)፡፡

add_index :achrtshufs, [:teteqami_id, :created_at]

ሁለቱንም ማለት የ‘ተጠቃሚ_መታወቂያ‘ን (teteqami_id) እና የ‘ተፈጠረ_በ (created_at) መስኮችን ልክ እንደ እንደ ድርድር በማካተት፣ ሬይልስን በርካታ የመረጃ-ጠቋሚ ቁልፎችን እንዲፈጥር ማዘጋጀት እንችላለን፤ ይህ ማለትም ንቅ መዝገብ ሁለቱንም ቁልፎች በአንድ ጊዜ ይጠቀማል ማለት ነው፡፡

ዝርዝር 13.3 ውስጥ ባለው ፍልሰት፣ እንደተለመደው አድርገን ውሂበጎታውን ማዘመን እንችላለን:-

$ rails db:migrate

መልመጃዎች

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

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

  1. በሬይልስ ሰሌዳ ውስጥ የ‘አጪርጽሑፍ.አዲስ (Achrtshuf.new) ዘዴን በመጠቀም፣ አንድ አጪርጽሑፍ የተባለ አዲስ የአጪርጽሑፍ ቁስን ቀርጹ እና ይዘቱን በ “አሳ በልቶ ውሃ” እና የተጠቃሚ-መታወቂያውን ደግሞ ከውሂበጎታው ውስጥ ያለውን የመጀመሪያ ተጠቃሚ ዋጋን ስጡት። የ‘ተፈጠረ_በ (created_at) እና የ‘ተዘመነ_በ (updated_at) መስክ ዋጋወች ምንድናቸው?
  2. የላይኛውን ጥያቄ በተመለከተ፣ የ‘ አጪርጽሑፍ.teteqami እና የ‘ አጪርጽሑፍ.teteqami.sim ዋጋወች ምንድናቸው?
  3. አጪርጽሑፉን ውሂበጎታው ላይ አስቀምጡ፡፡ የአስማታዊ መስኮቹ ዋጋወች አሁን ምንድንነው?

13.1.2 የአጪርጽሑፍ ማረጋገጫወች

አሁን መሰረታዊውን ቅርጸት ፈጥረናል፣ የተፈለጉትን የእገዳ ንድፎች ለማስፈጸም፣ የተወሰኑ ማረጋገጫዎችን እንጨምራለን፡፡ በአጪርጽሑፍ ቅርጸቱ ውስጥ አስፈላጊ ከሆኑት ገጽታዎች ውስጥ አንዱ፣ የትኛው ተጠቃሚ አጪርጽሑፉን እንደፈጠረው ለማወቅ የሚያገለግለው፣ አንድ የተጠቃሚ-መታወቂያ መኖሩ ነው፡፡ ይህንን ስነአጻጻፉ/ስነአነጋገሩ ትክክለኛ በሆነ መንገድ ለመስራት በክፍል 13.1.3 ላይ ተግባራዊ የምናደርገውን የንቅ መዝገብ ማህበሮችን (Associations) በመጠቀም ይሆናል፣ አሁን ግን በ‘አጪርጽሑፍ (Achrtshuf) ቅርጸቱ ላይ በቀጥታ እንሰራለን።

የመጀመሪያወቹ የአጪርጽሑፉ ፈተናወች፣ ከተጠቃሚ ቅርጸት ፈተናወቹ ጋር ትይዩዎች ናቸው (ዝርዝር 6.7)፡፡ በ‘አዘጋጅ (setup) ዘዴ ውስጥ፣ አንድ አዲስ አጪርጽሑፍ በመፍጠር ከአንድ ብቁ የእቃ ተጠቃሚ ጋር እናዛምድ እና፣ ከዚያ ውጤቱ ብቁ መሆኑን እንፈትሻለን፡፡ እያንዳንዱ አጪርጽሑፍ የተጠቃሚ-መታወቂያ ሊኖረው ስለሚገባ፣ የ‘ተጠቃሚ_መታወቂያ (teteqami_id) መኖሩን ለማረጋገጥ፣ አንድ የመኖር ማረጋገጫ ፈተናን እናክላለን፡፡ እነዚህን ነገሮች በአንድ ላይ አሰባስቦ ማሰናዳቱ፣ በዝርዝር 13.4 ውስጥ ያለውን ፈተና ያስገኛል፡፡

ዝርዝር 13.4: የአንድ አዲስ አጪርጽሑፍ ብቃትን የሚያረጋግጡ ፈተናዎች። አረንጓዴ test/models/achrtshuf_test.rb
require "test_helper"

class AchrtshufTest < ActiveSupport::TestCase

  def setup
    @teteqami = teteqamis(:michael)
    # ይህ ኮድ በስነአጻጻፉ/በስነአነጋገሩ ትክክል አይደለም፡፡
    @achrtshuf = Achrtshuf.new(yizet: "አሳ በልቶ ውሃ", teteqami_id: @teteqami.id)
  end

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

  test "የተጠቃሚ-መታወቂያ መኖር አለበት" do
    @achrtshuf.teteqami_id = nil
    assert_not @achrtshuf.valid?
  end
end

በ‘አዘጋጅ (setup) ዘዴ ውስጥ ባለው አስተያየት ላይ እንደተመለከተው፣ አጪርጽሑፍን ለመፍጠር የተጠቀምንበት ኮድ ስነአጻጻፉ/ስነአነጋገሩ ትክክለኛ አይደለም፣ ይህንንም በክፍል 13.1.3 ላይ እናስተካክለዋለን፡፡

ልክ እንደ መጀመሪያው የተጠቃሚ ቅርጸት ፈተና (ዝርዝር 6.5)፣ በዝርዝር 13.4 ውስጥ ያለው የመጀመሪያ ፈተና የእውነታ ማረጋገጫ ብቻ ሲሆን፣ የሁለተኛው ፈተና ግን የተጠቃሚው መታወቂያ መኖሩን የሚፈትን ነው፣ ለዚህም በዝርዝር 13.5 ውስጥ የሚታየውን የመኖር ማረጋገጫን እናክላለን፡፡

ዝርዝር 13.5: በአጪርጽሑፍ ላይ የ‘ተጠቃሚ_መታወቂያ (teteqami_id) መኖሩን ማረጋገጥ። አረንጓዴ app/models/achrtshuf.rb
class Achrtshuf < ApplicationRecord
  belongs_to :teteqami
  validates :teteqami_id, presence: true
end

በነገራችን ላይ፣ ከአምስተኛው የሬይልስ እትም ጀምሮ በዝርዝር 13.4 ውስጥ ያሉ ፈተናዎች በርግጥ ያለ ዝርዝር 13.5 ማረጋገጫ ያልፋሉ፣ ይህ የሚሆነው ግን በዝርዝር 13.4 ውስጥ ስነአጻጻፉ/ስነአነጋገሩ ትክክለኛ ያልሆነውን በደማቅ ቀለም የተሰመረበት ኮድን ስትጠቀሙ ብቻ መሆኑን ልትገነዘቡ ይገባል፡፡ በዝርዝር 13.12 ላይ ስነአጻጻፉ/ስነአነጋገሩ ትክክለኛ ወደሆነ ኮድ ከተቀየረ በኋላ፣ የተጠቃሚ-መታወቂያ ማረጋገጫ አስፈላጊ ስለሆነ፣ እኛም ያንን ለማመቻቸት ስንል እዚህ ጋር አክለነዋል፡፡

ዝርዝር 13.5 ውስጥ ካለው ኮድ ጋር ፈተናዎቹ (አሁንም) አረንጓዴመሆን አለባቸው:-

ዝርዝር 13.6: አረንጓዴ
$ rails test:models

በመቀጠል፣ (የክፍል 2.3.2 ምሳሌን በመከተል) ለአጪርጽሑፍ የ‘ይዘት (yizet) ባሕሪ ማረጋገጫዎችን እናክላለን፡፡ ልክ እንደ ተጠቃሚ_መታወቂያ‘ው (teteqami_id) ሁሉ የ‘ይዘት (yizet) ባሕሪውም ግዴታ መኖር አለበት፣ ከ 140 ሆሄወች የበለጠ እንዳይሆንም ይገደባል፣ ይህ ባህሪም አጪር ለሆነ መጣጥፍነት ማለት አጪርጽሑፍነት ብቁ እንዲሆን ያበቃዋል፡፡

የተጠቃሚ ቅርጸት ማረጋገጫዎች ላይ እንዳደረግነው ሁሉ (ክፍል 6.2)፣ የአጪርጽሑፍ ይዘት ማረጋገጫዎችን ለማከልም ፈተና-መሬ ብልጸጋን እንጠቀማለን። በዝርዝር 13.7 ላይ እንደሚታየው፣ የተገኙት የፈተና ውጤቶች በአጠቃላይ የተጠቃሚ ቅርጸት ማረጋገጫ ፈተናዎች ምሳሌዎችን ይከተላሉ፡፡

ዝርዝር 13.7: የአጪርጽሑፍ ቅርጸት ማረጋገጫዎችን መፈተን። ቀይ test/models/achrtshuf_test.rb
require "test_helper"

class AchrtshufTest < ActiveSupport::TestCase

  def setup
    @teteqami = teteqamis(:michael)
    @achrtshuf = Achrtshuf.new(yizet: "አሳ በልቶ ውሃ", teteqami_id: @teteqami.id)
  end

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

  test "የተጠቃሚ-መታወቂያ መኖር አለበት" do
    @achrtshuf.teteqami_id = nil
    assert_not @achrtshuf.valid?
  end

  test "ይዘት መኖር አለበት" do
    @achrtshuf.yizet = "   "
    assert_not @achrtshuf.valid?
  end

  test "ይዘት ቢበዛ 140 ሆሄወች መሆን አለበት" do
    @achrtshuf.yizet = "ሀ" * 141
    assert_not @achrtshuf.valid?
  end
end

ልክ እንደ ክፍል 6.2 ዝርዝር 13.7 ውስጥ ያለው ኮድም፣ የአጪርጽሑፍ እርዝመት ማረጋገጫውን ለመፈተን የሃረግ ማባዛትን ይጠቀማል:-

$ rails console
>> "ነ" * 10
=> "ነነነነነነነነነነ"
>> "ነ" * 141
=> "ነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነ
ነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነነ"

ዝርዝር 13.8 ላይ እንደሚታየው፡ ይህ ኮድ ከተጠቃሚዎች የ‘ስም (sim) ማረጋገጫ ኮድ ጋር በጣም ተመሳሳይ ነው (ዝርዝር 6.16)፡፡

ዝርዝር 13.8: የአጪርጽሑፍ ቅርጸት ላይ ማረጋገጫን ማከል። አረንጓዴ app/models/achrtshuf.rb
class Achrtshuf < ApplicationRecord
  belongs_to :teteqami
  validates :teteqami_id, presence: true
  validates :yizet, presence: true, length: { maximum: 140 }
end

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

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

መልመጃዎች

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

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

  1. በሬይልስ ሰሌዳ ላይ፣ የተጠቃሚ-መታወቂያ የሌለው፣ ይዘቱ ደግሞ ባዶ የሆነ አንድ አጪርጽሑፍን ቀርጹ። አጪርጽሑፉ ብቁ ነውን? የአጪርጽሑፉ የስህተት መልእክቶች ምንድናቸው?
  2. በሬይልስ ሰሌዳ ላይ፣ የተጠቃሚ-መታወቂያ የሌለው፣ ይዘቱ ደግሞ ረጅም የሆነ አንድ ሁለተኛ አጪርጽሑፍን ቀርጹ። አጪርጽሑፉ ብቁ ነውን? የአጪርጽሑፉ የስህተት መልእክቶች ምንድናቸው?

13.1.3 የተጠቃሚ እና የአጪርጽሑፎች ማህበራት

ለድር አፕልኬሽኖች የውሂብ ቅዶችን በሚሰሩበት ጊዜ፣ በእያንዳንዱ ቅርጸት መካከል ማሕበር እንዲኖር ማድረጉ በጣም አስፈላጊ ነው፡፡ አሁን ባለበት ሁኔታ እያንዳንዱ አጪርጽሑፍ ከአንድ ተጠቃሚ ጋር የተዛመደ ሲሆን፣ እያንዳንዱ ተጠቃሚ ደግሞ ከበርካታ አጪርጽሑፎች ጋር ይዛመዳል፣ ይህንን ትስስርም በክፍል 2.3.3 ላይ በግልጽ አይተነዋል፣ አሁን ደግሞ በምስል 13.2 እና በምስል 13.3 ላይ በንድፋዊ መልኩ ይታያል። እነዚህን ማሕበሮች ተግባር ላይ ለማዋል በምናደርገው ሂደት ላይ፣ ለአጪርጽሑፍ ቅርጸቱ አንዳንድ ፈተናዎችን ስንጽፍ፣ በተጠቃሚ ቅርጸቱ ላይ ደግሞ አንዳንድ ፈተናዎችን እናክላለን፡፡

images/figures/micropost_belongs_to_user
ምስል 13.2: በአንድ አጪርጽሑፍ እና በተዛማጅ ተጠቃሚው መካከል ያለው የ‘ባለቤትነት (belongs_to) ትስስር።
images/figures/user_has_many_microposts
ምስል 13.3: በአንድ ተጠቃሚ እና በተዛማጆቹ አጪርጽሑፎች መካከል ያለው የ‘ብዙ_አለው (has_many) ትስስር።

በዚህ ክፍል ውስጥ የተበየነውን የ‘ባለቤት_ነው (belongs_to) እና የ‘ብዙ_አለው (has_many) ማሕበርን በመጠቀም፣ ሬይልስ በሰንጠረዥ 13.1 ላይ የተመለከቱትን ዘዴወች ይገነባል፡፡ ይህንን ዘዴ እንደዚህ አድርጎ ከመጠቀም:-

Achrtshuf.create
Achrtshuf.create!
Achrtshuf.new

ሰንጠረዥ 13.1 ላይ ያለውን ዘዴ ስራ ላይ በማዋል፤ እንደዚህ አድርገን የመጠቀም ችሎታን ማግኘት እንደምንችል አስተውሉ:-

teteqami.achrtshufs.create
teteqami.achrtshufs.create!
teteqami.achrtshufs.build

እነዚህ የኋለኞቹ ዘዴወች፣ በአንድ ተጠቃሚ ማሕበር በኩል (through) አንድ አጪርጽሑፍን ለመስራት፣ ስነአጻጻፉ/ስነአነጋገሩ ትክክለኛ የሆነውን መንገድ ያስማማሉ፡፡ በዚህ መንገድ አንድ አዲስ አጪርጽሑፍ ሲሰራ፣ የ‘ተጠቃሚ_መታወቂያ‘ው (teteqami_id) ከተዛማጁ አጪርጽሑፍ ጋር በራስሰር ይዘጋጃል። ስለዚህ በዝርዝር 13.4 ላይ ያለውን የ‘ተጠቃሚ_መታወቂያ (teteqami_id) በማጥፋት:-

@teteqami = teteqamis(:michael)
# ይህ ኮድ በስነአጻጻፉ/በስነአነጋገሩ ትክክል አይደለም፡፡
@achrtshuf = Achrtshuf.new(yizet: "አሳ በልቶ ውሃ", teteqami_id: @teteqami.id)

በዚህ ኮድ መተካት እንችላለን:-

@teteqami = teteqamis(:michael)
@achrtshuf = @teteqami.achrtshufs.build(yizet: "አሳ በልቶ ውሃ")

(ልክ እንደ አዲስ (new) ዘዴ የ‘ገንባ (build) ዘዴም፣ አንድ ቁስን በማህደረ-ትውስታ (Memory) ላይ ፈጥሮ ይመልሳል፣ ይሁን እንጂ ውሂበጎታውን ጪራሽ አይቀይርም።)4 ተገቢወቹን ማሕበሮች ከበየንን በኋላ፣ የሚገኘው የ‘@አጪርጽሑፍ (@achrtshuf) ተለዋዋጪ፣ ከተዛማጁ ተጠቃሚ-መታወቂያ ጋር እኩል የሆነ አንድ የ‘ተጠቃሚ_መታወቂያ (teteqami_id) በራስሰር ይኖረዋል። ይህ በኮድ ሲጻፍ ምን እንደሚመስል በአጪር ጊዜ የምናየው ይሆናል።

ዘዴ ጥቅም
achrtshuf.teteqami ከአጪርጽሑፉ ጋር የሚዛመደውን የተጠቃሚ ቁስ መመለስ
teteqami.achrtshufs የተጠቃሚውን የአጪርጽሑፎች ክምችት መመለስ
teteqami.achrtshufs.create(arg) ከተጠቃሚው (teteqami) ጋር የተዛመደ አንድ አጪርጽሑፍን መፍጠር
teteqami.achrtshufs.create!(arg) ከተጠቃሚው (teteqami) ጋር የተዛመደ አንድ አጪርጽሑፍን መፍጠር (በውድቀት ጊዜ ልዩነትን ያስነሳል)
teteqami.achrtshufs.build(arg) ከተጠቃሚው (teteqami) ጋር የተዛመደ አንድ አዲስ የአጪርጽሑፍ ቁስን መመለስ
teteqami.achrtshufs.find_by(id: 1) የአጪርጽሑፉ መታወቂያው 1፣ እና የ‘ተጠቃሚ-መታወቂያው (teteqami.id) ከ‘ተጠቃሚ_መታወቂያ‘ው (teteqami_id) ጋር እኩል የሆነ አጪርጽሑፍን መፈለግ
ሰንጠረዥ 13.1: የተጠቃሚ እና የአጪርጽሑፍ ማሕበር ዘዴወች አንድ ማጠቃለያ።

ልክ እንደ @ተጠቃሚ.አጪርጽሑፎችን.ገንባ (@teteqami.achrtshufs.build) ያለው ኮድ እንዲሰራ ለማድረግ፣ ማለት የተጠቃሚ እና የአጪርጽሑፍ ቅርጸቱን ለማዛመድ፣ እነሱን በኮድ ማዘመን ይኖርብናል፡፡ በዝርዝር 13.10 ላይ እንደሚታየው፣ ከነዚህ ውስጥ የመጀመሪያው፣ ማለት ባለቤት_ነው :ተጠቃሚ (belongs_to :teteqami) የተባለው ኮድ፣ በዝርዝር 13.3 ውስጥ ባለው ፍልሰት በኩል በራስሰር ተካቷል፡፡ ሁለተኛውን ማሕበር ማለት ብዙ_አለው :አጪርጽሑፎች‘ን (has_many :achrtshufs) ደግሞ በዝርዝር 13.11 ላይ እንደሚታየው፣ እኛው እራሳችን በእጃችን ማከል ይኖርብናል፡፡

ዝርዝር 13.10: ተጠቃሚው የአጪርጽሑፉ ባለቤት_ነው (belongs_to)፡፡ አረንጓዴ app/models/achrtshuf.rb
class Achrtshuf < ApplicationRecord
  belongs_to :teteqami
  validates :teteqami_id, presence: true
  validates :yizet, presence: true, length: { maximum: 140 }
end
ዝርዝር 13.11: አንድ ተጠቃሚ ብዙ (has_many) አጪርጽሑፎች አሉት፡፡ አረንጓዴ app/models/teteqami.rb
class Teteqami < ApplicationRecord
  has_many :achrtshufs
  .
  .
  .
end

ዝርዝር 13.12 ላይ እንደሚታየው፣ በሁለቱ መካከል ያለው ማሕበር ከተመሰረተ በኋላ፣ አንድ አዲስ አጪርጽሑፍን ለመገንባት ስነአጻጻፉ/ስነአነጋገሩ ትክክለኛ የሆነውን መንገድ በመከተል፣ በዝርዝር 13.4 ውስጥ ያለውን የ‘አዘጋጅ (setup) ዘዴ ማዘመን እንችላለን።

ዝርዝር 13.12: አንድ አጪርጽሑፍን ለመገንባት ስነአጻጻፉ/ስነአነጋገሩ ትክክለኛ የሆነ ኮድን መጠቀም። አረንጓዴ test/models/achrtshuf_test.rb
require "test_helper"

class AchrtshufTest < ActiveSupport::TestCase

  def setup
    @teteqami = teteqamis(:michael)
    @achrtshuf  = @teteqami.achrtshufs.build(yizet: "አሳ በልቶ ውሃ")
  end

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

  test "የተጠቃሚ-መታወቂያ መኖር አለበት" do
    @achrtshuf.teteqami_id = nil
    assert_not @achrtshuf.valid?
  end
  .
  .
  .
end

በእርግጥ፣ ከዚህ ትንሽ የኮድ ማጣራት ስራ በኋላም፣ የፈተና ስብስቡ አረንጓዴመሆን ይኖርበታል:-

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

መልመጃዎች

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

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

  1. በውሂበጎታው ውስጥ የሚገኘውን የመጀመሪያ ተጠቃሚ፣ ለ ተጠቃሚ ሰይሙ። ይህንን:- achrtshuf = ተጠቃሚ.achrtshufs.create(yizet: "አሳ በልቶ ውሃ") ትእዛዝ ስትፈጽሙ ምን ተፈጠረ?
  2. ከላይ ያለው ትእዛዝ አንድ አጪርጽሑፍን በውሂበጎታው ውስጥ መፍጠር ይኖርበታል። ይህንንም ይሄንን:- ተጠቃሚ.achrtshufs.find(achrtshuf.id) ትእዛዝ በማስኬድ አረጋግጡ፡፡ በ‘አጪርጽሑፍ.መታወቂያ (achrtshuf.id) ፈንታ አጪርጽሑፍ‘ን (achrtshuf) ብትጠቀሙስ?
  3. የዚህ ኮድ:- ተጠቃሚ == achrtshuf.ተጠቃሚ ውጤት/ዋጋ ምንድነው? የዚህ ኮድ:- ተጠቃሚ.achrltfs.first == achrtshuf ውጤትስ/ዋጋስ?

13.1.4 አጪርጽሑፍን ማጣራት

በዚህ ክፍል ውስጥ የተጠቃሚ/የአጪርጽሑፍ ማሕበር ላይ አስፈላጊ የሆኑ ሁለት ማጣሪያዎችን እናክላለን። በተለይም፣ የአንድ ተጠቃሚ አጪርጽሑፎች በአንድ የተወሰነ ቅደም ተከተል ተፈልገው እንዲወጡ እናዘጋጃቸዋለን፣ እንዲሁም ከአጪርጽሑፎቹ ጋር ተዛማጁ ተጠቃሚ፣ ከውሂበጎታው ሲጠፋ አጪርጽሑፎቹም በራስሰር አብረው ይጠፉ ዘንድ፣ አጪርጽሑፎቹን የተጠቃሚዎቹ ጥገኛ (Dependent) እናደርጋቸዋለን።

ነባሪ ክልል

በነባሪነት የ‘ተጠቃሚ.አጪርጽሑፎች (teteqami.achrtshufs) ዘዴው ስለ ቅምጦቹ ቅደም ተከተል ምንም ዓይነት ዋስትናን አይሰጥም፤ ይሁን እንጂ አጪርጽሑፎቹ ከተፈጠሩ በኋላ፣ (የብሎጎችና የትዊተር ደንብን በመከተል) በተገላቢጦሽ ቅድም ተከተል ከውሂበጎታው እንዲወጡ እንፈልጋለን፡፡5 ስለሆነም፣ ወቅታዊው ቅምጥ መጀመሪያ ላይ መሆን አለበት ማለት ነው፡፡ ይህንን አሰራር ተግባራዊ ለማድረግ አንድ ነባሪ ክልልን እናዘጋጃለን።

ይህ በትክክል ወደ አንድ አታላይ የፈተና እልፈት ሊያመራ የሚችል ገጸባህሪ ስለሆነ (ማለትም የአፕልኬሽን ኮዱ የተሳሳተ ቢሆንም እንኳ የሚያልፍ ፈተና ነው)፣ ስለሆነም፣ ትክክለኛውን ነገር እየፈተን መሆናችንን ለማረጋገጥ፣ ፈተና-መሬ ብልጸጋን መጠቀሙን እንቀጥላለን። በዝርዝር 13.14 ላይ እንደሚታየው በተለይ ደግሞ፣ በውሂበጎታ ውስጥ ያለው የመጀመሪያው አጪርጽሑፍ የቅርብ_ጊዜ (yeqrb_gizei) ብለን ከምንጠራው አንድ የእቃ አጪርጽሑፍ ጋር አንድ ዓይነት እንደሆነ ለማረጋገጥ አንድ ፈተናን እንጽፋለን፡፡

ዝርዝር 13.14: የአጪርጽሑፉን ቅደም ተከተል መፈተን። ቀይ test/models/achrtshuf_test.rb
require "test_helper"

class AchrtshufTest < ActiveSupport::TestCase
  .
  .
  .
  test "ቅደም ተከተሉ ወቅታዊው በመጀመሪያ መሆን አለበት" do
    assert_equal achrtshufs(:yeqrb_gizei), Achrtshuf.first
  end
end

ዝርዝር 13.14 የአጪርጽሑፍ እቃወች መኖር ላይ ጥገኛ ነው፤ ይህንንም በዝርዝር 11.5 ላይ እንደታየው፣ ልክ የተጠቃሚ እቃዎችን እንደበየነው አድርገን ልንበይነው እንችላለን። በክፍል 13.1.1 ላይ ከተበየነው የ‘ይዘት (yizet) ባሕሪ በተጨማሪ፣ ከይዘቱ ጋር የሚዛመድ አንድ ተጠቃሚ‘ንም (teteqami) መበየን ይኖርብናል፡፡ ሬይልስም እቃዎች ውስጥ ማሕበርን ለመገንባት ይህንን የመሰለ አንድ መንገድን በሚመች ሁኔታ አካቷል:-

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

ተጠቃሚውን (teteqami) ማይክል (michael) ብለን በማስተዋወቅ፣ ሬይልስ ይህንን አጪርጽሑፍ ከተጠቃሚዎች እቃ ውስጥ ካለው ተጓዳኝ ተጠቃሚ ጋር እንዲያዛምድ እንነግረዋለን:-

michael:
  sim: Micheal Abnet
  emelekt: michael@misalei.com
  .
  .
  .

የተሟሉት የአጪርጽሑፉ እቃወች በዝርዝር 13.15 ላይ ይታያሉ፡፡

ዝርዝር 13.15: የአጪርጽሑፍ እቃወች። test/fixtures/achrtshufs.yml
weba:
  yizet: "ወባ ፊት የነሳው ሰውየ ቡዳ እንዳይበላኝ አለ።"
  created_at: <%= 10.minutes.ago %>
  teteqami: michael

tau_manifesto:
  yizet: "በ @mhartl  @tauday ጣቢያን ተመልከቱ https://tauday.com"
  created_at: <%= 3.years.ago %>
  teteqami: michael

yedmet_video:
  yizet: "የሚያሳዝኑ ድመቶች አሳዛኞች ናቸው: https://youtu.be/PKffm2uI4dk"
  created_at: <%= 2.hours.ago %>
  teteqami: michael

yeqrb_gizei:
  yizet: "አንድ አጪር ፈተና እየጻፍኩ ነው።"
  created_at: <%= Time.zone.now %>
  teteqami: michael

ዝርዝር 13.15 ክት ሩቢን በመጠቀም የተፈጠረ_በ (created_at) መስክን በግልጽ እንደሚያዘጋጅ ልብ በሉ፡፡ ይህ መስክ በሬይልስ በራስሰር የሚዘምን አንድ “የአስማት” መስክ ስለሆነ፣ ይህንን መስክ በተለምዶ በእጅ ማዘጋጀት አይቻልም፣ በእቃወች ውስጥ ግን ይቻላል።6

ዝርዝር 13.14 እና በዝርዝር 13.15 ውስጥ ባሉት ኮዶች የፈተና ስብስቡ ቀይመሆን አለበት፡-

ዝርዝር 13.16: ቀይ
$ rails test test/models/achrtshuf_test.rb

አንድ ነባሪ_ክልል (default_scope) ተብሎ የሚጠራ የሬይልስ ዘዴን በመጠቀም ፈተናው እንዲያልፍ እናደርገዋለን፣ ይህም ሌሎች ከሚሰጣቸው ጥቅሞች ውስጥ፣ የትኞቹ አባላቶች ከውሂበጎታው ተፈልገው ማውጣት እንዳለባቸው፣ አንድ ነባሪ ቅደም ተከተልን ለማዘጋጀት ሊጠቅም ይችላል። አንድ የተወሰነ ቅደም ተከተልን ለማስከበር፣ በ‘ነባሪ_ክልል (default_scope) ውስጥ የ‘ቅደም-ተከተል (order) ነጋሪአሴትን አናክላለን፣ ይህም እንደሚከተለው፣ በ‘ተፈጠረ_በ (created_at) መስክ መሰረት ቅደም ተከተል እንድናደርግ ያስችለናል፡-

order(:created_at)

አለመታደል ሆኖ፣ ይህ ቅደም ተከተል ውጤቱን በሽቅብታ (Ascending) ቅደም ተከተል፣ ከትንሽ ቁጥር ወደ ትልቅ ቁጥር ቅደም ተከተል በማድረግ ያቀርባል፣ ይህ ማለት በጣም የድሮዎቹ አጪርጽሑፎች መጀመሪያ ላይ ይመጣሉ ማለት ነው፡፡ ውጤቱን በተገላቢጦሽ ለማግኘት፣ ማለት እኛ የፈለገውን ውጤት ለማግኘት፣ ትንሽ ጥሬ ተ.መ.ቋን ከአንድ ሃረግ ጋር እንጨምራለን:-

order('created_at DESC')

እዚህ ላይ “አቆልቋይ (descending)” ማለት DESC የሚለው ቃል ሙሉ አባባል ሲሆን ይህም ተ.መ.ቋ ነው፣ አቆልቋይ (Descending) ቅደም ተከተል ማለት ቅደም ተከተሉ ከአዲሱ ወደ አሮጌው/ወደቆየው ማለት ነው።7 በቀድሞዎቹ የሬይልስ ስሪቶች ውስጥ የሚፈለገውን ባህሪ ለማግኘት ይህንን ጥሬ ተ.መ.ቋ መጠቀሙ አንዱ እና ብቸኛው አማራጪ ሆኖ ያገለግል ነበር፣ ከሬይልስ 4.0 በኋላ ግን አንድ የበለጠ ተፈጥሮዋዊ የሆነ ጥሬ-የሩቢ አገባብን በመጠቀም እንደሚታየው አድርገን ልንጽፈው እንችላለን:-

order(created_at: :desc)

ይህንን አንድ ነባሪ ክልል በአጪርጽሑፍ ቅርጸቱ ውስጥ ማከሉ፣ ዝርዝር 13.17 ‘ን ይሰጣል።

ዝርዝር 13.17: አጪርጽሑፎችን በ‘ነባሪ_ክልል (default_scope) ቅደም ተከተል ማስያዝ፡፡ አረንጓዴ app/models/achrtshuf.rb
class Achrtshuf < ApplicationRecord
  belongs_to :teteqami
  default_scope -> { order(created_at: :desc) }
  validates :teteqami_id, presence: true
  validates :yizet, presence: true, length: { maximum: 140 }
end

ዝርዝር 13.17 አንድ የአሰራ (የአሰራር) (Proc (procedure)) ወይም የላምዳ (lambda) የተባለ ቁስን ለመጥራት ይሄን “->” ያስተዋውቃል፣ ይህ ምልክት “ስታቢ ላምዳ” ይባላል፣ ይህም ስም አልባ ሥልት (Anonymous Function) ነው (አንድ ያለ ስም የተፈጠረ ሥልት ማለት ነው)። ስታቢ ላምዳ አንድ ጥምርን (ክፍል 4.3.2) ይወስድ እና አንድ አሰራርን (ፕሮክን) ይመልሳል፣ ከዚያ በኋላም በ‘ጥሪ (call) ዘዴ ሊገመገም ይችላል። ይህ እንዴት እንደሚሰራ በሰሌዳው ውስጥ ማየት እንችላለን:-

>> -> { puts "turye" }
=> #<Proc:0x007fab938d0108@(irb):1 (lambda)>
>> -> { puts "hani" }.call
hani
=> nil

(ይህ ትንሽ ላቅ ያለ የሩቢ ርዕስ ስለሆነ፣ እንዴት እንደሚሰራ ወድያውኑ ካልገባችሁ ብዙ ልትጨነቁ አይገባም።)

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

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

ጥገኛውን መደምሰስ

ትክክለኛውን ቅደም ተከተል ከመጨመር ባሻገር፣ በአጪርጽሑፎች ላይ አንድ ማከል የምንፈልገው ሁለተኛ ማጣሪያ አለ፡፡ በክፍል 10.4 ትምህትታችን ላይ፣ የጣቢያው አስተዳዳሪዎች ተጠቃሚዎችን የማጥፋት ስልጣን እንዳላቸው ታስታውሳላችሁ፡፡ ይህም አንድ ተጠቃሚ ከጠፋ፣ የተጠቃሚው አጪርጽሑፎችም መጥፋት አለባቸው ለሚለው እውነታ ምክንያት ይሆናል።

ዝርዝር 13.19 ላይ እንደተመለከተው፣ አንድ አማራጪን ወደ ብዙ_አለው (has_many) የማሕበር ዘዴ በማሳለፍ ይህንን ባህሪ ማዘጋጀት እንችላለን:-

ዝርዝር 13.19: የአንድ ተጠቃሚ አጪርጽሑፎች ከተጠቃሚው ጋር አብረው መሰረዛቸውን ማረጋገጥ። app/models/teteqami.rb
class Teteqami < ApplicationRecord
  has_many :achrtshufs, dependent: :destroy
  .
  .
  .
end

እዚህ ላይ የ‘ጥገኛ: :አጥፋ (dependent: :destroy) አማራጩ፣ ተጠቃሚው ራሱ ሲጠፋ ከተጠቃሚው ጋር ጥገኛ የሆኑት አጪርጽሑፎችም አብረው እንዲጠፉ ያዘጋጃል፡፡ ይህም አስተዳዳሪዎች፣ ተጠቃሚዎችን ከውሂበጎታው ሲያጠፏቸው፣ ተጠቃሚ አልባ የሆኑ አጪርጽሑፎች በውሂበጎታው ውስጥ እንዳይቀሩ ይከለክላል፡፡

የተጠቃሚ ቅርጸቱን በመፈተን በዝርዝር 13.19 ውስጥ ያለው ኮድ እንደሚሰራ ማረጋገጥ እንችላለን። ይህንን ለማረጋገጥ ማድረግ ያለብን ነገር ቢኖር፣ ተጠቃሚውን ማስቀመጥ (በዚህ ጊዜ አንድ መታወቂያን ያገኛል) እና ከዚያ ከሱ ጋር የሚዛመድ አንድ አጪርጽሑፍን መፍጠር ይሆናል። ከዚያ ተጠቃሚውን በማጥፋት የአጪርጽሑፎቹ ብዛት በ 1 እንደቀነሰ ማረጋገጥ ይሆናል፡፡ ውጤቱም በዝርዝር 13.20 ውስጥ ይታያል፡፡ (ይህን በዝርዝር 10.62 ውስጥ የ “ሰርዝ” አገናኞችን ከሚፈትነው የውህደት ፈተና ጋር አነጻጽሩ፡፡)

ዝርዝር 13.20: አንድ ፈተናን ለጥገኛ አጥፊ (dependent: :destroy) ማከል። አረንጓዴ test/models/teteqami_test.rb
require 'test_helper'

class TeteqamiTest < ActiveSupport::TestCase

  def setup
    @teteqami = Teteqami.new(sim: "Abnetawi Teteqami", emelekt: "teteqami@misalei.com",
                     password: "yonatan", password_confirmation: "yonatan")
  end
  .
  .
  .
  test "ተዛማጅ አጪርጽሑፎች መጥፋት አለባቸው" do
    @teteqami.save
    @teteqami.achrtshufs.create!(yizet: "አሳ በልቶ ውሃ")
    assert_difference 'Achrtshuf.count', -1 do
      @teteqami.destroy
    end
  end
end

ዝርዝር 13.19 ውስጥ ያለው ኮድ በትክክል እየሰራ ከሆነ፣ የፈተና ስብስቡ አሁንም አረንጓዴመሆን አለበት:-

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

መልመጃዎች

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

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

  1. በ‘አጪርጽሑፍ.መጀመሪያ.ተፈጠረ (Achrtshuf.first.created_at) ዋጋ እና በ‘አጪርጽሑፍ.መጨረሻ.ተፈጠረ (Achrachrtshuf.last.created_at) ዋጋ መካከል ምን ልዩነት አለ?
  2. የ‘አጪርጽሑፍ.መጀመሪያ (Achrtshuf.first) እና የ‘አጪርጽሑፍ.መጨረሻ (Achrtshuf.last) የተ.መ.ቋ መጠይቆች ምን ይመስላሉ? ጠቃሚ ምክር:- እዛው ያላችሁበት ሰሌዳ ላይ ታትመዋል፡፡
  3. ተጠቃሚ ‘ን በውሂበጎታው ላይ ያለው የመጀመሪያ ተጠቃሚን እናድርገው እንበል፤ የሱ የመጀመሪያ የአጪርጽሑፍ መታወቂያ ስንት ነው? የ‘አጥፋ (destroy) ዘዴን በመጠቀም የመጀመሪያውን ተጠቃሚ ከውሂበጎታው አጥፉ፣ ከዚያ አጪርጽሑፍ.ፈልግ (Achrtshuf.find) ዘዴን በመጠቀም፣ የተጠቃሚው የመጀመሪያው አጪርጽሑፍም አብሮ ከሱ ጋር እንደጠፋ አረጋግጡ፡፡

13.2 አጪርጽሑፎችን ማሳየት

ምንም እንኳን እስከ አሁን ድረስ፣ በድር በኩል የአጪርጽሑፍ መፍጠሪያ ቅጽን ተጠቅመን አጪርጽሑፎችን የምንፈጥርበት አንድ መንገድ ባይኖርም፣ ድሩ እነሱን ለማሳየት ግን አያግደንም (በክፍል 13.3.2 ውስጥ አንድ ቅጽን በመጠቀም አጪርጽሑፎችን መፍጠር እንጀምራለን)። የትዊተርን አሰራር በመከተል፣ የተጠቃሚውን አጪርጽሑፎች በአንድ የተለየ የአጪርጽሑፎች ማውጫ (index) ገጽ ላይ ከማሳየት ይልቅ፣ በምስል 13.4 ስእላዊ መግለጫ ላይ እንደሚታየው፣ የተጠቃሚውን አጪርጽሑፎች፣ በቀጥታ በተጠቃሚው መገለጫ ማሳያ (show) ገጽ ላይ ለማሳየት አቅደናል፡፡ በተጠቃሚው መገለጫ ላይ አንድ የአጪርጽሑፍ ማሳያን ለማከል፣ ቀላል በሆኑ የክ.ሩ (ERb) ዝግጁገጽታዎች እንጀምራለን፣ ከዚያ በተጠቃሚው መገለጫ ገጽ ላይ የሚታዩ አጪርጽሑፎች ይኖሩን ዘንድ፣ ክፍል 10.3.2 ላይ ካለው የውሂብ ዘር ላይ ጥቂት አጪርጽሑፎችን እናክላለን፡፡

images/figures/user_microposts_mockup
ምስል 13.4: አንድ የመገለጫ ገጽ ከአጪርጽሑፎቹ ጋር የሚያሳይ አንድ ስእላዊ መግለጫ።

13.2.1 አጪርጽሑፎችን ማቅረብ

ዓላማችን፣ ለእያንዳንዱ ተጠቃሚ የሰራውን አጪርጽሑፍ እና የአጪርጽሑፎቹን ብዛት በራሱ መገለጫ ገጽ ላይ (አሳይ.ሃጽመቋ.ክሩ (show.html.erb)) ማሳየት ነው፣ ከዚህ በኋላ እንደምናየው፣ አብዛኞቹ ሃሳቦች በክፍል 10.3 ላይ ካለው ማለት፣ ሁሉንም ተጠቃሚዎች በማሳየት ስራ ላይ ከሰራናቸው ስራወች ጋር ተመሳሳዮች ናቸው፡፡

መልመጃ ስትሰሩ በውሂበጎታው ውስጥ የፈጠራችኋቸው አንዳንድ አጪርጽሑፎች ካሉ፣ በዚህ ጊዜ ውሂበጎታውን እንደገና ለማስጀመር እና እንደገና ለመዝራት፣ የሚከተሉትን ትእዛዛት አስኪዱ:-

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

ምንም እንኳን እስከ ክፍል 13.3 የአጪርጽሑፎች መቆጣጠሪያ የማያስፈልገን ቢሆንም፣ የትይታ ማውጫ ግን ላሁኑ ያስፈልገናል፣ ስለዚህ መቆጣጠሪያውን አሁን እናመንጪ:-

$ rails generate controller Achrtshufs

በዚህ ክፍል ውስጥ ዋናው ዓላማችን ለእያንዳንዱ ተጠቃሚ ሁሉንም አጪርጽሑፎች በመገለጫ ገጹ ላይ ማቅረብ ይሆናል፡፡ በክፍል 10.3.5 ውስጥ እንዳየነው ይህ ኮድ:-

<ul class="አጪርጽሑፎች">
  <%= render @teteqamis %>
</ul>

የ‘ _ተጠቃሚ.ሃጽመቋ.ክሩ (_teteqami.html.erb) ከፊልን በመጠቀም በ@ተጠቃሚዎች (@teteqamis) ተለዋዋጪ ውስጥ የለ ተጠቃሚን አንድባንድ ለቃቀሞ በራስሰር እንደሚያቀርብ አይተናል። ይህንን መሰረት በማድረግ አንድ ተመሳሳይ የ‘ _አጪርጽሑ.ሃጽመቋ.ክሩ (_achrtshuf.html.erb) ከፊልን እንበይናለን፣ ስለሆነም አንድ ዓይነት ስልትን፣ በአንድ አጪርጽሑፎች ክምችት ውስጥ እንደሚከተለው እናደርጋለን መጠቀም እንችላለን:-

<ol class="አጪርጽሑፎች">
  <%= render @achrtshufs %>
</ol>

እዚህ ላይ የባለ-ቁጥር ዝርዝር (ol) መለያን ተጠቅመናል፣ ይህንን የተጠቀምንበት ምክንያትም አጪርጽሑፎቹን በአንድ የተወሰነ ቅደም ተከተል ለመዘርዘር ስለሚጠቅመን ነው፤ (የቁጥር-አልባ ዝርዝር (ul) መለያ ከባለ-ቁጥር ዝርዝር (ol) መለያ አንጻር በሆነ መልኩ ይሰራል)። ተዛማጁ ከፊል በዝርዝር 13.22 ውስጥ ይታያል፡፡

ዝርዝር 13.22: አንድ ነጠላ አጪርጽሑፍን ለማሳየት የሚያገለግል አንድ ከፊል። app/views/achrtshufs/_achrtshuf.html.erb
<li id="achrtshuf-<%= achrtshuf.id %>">
  <%= link_to amsaya_le(achrtshuf.teteqami, meten: 50), achrtshuf.teteqami %>
  <span class="ተጠቃሚ"><%= link_to achrtshuf.teteqami.sim,
                                        achrtshuf.teteqami %></span>
  <span class="ይዘት"><%= achrtshuf.yizet %></span>
  <span class="ማህተመጊዜ"><%= time_ago_in_words(achrtshuf.created_at) %> በፊት ተለጠፈ።
  </span>
</li>

ይህ ምን እንደሚያደርግ ለማወቅ ግልጽ የሆነውን እና አበርክቶውን በክፍል 13.2.2 ላይ የምናየውን ምርጡን የ‘ጊዜ_በፊት_በቃላት (time_ago_in_words) ረጅ ዘዴን ይጠቀማል። ዝርዝር 13.22 እንዲሁ ለእያንዳንዱ አጪርጽሑፍ አንድ የቅ.ቋ መለያን በመጠቀም ይህንን ያክላል:-

<li id="achrtshuf-<%= achrtshuf.id %>">

ለወደፊቱ አጪርጽሑፍችን በተናጠል ለማንቀሳቀስ (ለምሳሌ ያህል ጃቫስክሪፕትን በመጠቀም) አንድ እድልን ስለሚከፍት፣ ይህንን የቅ.ቋ መለያ አስቀድሞ ማድረጉ በአጠቃላይ በጣም ጥሩ ልምድ ነው፡፡

ቀጣዩ ሂደት ብዙ አጪርጽሑፎችን ለማሳየት የሚያጋጥመውን ችግር መፍታት ነው፡፡ ይህንን ችግር፣ በክፍል 10.3.3 ውስጥ በተጠቃሚዎች ላይ ገጸቁጥርን በመጠቀም በፈታንበት ተመሳሳይ መንገድ እንፈታዋለን፡፡ አሁንም እንደበፊቱ የ‘ዊል_ገጽቁጥርስጥ (will_paginate) ዘዴን እንጠቀማለን (የገጸቁጥሩ ገጽ መቀየሪያ በአማርኛ ይሆንል ዘንድ፣ ለ previouslabel አማራጪ ቀዳሚ እና ለ nextlabel አማራጪ ደግሞ ቀጣይ የተባለ ሃረግን እንዳሳለፍን ልትገነዘቡ ይገባል)፡-

<%= will_paginate @achrtshufs, :previous_label => "ቀዳሚ", :next_label => "ቀጣይ" %>

ዝርዝር 10.45 ላይ ብትመለከቱ፣ የነበረን ኮድ ይህንን ይመስላል:-

<%= will_paginate :previous_label => "ቀዳሚ", :next_label => "ቀጣይ" %>

እዚህ ላይ የ‘ዊል_ገጽቁጥርስጥ (will_paginate) ዘዴ በተጠቃሚዎች መቆጣጠሪያ አውድ ውስጥ አንድ የ‘@ተጠቃሚዎች (@teteqamis) ተለዋዋጪ መኖሩን ስለሚገምት እና ስላለም ሊሰራ ችሏል (በክፍል 10.3.3 ላይ እንዳየነው የ‘ንቅመዝገብ::ዝምድና (ActiveRecord::Relation) ክፍል መሆን አለበት)፡፡ አሁን ባለው ሁኔታ ላይ በተጠቃሚዎች መቆጣጠሪያ ውስጥ ሁነን፣ ነገር ግን በአጪርጽሑፎች ላይ ገጸቁጥርን ማድረግ እንፈልጋለን፤ ስለዚህ ለ‘ዊል_ገጽቁጥርስጥ (will_paginate) ዘዴ አንድ የ‘@አጪርጽሑፎች (@achrtshufs) ተለዋዋጪን በቁም ነገር ማሳለፍ ይኖርብናል። እሱንም ያለ ጥርጥር፣ በተጠቃሚ አሳይ (show) ተግባር ውስጥ መበየን ይኖርብናል ማለት ነው (ዝርዝር 13.23)፡፡

ዝርዝር 13.23: በተጠቃሚ አሳይ (show) ተግባር ውስጥ አንድ @አጪርጽሑፎች (@achrtshufs) ቅርፀ ተለዋዋጪን ማከል። app/controllers/teteqamis_controller.rb
class TeteqamisController < ApplicationController
  .
  .
  .
  def show
    @teteqami = Teteqami.find(params[:id])
    @achrtshufs = @teteqami.achrtshufs.paginate(page: params[:page])
  end
  .
  .
  .
end

እዚህ ላይ የ‘ገጽቁጥርስጥ (paginate) ዘዴ ምን ያህል አስደናቂ ስራ እንዳከናወነ አስተውሉ፤ ወደ አጪርጽሑፎች (achrtshufs) ሰንጠረዥ በመግባት እና የሚፈለጉትን የአጪርጽሑፎች ገጾችን ጎትቶ ለማውጣት፣ በአጪርጽሑፎች ማሕበር በኩል (through) ሳይቀር እንኳን ይሰራል፡፡

የመጨረሻው ስራችን የእያንዳንዱን ተጠቃሚ የአጪርጽሑፎች ብዛት ለተጠቃሚው ማሳየት ነው፣ ይህንንም በ‘ቁጠር (count) ዘዴ እንዲህ አድርገን ልንሰራው እንችላለን:-

teteqami.achrtshufs.count

ገጽቁጥርስጥ‘ን (paginate) በማሕበሩ በኩል እንደተጠቀምንበት ሁሉ፣ የ‘ቁጠር (count) ዘዴንም በዛው መልኩ ልንመጠቀምበት እንችላለን፡፡ በተለይ ደግሞ፣ የ‘ቁጠር (count) ዘዴ የአጪርጽሑፎቹን ብዛት ለማግኘት፣ ከውሂበጎታው ውስጥ ያሉትን አጪርጽሑፎች ከውሂበጎታው ካወጣ በኋላ፣ በተገኘው ድርድር ላይ የ‘እርዝመት (length) ዘዴን አይጠራም (ምክንያቱም ይህ አሰራር የአጪርጽሑፎቹ ብዛት እየጨመረ ሲሄድ ውጤታማ ስለማይሆን ነው)። በምትኩ፣ በተሰጠው የ‘ተጠቃሚ_መታወቂያ (teteqami_id) መሰረት ውሂበጎታው አጪርጽሑፎቹን እንዲቆጥርለት በመጠየቅ፣ እዛው ውሂበጎታው ውስጥ ስሌቱን በቀጥታ ያካሂዳል (ይህ ሁሉም ውሂበጎታዎች በጣም የሚተቡበት (optimize) ክዋኔ ነው)።8 (የ‘ቁጠር (count) ዘዴን ስትጠቀሙ አፕልኬሽናችሁን ባልተጠበቀ ሁኔታ የሚዘገይ ከሆነ፣ የበለጠ ቀልጣፋ እንዲሆን ለማድረግ ካውንተር ካሽ የተባለውን እንቁ መጠቀም ትችላላችሁ፡፡)

ዝርዝር 13.24 ላይ እንደሚታየው፣ ከላይ የዘረዘርናቸውን ሁሉ ባንድ ላይ በማስቀመጥ፣ አሁን በተጠቃሚው መገለጫ ገጽ ላይ አጪርጽሑፎችን ለማከል የሚያስችል አንድ አቋም ይኖረናል፡፡ @ተጠቃሚ.አጪርጽሑፎች.ማንኛውም? ካሉት (if @teteqami.achrtshufs.any?) የሚለው ኮድ ጥቅምን አስተውሉ፣ ይህ (ከዚህ በፊት በዝርዝር 7.21 ውስጥ ያየነው ግንባታ) ተጠቃሚው አጪርጽሑፎች ከሌሉት ባዶ ዝርዝር አለመታየቱን ያረጋግጣል፡፡

ዝርዝር 13.24: አጪርጽሑፎችን በተጠቃሚ ማሳያ (show) ገጽ ላይ ማከል። 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>
  </aside>
  <div class="col-md-8">
    <% if @teteqami.achrtshufs.any? %>
      <h3>(<%= @teteqami.achrtshufs.count %>) አጪርጽሑፎች</h3>
      <ol class="አጪርጽሑፎች">
        <%= render @achrtshufs %>
      </ol>
      <%= will_paginate @achrtshufs, :previous_label => "ቀዳሚ",
                                          :next_label => "ቀጣይ" %>

    <% end %>
  </div>
</div>

በዚህ ጊዜ፣ የተዘመነውን የተጠቃሚ መገለጫ ገጻችንን በምስል 13.5 ላይ ማየት እንችላለን፡፡ የሚያሳዝነው ግን ለማየት የጓጓነው ነገር አለመኖሩ ነው፣ በእርግጥ ይህ የሆነበት ምክንያት፣ በአሁኑ ጊዜ ምንም አይነት አጪርጽሑፍ በገጹ ላይ ስለለለ ነው። አሁን ይህን አሳዛኝ ሁኔታ የመቀየሪያ ጊዜ ነው።

images/figures/user_profile_no_microposts
ምስል 13.5: የተጠቃሚ መገለጫ ገጽ ከአጪርጽሑፎች ኮድ ጋር፣ ግን ምንም አጪርጽሑፍ የለም።

መልመጃዎች

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

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

  1. ክፍል 7.3.3 እንደተጠቀሰው፣ እንደ ጊዜ_በፊት_በቃላት (time_ago_in_words) ያሉ ረጅ ዘዴወች በሬይልስ ሰሌዳ ውስጥ ረጅ (helper) በተባለው ቁስ በኩል ይገኛሉ፡፡ ረጅ‘ን (helper) ከ‘ጊዜ_በፊት_በቃላት (time_ago_in_words) ጋር በመጠቀም የ‘ከ3.ሳምንታት.በፊት (3.weeks.ago) እና የ‘ከ6.ወራት.በፊት (6.months.ago) ዋጋን አግኙ። ጠቃሚ ምክር:- የሚከተለውን ምሳሌ ተጠቀሙ helper.time_ago_in_words(1.year.ago)
  2. የዚህ ኮድ helper.time_ago_in_words(1.year.ago) ውጤትስ ምንድነው?
  3. የአጪርጽሑፎች ገጽ የማንኛው የሩቢ ክፍል አባል ነው? ጠቃሚ ምክር:- በዝርዝር 13.23 ላይ የለውን ኮድ ልክ እንደ አንድ መመሪያ በመውሰድ፣ ገጽቁጥርስጥ (paginate) ላይ ‘ገጽ: ምንም (page: nil) የሚል ነጋሪአሴትን በማሳለፍ የ‘ክፍል (class) ዘዴን ጥሩ፡፡

13.2.2 የአጪርጽሑፎች ናሙና

ክፍል 13.2.1 ውስጥ የተጠቃሚውን አጪርጽሑፎች ለማሳየት ያሁሉ ዝግጁገጽታዎችን የመስራቱ ድካም መጨረሻ ላይ ካሳው አመርቂ አልነበረም፡፡ ክፍል 10.3.2 ላይ የተገኘው የውሂብ ዘር ላይ ጥቂት አጪርጽሑፎችን በማከል ይህንን አሳዛኝ ሁኔታ ማስተካከል እንችላለን፡፡

ሁሉም ተጠቃሚዎች ላይ የአጪርጽሑፎች ናሙናን ማከሉ በጣም ጊዜ ስለሚወስድ፣ የ‘ውሰድ (take) ዘዴን በመጠቀም መጀመሪያ ላይ የሚገኙትን ስድስት ተጠቃሚዎች ብቻ በመምረጥ፣ ለነሱ የአጪርጽሑፎች ናሙናዎችን እናክልላቸዋለን (ማለትም፣ አንዱ ተጠቃሚ ነባሪ አምሳያ ሲኖረው፣ አምስቱ ተጠቃሚዎች ደግሞ ብጁ አምሳያ ይደረግላቸዋል):-

Teteqami.order(:created_at).take(6)

የቅደም-ተከተል (order) ጥሪ መጀመሪያ ላይ የተፈጠሩትን ስድስት ተጠቃሚዎችን ማግኘታችንን ያረጋግጥልናል፡፡

ለእያንዳንዱ ምርጥ ተጠቃሚ፣ 50 አጪርጽሑፎችን እንሰራለን (በአንድ ገጽ ውስጥ ከ 30 አጪርጽሑፎች በላይ ስለሚኖር፣ የገጸቁጥር ተግባርን ለማስጀመር በቂ ነው)። የናሙናውን ይዘት ለእያንዳንዱ አጪርጽሑፍ ለማመንጨት የአስመሳይ እንቁ የሰጠንን ምቹ የ‘ሎረም.ዓረፍተነገር (Lorem.sentence) ዘዴን እንጠቀማለን።9 አዲሱ የውሂብ ዘር ዘዴ ውጤት በዝርዝር 13.25 ውስጥ ይታያል፡፡ (በዝርዝር 13.25 ላይ በምልልሱ ውስጥ ቅደም ተከተል የተደረገበት ምክንያት፣ በሁኔታ ቀላቢ ውስጥ ጥቅም ላይ የሚውሉ አጪርጽሑፎችን ለማደባለቅ ነው (ክፍል 14.3)፡፡ በመጀመሪያው ተጠቃሚ ላይ በተሰጠ አንድ አጪርጽሑፍ ላይ መመላለሱ፣ ለሁሉም ተጠቃሚ፣ ከመጀመሪያው ተጠቃሚ ጋር ፍጹም አንድ አይነት የሆነ ሁኔታ ቀላቢን ስለሚሰጥ ለአይን የሚስብ አይሆንም።)

ዝርዝር 13.25: ለናሙና ውሂቡ ጥቂት አጪርጽሑፎችን ማከል። db/seeds.rb
.
.
.
# ለክፍለንዑስ ተጠቃሚዎች አጪርጽሑፎችን ያመነጫል።
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

በዚህ ጊዜ፣ እንደተለመደው የብልጸጋ ውሂበጎታውን እንደገና መዝራት እንችላለን:-

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

የሬይልስ ብልጸጋ አገልጋያችሁን አቁማችሁ እንደ አዲስ ማስጀመር ይኖርባችኋል፡፡

ክፍል 13.2.1 ላይ ላፈሰስነው ላብ፣ አሁን የእያንዳንዱን የአጪርጽሑፍ መረጃ በተጠቃሚው የመገለጫ ገጽ ላይ በማሳየት በላባችን ዋጋ የምንደሰትበት ሁኔታ ላይ እንገኛለን።10 የመባቻ ውጤቱ በምስል 13.6 ላይ ይታያል፡፡

images/figures/user_profile_microposts_no_styling
ምስል 13.6: የተጠቃሚ የመገለጫ ገጹ ቅጥ ካልተደረጉ አጪርጽሑፎች ጋር።

ምስል 13.6 ላይ የሚታየው ገጽ፣ አጪርጽሑፍ ተኮር ቅጥ የለውም፣ ስለሆነም እስኪ ጥቂት ቅጥ እናክልበት እና የተገኙትን ገጾች እንመልከት (ዝርዝር 13.26)፡፡11

ዝርዝር 13.26: ለአጪርጽሑፎች እና ለዚህ ምዕራፍ የሚሆን ቅ.ቋን ማከል። app/assets/stylesheets/bju.scss
.
.
.
/* አጪርጽሑፎች */

.አጪርጽሑፎች {
  list-style: none;
  padding: 0;
  li {
    padding: 10px 0;
    border-top: 1px solid #e8e8e8;
  }
  .ተጠቃሚ {
    margin-top: 5em;
    padding-top: 0;
  }
  .ይዘት {
    display: block;
    margin-left: 60px;
    img {
      display: block;
      padding: 5px 0;
    }
  }
  .ማህተመጊዜ {
    color: $gray-light;
    display: block;
    margin-left: 60px;
  }
  .አምሳያ {
    float: left;
    margin-right: 10px;
    margin-top: 5px;
  }
}

aside {
  textarea {
    height: 100px;
    margin-bottom: 5px;
  }
}

span.image {
  margin-top: 10px;
  input {
    border: 0;
  }
}

ምስል 13.7 የመጀመሪያውን ተጠቃሚ የመገለጫ ገጽ ሲያሳይ፣ ምስል 13.8 ደግሞ የሁለተኛውን ተጠቃሚ የመገለጫ ገጽ ያሳያል፡፡ በመጨረሻም፣ ምስል 13.9 ለመጀመሪያው ተጠቃሚ የአጪርጽሑፎቹ ሁለተኛ ገጽን ከግርጌው ላይ የገጸቁጥር አገናኞቹን ጨምሮ ያሳያል፡፡ በሶስቱም ሁኔታወች ላይ እያንዳንዱ የአጪርጽሑፍ ማሳያ፣ ከተፈጠረበት ጊዜ ጀምሮ ያለውን ጊዜ የሚያመለክት መሆኑን ተገንዘቡ (ምሳሌ፣ “ከ 6 ሰዓት በፊት ተለጠፈ”)፡፡ ይህ ከዝርዝር 13.22 የተገኘ የ‘ጊዜ_በፊት_በቃላት (time_ago_in_words) ዘዴ ስራ ውጤት ነው፡፡ ለጥቂት ደቂቃወች ቆይታችሁ እንደገና ገጾቹን ብትጫኑ፣ በአዲሱ ጊዜ ላይ በመመስረት ጽሑፉ በራስሰር እንዴት እንደሚዘምን ልታዩ ትችላላችሁ።

images/figures/user_profile_with_microposts
ምስል 13.7: የመጀመሪያው ተጠቃሚ የመገለጫ ገጽ ከአጪርጽሑፎቹ ጋር (/teteqamis/1)።
images/figures/other_profile_with_microposts
ምስል 13.8: የአምስተኛው ተጠቃሚ የመገለጫ ገጽ ከአጪርጽሑፎቹ ጋር (/teteqamis/5)።
images/figures/user_profile_microposts_page_2
ምስል 13.9: የአጪርጽሑፍ ገጸቁጥር አገናኞች (/teteqamis/1?page=2)።

መልመጃዎች

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

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

  1. ይህንን:- (1..10).to_a.take(6) ኮድ ማስኬዱ ምን ውጤት እንደሚያመጣ መገመት ትችላላችሁን? ግምታችሁ ትክክል መሆኑን ለማረጋገጥ ይህንኑ ኮድ ሰሌዳችሁ ላይ አስኪዱት።
  2. ከላይኛው መልመጃ ጋር የ‘ወደ_ሃ (to_a) ዘዴን መጠቀሙ አስፈላጊ ነውን?
  3. የአስመሳይ እንቁ በጣም ብዙ የሆኑ የሚያስደስቱ አፕልኬሽኖች አሉት። የአስመሳይ ሰነድን በመመልከት:- አንድ የሐሰት የዩኒቨርሲቲ ስምን፣ አንድ የስልክ ቁጥርን፣ አንድ ዘመናዊ (ሂፕስተር) የኢፕሰም ዓረፍተ ነገርን እና አንድ የሐሰት ቸክ ኖሪስ እውነታን እንዴት ተደርጎ ሰሌዳ ላይ እንደሚታተም ለማወቅ ሞክሩ።

13.2.3 የመገለጫው አጪርጽሑፍ ፈተናዎች

አዲስ የነቁ ተጠቃሚዎች ወደ መገለጫ ገጾቻቸው ሲዟዟሩ፣ የመገለጫ ገጹ በትክክል መቅረቡን የሚያረጋግጥ አንድ ፈተና ቀድሞውኑ ስላለን (ዝርዝር 11.33)፣ በዚህ ክፍል ውስጥ፣ በመገለጫ ገጹ ላይ ላሉ አንዳንድ ነገሮች እና በዚህ ክፍል ውስጥ ለሰራናቸው ነገሮች የሚሆን፣ አንድ አጪር የውህደት ፈተናን እንጽፋለን። የጣቢያችን ተጠቃሚዎች መገለጫወችን ለመፈተን፣ አንድ የውህደት ፈተናን በማመንጨት እንጀምራለን:-

$ rails generate integration_test teteqamis_glemahder
      invoke  test_unit
      create    test/integration/teteqamis_glemahder_test.rb

የአጪርጽሑፍ ገጸቁጥርን ለመፈተን፣ በዝርዝር 10.47 ውስጥ ተጨማሪ ተጠቃሚዎችን ለመፍጠር የተጠቀምንበትን ማለት የክት ሩቢ ስልትን በመጠቀም፣ የተወሰኑ ተጨማሪ የአጪርጽሑፎች እቃዎችን እናመነጫለን:-

<% 30.times do |n| %>
achrtshuf_<%= n %>:
  yizet: <%= Faker::Lorem.sentence(word_count: 5) %>
  created_at: <%= 42.days.ago %>
  teteqami: michael
<% end %>

ዝርዝር 13.15 የነበረው ኮድ ላይ የላይኛውን ኮድ ማከሉ፣ በዝርዝር 13.27 ውስጥ የዘመነውን የአጪርጽሑፍ እቃዎችን ይሰጣል።

ዝርዝር 13.27: የአጪርጽሑፍ እቃዎች አዲስ ከመነጩ አጪርጽሑፎች ጋር test/fixtures/achrtshufs.yml
weba:
  yizet: "ወባ ፊት የነሳው ሰውየ ቡዳ እንዳይበላኝ አለ።"
  created_at: <%= 10.minutes.ago %>
  teteqami: michael

tau_manifesto:
  yizet: "በ @mhartl  @tauday ጣቢያን ተመልከቱ https://tauday.com"
  created_at: <%= 3.years.ago %>
  teteqami: michael

yedmet_video:
  yizet: "የሚያሳዝኑ ድመቶች አሳዛኞች ናቸው: https://youtu.be/PKffm2uI4dk"
  created_at: <%= 2.hours.ago %>
  teteqami: michael

yeqrb_gizei:
  yizet: "አንድ አጪር ፈተና እየጻፍኩ ነው።"
  created_at: <%= Time.zone.now %>
  teteqami: michael

<% 30.times do |n| %>
achrtshuf_<%= n %>:
  yizet: <%= Faker::Lorem.sentence(word_count: 5) %>
  created_at: <%= 42.days.ago %>
  teteqami: michael
<% end %>

ከዚህ የፈተና ውሂብ ተዘጋጅቶ መቅረብ በኋላ፣ የሚደረገው ፈተና በትክክል ግልጽ ነው፤ የተጠቃሚውን የመገለጫ ገጽ እንጎበኝ እና በገጹ ላይ የገጹ አርዕስት፣ የተጠቃሚው ስም፣ የተጠቃሚው አምሳያ፣ የተጠቃሚው አጪርጽሑፎች ብዛት እና ገጸቁጥር ያለው አጪርጽሑፍ መኖሩን እንፈትሻለን። ውጤቱ በዝርዝር 13.28 ውስጥ ይታያል፡፡ የገጹን አርዕስት ለመፈተን ዝርዝር 4.2 ላይ ያለውን የ‘ሙሉ_አርዕስት (mulu_arest) ረጅን እንደተጠቀምን አስተውሉ፤ ይህ ረጅ በዚህ ፈተና ውስጥ እንዲደረስ ለማድረግ፣ የአፕልኬሽን ረጅ ክፍለክፍሉን (Module)፣ በፈተናው ውስጥ ማካተት ይኖርብናል፡፡ 12

ዝርዝር 13.28: የተጠቃሚ መገለጫን መፈተን። አረንጓዴ test/integration/teteqamis_glemahder_test.rb
require "test_helper"

class TeteqamisGlemahderTest < ActionDispatch::IntegrationTest
  include ApplicationHelper

  def setup
    @teteqami = teteqamis(:michael)
  end

  test "የመገለጫ ማሳያ" do
    get teteqami_path(@teteqami)
    assert_template 'teteqamis/show'
    assert_select 'title', mulu_arest(@teteqami.sim)
    assert_select 'h1', text: @teteqami.sim
    assert_select 'h1>img.አምሳያ'
    assert_match @teteqami.achrtshufs.count.to_s, response.body
    assert_select 'div.pagination'
    @teteqami.achrtshufs.paginate(page: 1).each do |achrtshuf|
      assert_match achrtshuf.yizet, response.body
    end
  end
end

ዝርዝር 13.28 ውስጥ የአጪርጽሑፎች ብዛት ማረጋገጫው የ‘መልስ.አካል (response.body) ዘዴን ይጠቀማል፣ ይህንንም በምዕራፍ 12 መልመጃዎች ውስጥ በግልጽ አይተነዋል (ክፍል 12.3.3.1)፡፡ ምንም እንኳ ስሙ ባይገልጸውም፣ የ‘መልስ.አካል (response.body) ዘዴ የገጹን ሙሉ የሃ.ጽ.መ.ቋ ምንጪ ሳይቀር ያጠቃልላል (የገጹን አካል ብቻ አይደለም፡፡) ይህ ማለት እኛ የምንፈልገው ነገር የአጪርጽሑፎቹ ብዛት በገጹ ላይ መታየቱን ብቻ ከሆነ፣ ይሄንኑ የሚያዛመድ አንድ ተዛማጅ እንዳለ እንደሚከተለው አድርገን መመልከት እንችላለን ማለት ነው:-

assert_match @teteqami.achrtshufs.count.to_s, response.body

ይሄ ልክ እንደ መለያ_አረጋግጥ (assert_select) በጣም ንጹር ነገር ላይ የተወሰነ ማረጋገጫ አይደለም፤ በተለይ ደግሞ፣ የ‘አቻነት_አረጋግጥ (assert_match) ማረጋገጫን መጠቀሙ፣ ልክ እንደ መለያ_አረጋግጥ (assert_select) ማረጋገጫ የሃ.ጽ.መ.ቋ መለያን እንድናስገባ አይፈቅድልንም።

ዝርዝር 13.28 እንዲሁ፣ የ‘መለያ_አረጋግጥ (assert_select) የእቅፍቅፍ አገባብን ያስተዋውቃል:-

assert_select 'h1>img.አምሳያ'

ይህ ፈተና በገጹ ላይ አንድ የ‘ምስል (img) መለያ ከ‘ አምሳያ ክፍል ጋር በአንድ ራስጌ1 (h1) አብይ-ደረጃ አርእስት ውስጥ መኖሩን ያረጋግጣል፡፡

የአፕልኬሽን ኮዱ እየሰራ ስለነበር፣ የፈተና ስብስቡ አረንጓዴመሆን ይኖርበታል፡-

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

መልመጃዎች

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

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

  1. ዝርዝር 13.28 ውስጥ ያሉትን ሁለት የ‘ራስጌ1 'h1' መለያወችን ከ አረንጓዴ ወደ ቀይለመቀየር የሚያስችለው የአፕልኬሽን ኮድ ላይ አስተያየት አድርጉ፡፡
  2. ዊል_ገጽቁጥርስጥ (will_paginate) በገጹ ላይ አንድ ጊዜ ብቻ እንዲታይ የሚያስችል አንድ ፈተናን በማከል ዝርዝር 13.28 ‘ን አዘምኑ፡፡ ጠቃሚ ምክር:- ሰንጠረዥ 5.2 ላይ ይመልከቱ፡፡

13.3 አጪርጽሑፎችን ማንቀሳቀስ

የውሂብ ቅዱን እና ለአጪርጽሑፎች ማሳያ የሚሆኑ ዝግጁገጽታዎችን ስለጨረስን፣ አሁን እነሱን በድር በኩል ለመፍጠር ትኩረታችንን ወደ በይነገጹ እናዞራለን። በዚህ ክፍል ውስጥ፣ በምዕራፍ 14 ውስጥ ሙሉ በሙሉ ፍጻሜ ላይ ይደርሳል ተብሎ ተስፋ የተደረገበትን፣ የሁኔታ ቀላቢ አሰራርን ለመጀመሪያ ጊዜ እንመለከታለን። በመጨረሻም፣ ልክ እንደ ተጠቃሚዎች፣ አጪርጽሑፎችንም በድር በኩል ማጥፋት እንደሚቻል እናደርጋለን።

እዚህ ላይ ካለፈው ተለምዷዊ አሰራር የተለየ አንድ ነገር እንዳለ ልብ ሊባል ይገባል፤ ለልዩነቱ ዋናው ምክንያት፣ የአጪርጽሑፎች ሃብት በይነገጹ ተፈጻሚነት የሚኖረው በተጠቃሚው የመገለጫ ገጽ እና በመነሻ ገጹ ላይ መሆኑ ነው፤ ስለሆነም የ‘አዲስ (new) እና የ‘አርትዕ (edit) ተግባሮች በአጪርጽሑፎች መቆጣጠሪያ ውስጥ አያስፈልጉንም፤ የ‘ፍጠር (create) እና የ‘አጥፋ destroy ተግባሮች ግን ያስፈልጉናል፡፡ ይህ በዝርዝር 13.30 ውስጥ ወደሚታየው፣ የአጪርጽሑፎች ሃብት ማዘዋወሪያዎች ይመረናል፡፡ በዝርዝር 13.30 ውስጥ ያለው ኮድ በሰንጠረዥ 13.2 ላይ የሚታየውን ሙሉየው.ሁ.ማ ማዘዋወሪያዎችን ይሰጣል፣ ይህም ሙሉ የማዘዋወሪያዎች ስብስብ ካሉት ሰንጠረዥ 2.3 ጋር ሲነጻጸር፣ የሙሉ ማዘዋወሪያዎቹን ስብስብ አነስተኛ ንዑስ-ስብስብን ይይዛል። ልክ ነው፣ ይህ ማለት ነገሮችን በቀላሉ የመስራት ጥበብን መጠቀማችን ምን ያህል በነገሩ እንደተካንን የሚያሳይ አንድ ምልክት ነው ማለት ነው፣ በእርግጥ ምዕራፍ 2 ውስጥ የመወጣጫ ስልት ላይ ተመርኩዘን አንዳንድ ነገሮችን ከሰራን ጀምሮ እስካሁን ያለው ጊዜ አጪር ጊዜ አይደለም፣ ከዚህ በኋላ የሱን የተወሳሰበ አሰራር አንፈልግም።

ዝርዝር 13.30: ለአጪርጽሑፎች ሃብቱ መዘዋወርያ ማከል። 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
  resources :meleya_magberyas, only: [:edit]
  resources :meda_masjemers,   only: [:new, :create, :edit, :update]
  resources :achrtshufs,       only: [:create, :destroy]
end
የሃ.ጽ.ማ.ስ መጠይቅ ዓ.አ.ሃ.አ ተግባር ስዩም ማዘዋወርያ
POST /achrtshufs create achrtshufs_path
DELETE /achrtshufs/1 destroy achrtshuf_path(achrtshuf)
ሰንጠረዥ 13.2: ዝርዝር 13.30 ውስጥ በአጪርጽሑፍ ሃብት የቀረቡ የሙሉየው.ሁ.ማ ማዘዋወርያዎች።

13.3.1 የአጪርጽሑፍ መዳረሻ መቆጣጠሪያ

በአጪርጽሑፎች መቆጣጠሪያ ውስጥ አንዳንድ የመዳረሻ መቆጣጠሪያዎችን በማከል፣ የአጪርጽሑፎች ሃብት ብልጸጋችንን እንጀምራለን፡፡ በተለይም፣ አጪርጽሑፎችን በተዛማጅ ተጠቃሚዎቻቸው በኩል ስለምንደርስ የ‘ፍጠርም (create) ሆነ የ‘አጥፋ (destroy) ተግባር ተጠቃሚዎች ግዴታ እንዲገቡ ሊጠይቅ ይገባል፡፡

የመግባት ሁኔታን የሚያስገድደው ፈተና፣ ካሁን በፊት ለተጠቃሚዎች መቆጣጠሪያ ከጻፍነው ፈተና ጋር ይመሳሰላል (ዝርዝር 10.20 እና ዝርዝር 10.61)። በዝርዝር 13.31 ላይ እንደሚታየው፣ ትክክለኛውን መጠይቅ ለእያንዳንዱ ተግባር በመስጠት፣ የአጪርጽሑፉ ብዛት እንዳልጨመረ እና ውጤቱም ወደ መግቢያ ዓ.አ.ሃ.አው ማዟዟር መሆኑን እናረጋግጣለን።

ዝርዝር 13.31: ለአጪርጽሑፎች መቆጣጠሪያው የፈቀዳ ፈተናዎች። ቀይ test/controllers/achrtshufs_controller_test.rb
require "test_helper"

class AchrtshufsControllerTest < ActionDispatch::IntegrationTest

  def setup
    @achrtshuf = achrtshufs(:weba)
  end

  test "ባልገባበት ጊዜ መፍጠር ማዟዟር አለበት" do
    assert_no_difference 'Achrtshuf.count' do
      post achrtshufs_path, params: { achrtshuf:
        { yizet: "ወባ ፊት የነሳው ሰውየ ቡዳ እንዳይበላኝ አለ።" } }
    end
    assert_redirected_to gba_url
  end

  test "ባልገባበት ጊዜ ማጥፋት ማዟዟር አለበት" do
    assert_no_difference 'Achrtshuf.count' do
      delete achrtshuf_path(@achrtshuf)
    end
    assert_redirected_to gba_url
  end
end

ዝርዝር 13.31 ውስጥ ያሉት ፈተናዎች ለማለፍ የሚያስፈልጋቸውን ኮድ ለመጻፍ፣ መጀመሪያ በአፕልኬሽኑ ኮድ ላይ አንድ ትንሽ የኮድ ማጣርት ስራን ይጠይቃል። በክፍል 10.2.1 ላይ የ‘ግብ_ተጠቃሚ (gb_teteqami) ዘዴ የሚጠራውን አንድ ቅድመአጣሪ በመጠቀም የግባት መስፈርቱን እንዳስገደድን አስታውሱ (ዝርዝር 10.15)፡፡ በዚያን ጊዜ ይህን ዘዴ በተጠቃሚዎች መቆጣጠሪያ ውስጥ ብቻ ፈልገነው ነበር፣ አሁን ግን በአጪርጽሑፎች መቆጣጠሪያ ውስጥም ያስፈልገናል፣ ስለሆነም የሁሉም መቆጣጠሪያዎች መሰረተ ክፍል ወደሆነው ማለት ወደ አፕልኬሽን መቆጣጠሪያው እናሻግረዋለን (ክፍል 4.4.4)።13 ውጤቱ ደግሞ በዝርዝር 13.32 ውስጥ ይታያል፡፡

ዝርዝር 13.32: የ‘ግብ_ተጠቃሚ (gb_teteqami) ዘዴን ወደ አፕልኬሽን መቆጣጠሪያ ማሸጋገር። ቀይ app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  include SessionsHelper

  private

    # አንድ የገባ ተጠቃሚን ያረጋግጣል።
    def gb_teteqami
      unless gebtual?
        adrasha_askemtie
        flash[:danger] = "እባክዎትን ይግቡ"
        redirect_to gba_url
      end
    end
end

በዚህ ጊዜ የኮድ ድግግሞሽን ለማስወገድ፣ የ‘ግብ_ተጠቃሚ (gb_teteqami) ዘዴን ከተጠቃሚዎች መቆጣጠሪያው ማስወገድ ይኖርባችኋል (ዝርዝር 13.33)።

ዝርዝር 13.33: የ‘ግብ_ተጠቃሚ (gb_teteqami) ዘዴን ከተጠቃሚዎች መቆጣጠሪያ ማስወገድ። ቀይ app/controllers/teteqamis_controller.rb
class TeteqamisController < ApplicationController
  before_action :gb_teteqami, only: [:index, :edit, :update, :destroy]
  .
  .
  .
  private

    def teteqami_negariaseitoch
      params.require(:teteqami).permit(:sim, :emelekt, :password,
                                   :password_confirmation)
    end

    # ቅድመአጣሪወች

    # ትክክለኛውን ተጠቃሚ ያረጋግጣል።
    def tkklegna_teteqami
      @teteqami = Teteqami.find(params[:id])
      redirect_to(root_url) unless ahun_teteqami?(@teteqami)
    end

    # አስተዳዳሪ ተጠቃሚን ያረጋግጣል።
    def astedadari_teteqami
      redirect_to(root_url) unless ahun_teteqami.astedadari?
    end
end

ዝርዝር 13.32 ውስጥ ካለው ኮድ ጋር፣ የ‘ግብ_ተጠቃሚ (gb_teteqami) ዘዴ አሁን በአጪርጽሑፎች መቆጣጠሪያ ውስጥ ይገኛል፣ ይህ ማለት ዝርዝር 13.34 ላይ እንደሚታየው፣ የ‘ፍጠር (create) እና የ‘አጥፋ destroy ተግባሮችን መቆጣጠሪያው ውስጥ ማከል እና አንድ ቅድመአጣሪን በመጠቀም በነሱ ላይ የመዳረሻ ግደባን ማስቀመጥ እንችላለን ማለት ነው፡፡

ዝርዝር 13.34: ለአጪርጽሑፎች መቆጣጠሪያ ተግባሮች ፈቃድን ማከል። አረንጓዴ app/controllers/achrtshufs_controller.rb
class AchrtshufsController < ApplicationController
  before_action :gb_teteqami, only: [:create, :destroy]

  def create
  end

  def destroy
  end
end

በዚህ ጊዜ ፈተናው ማለፍ አለበት:-

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

መልመጃዎች

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

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

  1. የ‘ግብ_ተጠቃሚ (gb_teteqami) ዘዴን በተጠቃሚዎች መቆጣጠሪያ ውስጥ መተው፣ መጥፎ የሆነበት ምክንያት ለምንድን ነው?

13.3.2 አጪርጽሑፎችን መፍጠር

ምዕራፍ 7 ውስጥ፣ በተጠቃሚዎች መቆጣጠሪያ ውስጥ ለ‘ፍጠር (create) ተግባር አንድ የሃ.ጽ.ማ.ስ ዓስቀምጥ (HTTP POST) መጠይቅን የሚሰጥ የሃ.ጽ.መ.ቋ ቅጽን በማቅረብ የተጠቃሚ ምዝገባን ተግባራዊ አድርገናል፡፡ አጪርጽሑፍን ለመፍጠር የሚደረገው የአሰራር ሂደትም ከዚሁ ጋር ተመሳሳይ ይሆናል፤ እዚህ ላይ ያለው ዋናው ልዩነት፣ አጪርጽሑፎቹን ለመፍጠር የተለየ አንድ ገጽን አጪርጽሑፎች/አዲስ (/achrtshufs/new) ላይ ከማድረግ ፈንታ በመነሻ ገጹ (ማለትም፣ በስር መንገዱ “/”) ላይ ይህንኑ ማድረጋችን ብቻ ነው፡፡ ይህም በምስል 13.10 ላይ በስእላዊ መግለጫ ላይ ቁልጪ ብሎ ይታያል፡፡

images/figures/home_page_with_micropost_form_mockup_bootstrap
ምስል 13.10: የመነሻ ገጹ ከአንድ አጪርጽሑፍ መፍጠሪያ ቅጽ ጋር የሚያሳይ አንድ ስእላዊ መግለጫ።

የመነሻ ገጹን መጨረሻ ላይ ስንሰናበተው፣ በምስል 5.8 ላይ እንደሚታየው፣ በአንድ አዝራር ውስጥ “ይመዝገቡ” የሚል ጽሑፍ ብቻ እንደያዘ ነበር። በአንድ የአጪርጽሑፍ መፍጠርያ ቅጽ አውድ ውስጥ፣ አንድ የገባ ተጠቃሚን ብቻ የሚመለከት ስለሆነ፣ የዚህ ክፍል አንዱ ግብ፣ በአንድ ጎብኝ የአገባብ ሁኔታ ላይ በመመርኮዝ የተለያዩ የመነሻ ገጽ ስሪቶችን ማስተናገድ ይሆናል፡፡ ይህንን ከዚህ በታች በዝርዝር 13.37 ላይ ተግባራዊ እናደርጋለን፡፡

ከተጠቃሚ አፈጣጠር ጋር ተመሳሳይ የሆነውን የአጪርጽሑፍ አፈጣጠር ለመጀመር፣ በአጪርጽሑፎች የፍጠር (create) ተግባር እንጀምራለን (ዝርዝር 7.26)፡፡ በዝርዝር 13.36 ላይ እንደሚታየው፣ ዋናው ልዩነት አጪርጽሑፉን ለ‘መፍጠር/ለ‘መገንባት (build) የተጠቃሚ እና የአጪርጽሑፉ ማሕበርን መጠቀሙ ላይ ነው፡፡ እዚህ ላይ በ‘አጪርጽሑፎች_ነጋሪአሴቶች (achrtshuf_negariaseitoch) በኩል የጠንካራ ሰሚአሴት አጠቃቀምን አስተውሉ፤ ይህ የአጪርጽሑፍ የይዘት (yizet) ባሕሪ ብቻ በድር በኩል እንዲሻሻል ይፈቅዳል፡፡

ዝርዝር 13.36: የአጪርጽሑፎች መቆጣጠሪያ የ‘ፍጠር (create) ተግባር። app/controllers/achrtshufs_controller.rb
class AchrtshufsController < ApplicationController
  before_action :gb_teteqami, only: [:create, :destroy]

  def create
    @achrtshuf = ahun_teteqami.achrtshufs.build(achrtshuf_negariaseitoch)
    if @achrtshuf.save
      flash[:success] = "አጪርጽሑፍ ተፈጥሯል!"
      redirect_to root_url
    else
      render 'quami_getss/menesha'
    end
  end

  def destroy
  end

  private

    def achrtshuf_negariaseitoch
      params.require(:achrtshuf).permit(:yizet)
    end
end

አጪርጽሑፎችን ለመፍጠር አንድ ቅጽን ለመገንባት፣ በዝርዝር 13.37 ውስጥ ያለውን ኮድ እንጠቀማለን፣ ይህም የጣቢያው ጎብኝ፣ በጣቢያው ውስጥ በመግባቱ እና ባለመግባቱ ላይ በመመርኮዝ የተለያየ ሃ.ጽ.መ.ቋን በማቅረብ ያስተናግዳል።

ዝርዝር 13.37: የአጪርጽሑፎች መፍጠርያን በመነሻ ገጹ ላይ ማከል (/)። 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/achrtshuf_qts' %>
      </section>
    </aside>
  </div>
<% else %>
  <div class="center jumbotron">
    <h1 id="እንኳን"> እንኳን ወደ ማሳያ አፕልኬሽን በደህና መጡ! </h1>

    <h2>
      ይህ <a href="https://www.railstutorial.org/">
      የሩቢ ኦን ሬይልስ ስልጠና ትምህርት</a>
      ማሳያ ለተባለው አፕልኬሽን፡ የመነሻ ገጽ ነው፡፡
    </h2>

    <%= link_to "ይመዝገቡ", temezgeb_path, class: "btn btn-lg btn-primary" %>
  </div>

  <%= link_to image_tag("rails.svg", alt: "የሬይልስ አርማ", width: "200"),
                        "https://rubyonrails.org/" %>
<% end %>

(በከሆነ-ካልሆነ (if-else) የሁኔታ ማጣሪያ መሃል በዛ ያሉ ኮዶችን በአንድ ቦታ መቆለሉ ደስ አይልም፣ እናም አንድ ከፊልን በመፍጠር ይህንን ማስዋቡ፣ ልክ እንደ አንድ መልመጃ ይሆናችሁ ዘንድ ለናንተ ተትቷል (ክፍል 13.3.2.1))።

ዝርዝር 13.37 ውስጥ የተበየነው ገጽ ስራውን እንዲጀምር፣ ሁለት ከፊሎችን መፍጠር እና እነሱን በሚገባቸው ኮድ መሙላት ይኖርብናል፡፡ በዝርዝር 13.38 ላይ እንደሚታየው፣ የመጀመሪያው የመነሻ ገጹ አዲሱ የጎን-አሞሌ ነው።

ዝርዝር 13.38: የተጠቃሚ መረጃው የጎን-አሞሌው ከፊል። app/views/gru/_teteqami_mereja.html.erb
<%= link_to amsaya_le(ahun_teteqami, meten: 50), ahun_teteqami %>
<h1><%= ahun_teteqami.sim %></h1>
<span><%= link_to "መገለጫዎን ይመልከቱ", ahun_teteqami %></span>
<span><%= abza(ahun_teteqami.achrtshufs.count, "achrtshuf") %></span>

የመገለጫ የጎን-አሞሌው፣ የአጪርጽሑፎቹን አጠቃላይ ብዛት ለተጠቃሚው እንደሚያሳይ ሁሉ (ዝርዝር 13.24)፣ በዝርዝር 13.38 ውስጥ ያለው የተጠቃሚ መረጃ ከፊልም እንደዛው እንደሚያደርግ አስተውሉ፡፡ ይሁን እንጅ በሁለቱ ገጾች ትይታ ላይ አንድ ትንሽ ልዩነት አለ፤ በመገለጫ የጎን-አሞሌው ውስጥ ያለው “አጪርጽሑፎች” የሚለው ጽሑፍ መለያ ስለሆነ 1 አጪርጽሑፍ ቢኖር “(1) አጪርጽሑፍ” ብሎ ገጹ ላይ ማሳየቱ ትርጉም ይሰጣል። በአሁኑ ሁኔታ ላይ ግን፣ የተጠቃሚው መረጃን የያዘው ከፊል ላይ አንድ አጪርጽሑፍ ብቻ ሲኖር “1 አጪርጽሑፎች” ብሎ ማሳየቱ ትክክል ያልሆነ አረፍተ ነገር ስለሚሆን፣ አንድ አጪርጽሑፍ ሲኖር “1 አጪርጽሑፍ” እና ሁለት አጪርጽሑፎች ሲኖሩ ደግሞ “2 አጪርጽሑፎች” ብሎ በገጹ ላይ እንዲያሳይ፣ ካሁን በፊት በክፍል 7.3.3 ላይ ያየነውን የ‘አብዛ (abza) ዘዴን እንጠቀማለን።

ቀጥለን፣ በዝርዝር 13.39 ውስጥ ከተጠቃሚ የምዝገባ ቅጽ ጋር ተመሳሳይ የሆነውን (ዝርዝር 7.15)፡ የአጪርጽሑፎች መፍጠርያ ቅጽን እንበይናለን።

ዝርዝር 13.39: የአጪርጽሑፎች መፍጠሪያ ቅጽ ከፊል፡፡ app/views/gru/_achrtshuf_qts.html.erb
<%= form_with(model: @achrtshuf, local: true) do || %>
  <%= render 'gru/shtet_melektoch', object: .object %>
  <div class="መስክ">
    <%= .text_area :yizet, placeholder: "አዲስ አጪርጽሑፍ አዘጋጅ..." %>
  </div>
  <%= .submit "አስቀምጥ", class: "btn btn-primary" %>
<% end %>

ዝርዝር 13.39 ውስጥ ያለው ቅጽ ስራ ላይ ከመዋሉ በፊት ሁለት ለውጦችን ማድረግ አለብን፡፡ መጀመሪያ ማድረግ ያለብን ነገር፣ በማሕበሩ በኩል (ከዚህ በፊት እንዳደረግነው) አንድ @አጪርጽሑፍ (@achrtshuf) የተባለ ቅርፀ ተለዋዋጪን መበየን ይሆናል:-

@achrtshuf = ahun_teteqami.achrtshufs.build

ውጤቱም በዝርዝር 13.40 ውስጥ ይታያል፡፡

ዝርዝር 13.40: በ‘መነሻ (menesha) ተግባሩ ውስጥ አንድ የአጪርጽሑፍ ቅርፀ ተለዋዋጪን ማከል። app/controllers/quami_getss_controller.rb
class QuamiGetssController < ApplicationController

  def menesha
    @achrtshuf = ahun_teteqami.achrtshufs.build if gebtual?
  end

  def erdata
  end

  def silegna
  end

  def agignun
  end
end

በእርግጥ፣ የ‘ዓሁን_ተጠቃሚ (ahun_teteqami) የሚኖረው ከገባ ብቻ ነው፣ ስለሆነም ምክንያቱ ይሄ ከሆነ ብቻ የ‘@አጪርጽሑፍ (@achrtshuf) ተለዋዋጪን መበየን ይኖርበታል ማለት ነው።

ዝርዝር 13.39 ውስጥ ያለው ቅጽ ስራ ላይ ከመዋሉ በፊት፣ ሁለተኛ ማድረግ ያለብን ነገር ደግሞ፣ ካሁን በፊት የሰራነውን የስህተት መልእክቶች ከፊልን እንደሚከተለው አድርገን እንዳዲስ መበየን ነው:-

<%= render 'gru/shtet_melektoch', object: .object %>

ዝርዝር 7.20 ውስጥ የስህተት መልእክቶች ከፊሉ የ‘@ተጠቃሚ (@teteqami) ተለዋዋጪን በግልጽ እንደሚያመላክት ታስተውሱ ይሆናል፣ አሁን ባለው ሁኔታ ላይ በምትኩ ያለን ግን አንድ የ‘@አጪርጽሑፍ (@achrtshuf) ተለዋዋጪ ነው፡፡ እነዚህ ሁኔታዎች ላይ አንድ የጋራ መፍትሄን ለመፍጠር  የተባለውን የቅጹን ተለዋዋጪ ወደ ከፊሉ ማሳለፍ እና የሚዛመደውን ቁሱ በ‘ቅ.ቁስ (ቅ.object) በኩል መድረስ ይሆናል፣ ስለዚህ በዚህ ውስጥ:-

form_with(model: @teteqami, local: true) do ||

የ‘ቅ.ቁስ (ቅ.object) ቁሱ @ተጠቃሚ (@teteqami) ይሆናል፡፡ በ:-

form_with(model: @achrtshuf, local: true) do ||

ውስጥ ደግሞ የ‘ቅ.ቁስ (ቅ.object) ቁሱ @አጪርጽሑፍ (@achrtshuf) ይሆናል፣ እና ሌላውም በዚሁ መልኩ ይቀጥላል (ወዘተረፈ)።

ቁሱን ወደ ከፊሉ ለማሳለፍ፣ የቁሱ ዋጋን እና ከፊሉ እንዲባል የሚፈለገውን የተለዋዋጪ ስምን እንደ ቁልፍ አድርጎ የያዘ አንድ ተርታን እንጠቀማለን፣ ዝርዝር 13.39 ውስጥ ያለው ሁለተኛው መስመር የሚያከናውነውም ይህንኑ ነው፡፡ በሌላ አማርኛ፣ ቁስ: ቅ.ቁስ (object: ቅ.object) የሚለው ኮድ አንድ ቁስ (object) የተባለ ተለዋዋጪን በ‘ስህተት_መልእክቶች (shtet_melektoch) ከፊል ውስጥ ይፈጥራል ማለት ነው፡፡ እናም በዝርዝር 13.41 ላይ እንደሚታየው፣ አንድ ብጁ የስህተት መልእክትን ለመገንባት ልንጠቀምበት እንችላለን ማለት ነው፡፡

ዝርዝር 13.41: ከሌሎች ቁሶች ጋር የሚሰሩ የስህተት መልእክቶች። ቀይ app/views/gru/_shtet_melektoch.html.erb
<% if object.errors.any? %>
  <div id="ስህተት_ማብራሪያ">
    <div class="alert alert-danger">
      ቅጹ <%= abza(object.errors.count, "shtet") %> ስህተት/ቶች ይዟል።
    </div>
    <ul>
    <% object.errors.full_messages.each do |melekt| %>
      <li><%= melekt %></li>
    <% end %>
    </ul>
  </div>
<% end %>

በዚህ ጊዜ፣ የፈተና ስብስቡ ቀይመሆኑን ማረጋገጥ ይኖርባችኋል:-

ዝርዝር 13.42: ቀይ
$ rails test

ይህ እያንዳንዱ የስህተት መልእክቶች ከፊልን የሚጠቀም ቅጽን ማዘመን እንዳለብን የሚጠቁም አንድ ፍንጪ ነው፣ እኛም ይህንን ተጠቃሚዎችን ለመመዝገብ (ዝርዝር 7.20)፣ መሕለፈቃሎችን ዳግም ለማስጀመር (ዝርዝር 12.14) እና ተጠቃሚዎችን ለማረም (ዝርዝር 10.2) ተጠቅመንበታል። የዘመኑት ቅጾች በዝርዝር 13.43፣ በዝርዝር 13.45 እና በዝርዝር 13.44 ላይ ይታያሉ፡፡

ዝርዝር 13.43: የተጠቃሚ ምዝገባ ስህተቶች ማቅረብን ማዘመን። ቀይ app/views/teteqamis/new.html.erb
<% provide(:title, 'ይመዝገቡ') %>
<h1 class="ራስጌ1">ይመዝገቡ</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= form_with(model: @teteqami, local: true) do || %>
      <%= render 'gru/shtet_melektoch', object: .object %>

      <%= .label :sim, 'ስም' %>
      <%= .text_field :sim, class: 'form-control' %>

      <%= .label :emelekt, 'ኤመልእክት' %>
      <%= .email_field :emelekt, class: 'form-control' %>

      <%= .label :password, 'መሕለፈቃል' %>
      <%= .password_field :password, class: 'form-control' %>

      <%= .label :password_confirmation, "አረጋግጥ" %>
      <%= .password_field :password_confirmation, class: 'form-control' %>

      <%= .submit "ለኔ መለያ ፍጠር", class: "btn btn-primary" %>
    <% end %>
  </div>
</div>
ዝርዝር 13.44: የተጠቃሚ እርማት ስህተቶች ማቅረብን ማዘመን። ቀይ app/views/teteqamis/edit.html.erb
<% provide(:title, "የተጠቃሚ እርማት") %>
<h1 class="ራስጌ1">መገለጫዎን ያዘምኑ</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= form_with(model: @teteqami, local: true) do || %>
      <%= render 'gru/shtet_melektoch', object: .object %>

      <%= .label :sim, 'ስም' %>
      <%= .text_field :sim, class: 'form-control' %>

      <%= .label :emelekt, 'ኤመልእክት' %>
      <%= .email_field :emelekt, class: 'form-control' %>

      <%= .label :password, 'መሕለፈቃል' %>
      <%= .password_field :password, class: 'form-control' %>

      <%= .label :password_confirmation, "አረጋግጥ" %>
      <%= .password_field :password_confirmation, class: 'form-control' %>

      <%= .submit "ለኔ መለያ ፍጠር", class: "btn btn-primary" %>
    <% end %>

    <div class="amsaya_artot">
      <%= amsaya_le @teteqami %>
      <a href="http://gravatar.com/emails" target="_blank" rel="noopener">ቀይር</a>
    </div>
  </div>
</div>
ዝርዝር 13.45: የመሕለፈቃል ዳግም ማስጀመርያ ስህተቶችን ማዘመን። አረንጓዴ app/views/meda_masjemers/edit.html.erb
<% provide(:title, 'መሕለፈቃል ዳግም ማስጀመርያ') %>
<h1 class="ራስጌ1">መሕለፈቃል ዳግም ማስጀመርያ</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= form_with(model: @teteqami, url: meda_masjemer_path(params[:id]),
                  local: true) do || %>
      <%= render 'gru/shtet_melektoch', object: .object %>
      <%= hidden_field_tag :emelekt, @teteqami.emelekt %>

      <%= .label :password, 'መሕለፈቃል' %>
      <%= .password_field :password, class: 'form-control' %>

      <%= .label :password_confirmation, "አረጋግጥ" %>
      <%= .password_field :password_confirmation, class: 'form-control' %>

      <%= .submit "መሕለፈቃልዎን ያዘምኑ", class: "btn btn-primary" %>
    <% end %>
  </div>
</div>

በዚህ ጊዜ፣ የፈተና ስብስቡ አረንጓዴመሆን ይኖርበታል:-

$ rails test

በተጨማሪም፣ በዚህ ክፍል ውስጥ የሰራናቸው ሁሉም የሃ.ጽ.መ.ቋ ኮዶች ማለት በምስል 13.11 ላይ እንደሚታየው፣ አንድ አዲስ የአጪርጽሑፍ መፍጠሪያ ቅጽ እና በምስል 13.12 ላይ እንዳለው፣ ማለት ቅጹ አንድ የማስረከብ ስህተት እንዳለው የሚያመለክት የመሳሰሉትን በትክክል ማቅረብ አለባቸው፡፡14

images/figures/home_with_form
ምስል 13.11: የመነሻ ገጹ ከአንድ አዲስ የአጪርጽሑፍ ቅጽ ጋር።
images/figures/home_form_errors
ምስል 13.12: የመነሻ ገጹ ከአንድ የሰህተት ቅጽ ጋር።

መልመጃዎች

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

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

  1. የመነሻ ገጹ በከሆነ-ካልሆነ (if-else) ዓረፍተሐሳብ መሃል ላሉት ሁለት ቅርንጫፎች የተለያዩ ከፊሎችን ይጠቀም ዘንድ፣ ኮዱን አጣሩ።

13.3.3 አንድ የቀደምት-ቀላቢ

ምንም እንኳን የአጪርጽሑፍ ቅጹ አሁን እየሰራ ቢሆንም፣ ተጠቃሚወች የአንድ የተሳካ ርክብ ውጤትን ግን ወዲያውኑ ማየት አይችሉም፣ ምክንያቱም አሁን የመነሻ ገጹ ምንም ዓይነት አጪርጽሑፍን ስለማያሳይ ነው፡፡ ተጠቃሚዎች ውጤቱን ለማየት ከፈለጉ፣ አንድ ያላቸው አማራጪ ዝርዝር 13.11 ላይ አንድ ብቁ አጪርጽሑፍን ካስረከቡ በኋላ፣ ከዚያ ቅምጡን ለማየት የመገለጫ ገጻቸውን መጎብኘት ይሆናል፣ ይህ ደግሞ ፍጹም የማይመች አሰራር ነው፡፡ በምስል 13.13 ስእላዊ መግለጫ ላይ እንደሚታየው፣ አንድ የተጠቃሚውን ቅምጦች የሚያካትት የአጪርጽሑፎች ቀላቢ ቢኖር በጣም የተሻለ ይሆናል። (በምዕራፍ 14 ውስጥ፣ የአሁኑን ተጠቃሚ፣ የሚከተሉት ተጠቃሚዎች አጪርጽሑፎችን ለማካተት፣ ይህንን ቀላቢ በማጠቃለል ትዊተርን እናስመስለዋለን።)

images/figures/proto_feed_mockup
ምስል 13.13: የመነሻ ገጹ ስእላዊ መግለጫ፣ ከአንድ ቀደምት-ቀላቢ ጋር።

እያንዳንዱ ተጠቃሚ አንድ ቀላቢ ሊኖረው ስለሚገባ፣ በተጠቃሚ ቅርጸቱ ውስጥ አንድ ቀላቢ (qelabi) የተባለ ዘዴን እናክላለን፣ ይህም የአሁኑ ተጠቃሚ የሆኑትን ሁሉንም አጪርጽሑፎች መጀመሪያ ላይ ብቻ የሚመርጥ ይሆናል፡፡ በዝርዝር 13.46 ላይ እንደሚታየው፡ በ‘አጪርጽሑፍ (Achrtshuf) ቅርጸት ላይ የ‘የት (where) ዘዴን በመጠቀም (ከዚያ በፊት በክፍል 11.3.3.1 ውስጥ ባየነው መሰረት) ይህንን ነገር እናሳካለን፡፡15

ዝርዝር 13.46: ለአጪርጽሑፍ ሁኔታ ቀላቢ፤ የመጀመሪያ ደረጃ ትግበራ፡፡ app/models/teteqami.rb
class Teteqami < ApplicationRecord
  .
  .
  .
  # አንድ ቀደምት-ቀላቢን ይበይናል።
  # ለተሟላ ትግበራ "ተጠቃሚዎችን መከተል" ላይ ተመልከቱ፡፡
  def qelabi
    Achrtshuf.where("teteqami_id = ?", id)
  end

  private
    .
    .
    .
end

እዚህ ላይ ያለው የጥያቄ ምልክት:-

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

የተ.መ.ቋ መጠይቁ ከመካተቱ በፊት፣ መታወቂያው (id) በስር በትክክል ማምለጡን ያረጋግጣል፣ በዚህም የተ.መ.ቋ ውግያ (SQL injection) ተብሎ የሚጠራውን አንድ ከባድ የጥበቃ ቀዳዳን ያስወግዳል፡፡ እዚህ ያለው የ‘መታወቂያ (id) ባሕሪ የያዘው የውሂብ ዓይነት አንድ ሙሉ ቁጥር ነው፣ (ማለትም ራሥ.መታወቂያ (self.id) ማለት ለተጠቃሚው ብቻ የተሰጠ ልዩ መታወቂያ ማለት ነው)፣ ስለሆነም በዚህ ሁኔታ ላይ የተ.መ.ቋ ውግያ ምንም አይነት አደጋ አያደርስም፣ ይሁን እንጂ ይህን ማድረጉ ምንም የማይጎዳ እና በተ.መ.ቋ ዓረፍተሐሳቦች ውስጥ የተወጉ/የገቡ ተለዋዋጮችን ሁል ጊዜ ማስመለጡ ከወዲሁ የሚደገፍ አንድ ጥሩ የሆነ ልምድ ነው።

አንዳንድ አስታዋይ አንባቢዎች በዚህን ጊዜ፣ በዝርዝር 13.46 ላይ ያለው ኮድ፣ የሚከተለው ኮድን ከመጻፍ ጋር አንድ ዓይነት ውጤት እንደሚሰጥ ሊያስተውሉ ይችሉ ይሆናል:-

def qelabi
  achrtshufs
end

ምዕራፍ 14 ላይ የሚያስፈልገውን ሙሉ የሁኔታ ቀላቢ ተፈጥሮዋዊ በሆነ መልኩ የበለጠ አጠቃላይ ያደርግልን ዘንድ፣ በምትኩ በዝርዝር 13.46 ውስጥ ያለውን ኮድ እንጠቀማለን፡፡

በአፕልኬሽኑ ውስጥ ቀላቢውን ለመጠቀም፣ በዝርዝር 13.47 ላይ እንደሚታየው፣ ለአሁኑ ተጠቃሚ መቀለቢያ አንድ ወሬ_ቀላቢ (@werie_qelabi) የተባለ ቅርፀ ተለዋዋጪን እናክል እና ከዚያ አንድ የሁኔታ ቀላቢ ከፊልን (ዝርዝር 13.48)፣ በመነሻ ገጹ ላይ እናክለለን (ዝርዝር 13.49)፡፡ አሁን ተጠቃሚው ገብቶ እያለ መሄድ የሚያስፈልጋቸው ሁለት መስመር ኮዶች መኖራቸውን እዚህ ላይ አስተውሉ፣ ይህንን ለማድረግም ዝርዝር 13.47 ይህንን ኮድ:-

@achrtshuf = ahun_teteqami.achrtshufs.build if gebtual?

ዝርዝር 13.40 ወደ ሚከተለው ይቀየራል :-

if gebtual?
  @achrtshuf = ahun_teteqami.achrtshufs.build
  @werie_qelabi = ahun_teteqami.qelabi.paginate(page: params[:page])
end

በዚህም ሁለቱን መስመሮች በ‘ከሆነ (if) እና በ‘ጨርስ (end) ዓረፍተሐሳብ ውስጥ ያሻግራል፡፡

ዝርዝር 13.47: በ‘መነሻ (menesha) ተግባር ውስጥ አንድ የቀላቢ ቅርፀ ተለዋዋጪን ማከል። app/controllers/quami_getss_controller.rb
class QuamiGetssController < ApplicationController

  def menesha
    if gebtual?
      @achrtshuf = ahun_teteqami.achrtshufs.build
      @werie_qelabi = ahun_teteqami.qelabi.paginate(page: params[:page])
    end
  end

  def erdata
  end

  def silegna
  end

  def agignun
  end
end
ዝርዝር 13.48: የሁኔታ ቀላቢው ከፊል። app/views/gru/_qelabi.html.erb
<% if @werie_qelabi.any? %>
  <ol class="አጪርጽሑፎች">
    <%= render @werie_qelabi %>
  </ol>
  <%= will_paginate @werie_qelabi, :previous_label => "ቀዳሚ",
                                       :next_label => "ቀጣይ" %>
<% end %>

የሁኔታ ቀላቢ ከፊሉ አቅርቦቱን በዝርዝር 13.22 ውስጥ ለተበየነው የአጪርጽሑፍ ከፊል ያስተላልፋል:-

<%= render @werie_qelabi %>

እዚህ ላይ እያንዳንዱ የ‘ወሬ_ቀላቢ (@werie_qelabi) አባል የ‘አጪርጽሑፍ (Achrtshuf) ክፍል ስላለው፣ ሬይልስ የአጪርጽሑፍ ከፊሉን እንደሚጠራ ጠንቅቆ ያውቃል፡፡ ይህም ሬይልስን በተሰጠው የትይታዎች ማውጫ ምንጪ ውስጥ፣ አንድ ተዛማጅ ስም ያለው ከፊልን እንዲመለከት ያደርገዋል:-

app/views/achrtshufs/_achrtshuf.html.erb

እንደተለመደው የቀላቢ ከፊሉን በማቅረብ፣ ቀላቢውን በመነሻ ገጹ ውስጥ ማከል እንችላለን (ዝርዝር 13.49)፡፡ ይህን በማከናወን የተገኘው ውጤትም እንደተፈለገው በመነሻ ገጹ ላይ የሚያገለግል አንድ የቀላቢ ማሳያ ነው (ምስል 13.14)።

ዝርዝር 13.49: አንድ የሁኔታ ቀላቢን በመነሻ ገጹ ውስጥ ማከል። 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/achrtshuf_qts' %>
      </section>
    </aside>
    <div class="col-md-8">
      <h3>አጪርጽሑፍ ቀላቢ</h3>
      <%= render 'gru/qelabi' %>
    </div>
  </div>
<% else %>
  .
  .
  .
<% end %>
images/figures/home_with_proto_feed
ምስል 13.14: የመነሻ ገጹ ከአንድ ቅደምት-ቀላቢ ጋር።

በዚህ ጊዜ፣ በምስል 13.15 ላይ እንደሚታየው፣ አንድ አዲስ አጪርጽሑፍን መፍጠሩ እንደተጠበቀው ይሰራል፡፡

images/figures/micropost_created
ምስል 13.15: የመነሻ ገጹ አንድ አዲስ አጪርጽሑፍ ከፈጠረ በኋላ፡፡

እዚህ ላይ አንድ እንከን አለ፣ ይህም አንድ ብቁ ያልሆነ አጪርጽሑፍ በሚረከብበት ጊዜ፣ የመነሻ ገጹ አንድ ወሬ_ቀላቢ (@werie_qelabi) ቅርፀ ተለዋዋጪን ይጠብቃል፡፡ ይህ ተለዋዋጪ ባለመኖሩ ምክንያት፣ በአሁኑ ወቅት ብቁ ያልሆነ አጪርጽሑፍን በምናስረክብ ጊዜ፣ አፕልኬሽኑ ይሰበራል። በዝርዝር 13.50 ውስጥ እንደተመለከተው፣ የዚህ መፍትሄ በአጪርጽሑፎች መቆጣጠሪያ የ‘ፍጠር (create) ተግባር ውስጥ፣ ያልተሳኩ ርክቦችን የሚያስተናግድ አስፈላጊ የቀላቢ ተለዋዋጪን በቅርንጫፉ ውስጥ መፍጠር ነው፡፡

ዝርዝር 13.50: በ‘ፍጠር (create) ተግባር ውስጥ አንድ (ባዶ) የ‘ወሬ_ቀላቢ (@werie_qelabi) ቅርፀ ተለዋዋጪን ማከል። app/controllers/achrtshufs_controller.rb
class AchrtshufsController < ApplicationController
  before_action :gb_teteqami, only: [:create, :destroy]

  def create
    @achrtshuf = ahun_teteqami.achrtshufs.build(achrtshuf_negariaseitoch)
    if @achrtshuf.save
      flash[:success] = "አጪርጽሑፍ ተፈጥሯል!"
      redirect_to root_url
    else
      @werie_qelabi = ahun_teteqami.qelabi.paginate(page: params[:page])
      render 'quami_getss/menesha'
    end
  end

  def destroy
  end

  private

    def achrtshuf_negariaseitoch
      params.require(:achrtshuf).permit(:yizet)
    end
end

አለመታደል ሆኖ፣ ገጸቁጥሩ አሁንም በትክክል አይሰራም። ይህ ለምን እንደዛ እንደሆነም አንድ ርዝመቱ ረጅም የሆነ አጪርጽሑፍን በማስረከብ መየት እንችላለን (ምስል 13.16)፡፡

images/figures/home_page_invalid_micropost
ምስል 13.16: አንድ ብቁ ያልሆነ አጪርጽሑፍ በመነሻ ገጹ ላይ።

የመነሻ ገጹን ወደታች ስንሸበልል፣ የገጸቁጥር አገናኞችን ማለት “2” እና “ቀጣይ” የሚሉ አገናኞችን እናያለን (ምስል 13.17)፡፡ እዚህ ላይ የ‘ፍጠር (create) ተግባር በአጪርጽሑፎች መቆጣጠሪያ ውስጥ (ዝርዝር 13.50)፣ ዓ.አ.ሃ.አው /አጪርጽሑፎች?ገጽ=2 (/achrtshufs?page=2) ነው፣ ይህም ጪራሽ ወዳልተፈጠረው የአጪርጽሑፎች ማውጫ (index) ተግባር ለመሄድ ይሞክራል። በዚህ ምክንያትም፣ ከሁለቱ አገናኞች ውስጥ ማንኛውንም ጠቅ ማድረጉ አንድ የማዟዟር ስህተትን ይሰጣል (ምስል 13.18)፡፡

images/figures/home_page_invalid_micropost
ምስል 13.18: በሁተኛው (2) ገጽ ላይ የተከሰተ አንድ የማዟዟር ስህተት።

ከመነሻ ገጹ ጋር የሚዛመዱ ግልጽ የ‘መቆጣጠርያ (controller) እና ግልጽ የ‘ተግባር (action) ሰሚአሴቶችን ለ‘ዊል_ገጽቁጥርስጥ (will_paginate) በመስጠት ይህንን ችግር መፍታት እንችላለን፡፡ ይህ ማለት መቆጣጠሪያ‘ው ተጠቃሚ_ገጾች (quami_getss) ሲሆን፣ ተግባሩ ደግሞ መነሻ (menesha) ይሆናል ማለት ነው፡፡16 ውጤቱ በዝርዝር 13.51 ላይ ይታያል፡፡

ዝርዝር 13.51: አንድ ግልጽ መቆጣጠሪያን እና ተግባርን ማቀናበር። app/views/gru/_qelabi.html.erb
<% if @werie_qelabi.any? %>
  <ol class="አጪርጽሑፎች">
    <%= render @werie_qelabi %>
  </ol>
  <%= will_paginate @werie_qelabi, params: { controller: :quami_getss,
    action: :menesha }, :previous_label => "ቀዳሚ", :next_label => "ቀጣይ" %>
<% end %>

ዝርዝር 13.19 ላይ እንደሚታየው፣ በዝርዝር  13.17 ውስጥ አሁን ከሁለቱ አገናኞች ውስጥ ማንኛውንም ጠቅ ማድረጉ የተጠበቀውን ሁለተኛውን ገጽ ያስገኛል።

images/figures/home_page_feed_second_page
ምስል 13.19: ወደ ሁለተኛው ገጽ ለመሄድ የሚሰራ የገጸቁጥር አገናኝ ውጤት።

መልመጃዎች

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

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

  1. አዲስ የተፈጠረውን የአጪርጽሑፍ የተጠቃሚ በይነገጽ (ተ.በ (UI)) በመጠቀም፣ የመጀመሪያውን እውነተኛ አጪርጽሑፍ ፍጠሩ። በአገልጋዩ ዘጋቢ ውስጥ ያለው የ‘አስገባ (INSERT) ትእዛዝ ይዘቶች ምንድናቸው?
  2. በሬይልስ ሰሌዳ ላይ ተጠቃሚ ተለዋዋጪን ውሂበጎታው ላይ ከሚገኘው የመጀመሪያ ተጠቃሚ ጋር አዘጋጁ። ከዚያ ይህ:- Achrtshuf.where("teteqami_id = ?", ተጠቃሚ.id) ከዚህ:- ተጠቃሚ.achrtshufs እና ከዚህ:- ተጠቃሚ.qelabi ጋር አንድ መሆኑን አረጋግጡ፡፡ ጠቃሚ ምክር:- በቀጥታ ይህንን:- == በመጠቀም ማነጻጸሩ ቀላል ሊሆን ይችላል።

13.3.4 አጪርጽሑፎችን ማጥፋት

የአጪርጽሑፎች ሃብትን ለመጨረስ የቀረ አንድ ተግባር ቢኖር፣ ቅምጦችን የማጥፋት ችሎታን ማከል ብቻ ነው፡፡ ልክ ተጠቃሚን ለማጥፋት (ክፍል 10.4.2) እንደተጠቀምነው ሁሉ፣ በምስል 13.20 ስእላዊ መግለጫ ላይ እንደሚታየው፣ የ “ሰርዝ” አገናኝን በመጠቀም ይህንን ተግባር እናከናውናለን፡፡ ከዛ ተጠቃሚን ለመሰረዝ ለአስተዳዳሪ ተጠቃሚዎች ብቻ ከተገደበው ስልጣን በተቃራነ መልኩ፣ የመሰረዣ አገናኞቹ በአሁኑ ተጠቃሚ ለተፈጠሩ አጪርጽሑፎች ብቻ የሚሰሩ ይሆናሉ።

የመጀመሪያ ደረጃ ሂደታችን በዝርዝር 13.22 የአጪርጽሑፍ ከፊል ውስጥ አንድ የመሰረዝ አገናኝን ማከል ይሆናል፡፡ ውጤቱ በዝርዝር 13.52 ውስጥ ይታያል፡፡

ዝርዝር 13.52: የአጪርጽሑፍ ከፊል ውስጥ አንድ የመሰርዣ አገናኝን ማከል። app/views/achrtshufs/_achrtshuf.html.erb
<li id="achrtshuf-<%= achrtshuf.id %>">
  <%= link_to amsaya_le(achrtshuf.teteqami, meten: 50), achrtshuf.teteqami %>
  <span class="ተጠቃሚ"><%= link_to achrtshuf.teteqami.sim,
                                        achrtshuf.teteqami %></span>
  <span class="ይዘት"><%= achrtshuf.yizet %></span>
  <span class="ማህተመጊዜ"><%= time_ago_in_words(achrtshuf.created_at) %> በፊት ተለጠፈ።
    <% if ahun_teteqami?(achrtshuf.teteqami) %>
      <%= link_to "ሰርዝ", achrtshuf, method: :delete,
                                       data: { confirm: "እርግጠኛ ነዎት?" } %>
    <% end %>
  </span>
</li>

ቀጣዩ ሂደት፣ በአጪርጽሑፎች መቆጣጠሪያ ውስጥ አንድ የ‘አጥፋ (destroy) ተግባርን መበየን ነው፤ ይህም ከዝርዝር 10.58 ውስጥ የተጠቃሚ ስረዛ አሰራር ጋር ተመሳሳይ ነው፡፡ ዋናው ልዩነቱ አንድ ተጠቃሚን በቀጥታ በ‘ተጠቃሚ.ፈልግ (Teteqami.find) ከመፈለግ ይልቅ፣ በተጠቃሚው ማሕበር በኩል አጪርጽሑፉን መፈለጋችን ነው:-

@achrtshuf = ahun_teteqami.achrtshufs.find_by(id: params[:id])

አንድ ተጠቃሚ የሌላ ተጠቃሚ አጪርጽሑፍን ለመሰረዝ ቢሞክር፣ ይህም በራስሰር ባለመሳካት ላይ ተጨማሪ (ምንም‘ን (nil) የሚመልስ) የጥብቅ/የደህንነት ጥቅም አለው።

ከውጤቱ የተገኘውን ፍለጋ (find) በአንድ ትክክለኛ_ተጠቃሚ (tkklegna_teteqami) ቅድመአጣሪ ውስጥ እናስቀምጠዋለን፣ ይህም የአሁኑ ተጠቃሚ ከተሰጠው መታወቂያ ጋር አንድ አጪርጽሑፍ በትክክል እንዳለው ያረጋግጣል (እና ከሌለው ወደ ስር ዓ.አ.ሃ.አው ያዟዙረዋል)። ውጤቱ በዝርዝር 13.53 ውስጥ ይታያል፡፡

ዝርዝር 13.53: በተጠቃሚው ማሕበር በኩል አንድ አጪርጽሑፍን መፈለግ፡፡ app/controllers/achrtshufs_controller.rb
class AchrtshufsController < ApplicationController
  before_action :gb_teteqami,       only: [:create, :destroy]
  before_action :tkklegna_teteqami, only: :destroy
  .
  .
  .
  private

    def achrtshuf_negariaseitoch
      params.require(:achrtshuf).permit(:yizet)
    end

    def tkklegna_teteqami
      @achrtshuf = ahun_teteqami.achrtshufs.find_by(id: params[:id])
      redirect_to root_url if @achrtshuf.nil?
    end
end

ትክክለኛውን የአጪርጽሑፍ ስረዛን ለማከናወን፣ በአጠቃላይ የዝርዝር 10.58 ተጠቃሚ አሰራረዝ ጥለትን እንከተላለን፣ እሱም ይህንን ይመስላል:-

def destroy
  Teteqami.find(params[:id]).destroy
  flash[:success] = "ተጠቃሚው ተሰርዟል"
  redirect_to teteqamis_url
end

በ‘ተጠቃሚ.ፈልግ(ሴሚአሴቶች[፡መታወቂያ]) (Teteqami.find(params[:id])) ምትክ @ተጠቃሚ (@teteqami) (በዝርዝር 13.53 ውስጥ በ‘ትክክለኛ_ተጠቃሚ (tkklegna_teteqami) ማጣሪያ የተበየነ) ይኖረናል፤ የብልጪችታ መልእክቱ በተመሳሰለ መልኩ አንድ አይነት ነው፣ ማለት በ “አጪርጽሑፉ” ምትክ “ተጠቃሚው” ን መተካት ነው። ውጤቱም እንደሚከተለው ሁኖ ይታያል:-

def destroy
  @achrtshuf.destroy
  flash[:success] = "አጪርጽሑፉ ተሰርዟል"
  # ማዟዟሩ ይወሰናል።
end

በተጠቃሚ እና በአጪርጽሑፉ ክፍል ሁኔታ መካከል ያለው ትልቁ ልዩነት በማዟዟር ሂደቱ ላይ ነው፡፡ ተጠቃሚዎች አጪርጽሑፉቸውን መገለጫ ገጹ ላይም ሆነ፣ መነሻ ገጹ ላይ ሁነው መሰረዝ ስለሚችሉ፣ ተጠቃሚዎችን መጠይቁ ወደ ቀረበበት (referring) ገጽ ማዟዟሩ ምቹ የሆነ አሰራር ነው፤ ስለሆነም ተጠቃሚዎች ሁልጊዜ መጠይቅ ወዳቀረቡበት ገጽ ይዟዟራሉ፡፡ ይህንንም የመጠይቅ.አቅራቢ (request.referrer) ዘዴን በመጠቀም ማከናወን እንችላለን:-17

redirect_to request.referrer

ይህ ዘዴ በወዳጃዊ ትልልፍ (ክፍል 10.2.3) ውስጥ ጥቅም ላይ ከዋለው የ‘ጠይቅ.የመጀመሪያው_ዓአሃአ (request.original_url) ተለዋዋጪ ጋር ይዛመዳል፣ እናም በዚህ ሁኔታ ላይ የቀድሞው ዓ.አ.ሃ.አ ማለት ነው።18

ምናልባት በሚገርም ሁኔታ፣ እዚህ ላይ ማስተናገድ የሚገባን ሁለት የጠርዝ ጉዳዮችም አሉ። የመጀመሪያው የማቅረቢያው ዓ.አ.ሃ.አ አንዳንድ ጊዜ በፈተናዎች ውስጥ ምንም (nil) የመሆኑ ጉዳይ ነው፣ ስለሆነም በዚያ ጉዳይ ላይ ወደ አንድ ነባሪ ዓ.አ.ሃ.አ ማዟዟር ይኖርብናል፡፡ ለዛም የስር ዓ.አ.ሃ.አው እንዲህ እንዲሆን እንመርጣለን:-

if request.referrer.nil?
  redirect_to root_url
else
  redirect_to request.referrer
end

ሁለተኛው የጠርዝ ጉዳይ በይበልጥ ረቀቅ/ሰወር ያለ ነው፣ እናም አንድ ብቁ ያልሆነ አጪርጽሑፍ ካስረከቡ በኋላ አንድ አጪርጽሑፉን ከመነሻ ገጹ ላይ ለመሰረዝ የመሞከር ጉዳይን ያሳትፋል፡፡19 አንድ አዲስ አጪርጽሑፍን ለመፍጠር ሲሞከር (ዝርዝር 13.39)፣ አፕልኬሽኑ የ‘ዓስቀምጥ (POST) መጠይቅን ወደ አጪርጽሑፎች_ዓአሃአ (achrtshufs_url) ይልካል (ሰንጠረዥ 2.3)፡፡ አጪርጽሑፉ ብቁ ካልሆነ አፕልኬሽኑ የመነሻ ገጹን እንዳዲስ ያቀርባል (ዝርዝር 13.36)፣ አለመታደል ሆኖ፣ ተጠቃሚው በዚያ ገጽ ላይ ሆኖ አንድ አጪርጽሑፍን ለመሰረዝ ቢሞክር፣ የሚቀርበው ዓ.አ.ሃ.አ የ‘አጪርጽሑፎች_ዓአሃአ (achrtshufs_url) ነው፣ እናም ወደኋላ ማዟዟሩ አይሳካም/ይወድቃል (ይህም አንድ መደበኛ የ‘ዓግኝ (GET) መጠይቅ ነው)፣ የሚወድቅበት ምክንያትም፣ በአሁኑ ጊዜ ከ‘ዓግኝ /አጪርጽሑፎች (GET /achrtshufs) ጋር የሚዛመድ መዞርያ ስለለለ (ዝርዝር 13.30) ነው።

ቀራቢው ዓ.አ.ሃ.አ ከ‘አጪርጽሑፎች_ዓአሃአ (achrtshufs_url) ጋር እኩል መሆኑን ለማየት በግልጽ በመሞከር፣ ይህንን ጉዳይ እንፈታዋለን፣ ጉዳዩ ይህ በሚሆን ጊዜም ወደ ስር ዓ.አ.ሃ.አው እናዟዙራለን። አቅራቢው ምንም (nil) በሚሆንበት ጊዜ ይህ ባህሪ አንድ አይነት ስለሆነ፣ ሁለቱን ጉዳዮች በአንድ ነጠላ የ‘ከሆነ (if) ውስጥ ማካተት እንችላለን:-

if request.referrer.nil? || request.referrer == achrtshufs_url
  redirect_to root_url
else
  redirect_to request.referrer
end

ከላይ ያለውን ውይይት ከዝርዝር 13.53 ጋር በአንድ ላይ ማስቀመጡ በዝርዝር 13.54 ውስጥ የተመለከተውን የ‘አጥፋ (destroy) ተግባር ይሰጣል፡፡

ዝርዝር 13.54: የአጪርጽሑፎች መቆጣጠሪያ የ‘አጥፋ (destroy) ተግባር። app/controllers/achrtshufs_controller.rb
class AchrtshufsController < ApplicationController
  before_action :gb_teteqami,       only: [:create, :destroy]
  before_action :tkklegna_teteqami, only: :destroy
  .
  .
  .
  def destroy
    @achrtshuf.destroy
    flash[:success] = "አጪርጽሑፉ ተሰርዟል"
    if request.referrer.nil? || request.referrer == achrtshufs_url
      redirect_to root_url
    else
      redirect_to request.referrer
    end
  end

  private

    def achrtshuf_negariaseitoch
      params.require(:achrtshuf).permit(:yizet)
    end

    def tkklegna_teteqami
      @achrtshuf = ahun_teteqami.achrtshufs.find_by(id: params[:id])
      redirect_to root_url if @achrtshuf.nil?
    end
end

ዝርዝር 13.54 ውስጥ ባለው ኮድ፣ የመነሻ ገጹ አሁን የሚሰሩ የመሰረዣ አገናኞች አሉት (ምስል 13.21)፣ ይህንንም ሁለተኛውን ቅምጥ በመሰረዝ ልታረጋግጡ ትችላላችሁ (ምስል 13.22)።

images/figures/home_post_delete
ምስል 13.21: የመነሻ ገጹ ከሰርዝ አገናኞች ጋር።
images/figures/delete_second_post
ምስል 13.22: ሁለተኛው አጪርጽሑፍ ከተሰረዘ በኋላ የተገኘ ውጤት።

መልመጃዎች

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

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

  1. አንድ አዲስ አጪርጽሑፍን ፍጠሩ እና ከዚያ ሰርዙት። በአገልጋይ ዘጋቢው ውስጥ የተገኙት የሠርዝ (DELETE) ትእዛዝ ይዘቶች ምንድን ናቸው?
  2. redirect_to request.referrer || root_url አድራሻ (ዓ.አ.ሃ.አ) የ redirect_back(fallback_location: root_url) አድራሻን (ዓ.አ.ሃ.አን) እንደሚተካ አሳሻችሁን በመጠቀም አረጋግጡ፡፡ (ይህ ዘዴ በሬይልስ 5 የታከለ ዘዴ ነው፡፡)

13.3.5 የአጪርጽሑፍ መፈተናዎች

ክፍል 13.3.4 ውስጥ ካለው ኮድ ጋር፣ የአጪርጽሑፍ ቅርጸቱ እና በይነገጹ ተጠናቋል፡፡ የቀረ ነገር ቢኖር፣ ፈቀዳውን ለማረጋገጥ እና አንድ የአጪርጽሑፍ ውህደት ፈተናውን ማለት ሁሉንም በአንድ ላይ ለመቋጨት አንድ አጪር የአጪርጽሑፍ መቆጣጠሪያ ፈተናን መጽፍ ነው፡፡

ዝርዝር 13.55 ላይ እንደሚታየው፣ ከተለያዩ የአጪርጽሑፍ ባለቤቶች ጋር ጥቂት አጪርጽሑፎችን፣ በአጪርጽሑፎች እቃዎች ውስጥ በማከል እንጀምራለን፡፡ (ለአሁኑ አንዱን እቃ ብቻ እንጠቀማለን፣ ነገር ግን ለወደፊት ማጣቀሻ እንዲሆኑን በማለት ሌሎችንም አክለናል፡፡)

ዝርዝር 13.55: ከአንድ የተለየ ባለቤት ጋር አንድ አጪርጽሑፍን ማከል። test/fixtures/achrtshufs.yml
.
.
.
gundan:
  yizet: "ጉንዳን ደም፣ ዝንብ ቤት የለውም።"
  created_at: <%= 2.years.ago %>
  teteqami: ermias

tekula:
  yizet: "ተኩላ እንደ አንበሳ እጮህ ብላ ተተረተረች።"
  created_at: <%= 3.days.ago %>
  teteqami: ermias

anbesa:
  yizet: "አንበሳ ሳይገድሉ ቆዳውን ያስማማሉ።"
  created_at: <%= 10.minutes.ago %>
  teteqami: gerie

shiro:
  yizet: "አነሰ ስትይ ሽሮ ስትጨምሪ፡ ወፈረ ስትይ ወሃ ስትጨምሪ ሞላ ገነፈለ ወዴት ታማስይ።"
  created_at: <%= 4.hours.ago %>
  teteqami: gerie

ከዚህ በመቀጠልም፣ በዝርዝር 13.56 ውስጥ እንደሚታየው፣ አንድ ተጠቃሚ የሌሎች ተጠቃሚዎች አጪርጽሑፍን መሰረዝ እንደማይችል እና ትክክለኛ መዟዟርን የሚያረጋግጥ አንድ አጪር ፈተናን እንጽፋለን፡፡

ዝርዝር 13.56: አንድ ተጠቃሚ የማይመለከተውን አጪርጽሑፍ መሰረዝ እንደማይችል መፈተን። አረንጓዴ test/controllers/achrtshufs_controller_test.rb
require "test_helper"

class AchrtshufsControllerTest < ActionDispatch::IntegrationTest

  def setup
    @achrtshuf = (:weba)achrtshufs
  end

  test "ባልገባበት ጊዜ መፍጠር ማዟዟር አለበት" do
    assert_no_difference 'Achrtshuf.count' do
      post achrtshufs_path, params: { achrtshuf:
        { yizet: "ወባ ፊት የነሳው ሰውየ ቡዳ እንዳይበላኝ አለ።" } }
    end
    assert_redirected_to gba_url
  end

  test "ባልገባበት ጊዜ ማጥፋት ማዟዟር አለበት" do
    assert_no_difference 'Achrtshuf.count' do
      delete achrtshuf_path(@achrtshuf)
    end
    assert_redirected_to gba_url
  end

  test "ለተሳሳተ አጪርጽሑፍ ማጥፋት ማዟዟር አለበት" do
    gba_ende(teteqamis(:michael))
    achrtshuf = achrtshufs(:gundan)
    assert_no_difference 'Achrtshuf.count' do
      delete achrtshuf_path(achrtshuf)
    end
    assert_redirected_to root_url
  end
end

በመጨረሻም፣ የሚከተለውን አንድ የውህደት ፈተና እንጽፋለን:- ከገባን በኋላ የአጪርጽሑፍ ገጸቁጥሩ መኖሩን እናረጋግጣለን፤ (ሀ) ብቁ ያልሆነ አጪርጽሑፍን እናስረክባለን፤ (ለ) ብቁ አጪርጽሑፍን እናስረክባለን፤ (ሐ) አንድ ቅምጥን እንሰርዛለን፤ (መ) ከዚያ የሌላውን ተጠቃሚ መገለጫ ገጽን በመጎብኘት የ “ሰርዝ” አገናኝ እንደለለ እናረጋግጣለን፡፡ ይህንን ተግባር ላይ ለመዋል እንደተለመደው፣ አንድ ፈተናን በማመንጨት እንጀምራለን:-

$ rails generate integration_test achrtshufs_beynegets
      invoke  test_unit
      create    test/integration/achrtshufs_beynegets_test.rb

ፈተናው በዝርዝር 13.57 ውስጥ ይታያል፡፡ እስኪ ከላይ ከተገለጸው የፈተና አሰራር ሂደት ጋር በዝርዝር 13.12 ውስጥ ያሉት ኮዶችን ማገናኘት ትችሉ እንደሆን ሞክሩ፡፡

ዝርዝር 13.57: ለአጪርጽሑፍ በይነገጹ አንድ የውህደት ፈተናን ማከል፡፡ አረንጓዴ test/integration/achrtshufs_beynegets_test.rb
require "test_helper"

class AchrtshufsBeynegetsTest < ActionDispatch::IntegrationTest

  def setup
    @teteqami = teteqamis(:michael)
  end

  test "የአጪርጽሑፍ በይነገጽ" do
    gba_ende(@teteqami)
    get root_path
    assert_select 'div.pagination'
    # (ሀ) ብቁ ያልሆነ ርክብ
    assert_no_difference 'Achrtshuf.count' do
      post achrtshufs_path, params: { achrtshuf: { yizet: "" } }
    end
    assert_select 'div#ስህተት_ማብራሪያ'
    assert_select 'a[href=?]', '/?page=2'  # ትክክለኛ የገጸቁጥር አገናኝ
    # (ለ) ብቁ ርክብ
    yizet = "በእውነቱ ይህ አጪርጽሑፍ ሁሉን ነገር አጠቃሎ ያቀርባል"
    assert_difference 'Achrtshuf.count', 1 do
      post achrtshufs_path, params: { achrtshuf: { yizet: yizet } }
    end
    assert_redirected_to root_url
    follow_redirect!
    assert_match yizet, response.body
    # (ሐ) ቅምጥን መሰረዝ
    assert_select 'a', text: 'ሰርዝ'
    first_achrtshuf = @teteqami.achrtshufs.paginate(page: 1).first
    assert_difference 'Achrtshuf.count', -1 do
      delete achrtshuf_path(first_achrtshuf)
    end
    # (መ) ሌላ ተጠቃሚን መጎብኘት (የመሰረዣ አገናኞች የሉም)
    get teteqami_path(teteqamis(:ermias))
    assert_select 'a', text: 'ሰርዝ', count: 0
  end
end

በመጀመሪያ የሚሰራ የአፕልኬሽን ኮድን ስለጻፍን፣ ያለምንም ጥርጥር የፈተና ስብስቡ አረንጓዴመሆን አለበት:-

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

መልመጃዎች

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

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

  1. ዝርዝር 13.57 ውስጥ በአስተያየቶች ለተመላከቱት አራት ሁኔታዎች (ከ “ (ሀ) ብቁ ያልሆነ ርክብ” በመጀመር)፣ የሚዛመዱ ፈተናወችን ወደ ቀይለመቀየር እና ከዚያ ወደ አረንጓዴለመመለስ የሚያስችሉት የአፕልኬሽኑ ኮዶች ላይ አስተያየት አድርጉ።
  2. በጎን-አሞሌው ላይ ለሚገኘው የአጪርጽሑፎች ቆጠራ፣ አንድ ፈተናን አክሉ፤ ይህም ተገቢውን ቃል በብዛቱ መጠን ማሳየቱን ማረጋገጥ አለበት፤ ለምሳሌ:- አንድ (1) ሰው ሁለት (2) ሰወች፡፡ ዝርዝር 13.59 ላይ ያለው ኮድ ይህንኑ ስራ ለመጀመር ይረዳችኋል፡፡
ዝርዝር 13.59: ለጎን-አሞሌው አጪርጽሑፎች ቆጠራ የሚያገለግል አንድ የፈተና አብነት። test/integration/achrtshufs_beynegets_test.rb
require "test_helper"

class AchrtshufsBeynegetsTest < ActionDispatch::IntegrationTest

  def setup
    @teteqami = teteqamis(:michael)
  end
  .
  .
  .
  test "የአጪርጽሑፍ የጎን-አሞሌ ቆጠራ" do
    gba_ende(@teteqami)
    get root_path
    assert_match "#{ይህን_ሙሉ} achrtshufs", response.body
    # ተጠቃሚ ከዜሮ አጪርጽሑፍ ጋር
    lela_teteqami = teteqamis(:abeba)
    gba_ende(lela_teteqami)
    get root_path
    assert_match "0 achrtshufs", response.body
    lela_teteqami.achrtshufs.create!(yizet: "አንድ አጪርጽሑፍ")
    get root_path
    assert_match ይህን_ሙሉ, response.body
  end
end

13.4 የአጪርጽሑፍ ምስሎች

አሁን ለሁሉም ማለት ከአጪርጽሑፍ ተግባሮች ጋር የሚዛመዱትን ድጋፎች አክለን ስለጨመርን፣ በዚህ ክፍል ውስጥ አጪርጽሑፎች ምስሎችን እና እነዚሁም ጽሑፍን እንደሚያካትቱ እናደርጋቸዋለን፡፡ አንድ ለብልጸጋ አገልግሎት በቂ በሆነ መሰረታዊ ስሪት እንጀምራር እና ከዚያ የምስል ሰቀላው ለምርት ዝግጁ እንዲሆን ለማድረግ፣ አመርቂ የሆኑ ተከታታይ መሻሽሎችን እናክላለን፡፡

ምስል ሰቀላን ለማከል፤ ሁለት የሚታዩ ዋና ነገሮችን ማከልን ያሳትፋል፤ እነሱም አንድ የምስል መስቀያ የቅጽ መስክን እና እራሳቸው የአጪርጽሑፍ ምስሎች ናቸው፡፡ ይህንን በማድረግ የተገኘው የ “Upload image” አዝራር እና የአጪርጽሑፍ ምስል ውጤት፣ በምስል 13.23 ላይ በስእላዊ መግለጫ መልክ ይታያል፡፡

images/figures/micropost_image_mockup
ምስል 13.23: የአጪርጽሑፍ ምስል ሰቀላን (ከአንድ የተሰቀለ ምስል ጋር) የሚሳይ አንድ ስእላዊ መግለጫ፡፡

13.4.1 መሰረታዊ የምስል ሰቀላ

በሬይልስ ውስጥ ፋይሎችን ለመስቀል በጣም አመችው መንገድ፣ ንቅ ማከማቻ የተባለውን አንድ አብሮገነብ ገጸባህሪን መጠቀም ነው፡፡20 ንቅ ማከማቻ አንድ የተሰቀለ ምስልን ለማስተናገድ እና ምስሉን ከመረጥነው አንድ ቅርጸት (ለምሳሌ:- የአጪርጽሑፍ ቅርጸት) ጋር ለማዛመድ ሁኔታዎችን እጅግ ቀላል ያደርጋል። ምንም እንኳን እኛ ንቅ ማከማቻን ምስሎችን ለመስቀል ብቻ የምንጠቀምበት ቢሆንም፣ በውነቱ እሱ ብዙነገሮችን ያጠቃልላል፣ እናም ጥሬ ጽሑፍን እና በርካታ የሁለትዮሽ ፋይሎችንም ሳይቀር ማስተናገድ ይችላል (ለምሳሌ፣ እንደ የድምጽ ፋይሎች እና እንደ የተ.ሰ.ቅ (PDF) ሰነዶች የመሳሰሉ ፋይሎችንም ማስተናገድ ይችላል)።

በንቅ ማከማቻ ሰነድ ላይ እንደተገለጸው፣ ንቅ ማከማቻን ወደ አፕልኬሽናችን ማከሉ፣ አንድ ነጠላ ትእዛዝን የማከል ያህል ቀላል ነገር ነው:-

$ rails active_storage:install

ይህ ትእዛዝ፣ የተያያዙ ፋይሎችን ለማከማቸት አንድ የውሂብ ቅድን የሚፈጥር አንድ የውሂበጎታ ፍልሰትን ይፈጥራል፡፡ እሱ የፈጠራቸውን ነገሮች በሙሉ መመልከት ትችላላችሁ፣ ነገር ግን ይሄ የትኞቹን በጥልቅ ማወቁ አስፈላጊ እና አላስፈላጊ መሆኑን ለይቶ ለማወቅ፣ ቴክኒካዊ ብልሃትን ተግባር ላይ ለማዋል የሚያግዝ አንድ ጥሩ የሆነ ምሳሌ ይሆናል፡፡ በዚህ ሁኔታ ላይ፣ አስፈላጊው ነገር፣ ከንቅ ማከማቻ ጋር የአ.ፕ.በ መተገባበር ነው፣ ይህንንም በአጪር ጊዜ የምናየው ይሆናል፤ እንዴት አድርጎ ይህንን ስራ እንደሚሰራ፣ በዝርዝር ማወቁ በዚህ ጊዜ ለኛ አስፈላጊ ነገር ስላልሆነ፣ ስለሱ ብዙ ልታስቡበት አይገባም። እሱን ለማዘጋጀት አንድ ማድረግ ያለብን ነገር ቢኖር፣ ፍልሰቱን ማካሄድ ብቻ ይሆናል (የትም ፍጪው ዱቄቱን አምጪው ነው ነገሩ):-

$ rails db:migrate

ከንቅ ማከማቻ አ.ፕ.በ የምንፈልገው የመጀመሪያው ክፍል የ‘አንድ_ተያያዝ_አለው (has_one_attached) ዘዴን ሲሆን፣ ይህም አንድ የተሰቀለ ፋይልን ከአንድ ከተሰጠ ቅርጸት ጋር እንድናዛምድ ያስችለናል፡፡ እናም በእኛ ሁኔታ ይህንን ተግባር ላይ ለማዋል፣ በዝርዝር 13.60 ላይ እንደሚታየው፣ ምስል (msl) ብለን እንጠራው እና ከአጪርጽሑፍ ቅርጸቱ ጋር እናዛምደዋለን፡፡

ዝርዝር 13.60: በአጪርጽሑፍ ቅርጸት ውስጥ አንድ ምስልን ማከል፡፡ app/models/achrtshuf.rb
class Achrtshuf < ApplicationRecord
  belongs_to :teteqami
  has_one_attached :msl
  default_scope -> { order(created_at: :desc) }
  validates :teteqami_id, presence: true
  validates :yizet, presence: true, length: { maximum: 140 }
end

አፕልኬሽናችንን ለአንድ አጪርጽሑፍ አንድ ምስል ብቻ እንዲቀበል አድርገን እንነድፈዋለን፣ ነገር ግን ንቅ ማከማቻ ብዙ_ተያያዝ_አለው (has_many_attached) የተባለ አንድ ሁለተኛ አማራጪንም ይሰጣል፣ ይህም በርካታ ፋይሎችን ወደ አንድ ንቅ ማከማቻ ቁስ ለማያያዝ ያገለግላል፡፡

ምስል 13.23 ላይ እንደሚታየው፣ በመነሻ ገጹ ላይ ምስል ሰቀላን ለማካተት፣ በዝርዝር 13.61 ውስጥ እና በምስል 13.24 ላይ እንደሚታየው፣ በአጪርጽሑፍ ቅጽ ውስጥ አንድ የፋይል_መስክ (file_field) መለያን ማካተት ይኖርብናል፡፡

ዝርዝር 13.61: በአጪርጽሑፍ መፍጠርያ ቅጽ ላይ አንድ የምስል መሰቀያን ማከል። app/views/gru/_achrtshuf_qts.html.erb
<%= form_with(model: @achrtshuf, local: true) do || %>
  <%= render 'gru/shtet_melektoch', object: .object %>
  <div class="መስክ">
    <%= .text_area :yizet, placeholder: "አዲስ አጪርጽሑፍ አዘጋጅ..." %>
  </div>
  <%= .submit "አስቀምጥ", class: "btn btn-primary" %>
  <span class="ምስል">
    <%= .file_field :msl %>
  </span>
<% end %>
images/figures/micropost_create_image_upload
ምስል 13.24: አንድ የምስል መስቀያ መስክን ማከል።

በመጨረሻም፣ ምስሉን አዲስ ወደተፈጠረው የአጪርጽሑፍ ቁስ ለማከል፣ የአጪርጽሑፎች መቆጣጠሪያውን ማዘመን ይኖርብናል፡፡ በአጪርጽሑፎች መቆጣጠሪያ የ‘ፍጠር (create) ተግባር ውስጥ የተጫነውን ምስል፣ ከ‘@አጪርጽሑፍ (@achrtshuf) ቁስ ጋር የሚያያይዘውን፣ ማለት በንቅ ማከማቻ አ.ፕ.በ የተሰጠውን የ‘አያይዝ (attach) ዘዴን በመጠቀም፣ ይህንን በይነገጽ ተግባራዊ ማድረግ እንችላለን፡፡ ሰቀላው እንዲያልፍ ለመፍቀድ፣ በድር በኩል እንዲሻሻሉ በተፈቀደላቸው የባሕሪዎች ዝርዝር ውስጥ ምስል‘ን (:msl) ለማከል የ‘አጪርጽሑፎች_ነጋሪአሴቶች (achrtshuf_negariaseitoch) ዘዴን ማዘመን አለብን፡፡ ውጤቱም በዝርዝር 13.62 ላይ ይታያል፡፡

ዝርዝር 13.62: በተፈቀዱ ባሕሪዎች ዝርዝር ውስጥ ምስል‘ን (msl) ማከል። app/controllers/achrtshufs_controller.rb
class AchrtshufsController < ApplicationController
  before_action :gb_teteqami,       only: [:create, :destroy]
  before_action :tkklegna_teteqami, only: :destroy

  def create
    @achrtshuf = ahun_teteqami.achrtshufs.build(achrtshuf_negariaseitoch)
    @achrtshuf.msl.attach(params[:achrtshuf][:msl])
    if @achrtshuf.save
      flash[:success] = "አጪርጽሑፍ ተፈጥሯል!"
      redirect_to root_url
    else
      @werie_qelabi = ahun_teteqami.qelabi.paginate(page: params[:page])
      render 'quami_getss/menesha'
    end
  end

  def destroy
    @achrtshuf.destroy
    flash[:success] = "አጪርጽሑፉ ተሰርዟል"
    if request.referrer.nil? || request.referrer == achrtshufs_url
      redirect_to root_url
    else
      redirect_to request.referrer
    end
  end

  private

    def achrtshuf_negariaseitoch
      params.require(:achrtshuf).permit(:yizet, :msl)
    end

    def tkklegna_teteqami
      @achrtshuf = ahun_teteqami.achrtshufs.find_by(id: params[:id])
      redirect_to root_url if @achrtshuf.nil?
    end
end

ዝርዝር 13.63 ላይ እንደሚታየው አንዴ ምስሉ ከተሰቀለ በኋላ፣ በአጪርጽሑፍ ከፊል ውስጥ የ‘ምስል_መለያ (image_tag) ረጅን በመጠቀም ተዛማጁን የአጪርጽሑፍ ምስል (achrtshuf.msl) ማቅረብ እንችላለን፡፡ ምስል በማይኖርበት ጊዜ፣ የምስል መለያ እንዳይታይ ለመከላከል፣ አንድ ተያይዟልን? (attached?) የተባለ የቡልየን ዘዴን እንደተጠቀምን አስተውሉ።

ዝርዝር 13.63: በአጪርጽሑፎች ውስጥ አንድ የምስል ማሳያን ማከል። app/views/achrtshufs/_achrtshuf.html.erb
<li id="achrtshuf-<%= achrtshuf.id %>">
  <%= link_to amsaya_le(achrtshuf.teteqami, meten: 50), achrtshuf.teteqami %>
  <span class="ተጠቃሚ"><%= link_to achrtshuf.teteqami.sim,
                                        achrtshuf.teteqami %></span>
  <span class="ይዘት">
    <%= achrtshuf.yizet %>
    <%= image_tag achrtshuf.msl if achrtshuf.msl.attached? %>
  </span>
  <span class="ማህተመጊዜ"><%= time_ago_in_words(achrtshuf.created_at) %> በፊት ተለጠፈ።
    <% if ahun_teteqami?(achrtshuf.teteqami) %>
      <%= link_to "ሰርዝ", achrtshuf, method: :delete,
                                       data: { confirm: "እርግጠኛ ነዎት?" } %>
    <% end %>
  </span>
</li>

አንድ አጪርጽሑፍን ከአንድ ምስል ጋር የመስራቱ ውጤት በምስል 13.25 ላይ ይታያል፡፡ እንደዚህ ያሉ ነገሮች በትክክል ሲሰሩ፣ ሁል ጊዜ እገረማለሁ፣ ነገር ግን በትክክል እንደሚሰሩ ማረጋገጫው ይሄው! (ለምስል መስቀያው፣ ቢያንስ አንድ ራስሰሬ የሆነ መሰረታዊ ፈተና መጻፉ ጥሩ ሃሳብ ነው፣ ይህም ልክ እንደ አንድ መልመጃ ይሆናችሁ ዘንድ፣ ለናንተ ተትቷል (ክፍል 13.4.1.1)።)

images/figures/microposts_with_image
ምስል 13.25: አንድ አጪርጽሑፍን ከአንድ ምስል ጋር የማስረከብ ውጤት።

መልመጃዎች

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

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

  1. አንድ ከምስል ጋር የተያያዘ አጪርጽሑፍን ስቀሉ፤ የሰቀላችሁት ምስል በጣም ትልቅ ይመስላልን? (ከሆነ አትጨነቁ፣ በክፍል 13.4.3 ላይ እናስተካክለዋለን)፡፡
  2. ዝርዝር 13.65 ውስጥ ያለውን አብነት በመከተል፣ ለክፍል 13.4 የምስል ሰቀይ አንድ ፈተናን ጻፉ፡፡ ለዚህ ፈተና ለመዘጋጀት፣ በዝርዝር 13.64 ውስጥ ያለውን ትእዛዝ መጠቀም እና የተገኘውን ምስል በእቃዎች (በፊክቸርስ) ማውጫ ውስጥ ማከል ይኖርባችኋል፡፡ በዝርዝር 13.65 ያሉት ተጨማሪ ማረጋገጫዎች፣ ማለት ይህን_ሙሉ የሚል ጽሑፍ ያለባቸው ማረጋገጫዎች፣ በመነሻ ገጹ ላይ አንድ የፋይል መስቀያ መስክ እና በብቁ ርክብ ምክንያት አንድ የምስል ባሕሪ እንደሚኖር ያረጋግጣሉ። በፈተና ውስጥ የእቃዎች ፋይልን ለመጫን ልዩ የሆነውን የ‘እቃ_ፋይል_ሰቃይ (fixture_file_upload) ዘዴን እንደተጠቀምን አስተውሉ፡፡21 ጠቃሚ ምክር:- የአንድ የ‘ምስል (msl) ባሕሪ ብቃትን ለማረጋገጥ፣ ከብቁ ርክብ በኋላ፣ በፍጠር (create) ተግባር ውስጥ አጪርጽሑፍን ለመድረስ፣ በክፍል 11.3.3 ውስጥ የተጠቀሰውን የ‘መድብ (assigns) ዘዴን ተጠቀሙ፡፡
ዝርዝር 13.64: በፈተና ጥቅም ላይ የሚውል አንድ የእቃ ምስልን ማውረድ።
$ curl -o test/fixtures/kitten.jpg -OL https://cdn.learnenough.com/kitten.jpg
ዝርዝር 13.65: የምስል ሰቀላን ለመፈተን የቀረበ አንድ አብነት። test/integration/achrtshufs_beynegets_test.rb
require "test_helper"

class AchrtshufsBeynegetsTest < ActionDispatch::IntegrationTest

  def setup
    @teteqami = teteqamis(:michael)
  end

  test "የአጪርጽሑፍ በይነገጽ" do
    gba_ende(@teteqami)
    get root_path
    assert_select 'div.pagination'
    assert_select 'input[type=ይህን_ሙሉ]'
    # (ሀ) ብቁ ያልሆነ ርክብ
    assert_no_difference 'Achrtshuf.count' do
      post achrtshufs_path, params: { achrtshuf: { yizet: "" } }
    end
    assert_select 'div#ስህተት_ማብራሪያ'
    assert_select 'a[href=?]', '/?page=2'  # ትክክለኛ የገጸቁጥር አገናኝ
    # (ለ) ብቁ ርክብ
    yizet = "በእውነቱ ይህ አጪርጽሑፍ ሁሉን ነገር አጠቃሎ ያቀርባል"
    msl = fixture_file_upload('test/fixtures/kitten.jpg', 'image/jpeg')
    assert_difference 'Achrtshuf.count', 1 do
      post achrtshufs_path, params: { achrtshuf:
                                      { yizet: yizet, msl: msl } }
    end
    assert ይህን_ሙሉ.msl.attached?
    assert assigns(:achrtshuf).msl.attached?
    assert_redirected_to root_url
    follow_redirect!
    assert_match yizet, response.body
    # (ሐ) ቅምጥን መሰረዝ
    assert_select 'a', text: 'ሰርዝ'
    first_achrtshuf = @teteqami.achrtshufs.paginate(page: 1).first
    assert_difference 'Achrtshuf.count', -1 do
      delete achrtshuf_path(first_achrtshuf)
    end
    # (መ) ሌላ ተጠቃሚን መጎብኘት (የመሰረዣ አገናኞች የሉም)
    get teteqami_path(teteqamis(:ermias))
    assert_select 'a', text: 'ሰርዝ', count: 0
  end
  .
  .
  .
end

13.4.2 የምስል ማረጋገጫ

ክፍል 13.4.1 ውስጥ ያለው የምስል መስቀያ ኮድ አንድ ጥሩ ጅማሬ ይኑረው እንጅ፣ የተወሰኑ ገደቦች ግን የሉትም፡፡ ለምሳሌ ያየን እንደሆን፣ በሚሰቀል ፋይል ላይ ምንም ዓይነት ገደብን አያስገድድም፣ ይህም ተጠቃሚዎች መጠኑ ትልቅ ወይም አይነቱ ብቁ ያልሆነ ፋይልን ለመስቀል በሚሞክሩበት ጊዜ በአፕልኬሽኑ ላይ ችግር ሊያስከትል ይችላል፡፡ ይህን ጉድለት ለማስተካከል፣ ለምስል መጠን እና ቅርጸት ማረጋገጫዎችን እናክላለን፡፡

ይህ ጽሑፍ እስከተጻፈበት ጊዜ ድረስ እንደሚታወቀው፣ ንቅ ማከማቻ እንደ የቅርጸት እና የመጠን ማረጋገጫዎች ለመሳሰሉት ነገሮች በተፈጥሮው ድጋፍ አይሰጥም (ይህም በጣም የሚያስገርም ነው)፤ ይሁን እንጂ ብዙውን ጊዜ ምክንያቱ ይሄ በሚሆንበት ጊዜ፣ ይህንኑ ክንዋኔ ለእኛ የሚያክል አንድ እንቁ አለ (ዝርዝር 13.66)።

ዝርዝር 13.66: ለንቅ ማከማቻ ማረጋገጫዎች አንድ እንቁን ማከል። Gemfile
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

gem 'rails',                      '6.1.4.1'
gem 'active_storage_validations', '0.8.9'
gem 'bcrypt',                     '3.1.13'
.
.
.

ከዚያ የጠቅል-ጫን (bundle install) ትእዛዝን አስኪዱ:-

$ bundle _2.2.17_ install

የእንቁው ሰነድ ላይ የተመለከተውን መመሪያ በመከተል፣ የ‘ይዘት_አይነቱ‘ን (content_type) እንደሚከተለው አድርገን በመመርመር፣ የምስሉን ቅርጸት ማረጋገጥ እንደምንችል እናያለን:-

content_type: { in: %w[image/jpeg image/gif image/png],
                message: "ብቁ የምስል ቅርጸትን መያዝ አለበት።" }

ይህ ምስሉ ሚሜ (MIME) ተብሎ በሚጠራው የፋይል ዓይነት የተደገፈ ቅርጸት መያዙን ያረጋግጣል፡፡ (ይህንን:- %w[] የድርድር-ገንቢ አገባብ፣ በክፍል 6.2.4 ውስጥ ድርድር ለመስራት እንደተጠቀምንበት አስታውሱ፡፡)

በተመሳሳይ መልኩ፣ የፋይሉን መጠን በዚህ መልኩ ማረጋገጥ እንችላለን:-

size: { less_than: 5.megabytes,
        message:  "ከ 5ሜባ በታች መሆን አለበት፡፡" }

ይህ ከዚህ በፊት በጊዜ (Time) ረጅ አውድ ውስጥ ያየነው አንድ አገባብን በመጠቀም፣ አንድ የ 5 ሜጋባይት ክልልን ያስቀምጣል (ሳጥን 9.1)፡፡

እነዚህን ማረጋገጫወች በአጪርጽሑፍ ቅርጸት ውስጥ ማከሉ፣ ዝርዝር 13.67 ውስጥ ያለውን ኮድ ይሰጣል፡፡

ዝርዝር 13.67: የምስል ማረጋገጫዎችን ማከል። app/models/achrtshuf.rb
class Achrtshuf < ApplicationRecord
  belongs_to :teteqami
  has_one_attached :msl
  default_scope -> { order(created_at: :desc) }
  validates :teteqami_id, presence: true
  validates :yizet,       presence: true, length: { maximum: 140 }
  validates :msl,   content_type: { in: %w[image/jpeg image/gif image/png],
                                    message: "ብቁ የምስል ቅርጸትን መያዝ አለበት።" },
                    size:         { less_than: 5.megabytes,
                                      message:   "ከ 5ሜባ በታች መሆን አለበት፡፡" }
end

አንድ መጠኑ ትልቅ እና የፋይል አይነቱ ብቁ ያልሆነ ምስልን ለመስቀል የተደረገ ሙከራ ያስከተለው ውጤት፣ በምስል 13.26 ላይ ይታያል። (ይህ የተደረገው ለውጥ በትክክል ይሰራ ዘንድ፣ የሬይልስ አገልጋያችሁን እንደገና ማስጀመር ሊኖርባችሁ ይችል ይሆናል።)

images/figures/large_invalid_image
ምስል 13.26: አንድ ትልቅ እና ብቁ ያልሆነ ምስልን ለመስቀል መሞከር።

ዝርዝር 13.67 ማረጋገጫዎች ጋር አብሮ የሚሄድ፣ ማለት በተገልጋይ በኩል (በአሳሽ በኩል) ለሚሰቀል ምስል፣ የመጠን እና የቅርጸት ማረጋገጫን እናክላለን። አንድ ተጠቃሚ አንድ በጣም ትልቅ የሆነ ምስልን ለመስቀል ከሞከረ አንድ ማስጠንቀቂያን ለመስጠት (ማለት ያልታሰበ የሰቀላ ጊዜን የሚከላከል እና በአገልጋዩ ላይ የሚያጋጥመውን ጪነት ቀለል የሚያደርግ) አንድ ትንሽ ጃቫስክሪፕትን (ማለት በግልጹ ጀኴይሪን) በማከል እንጀምራለን። ውጤቱ በዝርዝር 13.68 ውስጥ ይታያል።22

ዝርዝር 13.68: የፋይሉን መጠን በጀኴይሪት መፈተሽ። app/views/gru/_achrtshuf_qts.html.erb
<%= form_with(model: @achrtshuf, local: true) do || %>
  <%= render 'gru/shtet_melektoch', object: .object %>
  <div class="መስክ">
    <%= .text_area :yizet, placeholder: "አዲስ አጪርጽሑፍ አዘጋጅ..." %>
  </div>
  <%= .submit "አስቀምጥ", class: "btn btn-primary" %>
  <span class="ምስል">
    <%= .file_field :msl %>
  </span>
<% end %>

<script type="text/javascript">
  $("#achrtshuf_msl").bind("change", function() {
    const size_in_megabytes = this.files[0].size/1024/1024;
    if (size_in_megabytes > 5) {
      alert("ከፍተኛው የፋይል መጠን 5ሜባ ነው። እባክዎ አንድ አናሳ ፋይል ይምረጡ።");
      $("#achrtshuf_msl").val("");
    }
  });
</script>

ምንም እንኳን የዚህ መጽሐፍ ትኩረት ጃቫስክሪፕትን ማስተማር ባይሆንም፣ ዝርዝር 13.68 ጃቫስክሪፕት ይሄንን ስራ በዚህ ገጽ ለመስራት በዝርዝር 13.61 ቅጽ ላይ ያለውን የ‘አጪርጽሑፍ_ምስል (achrtshuf_msl) የቅ.ቋ መታወቂያን እንደሚጠቀም ልትገምቱ ትችሉ ይሆናል (በርግጥ እዚህ ላይ ጃቫስክሪፕት የቅ.ቋ መታወቂያን እንደሚጠቀም በዚህ ምልክት:-  # መገመት ይቻላል)፣ (ይህንን ለማወቅ ከፈለጋችሁ፡ ተቆር-ጠቅን (Ctrl-click) ካደረጋችሁ በኋላ፣ “አባል መርምር (inspect element)” ላይ ጠቅ በማድረግ፣ ድራችሁን መመርመር ይኖርባችኋል።) በቅ.ቋ መታወቂያ ውስጥ ያለው አባል በሚቀየርበት ጊዜ፣ በምስል 13.27 ላይ እንደሚታየው፣ የጀኴይሪው ሥልት ይተኮስ እና ፋይሉ በጣም ትልቅ ከሆነ የ‘አስጠንቅቅ (alert) ዘዴውን ይሰጣል።23

images/figures/javascript_file_too_big
ምስል 13.27: ለአንድ ትልቅ ፋይል አንድ የጃቫስክሪፕት ማስጠንቀቂያ፡፡

በመጨረሻም፣ በ‘ፋይል_መስክ (file_field) ግብዓት መለያው ውስጥ ያለውን የ‘ተቀበል (accept) ሰሚአሴትን በመጠቀም፣ ብቁ ቅርጸቶችን ብቻ ሊፈቅድ እንዲገባው በዝርዝር ለይተን መስጠት እንችላለን (ዝርዝር 13.69)፡፡

ዝርዝር 13.69: ብቁ የምስል ቅርጸቶችን ብቻ መፍቀድ። app/views/gru/_achrtshuf_qts.html.erb
<%= form_with(model: @achrtshuf, local: true) do || %>
  <%= render 'gru/shtet_melektoch', object: .object %>
  <div class="መስክ">
    <%= .text_area :yizet, placeholder: "አዲስ አጪርጽሑፍ አዘጋጅ..." %>
  </div>
  <%= .submit "አስቀምጥ", class: "btn btn-primary" %>
  <span class="ምስል">
    <%= .file_field :msl, accept: "image/jpeg, image/gif, image/png" %>
  </span>
<% end %>

<script type="text/javascript">
  $("#achrtshuf_msl").bind("change", function() {
    const size_in_megabytes = this.files[0].size/1024/1024;
    if (size_in_megabytes > 5) {
      alert("ከፍተኛው የፋይል መጠን 5ሜባ ነው። እባክዎ አንድ አናሳ ፋይል ይምረጡ።");
      $("#achrtshuf_msl").val("");
    }
  });
</script>

ዝርዝር 13.69 በመጀመሪያ ብቁ የሆኑ የምስል ዓይነቶች ተመርጠው እንዲፈቀዱ ሲያዘጋጅ፣ ማንኛውንም ሌላ አይነት ፋይል ላይ ደግሞ ሽበት ያደርጋል24 (ብቁ ያልሆኑትን የፋይል ዓይነቶች ደግሞ፣ ቀለማቸውን ግራጫማ በማድረግ ተቀባይነት እንዳይኖራቸው ያደርጋቸዋል) (ምስል 13.28)።

images/figures/grayed_out
ምስል 13.28: የሸበቱ ብቁ ያልሆኑ የፋይል አይነቶች።

ጃቫስክሪፕትን በመጠቀም፣ ብቁ ያልሆኑ ምስሎችን፣ በአንድ አሳሽ በኩል እንዳይሰቀሉ መከላከሉ አንድ ጥሩ ገጸባህሪ ነው፣ ነገር ግን ይህ ዓይነቱ ኮድ፣ አንድ ልክ ያልሆነ የፋይል ዓይነትን ወይም አንድ ትልቅ ፋይልን ለመስቀል አስቸጋሪ እንዲሆን የሚያደርገው፣ አንድ አሳሽን ተጠቅመው ይህንኑ ነገር ለማድረግ ለሚሞክሩ ተጠቃሚዎች ብቻ መሆኑን ልትገነዘቡ ይገባል፤ ብቃት የለለለው የፋይል ዓይነትን ለመስቀል የወሰነ አንድ ተጠቃሚ፣ ሁልጊዜ ለምሳሌ:- ከርል (curl) የተባለውን አፕልኬሽን በመጠቀም በቀጥታ አንድ የ‘ዓስቀምጥ (POST) መጠይቅን በመስጠት አላማውን ሊያሳካ ይችላል። ስለሆነም በዝርዝር 13.67 ላይ የተመለከተው ዓይነት ማለት በአገልጋዩ-በኩል የሚያገለግሉ ማረጋገጫዎችን ማካተቱ በጣም አስፈላጊ ይሆናል።

መልመጃዎች

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

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

  1. ከ 5 ሜጋባይቶች በላይ የሆነ ምስልን ለመስቀል ብትሞክሩ ምን ይከሰታል?
  2. አንድ ብቁ ያልሆነ የፋይል ቅጥያ ያለው ምስልን ለመስቀል ብትሞክሩ ምን ይከሰታል?

13.4.3 ምስልን ዳግም መመጠን

ክፍል 13.4.2 ውስጥ ያሉት የምስል መጠን ማረጋገጫዎች ጥሩ ጅማሬዎች ይሁን እንጅ፣ በአሁኑ ወቅት የጣቢያችንን ገጽታ ለመስበር ብቃት ያላቸው ምስሎች እንዲሰቀሉ ይፈቅዳሉ (ምስል 13.29)። ተጠቃሚዎች በሰፈራቸው ዲስክ ውስጥ ያሉ በጣም ትልቅ የሆኑ ምስሎችን እንዲመርጡ መፍቀዱ አመች ቢሆንም፣ ምስሉን በአሳሹ ላይ ከማሳየት በፊት መጠኑን ዳግም መመጠኑ ግን አንድ ጥሩ ሃሳብ ነው።25

images/figures/large_uploaded_image
ምስል 13.29: አንድ ትልቅ የሚያስበረግግ የተሰቀለ ምስል።

ኢሜጅማጂክ (ImageMagick) የተባለውን የምስል ማንቀሳቀሻያ ፕሮግራም በመጠቀም፣ ምስሎችን ዳግም እንመጥናለን፣ ይህንንም በማበልጸጊያ አካባቢያችን ላይ መጫን ይኖርብናል፡፡ (በክፍል 13.4.4 ላይ እንደምናየው፣ ሃረኩን ለስምሪት በምንጠቀምበት ጊዜ፣ የኢሜጅማጂክ ፕሮግራም በምርት ውስጥ ቀድሞውኑ-ተጪኖ እንደመጣ እንመላከታለን፡፡) በደመና ቅ.ማ.አ ላይ እሱን ለመጫን እንደሚከተለው ማድረግ እንችላለን:-

$ sudo apt-get -y install imagemagick

(የደመና ቅ.ማ.አን የማትጠቀሙ ከሆነ ወይም ሌላ ዓይነት የሊኒክስ ስርዓት እየተጠቀማችሁ ከሆነ፣ እንደዚህ ብላችሁ:- “Imagemagick <የናንተን ስርዓተ ክወና>” በማስገባት መጎልጎል ትችላላችሁ፡፡ በማክ ኦኤክስ (macOS) ላይ ሆምብሬው (Homebrew) የተባለው ፕሮግራም ተጪኖ ከሆነ፣ የ‘ብሬው ጫን ኢሜጅማጅክ (brew install imagemagick) ትእዛዝን በአንድ ማዘዥያ መስመር ላይ በማስኬድ ፕሮግራሙን መጫን ይቻላል። መላው ከጠፋችሁ፣ ቴክኒካዊ ብልሀታችሁን ተጠቀሙ (ሳጥን 1.2)።)

በመቀጠል፣ የገዛ ስሙ ስራውን በትክክል የሚገልጸውን የ‘ምስል_ማቀናበርያ (image_processing) እንቁን እና በሩቢ ኢሜጅማጂክን ለማስኬድ የሚያገለግለውን የሚኒ_ማጅክ (mini_magick) እንቁን ማለት ለምስል ሂደት የሚያገለግሉንን ሁለት እንቁዎች በእንቁ ፋይላችን ውስጥ ማከል ይኖርብናል (ዝርዝር 13.70)፡፡

ዝርዝር 13.70: ለምስል ማቀነባበሪያ የሚያገለግሉ እንቁዎችን ማከል። Gemfile
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

gem 'rails',                      '6.1.4.1'
gem 'image_processing',           '1.9.3'
gem 'mini_magick',                '4.9.5'
gem 'active_storage_validations', '0.8.9'
.
.
.

ከዚያ እንደተለመደው አድርጎ መጫን ነው:-

$ bundle _2.2.17_ install

እዚህ ላይ ምናልባት የሬይልስ አገልጋያችሁን ዳግም ማስጀመር ያስፈልጋችሁ ይሆናል።

አስፈላጊው ሶፍትዌር ስለተጫነ፣ አሁን የተለወጡ ምስሎችን ለመፍጠር በንቅ ማከማቻ የቀረበውን የተለያየ-መልክ (variant) ዘዴን ለመጠቀም ዝግጁ ነን፡፡ በተለይም የምስሉ ስፋትም ሆነ ቁመት ከ 500 ፒክስል የማይበልጥ መሆኑን ለማረጋገጥ፣ ዳግም_ምጠናን_ገድብ (resize_to_limit) የተባለውን አማራጪ ለመጠቀም እንደሚከተለው እናደርጋለን:-

msl.variant(resize_to_limit: [500, 500])

ለአሰራር አመች ይሆን ዘንድ፣ በዝርዝር 13.71 ውስጥ እንደሚታየው፣ ይህንን ኮድ በአንድ የተለየ ማለት ምስል_ማሳያ (msl_masaya) በተባለ ዘዴ ውስጥ እናስቀምጠዋለን፡፡

ዝርዝር 13.71: አንድ ዳግም የተመጠነ የምስል ማሳያን ማከል። app/models/achrtshuf.rb
class Achrtshuf < ApplicationRecord
  belongs_to :teteqami
  has_one_attached :msl
  default_scope -> { order(created_at: :desc) }
  validates :teteqami_id, presence: true
  validates :yizet,       presence: true, length: { maximum: 140 }
  validates :msl,   content_type: { in: %w[image/jpeg image/gif image/png],
                                    message: "ብቁ የምስል ቅርጸትን መያዝ አለበት።" },
                    size:         { less_than: 5.megabytes,
                                      message:   "ከ 5ሜባ በታች መሆን አለበት፡፡" }

  # አንድ የተመጠነ የምስል ማሳያን ይመልሳል።
  def msl_masaya
    msl.variant(resize_to_limit: [500, 500])
  end
end

በመጨረሻ፣ በዝርዝር 13.72 ላይ እንደሚታየው፣ የምስል-ማሳያ (msl_masaya) ዘዴውን በአጪርጽሑፍ ከፊል ውስጥ መጠቀም እንችላለን፡፡

ዝርዝር 13.72: የተመጠነውን የ‘ምስል_ማሳያ‘ን (msl_masaya) መጠቀም። app/views/achrtshufs/_achrtshuf.html.erb
<li id="achrtshuf-<%= achrtshuf.id %>">
  <%= link_to amsaya_le(achrtshuf.teteqami, meten: 50), achrtshuf.teteqami %>
  <span class="ተጠቃሚ"><%= link_to achrtshuf.teteqami.sim,
                                        achrtshuf.teteqami %></span>
  <span class="ይዘት">
    <%= achrtshuf.yizet %>
    <%= image_tag achrtshuf.msl_masaya if achrtshuf.msl.attached? %>
  </span>
  <span class="ማህተመጊዜ"><%= time_ago_in_words(achrtshuf.created_at) %> በፊት ተለጠፈ።
    <% if ahun_teteqami?(achrtshuf.teteqami) %>
      <%= link_to "ሰርዝ", achrtshuf, method: :delete,
                                       data: { confirm: "እርግጠኛ ነዎት?" } %>
    <% end %>
  </span>
</li>

ዘዴው በዝርዝር 13.72 ውስጥ ለመጀመሪያ ጊዜ ሲጠራ፣ በዝርዝር 13.71 ውስጥ ያለው የተለያየ-መልክ (variant) ዳግም ምጠና እንደ አስፈላጊነቱ ተፈጻሚ ይሆን እና የሚቀጥሉ አጠቃቀሞችን ውጤታማ ለማድረግ ይሸጎጣል (Cache)፤ (ማለት በተጠቃሚው አሳሽ ውስጥ ምስሎቹን ያስቀምጣል ማለት ነው)፡፡26 ውጤቱም በምስል 13.30 ላይ እንደሚታየው፣ አንድ በትክክል ዳግም የተመጠነ የምስል ማሳያ ነው፡፡

images/figures/resized_image
ምስል 13.30: አንድ በትክክል ዳግም የተመጠነ ምስል።

መልመጃዎች

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

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

  1. አንድ ትልቅ ምስል ስቀሉ እና የምስሉ ዳግም መመጠኛ በትክክል እየሰራ መሆኑን በቀጥታ አረጋግጡ። ምስሉ ካሬ ባይሆንም እንኳ፣ ዳግም መመጠኛው ይሰራልን?

13.4.4 ምስልን በምርት ላይ መስቀል

ክፍል 13.4.3 ላይ የበለጸገው የምስል መስቀያ ለማበልጸጊያ በቂ ነው፣ ይሁን እንጅ (ከዚህ በታች በዝርዝር 13.74 ላይ እንደሚታየው) ምስሎችን ለማከማቸት፣ በምርት ላይ ተቀባይነት የለለውን የሰፈር ዲስክን ይጠቀማል። (ከዚያ ባሻገር፣ የሃረኩ የፋይል ማከማቻ ቋሚ ሳይሆን ጊዜያዊ ነው፣ ስለሆነም በሃረኩ ላይ ባሰማራችሁ ቁጥር፣ ከዚያ በፊት የተጫኑ ምስሎች በሙሉ ይሰረዛሉ ማለት ነው።) ስለዚህ ምስሎችን በሃረኩ ላይ ከማስቀመጥ ይልቅ፣ ከአፕልኬሽናችን መቀመጫ ቦታ በተለየ መልኩ፣ ምስሎችን ለማከማቸት አንድ የደመና ማከማቻ አገልግሎትን እንጠቀማለን።

ብዙ የደመና ማከማቻ አገልግሎትን የሚሰጡ የደመና አገልግሎት ድርጅቶች አሉ፣ ይሁን እንጂ እኛ በጣም ታዋቂ የሆነውን የአማዞን የድር አገልግሎቶች (AWS) አካል የሆነውን እና ቀላል የማከማቻ አገልግሎት (S3) በመባል የሚታወቀውን፣ የደመና አገልግሎትን እንጠቀማለን፡፡27

አፕልኬሽናችን በምርት ወቅት የደመና ማከማቻውን እንዲጠቀም ለማዘጋጀት፣ በዝርዝር 13.73 ላይ እንደሚታየው፣ የ‘አድአ-ሶማስ-3ኤሶች (aws-sdk-s3)28 እንቁን፣ በ‘ምርት (:production) አካባቢ ውስጥ እናክላለን፡፡

ዝርዝር 13.73: ለአማዞን የድር አገልግሎቶች አንድ እንቁን ማከል። Gemfile
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

gem 'rails',                      '6.1.3.2'
gem 'image_processing',           '1.9.3'
gem 'mini_magick',                '4.9.5'
gem 'active_storage_validations', '0.8.9'
.
.
.
group :production do
  gem 'pg',         '1.2.3'
  gem 'aws-sdk-s3', '1.87.0', require: false
end
.
.
.

ከዛ አሁንም ጠቅልን (bundle) አንድ ጊዜ ማስኬድ ነው:-

$ bundle _2.2.17_ install

አ.ድ.አን (AWS) ማዋቀር

በዚህ ጊዜ የ S3 አገልግሎትን ለመጠቀም፣ የአ.ድ.አ ስርዓታችሁን ማዋቀር ያስፈልጋችኋል። ይህንን ለማድረግ የሚያስፈልጋችሁ መሰረታዊ ሂደት እንደሚከተለው ይሆናል:-29

  1. የአማዞን የድር አገልግሎቶች መለያ ከለላችሁ፣ ተመዝገቡ (ምስል 13.31)። (በክፍል 1.1.1 የክላውድ9 ቅ.ማ.አን ለመጠቀም ተመዝባችሁ ከሆነ፣ አንድ የአ.ድ.አ መለያ አላችሁ ማለት ነው፣ ስለዚህ ይህንን ቅደም ተከተል ማለፍ ትችላላችሁ፡፡)
  2. በአ.ድ.አ የማንነት እና የማስተዳደር ባለስልጣን (ማ.ማ.ባ (IAM)) በኩል አንድ የማ.ማ.ባ (IAM) ተጠቃሚን ለመፍጠር የማ.ማ.ባ ተጠቃሚዎች ገጽን መጎብኘትን ይጠይቃል እናም የሚከተለውን አድርጉ:- (ሃ) ምስል 13.32 ላይ እንደሚታየው፣ “Get started with AWS IAM” ላይ ጠቅ አድርጉ (ይህ ወደ ማ.ማ.ባ ገጽ ይወስዳችኋል)፣ (ለ) ምስል 13.33 ላይ እንደሚታየው፣ “Users” ላይ ጠቅ አድርጉ፣ (ሐ) ምስል 13.34 ላይ እንደሚታየው፣ User name የሚለው ቦታ ላይ ስማችሁን አስገቡ፤ “programmatic access” የሚለውን ደግሞ ምረጡ። (መ) ምስል 13.35 ላይ እንደሚታየው፡ “Attach existing policies directly” ላይ ጠቅ በማድረግ “Adminstrator Access” የሚለውን ምረጡ። (ሰ) ምስል 13.36 ላይ እንደሚታየው፣ “Add tags (optional)” የሚለውን ገጽ ዝለሉ።
  3. “Create user” የሚለውን ጠቅ ካደረጋችሁ በኋላ፣ በምስል 13.37 ላይ እንደሚታየው፣ የተጠቃሚውን ስም፣ በ “Access key ID” እና በ “Secret access key” ከሚሉት ጽሑፎች ስር የነሱን መረጃ ማግኘት አለባችሁ። እነዚህን ሚስጥራዊ ቁልፎች ቀድታችሁ ጥብቅ የሆነ ቦታ ላይ ልታስቀምጧቸው ይገባል፡፡
  4. ምስል 13.38 ላይ እንደሚታየው፣ “Create bucket” ላይ ጠቅ በማድረግ አንድ የ S3 ሸንኬሎን ፍጠሩ። የ S3 ሸንኬሎዎች በአንድ ሁሉአቀፍ የቦታስም (Global Namespace) መፈጠር አለባቸው፣ ስለሆነም የምትፈጥሩት የሸንኬሎ ስም፣ ካሁን በፊት ጥቅም ላይ ያልዋለ መሆን ይገባዋል ማለት ነው፡፡30 እናንተ ሸንኬሎውን ካልሰየማችሁት ግን፣ ነባሪዎቹ የሸንኬሎው ዝግጅቶች ምንም አይሏችሁም።

የ S3 አገልግሎትን ማዘጋጀቱ ትንሽ ፈታኝ ሊሆን ይችላል (ሳጥን 1.2)፣ ከዚህ በላይ ለተጠቀሱት ቅደም ተከተሎች፣ ተጨማሪ መረጃ ለማግኘት የ S3 ሰነድ ላይ፣ “ሬይልስ 5‘ን [ወይም ከዚያ በላይን] ከአማዞን S3 እና ከንቅ ማከማቻ ጋር ማዘጋጀት” የሚለውን አንብቡ፣ እንዲሁም አስፈላጊ ከሆነ ጎግልን ወይም ስታክኦቨርፍሎውን በመጠቀም ስለዚሁ ጉዳይ የበለጠ መረጃ ልታገኙ ትችላላችሁ፡፡

images/figures/aws_signup
ምስል 13.31: ለአ.ድ.አ መመዝገብ፡፡
images/figures/iam_interface
ምስል 13.32: የአ.ድ.አ ማ.ማ.ባ (IAM) በይነገጽ።
images/figures/aws_create_user
ምስል 13.34: አንድ ተጠቃሚን ከ “programmatic access” ጋር መፍጠር።
images/figures/aws_admin_access
ምስል 13.35: ለተጠቃሚው የአስተዳዳሪያዊ መዳረሻን መስጠት።
images/figures/aws_skip_tags
ምስል 13.36: የተጠቃሚ መለያ አማራጮችን መዝለል።
images/figures/aws_keys
ምስል 13.37: “Access key ID” እና “Secret access key” የተባሉት ቁልፎችን ማሳየት።
images/figures/aws_bucket
ምስል 13.38: አንድ የአ.ድ.አ ሸንኬሎን መፍጠር።

አ.ድ.አን በምርት ጥቅም ላይ ማዋል

በምርት ኤመልእክት መዋቅር ላይ እንዳደረግነው ሁሉ፣ (ዝርዝር 11.44)፣ የአ.ድ.አ ቁልፎችን በመሰሉ ተነቃፊ መረጃወች ላይ ሊደርስ የሚችለውን ጥቃት ለማስወገድ፣ የሃረኩ የ‘አካባቢ (ENV) ተለዋዋጪን እንጠቀማለን፡፡ በክፍል 11.4 እና በክፍል 12.4 ላይ እነዚህ ተለዋዋጮች በሴንድግሪድ ተጨማሪ-አገልግሎት በኩል በራስሰር ተበይነው ነበር፣ በዚህ ሁኔታ ላይ ግን እነዚህን ተለዋዋጮች እኛው እራሳችን በግልጽ መበየን ይኖርብናል፡፡ በእንቁው ማዋቀርያ ሰነድ መሰረት፣ እነዚህ ተለዋዋጮች AWS የሚል ቅድመ ቅጥያ ያለው ስም መያዝ እንዳለባቸው እንገነዘባለን፣ ስለሆነም የ‘ሃረኩ መዋቅር:አዘጋጅ (heroku config:set) ዘዴን በመጠቀም ከዚህ በታች እንደሚታየው አድርገን ይህንን ማከናወን እንችላለን:-31

$ heroku config:set AWS_ACCESS_KEY_ID=<የመዳረሻ ቁልፍ> \
                    AWS_SECRET_ACCESS_KEY=<የምስጢር ቁልፍ> \
                    AWS_REGION=<ክልል> \
                    AWS_BUCKET=<የሸንኬሎ ስም>

ከላይ ለቦታ መያዣ ተብለው የገቡ ዋጋወችን፣ በትክክለኛ ዋጋወች መተካት ይኖርባችኋል፡፡ ክልሉን (region) ለማግኘት በ S3 ሰሌዳ ገጽ ላይ ዓ.አ.ሃ.አውን መመርመር ትችላላችሁ (ምስል 13.39)። ምስል 13.39 ላይ መመልከቱ የበለጠ ግልጽ ሊያደርገው ይችላል።

images/figures/aws_region
ምስል 13.39: የአ.ድ.አ ክልልን ከ S3 ሰሌዳ ዓ.አ.ሃ.አ ላይ ማግኘት።

አንዴ የሃረኩ ተለዋዋጮች ከተዘጋጁ በኋላ፣ ቀጣዩ ሂደት ማከማቻ.ያምል (storage.yml) የተባለውን የማከማቻ አማራጪን ለማዋቀር እነሱን አንድ ልዩ የያምል (YAML) ፋይል ውስጥ መጠቀም ነው፡፡ በዝርዝር 13.74 ውስጥ ያለውን ኮድ በመጠቀም፣ አንድ የአማዞን ማከማቻ አማራጪን መፍጠር እንችላለን፡፡

ዝርዝር 13.74: የአማዞን አ.ድ.አን እንደ አንድ ማከማቻ አድርጎ መምረጥን ማከል። config/storage.yml
test:
  service: Disk
  root: <%= Rails.root.join("tmp/storage") %>

local:
  service: Disk
  root: <%= Rails.root.join("storage") %>

amazon:
  service: S3
  access_key_id:     <%= ENV['AWS_ACCESS_KEY_ID'] %>
  secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %>
  region:            <%= ENV['AWS_REGION'] %>
  bucket:            <%= ENV['AWS_BUCKET'] %>

በመጨረሻም፣ በዝርዝር 13.74 ላይ የተበየነው ምርጫ በአንድ ምርት አካባቢ ውስጥ ይሰራ ዘንድ፣ በ‘ምርት.አርቢ (production.rb) ፋይል ውስጥ በ‘አዋቅር.ንቅ_ማከማቻ.አገልግሎት (config.active_storage.service) ሰሚአሴት ላይ እናክለዋለን። ውጤቱ በዝርዝር 13.75 ውስጥ ይታያል፡፡

ዝርዝር 13.75: የምርት አካባቢው የአማዞን አ.ድ.አን (S3) እንዲጠቀም ማዋቀር። config/environments/production.rb
Rails.application.configure do
  .
  .
  .
  # የተሰቀሉ ፋይሎችን በአማዞን አ.ድ.አ ላይ ማከማቸት።
  config.active_storage.service = :amazon
  .
  .
  .
end

ከላይ ካለው መዋቅር ጋር፣ ለውጦቻችንን ለማቀላቀል እና ለማሰማራት ዝግጁ ነን:-

$ rails test
$ git add -A
$ git commit -m "የተጠቃሚ አጪርጽሑፎችን ማከል"

የሆነ አፕልኬሽን በሚዋቀርበት ጊዜ፣ በውቅረቱ ላይ ብዙ ስህተቶች ሊያጋጥሙ ስለሚችሉ፣ አፕልኬሽናችን በትክክል መስራቱን ለማረጋገጥ፣ አሁን ያለበትን ቅርንጫፍ ወደ ዋና‘ው (main) ቅርንጫፍ ከማዋሃዳችን በፊት አሁን ባለበት የርእስ ቅርንጫፍ ላይ እንዳለ በቀጥታ እናሰማራዋለን። ወደ ሃረኩ የሚደረገው ግፊት ላይ ይህን የቅርንጫፍ ስምም እንደሚከተለው አድርገን ማካተት እንችላለን:-

$ git push heroku የተጠቃሚ-አጪርጽሑፎች:main

እንደተለመደው፣ ከዚያ በኋላ ውሂበጎታውን በድጋሜ እናስጀምር እና የናሙና መረጃውን በድጋሜ እንዘራለን:-

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

ሃረኩ ከአንድ የተጫነ የኢሜጅማጂክ ፕሮግራም ጋር ስለሚመጣ፣ በምስል 13.40 ላይ እንደሚታየው፣ የተገኘው ውጤትም የተሳከ የምስል ዳግም ምጠና እና በምርት ላይ ምስል ሰቀላ ነው።

images/figures/image_upload_production
ምስል 13.40: በምርት ላይ የተሰቀለ አንድ ምስል።

መልመጃዎች

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

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

  1. አንድ ትልቅ ምስልን ስቀሉ እና የምስሉ ዳግም መመጠኛ በምርት ላይ በትክክል እየሰራ መሆኑን በቀጥታ አረጋግጡ። ምስሉ ካሬ ባይሆንም እንኳ፣ ዳግም መመጠኛው ይሰራልን?

13.5 ማጠቃለያ

የአጪርጽሑፎች ሃብትን ስለጨመርን፣ የማሳያ አፕልኬሽናችንን ለማጠናቀቅ ተቃርበናል። ከዚህ በኋላ የሚቀረው ነገር፣ ተጠቃሚዎች እርስ በርሳቸው እንዲከታተሉ የሚያደርግ አንድ ማህበራዊ ንጣፍን ማከል ብቻ ይሆናል። እንደዚህ ያሉ የተጠቃሚ ትስስሮችን እንዴት አድርገን መቀረጽ እንደምንችል እንማራለን፣ እናም የአጪርጽሑፎች ቀላቢ ያለውን ተሳትፎ በምዕራፍ 14 ላይ እንመለከታለን፡፡

ክፍል 13.4.4 ‘ን ዘላችሁ አልፋችሁ ከሆነ፣ ለውጦቻችሁን ማቀላቀላችሁን አረጋግጡ:-

$ rails test
$ git add -A
$ git commit -m "የተጠቃሚ አጪርጽሑፎችን ማከል"

ከዚያ ከ‘ዋና‘ው (main) ቅርንጫፍ ጋር አዋህዱ:-

$ git checkout main
$ git merge የተጠቃሚ-አጪርጽሑፎች
$ git push

እና በመጨረሻም ወደ ምርት አሰማሩት:-

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

ይህ ምዕራፍ የመጨረሻውን እና በጣም አስፈላጊ የሆኑትን የእንቁ ጪነቶች፣ ለማየት እንደበቃ ልብ ልትሉት ይገባል፡፡ ለማጣቀሻ ይሆን ዘንድ፣ የመጨረሻው የእንቁ ፋይል (Gemfile) በዝርዝር 13.76 ውስጥ ይታያል።32

ዝርዝር 13.76: የማሳያ አፕልኬሽኑ የመጨረሻው የ‘እንቁፋይል (Gemfile)።
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

gem 'rails',                      '6.1.4.1'
gem 'image_processing',           '1.9.3'
gem 'mini_magick',                '4.9.5'
gem 'active_storage_validations', '0.8.9'
gem 'bcrypt',                     '3.1.13'
gem 'faker',                      '2.11.0'
gem 'will_paginate',              '3.3.0'
gem 'bootstrap-will_paginate',    '1.0.0'
gem 'bootstrap-sass',             '3.4.1'
gem 'puma',                       '5.3.1'
gem 'sass-rails',                 '6.0.0'
gem 'webpacker',                  '5.4.0'
gem 'turbolinks',                 '5.2.1'
gem 'jbuilder',                   '2.10.0'
gem 'bootsnap',                   '1.7.2', require: false

group :development, :test do
  gem 'sqlite3', '1.4.2'
  gem 'byebug',  '11.1.3', platforms: [:mri, :mingw, :x64_mingw]
end

group :development do
  gem 'web-console',        '4.1.0'
  gem 'rack-mini-profiler', '2.3.1'
  gem 'listen',             '3.4.1'
  gem 'spring',             '2.1.1'
end

group :test do
  gem 'capybara',                 '3.35.3'
  gem 'selenium-webdriver',       '3.142.7'
  gem 'webdrivers',               '4.6.0'
  gem 'rails-controller-testing', '1.0.5'
  gem 'minitest',                 '5.11.3'
  gem 'minitest-reporters',       '1.3.8'
  gem 'guard',                    '2.16.2'
  gem 'guard-minitest',           '2.4.6'
end

group :production do
  gem 'pg',         '1.2.3'
  gem 'aws-sdk-s3', '1.87.0', require: false
end

# ዊንዶውስ የዞን መረጃ ፋይሎችን አያካትትም፤ ስለሆነም፣ በአንድ የቤተኛ የዊንዶውስ ስርዓት
# ላይ፣ ሬይንስን የምታካሂዱ ከሆነ፣ የሚከተለው እንቁ ላይ ያለውን የአስተያየት ምልክት ማስወገድ
# ይኖርባችኋል:-
# gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

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

  • አጪርጽሑፎችም ልክ እንደ ተጠቃሚዎች፣ በአንድ ንቅ መዝገብ ቅርጸት የሚታገዝ አንድ ሃብት ተደርገው እንደተቀረጹ
  • ሬይልስ ብዛት ያላቸው መረጃ-ጠቋሚዎችን እንደሚደግፍ፣
  • በተጠቃሚ ቅርጸት ውስጥ ብዙ_አለው‘ን (has_many) እና በአጪርጽሑፎች ቅርጸት ውስጥ ባለቤት_ነው (belongs_to) የተባሉት ዘዴወችን በመጠቀም፣ አንድ ተጠቃሚን ብዙ አጪርጽሑፎች እንዳሉት አድርገን መቅረጽ እንደምንችል፣
  • የ‘ብዙ_አለው (has_many) እና የ‘ባለቤት_ነው (belongs_to) ዘዴወች ጥምረት በማሕበሩ በኩል የሚሰሩ ዘዴወችን እንደሚሰጡን፣
  • ተጠቃሚ.አጪርጽሑፎች.ገንባ (teteqami.achrtshufs.build(...)) የተባለው ኮድ፣ ከአንድ ከተሰጠ ተጠቃሚ ጋር የሚዛመድ አንድ አዲስ የአጪርጽሑፍ ቁስን በራስሰር እንደሚመልስ፣
  • ሬይልስ በነባሪ_ክልል (default_scope) በኩል ነባሪ ቅደም ተከተል ማድረግን እንደሚደግፍ፣
  • ክልሎች ስም አልባ ሥልትን እንደ ነጋሪአሴቶች አድርገው እንደሚቀበሉ፤
  • የ‘ጥገኛ አጥፊ (dependent: :destroy) አማራጪ አንድ ቁስ በሚጠፋበት ጊዜ፣ የሱ ተዛማጆች በሙሉ በአንድ ጊዜ አብረው እንዲጠፉ እንደሚያደርግ፣
  • የገጸቁጥር እና የቁስ ቆጠራ፣ በማሕበር በኩል ሊከናወን የሚችል ውጤታማ ኮድን በራስሰር እንደሚሰጡ፣
  • እቃወች የማሕበሮች መፈጠርን እንደሚደግፉ፣
  • ተለዋዋጮችን ወደ ሬይልስ ከፊሎች ማሳለፍ እንደሚቻል፣
  • የ‘የት (where) ዘዴ የንቅ መዝገብ ምርጫዎችን ለማከናወን ሊያገለግል እንደሚችል፣
  • በማሕበራቸው በኩል ቁሶችን ሁልጊዜ በመፍጠር እና ጥገኞቹን ቁሶች ደግሞ በማጥፋት ደህንነቱ የተጠበቀ ክንውንን ማስገደድ እንደምንችል እና
  • ንቅ ማከማቻን በመጠቀም ምስሎችን መስቀል እንደምንችል ተምረናል።
1. አጪርጽሑፍ የሚለው ስም፣ ለስሙ መነሻ የሆነው ማይክሮብላግ (microblog) በትዊተር እንዲህ የሚል የተለመደ አገላለጽ ስላለው ነው:- ብሎጎች የጽሑፍ ምላሽ ስለሚኖራቸው ማይክሮብሎጎች ደግሞ አጪርጽሑፎች ሊኖራቸው ይገባል፣ እነዚህንም “ትዊቶች” ጋር አንድ ዓይነት እንደሆኑ ተደርጎ ማየት ይችላል።
2. www.postgresql.org/docs/9.1/static/datatype-character.html
3. የውጪ ቁልፍ ማጣቀሻው፣ በአጪርጽሑፎች (Achrtshufs) ሰንጠረዥ ውስጥ ያለው የተጠቃሚ-መታወቂያ በ Teteqamis ሰንጠረዥ ውስጥ ያለውን የመታወቂያ ረድፍ ያመለክታል፡፡ የዚህን አሰራር በዝርዝር ማወቁ በዚህ ስልጠና ውስጥ በጪራሽ አስፈላጊ አይሆንም። ይህ የውጪ ቁልፍ ማጣቀሻ፣ በሁሉም ውሂበጎታ ላይ ተቀባይነት የለውም። (አፕልኬሽናችን በምርት ላይ በሚሆንበት ጊዜ በምንጠቀምበት በፖስትግሬስስኴል ውሂበጎታ ላይ ተቀባይነት ሲኖረው፣ አፕልኬሽናችን በምናበለጽግበት ማለት በስዄልላይት ውሂበጎታ አስማሚ (አዳብተር) ላይ ግን ፈጽሞ ተቀባይነት የለውም።) በክፍል 14.1.2 ላይ ስለ የውጪ ቁልፎች ማጣቀሻ በበለጠ እንማራለን፡፡
4. የኮዱን ምንጪ ከተመለከታችሁ የ‘ገንባ (build) ዘዴ ለአዲስ (new) ዘዴ የቅጽል ስሙ እንደሆነ ትገነዘባላችሁ። ይህንን ለጠቆሙት ክቡር አንባቢ አብደላ ቡድሪን ከልብ አመሰግናለሁ፡፡
5.ክፍል 10.5 ውስጥ በተጠቃሚዎች መረጃ-ጠቋሚ አውድ ውስጥ እዚህ ጋር ተመሳሳይ የሆነ፣ አንድ ትንሽ ችግር አጋጥሞን ነበር፡፡
6. ይህ አስፈላጊ ላይሆን ይችላል ምክንያቱም፣ በብዙ ስርዓተ ክወናዎች ላይ እቃዎቹ፣ አሁን በፋይሉ ውስጥ በሚታዩበት ቅደም ተከተል መሰረት ስለሚፈጠሩ ነው፡፡ ስለዚህ በዚህ ፋይል ውስጥ የሚኖረው የመጨረሻ እቃ መጨረሻ ላይ የተፈጠረ ነው ማለት ነው (ይህም ወቅታዊው ነው ማለት ነው)፤ ነገር ግን በዚህ ባህሪ ላይ መተማመኑ ሞኝነት ነው፤ ይህም ፈርካሻ እና ምናልባትም በአንድ ስርዓት ላይ የተመረኮዘ ስርዓተ-ጥገኛ ሊሆን ይችላል።
7. ተ.መ.ቋ መልከፊደል-ግድየለሽ ነው። ይህንን ችግር ለማስወገድ የተ.መ.ቋ ቃላቶችን በዓብይ ፊደላት መጻፉ በብዙ ሰወች ዘንድ በጣም የተለመደ አጻጻፍ ነው (ለምሳሌ:- DESC)።
8. ማትባት (optimize) ማለት፣ አንድ ፕሮግራም በፍጥነት እንዲሰራ፣ ወይም አነስተኛ ቦታ እንዲይዝ ለማድረግ አንድ ፕሮግራምን ማስተካከል ማለት ነው፡፡
9. Faker::Lorem.sentence የተባለው ዘዴ፣ ከሎረም ኢፕሰም ጽሑፍ የተዘጋጁ አረፍተ ነገሮችን ያቀርባል/ይመልሳል፣ በምዕራፍ 7 ውስጥ እንደተገለጸው፣ ሎረም ኢፕሰም ስለ አመጣጡ ብዙ የሚያስገርም ታሪክ አለው፡፡
10. የአስመሳይ እንቁ ሲሰራ፣ ሆን ተብሎ አረፍተ ነገሮችን በነሲብ እንዲሰራ ተደርጎ ነው የተሰራው፤ ስለሆነም የአጪርጽሑፉችሁ ይዞታዎች እዚህ ከምታዩዋቸው ይዞታዎች ጋር ላይመሳሰሉ ይችላሉ፡፡
11. ሁሉ ነገር የተሟላ ይሆን ዘንድ፣ ዝርዝር 13.26 ለዚህ ምዕራፍ የሚያስፈልጉትን ቅ.ቋ ሁሉ ይዟል፡፡
12. የ‘ሙሉ_አርዕስት (mulu_arest) ረጅን ሌሎች ፈተናዎች ላይ ለመጠቀም ከፈለጋችሁ፣ የአፕልኬሽን ረጅውን በ‘ፈተና_ረጅ.አርቢ (test_helper.rb) ፋይል ውስጥ ማካተት ትችላላችሁ(ለምሳሌ:- እንደ ዝርዝር 3.32 የመሳሰሉትን ለመፈተን ከፈለጋችሁ እንደዛ ማድረግ ይጠበቅባችኋል)፡፡
13. እንደ ጃቫ ወይም ሲ ++ ባሉ ቋንቋዎች ውስጥ ካለው ባህሪ በተለየ መልኩ፣ በሩቢ ውስጥ ያሉ የግል የተባሉት ዘዴወች እነሱን ከፈጠራቸው ክፍል ውስጥ በሚገኝ ማንኛውንም ቅርፀ ተለዋዋጪ መጠራት እንደሚችሉ ልትረዱት ይገባል፡፡ ይህንን ልዩነት እንዳተኩርበት ያስገነዘበኝን ክቡር አንባቢ ቪሻል አንቶኒን ከልብ ላመሰግናቸው እወዳለሁ።
14. ከአንድ የስህተት አቅርቦት በኋላ ዓ.አ.ሃ.አው /አጪርጽሑፎች (/achrtshufs) መሆኑን ልብ በሉ፣ ለዚህ ዓ.አ.ሃ.አም በዝርዝር 13.30 ላይ ከተበየኑት ማዛወሪያወች ውስጥ ለአንድ ዓግኝ (GET) መጠየቅ ምላሽ የሚሰጥ የለም፡፡ የአድራሻ አሞሌውን የኋሊት መምታት (ወይም ዓ.አ.ሃ.አውን ከአድራሻ አሞሌው ላይ ቀድቶ መገልበጥ) አንድ የማዟዟር ስህተትን ያስከትላል። ምንም እንኳን በአፕልኬሽኑ መደበኛ ሂደት ውስጥ ይህ ችግር በጪራሽ የማያጋጥም ቢሆንም፣ get '/microposts', to: 'staticpageshome' ማዘዋዋሪያን በ‘አዋቅር/ማዘዋወርያወች/አርቢ (config/routes.rb) ፋይል ውስጥ በመጨመር ግን ይህ ችግር በጪራሽ እንዳይከሰት መከላከል ትችላላችሁ፡፡
15. ስለ የት (where) እና ከሱ ጋር ተዛማጅ ስለሆኑት ዘዴወች የበለጠ ለመረዳት በሬይልስ መመሪያ ውስጥ የሚገኘውን የ የንቅ ሬከርድ የመጠይቅ በይነገጽን ተመልከቱ።
16. ይህንን መፍትሄ ለጠቆሙት ክቡር አንባቢ ማርቲን ፍራንክሊንን ከልብ አመሰግናለሁ፡፡
17. ይህ በሃ.ጽ.ማ.ስ ዝርዝር መግለጫ ላይ እንደተበየነው፣ ከሃ.ጽ.ማ.ስ_አቅራቢ (HTTP_REFERER) ጋር ይዛመዳል። “REFERER” የሚለው ቃል አሁን በዚህ ስልጠና ውስጥ የፊደል ስህተት የተደረገበት እንዳልሆነ ልብ ልትሉ ይገባል፣ በእውነቱ ቃሉ በዝርዝር መግለጫው ላይም በትክክል አልሰፈረም፡፡ ሬይልስ በትክክል በተጻፈው በ‘አቅራቢ (referrer) ዘዴ አማካይነት፣ አቅራቢውን ዓ.አ.ሃ.አ በመድረስ ይህንን ስህተት ያስተካክላል፡፡
18. በሬይልስ አፕልኬሽን ውስጥ ይህንን ዓ.አ.ሃ.አ እንዴት ማግኘት እንደምንችል አላውቅም ነበረ፣ እናም “rails request previous url” ብየ ጎለጎልኩ (ጎግል አደረኩ) ከዚያ ስታክ ኦቨርፍሎው ላይ ጥያቄውን እስከ መልሱ አገኘሁ፡፡
19. የተከበሩ አንባቢ ቪክቶር ፌኝን፣ ይህንን ስለ ጠቆሙ ከልብ አመሰግናለሁ።
20. ንቅ ማከማቻ በሬይልስ 5.2 ውስጥ የተካተተ ገጸባህሪ ነው።
21. የዊንዶውስ ተጠቃሚዎች አንድ የ :binary ሰሚአሴትን:- fixture_file_upload(file, type, :binary) ማከል አለባችሁ፡፡
22. ጃቫስክሪፕትን በደንብ የሚያውቁ ሰወች፣ ይህንን የምስል መጠን ማረጋገጫ ኮድ ለማጣራት፣ አንድ እራሱን የቻለ ፋይል ላይ ሊያስቀምጡት ይችሉ ይሆናል፣ ይህ በንዲህ እያለ፣ ይህ ስልጠና የጃቫስክሪፕት ስልጠና ስላልሆነ፣ በዝርዝር 13.68 ውስጥ ያለው ኮድ ለዓላማችን መሳካት አሁን ባለበት ቦታ ላይ ቢሆንም ምንም አይልም።
23. እንደዚህ ያሉ ነገሮችን እንዴት ማድረግ እንደምትችሉ ለመማር፣ ልክ እኔ እንዳደረኩት ማድረግ ትችላላችሁ፤ የሆነ ነገር ስታክ ኦቨርፍሎው ላይ እስክታገኙ ድረስ፣ እንደዚህ ብላችሁ ጎልጉሉ (ጎግል አድርጉ) “javascript maximum file size” ፡፡
24. ሽበታ (Grayed out) በአንድ የስእላዊ የተጠቃሚ በይነገጽ ውስጥ አንድ የተሰናከለ የስእላዊ የቁጥጥር አባልን ለመግለጽ የሚያገለግል ስነአባባል ነው።
25. ቅ.ቋን በመጠቀም መታየት የሚገባውን የማሳያ መጠን መገደብ ይቻላል፣ ነገር ግን ይህ ደንብ የምስሉን መጠን አይለውጠውም፤ በተለይ ደግሞ ትልቅ ምስሎችን ለመጫን እንዲሁ ትንሽ ጊዜንም ይወስዳል። (አንዳንድ ጣቢያዎችን ስትጎበኙ “ትናንሽ” ምስሎችን ለመጫን ብዙ ጊዜ ሲወስድባቸው አጋጥሟችሁ ሊሆን ይችላል፣ ለዚህ ነው እንደዛ ዓይነት ችግር ያያችሁት፡፡)
26. ምናልባት ለትላልቅ የድር ጣቢያወች እንዲህ ዓይነቱን ሂደት ወደ በዳራ ሂደት ማስተላለፉ የተሻለ አሰራር ሊሆን ይችላል፤ ይህ ዘዴ ከዚህ ስልጠና ወሰን ውጪ ነው፣ ነገር ግን እንደዛ ማድረግ ከፈለጋችሁ፣ Active Job የተባለውን በይነገጽ በመጠቀም፣ እሱን ተግባራዊ ማድረግ የምትችሉበትን መንገድ ሊከፍትላችሁ ይችላል፡፡
27. S3 የሚከፈልበት አገልግሎት ነው፤ ይሁን እንጅ ይህን የሬይልስ ስልጠና አፕልኬሽንን ለማዘጋጀት እና ለመሞከር የሚያስፈልገው ማከማቻን ለመክፈል የሚወስደው ገንዘብ፣ በአንድ ወር ውስጥ ከአንድ ሳንቲም ያነሰ ነው፡፡
28. ሶማስ (sdk) ማለት የሶፍትዌር ማበልጸጊያ ስብስብ (ሶማስ) (Software Development Kit (sdk)) ማለት ሲሆን፣ ለሶስተኛ ወገን አበልጻጊዎች አንድ የተወሰነ ማዕቀፍን ወይም በይነገጽን በመጠቀም አፕልኬሽኖችን ለመስራት እንዲጠቀሙባቸው የተዘጋጁ የመሳሪያዎች ስብስቦች ናቸው።
29. እነዚህ የአሰራር ሂደቶች ይሄ ጽሑፍ በተጻፈበት ወቅት ወቅታዊ የነበሩ ናቸው፣ ነገር ግን እንደ አ.ድ.አ ያሉ አገልግሎቶች ያለማቋረጥ የሚሻሻሉ ስለሆኑ፣ የተጠቃሚ በይነገጹ በዚህ ጊዜ ሊቀየር ይችል ይሆናል። ማንኛውንም ችግር ለመፍታት ቴክኒካዊ ዘይቤያችሁን ልትጠቀሙ ይገባል።
30. በኮምፕዩተር ሳይንስ ውስጥ የቦታስም ማለት፣ የተለያዩ ዓይነቶች ቁሶችን ለመለየት እና ለመጥቀስ የሚያገለግሉ የምልክቶች (የስሞች) ስብስብ ሲሆን እሱም፣ ሁሉም የቦታስም የተሰጣቸው ቁሶች፣ ልዩ ስሞች ስለሚኖራቸው በቀላሉ እንዲለዩ ያስችላል፡፡
31. የማዘዥያ መስመር ቀጣይ ሆሄ \ ‘ን በመጠቀም፣ ሁሉንም የውቅረት ቅንጅቶች በአንድ መስመር ላይ በማስቀመጥ፣ ሃረኩ ብዙ ጊዜ፣ እንደገና እንዳይጀምር ለመከላከል ተገቢውን ቅንጅት እናደርጋለን፡፡ ይህንን ለጠቆሙት ክቡር አንባቢ ኒኮ ግሪናሪን ከልብ አመሰግናለሁ፡፡
32. እንደ ሁልጊዜው፣ እዚህ ላይ የተዘረዘሩትን የእንቁ ስሪት ቁጥሮችን ከመጠቀም ይልቅ፣ በ gemfiles-6th-ed.railstutorial.org ላይ የተዘረዘሩትን የእንቁ ስሪት ቁጥሮችን መጠቀም ይኖርባችኋል።