כיצד ליצור משאבים מקוננים עבור יישום Ruby on Rails

הקדמה

Ruby on Rails הוא סביבת פיתוח ליישומי רשת שנכתבה ב־Ruby ומציעה למפתחים גישה אופיינית לפיתוחי יישומים. העבודה עם Rails נותנת למפתחים:

  • קונבנציות לטיפול בדברים כמו ניתוב, מידע מצבי, וניהול נכסים.
  • A firm grounding in the model-view-controller (MCV) architectural pattern, which separates an application’s logic, located in models, from the presentation and routing of application information.

כשאתה מוסיף מורכבות ליישומי ה־Rails שלך, ייתכן ותעבוד עם מספר רב של מודלים, שמייצגים את הלוגיקה העסקית של היישום שלך ומתממשקים עם מסד הנתונים שלך. הוספת מודלים קשורים משמעות שאתה צריך להגדיר יחסים משמעותיים ביניהם, וכך להשפיע על איך מידע מועבר דרך הבקרים של היישום שלך, וכיצד הוא נלכד ומוצג בחזרה למשתמשים דרך התצוגות.

במדריך זה, תבנה על יישום Rails קיים שמציע למשתמשים עובדות על סופר ים. היישום הזה כבר כולל מודל לטיפול במידע על סופרי ים, אך תוסיף משאב מקונן עבור פוסטים על סופר ים יחידים. זה יאפשר למשתמשים לבנות מגוון רחב יותר של רעיונות ודעות על סופר ים יחידים.

דרישות מוקדמות

כדי לעקוב אחרי המדריך הזה, תצטרך:

  • A local machine or development server running Ubuntu 18.04. Your development machine should have a non-root user with administrative privileges and a firewall configured with ufw. For instructions on how to set this up, see our Initial Server Setup with Ubuntu 18.04 tutorial.
  • Node.js ו־npm מותקנים במכונת המחשב המקומית שלך או בשרת הפיתוח. המדריך הזה משתמש בגרסת Node.js 10.16.3 ובגרסת npm 6.9.0. להדרכה בנושא התקנת Node.js ו־npm על Ubuntu 18.04, יש לעקוב אחר ההוראות בחלק "התקנה באמצעות PPA" של כיצד להתקין את Node.js על Ubuntu 18.04.
  • Ruby, rbenv, ו־Rails מותקנים במכונת המחשב המקומית שלך או בשרת הפיתוח, בהתאם לשלבים 1-4 ב־כיצד להתקין את Ruby on Rails עם rbenv על Ubuntu 18.04. המדריך הזה משתמש ב־Ruby 2.5.1, rbenv 1.1.2, ו־Rails 5.2.3.
  • SQLite מותקן, ואפליקציית מידע בסיסית על סוגי הכרישים נוצרה, על פי ההוראות ב־כיצד לבנות אפליקציית Ruby on Rails.

שלב 1 — יצירת מודל מקונן

היישום שלנו ינצל את הקשרים של רשומת פעילות כדי לבנות קשר בין מודלי "שרק" ו"פוסט": פוסטים ישתייכו לסוגי דגים מסוימים, וכל דג יכול להכיל מספר פוסטים. מודלי "שרק" ו"פוסט" שלנו יתקשרו דרך הקשרים belongs_to ו־has_many.

השלב הראשון לבניית היישום בדרך הזו יהיה ליצור מודל של Post ומשאבים קשורים. כדי לעשות זאת, נוכל להשתמש בפקודת rails generate scaffold, שתספק לנו מודל, התזזה של מסד נתונים לשינוי סכימת המסד, בקר, סט מלא של תצוגות לניהול פעולות צור, קרא, עדכן, ומחק (CRUD) סטנדרטיות, ותבניות עבור חלקי, עוזרים, ובדיקות. נצטרך לשנות את המשאבים הללו, אך בשימוש בפקודת scaffold תחסוך לנו זמן ואנרגיה מאחר והיא יוצרת מבנה שנוכל להשתמש בו כנקודת התחלה.

ראשית, וודא שאתה נמצא בתיקיית sharkapp לפרוייקט Rails שיצרת בדרישות הקדם:

  1. cd sharkapp

צור את משאבי ה־Post שלך עם הפקודה הבאה:

rails generate scaffold Post body:text shark:references

body:text, אנו מספרים ל־Rails לכלול שדה body בטבלת המסד נתונים posts – הטבלה שממפה למודל Post. אנו כן כוללים את המילת המפתח :references, שמכינה את הקשר בין מודלי Shark ו־Post. במדויק, זה יבטיח שמפתח זר המייצג כל רשומת צום במסד הנתונים sharks יתווסף למסד הנתונים posts.

פעם שהפקקת את הפקודה, תראה פלט שמאשר את המשאבים שהריילס ייצרה עבור היישום. לפני שתמשיך, תוכל לבדוק את קובץ המיגרציה של בסיס הנתונים שלך כדי לראות את היחס שקיים כעת בין המודלים שלך וטבלאות המסד. השתמש בפקודה הבאה כדי לצפות בתוכן של הקובץ, וודא שאתה מחליף את הזמן הסטמפ של קובץ המיגרציה שלך במה שמוצג כאן:

  1. cat db/migrate/20190805132506_create_posts.rb

תראה את הפלט הבא:

Output
class CreatePosts < ActiveRecord::Migration[5.2] def change create_table :posts do |t| t.text :body t.references :shark, foreign_key: true t.timestamps end end end

כפי שתוכל לראות, הטבלה כוללת עמודה עבור מפתח זר של צום. מפתח זה ייקח את הצורה של model_name_id – במקרה שלנו, shark_id.

ריילס הקים את היחס בין המודלים במקומות אחרים גם. תסתכל על המודל החדש שנוצר, Post, בעזרת הפקודה הבאה:

cat app/models/post.rb
Output
class Post < ApplicationRecord belongs_to :shark end

ההתאמה belongs_to מייצרת יחס בין מודלים שבו ייחודית למודל המכריע שייחשב כייחודי למודל שקוראים בשםו. במקרה של היישום שלנו, זה אומר שפוסט יחיד משתייך לצום יחיד.

בנוסף להגדרת הקשר הזה, פקודת rails generate scaffold יצרה גם מסלולים ותצורות עבור הפוסטים, כפי שעשתה עבור משאבי הכרישים שלנו בשלב 3 של איך לבנות אפליקציית Ruby on Rails.

זהו התחלה שימושית, אך נצטרך להגדיר מסלולים נוספים ולחזק את הקשר של Active Record עבור מודל הShark כדי שהיחס בין המודלים והמסלולים שלנו יעבוד כפי שרצינו.

שלב 2 — ציון מסלולים מקוננים וקשרים עבור מודל ההורה

Rails כבר הגדירה את הקשר belongs_to במודל הPost שלנו, בזכות המילה המפתח :references בפקודת rails generate scaffold, אך כדי שהיחס הזה יעבוד כראוי, נצטרך לציין קשר has_many גם במודל הShark שלנו. נצטרך גם לבצע שינויים במסלול המוגדר כברירת מחדל של Rails כדי להפוך את משאבי הפוסט לילדי משאבי הכרישים.

להוסיף את הקישור has_many למודל Shark, פתח את app/models/shark.rb באמצעות nano או העורך האהוב עליך:

  1. nano app/models/shark.rb

הוסף את השורה הבאה לקובץ כדי להציב את הקשר בין כרישים ופוסטים:

~/sharkapp/app/models/shark.rb
class Shark < ApplicationRecord
  has_many :posts
  validates :name, presence: true, uniqueness: true
  validates :facts, presence: true
end

דבר אחד ששווה להידמיין כאן הוא מה קורה לפוסטים פעם אחת שכריש מסוים נמחק. כנראה שאנחנו לא רוצים שהפוסטים הקשורים לכריש שנמחק יישארו בבסיס הנתונים. כדי להבטיח שכל הפוסטים הקשורים לכריש נתוך יימחקו כאשר הכריש הוא נמחק, נוכל לכלול את האפשרות dependent עם הקישור.

הוסף את הקוד הבא לקובץ כדי להבטיח שפעולת destroy על כריש מסוים תמחק כל פוסטים קשורים:

~/sharkapp/app/models/shark.rb
class Shark < ApplicationRecord
  has_many :posts , dependent: :destroy
  validates :name, presence: true, uniqueness: true
  validates :facts, presence: true
end

כאשר תסיים לבצע את השינויים הללו, שמור וסגור את הקובץ. אם אתה משתמש ב־nano, תוכל לעשות זאת על ידי לחיצה על CTRL+X, Y, ואז ENTER.

לאחר מכן, פתח את קובץ הנתיבים שלך config/routes.rb כדי לשנות את היחס בין הנתיבים שלך:

  1. nano config/routes.rb

כרגע, הקובץ נראה כך:

~/sharkapp/config/routes.rb
Rails.application.routes.draw do
  resources :posts 
  resources :sharks

  root 'sharks#index'
  # לפרטים נוספים על ה־DSL הזמינים בתוך קובץ זה, ראה http://guides.rubyonrails.org/routing.html
end

הקוד הנוכחי מציב יחס עצמאי בין הנתיבים שלנו, כאשר מה שנרצה להביע הוא יחס תלוי בין כרישים לפוסטים הקשורים אליהם.

Let’s update our route declaration to make :sharks the parent of :posts. Update the code in the file to look like the following:

~/sharkapp/config/routes.rb
Rails.application.routes.draw do
  resources :sharks do
    resources :posts
end
  root 'sharks#index'
  # עבור פרטים נוספים על DSL הזמין בתוך קובץ זה, ראה http://guides.rubyonrails.org/routing.html
end

שמור וסגור את הקובץ כאשר תסיים לערוך.

עם השינויים האלה במקום, תוכל להמשיך ולעדכן את הקונטרולר שלך posts.

שלב 3 — עדכון הקונטרולר של הפוסטים

האיגוד בין המודלים שלנו נותן לנו שיטות שאנו יכולים להשתמש בהן כדי ליצור מופעי פוסט חדשים הקשורים לסוגי כריש מסוימים. כדי להשתמש בשיטות אלו, נצטרך להוסיף אותן לקונטרולר שלנו.

פתח את קובץ הקונטרולר של הפוסטים:

  1. nano app/controllers/posts_controller.rb

כרגע, הקובץ נראה כך:

~/sharkapp/controllers/posts_controller.rb
class PostsController < ApplicationController
  before_action :set_post, only: [:show, :edit, :update, :destroy]

  # GET /פוסטים
  # GET /פוסטים.json
  def index
    @posts = Post.all
  end

  # GET /פוסטים/1
  # GET /פוסטים/1.json
  def show
  end

  # GET /פוסטים/new
  def new
    @post = Post.new
  end

  # GET /פוסטים/1/edit
  def edit
  end

  # POST /פוסטים
  # POST /פוסטים.json
  def create
    @post = Post.new(post_params)

    respond_to do |format|
      if @post.save
        format.html { redirect_to @post, notice: 'Post was successfully created.' }
        format.json { render :show, status: :created, location: @post }
      else
        format.html { render :new }
        format.json { render json: @post.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /פוסטים/1
  # PATCH/PUT /פוסטים/1.json
  def update
    respond_to do |format|
      if @post.update(post_params)
        format.html { redirect_to @post, notice: 'Post was successfully updated.' }
        format.json { render :show, status: :ok, location: @post }
      else
        format.html { render :edit }
        format.json { render json: @post.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /פוסטים/1
  # DELETE /פוסטים/1.json
  def destroy
    @post.destroy
    respond_to do |format|
      format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # השתמש ב-callbacks כדי לשתף פעולה או אילוצים משותפים בין פעולות.
    def set_post
      @post = Post.find(params[:id])
    end

    # אל תאמן על פרמטרים מהאינטרנט המפחיד, רק תרשום את הרשימה הלבנה דרך.
    def post_params
      params.require(:post).permit(:body, :shark_id)
    end
end

כמו בשליטה שלנו על סנפירים, פעולות השליטה של זווית הפוסטים הזו עובדות עם מופעים של מחלקת הפוסט הקשורה. לדוגמה, פעולת ה-new יוצרת מופע חדש של מחלקת הפוסט, פעולת ה-index מחזירה את כל המופעים של המחלקה, ופעולת ה-set_post משתמשת ב-find וב-params כדי לבחור פוסט מסוים לפי ה-id. אם, בכל זאת, נרצה שהמופעים שלנו יהיו מקושרים עם מופעי סנפיר מסוימים, נצטרך לשנות את הקוד הזה, מאחר ומחלקת הפוסט פועלת כיום כיחידה עצמאית.

השינויים שלנו יעשו שימוש בשני דברים:

  • השיטות שהפכו זמינות עבורנו כאשר הוספנו את הקישוריות belongs_to ו־has_many למודלים שלנו. למעשה, כעת יש לנו גישה ל־build באמצעות הקישוריות has_many שהגדרנו במודל ה־Shark שלנו. שיטה זו תאפשר לנו ליצור אוסף של אובייקטים פוסט המקושרים לאובייקט ספציפי של צום, באמצעות המפתח הזר של shark_id שקיים בבסיס הנתונים שלנו posts.
  • הנתיבים ועוזרי הניתוב שהפכו זמינים כאשר יצרנו נתיב מקונן ל־posts. עבור רשימה מלאה של נתיבים דוגמתיים שהופכים זמינים כאשר אתה יוצר יחסים מקוננים בין משאבים, ראה את מסמכי ההוראות של Rails. לעת עתה, יהיה מספיק לנו לדעת שעבור כל צום ספציפי — נניח sharks/1 — יהיה נתיב מקושר עבור הפוסטים הקשורים לצום זה: sharks/1/posts. יהיו גם עוזרי ניתוב כמו shark_posts_path(@shark) ו־edit_sharks_posts_path(@shark) שמפנים אל הנתיבים המקוננים אלו.

בקובץ, נתחיל בכתיבת שיטה, get_shark, שתרוץ לפני כל פעולה בבקר. שיטה זו תיצור משתנה מקומי @shark על ידי חיפוש אחר מופע של צום לפי shark_id. עם המשתנה הזה זמין לנו בקובץ, יהיה ניתן לקשר פוסטים לצום ספציפי בשאר השיטות.

מעל לשיטות private האחרות בתחתית הקובץ, הוסף את השיטה הבאה:

~/sharkapp/controllers/posts_controller.rb
. . . 
private
  def get_shark
@shark = Shark.find(params[:shark_id])
end
  # השתמש ב-callbacks כדי לשתף פעולה או אילוצים משותפים בין פעולות.
. . . 

לאחר מכן, הוסף את הפילטר התואם לתחילת הקובץ, לפני הפילטר הקיים:

~/sharkapp/controllers/posts_controller.rb
class PostsController < ApplicationController
  before_action :get_shark

כך תוודא ש-get_shark יתבצע לפני כל פעולה הוגדרה בקובץ.

בנוסף, תוכל להשתמש במשתנה @shark הזה כדי לכתוב את השיטה index מחדש. במקום לאסוף את כל המופעים של מחלקת Post, נרצה ששיטה זו תחזיר את כל המופעים של פוסט הקשורים למופע מסוים של יונקין.

שנה את השיטה index כך:

~/sharkapp/controllers/posts_controller.rb
. . .
  def index
    @posts = @shark.posts
  end
. . .

השיטה new תצטרך תיקון דומה, מאחר ונרצה שמופע חדש של פוסט יתווסף ליונקין מסוים. כדי להשיג זאת, נוכל להשתמש בשיטת build, יחד עם משתנה ה-instance המקומי שלנו, @shark.

שנה את השיטה new כך:

~/sharkapp/controllers/posts_controller.rb
. . . 
  def new
    @post = @shark.posts.build
  end
. . . 

שיטה זו יוצרת אובייקט פוסט המקושר למופע היונקין הספציפי מהשיטה get_shark.

לבסוף, נטפל בשיטה הכי מקושרת ל-new: create. שיטת create עושה שניים דברים: היא בונה מופע פוסט חדש באמצעות הפרמטרים שמשתמשים הזינו לטופס new, ואם אין שגיאות, היא שומרת את המופע הזה ומשתמשת בעוזר נתיב כדי להפנות את המשתמשים למקום שבו הם יכולים לראות את הפוסט החדש. במקרה של שגיאות, היא מציגה מחדש את תבנית new.

עדכן את השיטה create כך:

~/sharkapp/controllers/posts_controller.rb
  def create
    @post = @shark.posts.build(post_params)

        respond_to do |format|
         if @post.save  
            format.html { redirect_to shark_posts_path(@shark), notice: 'Post was successfully created.' }
            format.json { render :show, status: :created, location: @post }
         else
            format.html { render :new }
            format.json { render json: @post.errors, status: :unprocessable_entity }
      end
    end
  end

בשלב הבא, תסתכל על השיטה update. השיטה הזו משתמשת במשתנה @post, שלא מוגדר באופן ברור בשיטה עצמה. מאיפה מגיע משתנה זה?

תבחן את המסננים בראש הקובץ. המסנן השני, שנוצר באופן אוטומטי, before_action מספק תשובה:

~/sharkapp/controllers/posts_controller.rb
class PostsController < ApplicationController
  before_action :get_shark
  before_action :set_post, only: [:show, :edit, :update, :destroy]
  . . .

השיטה update (כמו show, edit, ו־ destroy) מקבלת משתנה @post מהשיטה set_post. השיטה הזו, המופיעה תחת השיטה get_shark עם השיטות ה־private האחרות שלנו, נראית כך כרגע:

~/sharkapp/controllers/posts_controller.rb
. . . 
private
. . . 
  def set_post
    @post = Post.find(params[:id])
  end
. . .

על פי השיטות שהשתמשנו בהן במקומות אחרים בקובץ, עלינו לשנות את השיטה הזו כך ש־@post יתייחס למופע מסוים ב־אוסף של הפוסטים המשויכים לצורך ספציפי. חשוב לזכור את השיטה build כאן — בזכות הקישורים בין המודלים שלנו והשיטות (כמו build) שזמינות לנו בשל קישורים אלה, כל אחד מהמופעים שלנו הוא חלק מאוסף של עצמים המשויכים לצורך ספציפי. לכן זה גורם להיות סביר שכאשר אנו פונים לפוסט ספציפי, נבצע שאילתה באוסף הפוסטים המשויכים לצורך ספציפי.

עדכן את set_post כך:

~/sharkapp/controllers/posts_controller.rb
. . . 
private
. . . 
  def set_post
    @post = @shark.posts.find(params[:id])
  end
. . .

במקום למצוא מופע מסוים של כל המחלקה Post לפי id, אנו במקום חופשיים לחפש את ה־id התואם באוסף הפוסטים המשויכים לצורך ספציפי של צורך ספציפי.

עם השיטה המעודכנת הזו, אנחנו יכולים לבדוק את השיטות update ו־destroy.

השיטה update משתמשת במשתנה המופע @post מתוך set_post, ומשתמשת בו עם post_params שהמשתמש הזין בטופס edit. במקרה של הצלחה, אנו רוצים ש־Rails ישלח את המשתמש חזרה לתצוגת ה־index של הפוסטים הקשורים לסוג מסוים של כריש. במקרה של שגיאות, ריילס יציג מחדש את תבנית ה־edit.

במקרה זה, השינוי היחיד שנצטרך לעשות הוא בהצהרת ה־redirect_to, כדי לטפל בעדכונים המוצלחים. עדכנו אותו כך שיפנה ל־shark_post_path(@shark), שיפנה לתצוגת ה־index של הפוסטים של הכריש שנבחר:

~/sharkapp/controllers/posts_controller.rb
. . . 
  def update
    respond_to do |format|
      if @post.update(post_params)
        format.html { redirect_to shark_post_path(@shark), notice: 'Post was successfully updated.' }
        format.json { render :show, status: :ok, location: @post }
      else
        format.html { render :edit }
        format.json { render json: @post.errors, status: :unprocessable_entity }
      end
    end
  end
. . .

לאחר מכן, נעשה שינוי דומה בשיטת destroy. עדכנו את שיטת ה־redirect_to כך שתפנה לבקשות של shark_posts_path(@shark) במקרה של הצלחה:

~/sharkapp/controllers/posts_controller.rb
. . . 
  def destroy
    @post.destroy
     respond_to do |format|
      format.html { redirect_to shark_posts_path(@shark), notice: 'Post was successfully destroyed.' }
      format.json { head :no_content }
    end
  end
. . .

זהו השינוי האחרון שנעשה. כעת יש לך קובץ של בקר פוסטים שנראה כך:

~/sharkapp/controllers/posts_controller.rb
class PostsController < ApplicationController
  before_action :get_shark
  before_action :set_post, only: [:show, :edit, :update, :destroy]

  # GET /פוסטים
  # GET /פוסטים.json
  def index
    @posts = @shark.posts
  end

  # GET /פוסטים/1
  # GET /פוסטים/1.json
  def show
  end

  # GET /פוסטים/new
  def new
    @post = @shark.posts.build
  end

  # GET /פוסטים/1/edit
  def edit
  end

  # POST /פוסטים
  # POST /פוסטים.json
  def create
    @post = @shark.posts.build(post_params)

        respond_to do |format|
         if @post.save  
            format.html { redirect_to shark_posts_path(@shark), notice: 'Post was successfully created.' }
            format.json { render :show, status: :created, location: @post }
         else
            format.html { render :new }
            format.json { render json: @post.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /פוסטים/1
  # PATCH/PUT /פוסטים/1.json
  def update
    respond_to do |format|
      if @post.update(post_params)
        format.html { redirect_to shark_post_path(@shark), notice: 'Post was successfully updated.' }
        format.json { render :show, status: :ok, location: @post }
      else
        format.html { render :edit }
        format.json { render json: @post.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /פוסטים/1
  # DELETE /פוסטים/1.json
  def destroy
    @post.destroy
    respond_to do |format|
      format.html { redirect_to shark_posts_path(@shark), notice: 'Post was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private

   def get_shark
     @shark = Shark.find(params[:shark_id])
   end
    # השתמש ב-callbacks כדי לשתף הגדרה או אילוצים משותפים בין פעולות.
    def set_post
      @post = @shark.posts.find(params[:id])
    end

    # אל תאמן על פרמטרים מהאינטרנט המפחיד, אפשר רק את רשימת ההיתרים דרך.
    def post_params
      params.require(:post).permit(:body, :shark_id)
    end
end

הבקר מנהל איך מידע מועבר מתבניות התצוגה למסד הנתונים ולהיפך. הבקר שלנו משקף כעת את היחס בין מודלי ה־Shark וה־Post שלנו, שבו פוסטים משוייכים לסנפירים מסוימים. אפשר להמשיך לשנות את תבניות התצוגה עצמן, שהן המקום שבו משתמשים יעבירו ויערכו מידע על פוסטים מסוימים שבנוגע לסנפירים מסוימים.

שלב 4 — שינוי תצוגות

התיקונים שלנו בתבניות התצוגה יכללו שינויים בתבניות שקשורות לפוסטים, וגם שינויים בתצוגת ה־show של הסנפירים שלנו, מאחר ונרצה שמשתמשים יראו את הפוסטים המשוייכים לסנפירים מסוימים.

בואו נתחיל עם התבנית היסודית שלנו עבור הפוסטים: חלק ה־form החלקי שמשמש חוזר במספר תבניות פוסט. פתחו את הטופס כעת:

  1. nano app/views/posts/_form.html.erb

במקום להעביר רק את המודל post לעוזר הטופס form_with, נעביר גם את המודלים shark ו־post, עם post מוגדר כמשאב משנה.

שנה את השורה הראשונה של הקובץ כך, כדי לשקף את היחס בין המשאבים שלנו – הכרחיות הערך בין הכרחיות:

~/sharkapp/views/posts/_form.html.erb
<%= form_with(model: [@shark, post], local: true) do |form| %>
. . . 

בשלב הבא, מחק את הקטע שמפרט את shark_id של השרק הקשור, מאחר וזה אינו מידע חיוני בתצוגה.

הטופס הסופי, עם השינויים שביצענו לשורה הראשונה וללא הקטע shark_id שנמחק, ייראה כך:

~/sharkapp/views/posts/_form.html.erb
<%= form_with(model: [@shark, post], local: true) do |form| %>
  <% if post.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(post.errors.count, "error") %> prohibited this post from being saved:</h2>

      <ul>
      <% post.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= form.label :body %>
    <%= form.text_area :body %>
  </div>

  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>

שמור וסגור את הקובץ כאשר תסיים לערוך.

בשלב הבא, פתח את תצוגת ה־index, שתציג את הפוסטים הקשורים לסוג מסוים של פיל.

  1. nano app/views/posts/index.html.erb

בזכות פקודת הפקדה של ריילס, ריילס יצר את רוב התבנית, כולל טבלה המציגה את השדה body של כל פוסט ואת הפיל המשוייך אליו.

מאוד דומה לקוד אחר שכבר שינינו, מבחינת התבנית הזו מטפלת בפוסטים כיישויות עצמאיות, בעוד שנרצה להשתמש ביחסים בין המודלים שלנו ובאוספים ובשיטות העזר שהם נותנים לנו.

בגוף הטבלה, עשה את העדכונים הבאים:

ראשית, עדכן post.shark ל־post.shark.name, כך שהטבלה תכלול את שדה השם של הפיל המשוייך, במקום מידע זיהוי אודות אובייקט הפיל עצמו:

~/sharkapp/app/views/posts/index.html.erb
. . . 
  <tbody>
    <% @posts.each do |post| %>
      <tr>
        <td><%= post.body %></td>
        <td><%= post.shark.name %></td>
. . . 

הבא, שנה את ההפניה של Show כך שתפנה את המשתמשים לתצוגת show עבור השרץ המתאים, מאחר והם כנראה ירצו דרך לחזור לשרץ המקורי. נוכל להשתמש במשתנה האינסטנס @shark שקבענו בבקר כאן, מאחר ו- Rails מציעה משתנים אינסטנס שנוצרו בבקר לכל התצוגות. נשנה גם את הטקסט עבור הקישור מ- Show ל- Show Shark, כך שהמשתמשים יבינו טוב יותר את הפעולה שלו.

עדכן את השורה הזו להיות כמו הבאה:

~/sharkapp/app/views/posts/index.html.erb
. . . 
  <tbody>
    <% @posts.each do |post| %>
      <tr>
        <td><%= post.body %></td>
        <td><%= post.shark.name %></td>
        <td><%= link_to 'Show Shark', [@shark] %></td>

בשורה הבאה, אנו רוצים לוודא שהמשתמשים מופנים לנתיב מקונן כאשר הם רוצים לערוך פוסט. זה אומר שבמקום להוביל אותם אל posts/post_id/edit, המשתמשים יופנו ל sharks/shark_id/posts/post_id/edit. כדי לעשות זאת, נשתמש בעוזר ניתוב shark_post_path ובמודלים שלנו, אותם תטפל Rails ככתובות URL. נשדרג גם את טקסט הקישור כך שהפעולה שלו תהיה ברורה יותר.

עדכן את השורה Edit כך שתיראה כמו הבאה:

~/sharkapp/app/views/posts/index.html.erb
. . . 
  <tbody>
    <% @posts.each do |post| %>
      <tr>
        <td><%= post.body %></td>
        <td><%= post.shark.name %></td>
        <td><%= link_to 'Show Shark', [@shark] %></td>
        <td><%= link_to 'Edit Post', edit_shark_post_path(@shark, post) %></td>

הבא, נוסיף שינוי דומה לקישור ה- Destroy, כדי לעדכן את הפונקציה שלו במחרוזת, ולהוסיף את המשאבים שלנו shark ו- post:

~/sharkapp/app/views/posts/index.html.erb
. . . 
  <tbody>
    <% @posts.each do |post| %>
      <tr>
        <td><%= post.body %></td>
        <td><%= post.shark.name %></td>
        <td><%= link_to 'Show Shark', [@shark] %></td>
        <td><%= link_to 'Edit Post', edit_shark_post_path(@shark, post) %></td>
        <td><%= link_to 'Destroy Post', [@shark, post], method: :delete, data: { confirm: 'Are you sure?' } %></td>

וסוף סוף, בתחתית הטופס, נרצה לעדכן את הנתיב של New Post כך שיקח את המשתמשים לנתיב מקונן כאשר הם רוצים ליצור פוסט חדש. עדכן את השורה האחרונה של הקובץ כך שתשתמש בעוזר ניתוב new_shark_post_path(@shark):

~/sharkapp/app/views/posts/index.html.erb
. . . 
<%= link_to 'New Post', new_shark_post_path(@shark) %>

הקובץ הסופי ייראה כך:

~/sharkapp/app/views/posts/index.html.erb
<p id="notice"><%= notice %></p>

<h1>Posts</h1>

<table>
  <thead>
    <tr>
      <th>Body</th>
      <th>Shark</th>
      <th colspan="3"></th>
    </tr>
  </thead>

  <tbody>
    <% @posts.each do |post| %>
      <tr>
        <td><%= post.body %></td>
        <td><%= post.shark.name %></td>
        <td><%= link_to 'Show Shark', [@shark] %></td>
        <td><%= link_to 'Edit Post', edit_shark_post_path(@shark, post) %></td>
        <td><%= link_to 'Destroy Post', [@shark, post], method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
    <% end %>
  </tbody>
</table>

<br>

<%= link_to 'New Post', new_shark_post_path(@shark) %>

שמור וסגור את הקובץ כאשר אתה מסיים לערוך.

העריכות האחרות שנעשה יהיו פחות מספריות, מאחר שהתצוגות האחרות שלנו משתמשות בקטע ה־form שכבר ערכנו. אך, נרצה לעדכן את ההפניות ל־link_to בתבניות הפוסטים האחרות כדי לשקף את השינויים שביצענו בקטע ה־form שלנו.

פתח את app/views/posts/new.html.erb:

  1. nano app/views/posts/new.html.erb

עדכן את ההפניה ל־link_to בתחתית הקובץ כך שתשתמש בעוזר ה־shark_posts_path(@shark):

~/sharkapp/app/views/posts/new.html.erb
. . . 
<%= link_to 'Back', shark_posts_path(@shark) %>

שמור וסגור את הקובץ כאשר אתה מסיים לעשות את השינוי הזה.

באשף הבא, פתח את התבנית edit:

  1. nano app/views/posts/edit.html.erb

בנוסף לנתיב ה־Back, נעדכן את Show כדי לשקף את המשאבים המקוננים שלנו. שנה את השורות האחרונות של הקובץ כך שיראו כך:

~/sharkapp/app/views/posts/edit.html.erb
. . . 
<%= link_to 'Show', [@shark, @post] %> |
<%= link_to 'Back', shark_posts_path(@shark) %>

שמור וסגור את הקובץ.

באשף הבא, פתח את התבנית show:

nano app/views/posts/show.html.erb

בצע את העריכות הבאות בנתיבי ה־Edit ו־Back בתחתית הקובץ:

~/sharkapp/app/views/posts/edit.html.erb
. . .
<%= link_to 'Edit', edit_shark_post_path(@shark, @post) %> |
<%= link_to 'Back', shark_posts_path(@shark) %>

שמור וסגור את הקובץ כאשר אתה מסיים.

כשלב אחרון, נרצה לעדכן את תצוגת ה־show עבור הכרישים שלנו כך שהפוסטים יהיו גלויים עבור כרישים יחידים. פתח את הקובץ עכשיו:

  1. nano app/views/sharks/show.html.erb

העריכות שלנו כאן תכלול הוספת סעיף Posts לטופס וקישור Add Post בתחתית הקובץ.

למטה מתחת לקטע ה־Facts עבור צורב מסוים, נוסיף מקטע חדש שמשוטט דרך כל המופעים באוסף הפוסטים המשוייכים לצורב זה, ומדפיס את ה־body של כל פוסט.

הוסף את הקוד הבא מתחת לקטע ה־Facts בטופס, ומעל ההפניות בתחתית הקובץ:

~/sharkapp/app/views/sharks/show.html.erb
. . .
<p>
  <strong>Facts:</strong>
  <%= @shark.facts %>
</p>

<h2>Posts</h2>
<% for post in @shark.posts %>
    <ul>
      <li><%= post.body %></li>
  </ul>
<% end %>

<%= link_to 'Edit', edit_shark_path(@shark) %> |
. . . 

לבסוף, הוסף הפניה חדשה כדי לאפשר למשתמשים להוסיף פוסט חדש עבור צורב מסוים זה:

~/sharkapp/app/views/sharks/show.html.erb
. . .
<%= link_to 'Edit', edit_shark_path(@shark) %> |
<%= link_to 'Add Post', shark_posts_path(@shark) %> |
<%= link_to 'Back', sharks_path %>

שמור וסגור את הקובץ כאשר תסיים לערוך.

עכשיו ביצעת שינויים במודלים, בבקרים ובתצוגות של היישום שלך כדי לוודא שפוסטים משוייכים תמיד לצורב מסוים. כצעד אחרון, נוכל להוסיף כמה אימותים למודל שלנו של Post כדי לוודא עקביות בנתונים שמתווספים למסד הנתונים.

שלב 5 — הוספת אימותים ובדיקת היישום

ב שלב 5 של איך לבנות אפליקציית Ruby on Rails, הוספת תיקונים לדגם ה־Shark שלך כדי להבטיח אחידות ועקביות בנתונים שנשמרים במסד הנתונים של sharks. עכשיו נקח צעד דומה כדי להבטיח את האסמים למסד הנתונים של posts.

פתח את הקובץ שבו מוגדר הדגם שלך של Post:

  1. nano app/models/post.rb

כאן, אנו רוצים לוודא שהפוסטים אינם ריקים ושהם לא מכילים תוכן כפול שאחרים יכולים היו פוסטו. כדי להשיג זאת, הוסף את השורה הבאה לקובץ:

~/sharkapp/app/models/post.rb
class Post < ApplicationRecord
  belongs_to :shark
  validates :body, presence: true, uniqueness: true
end

שמור וסגור את הקובץ כאשר תסיים לערוך.

עם השינוי האחרון הזה במקום, אתה מוכן להריץ את ההעברות שלך ולבדוק את האפליקציה.

ראשית, הרץ את ההעברות שלך:

  1. rails db:migrate

לאחר מכן, הפעל את השרת שלך. אם אתה עובד מקומית, אתה יכול לעשות זאת על ידי הרצת:

  1. rails s

אם אתה עובד על שרת פיתוח, הרץ את הפקודה הבאה במקום:

  1. rails s --binding=your_server_ip

נווט אל תיק היישום שלך בכתובת http://localhost:3000 או http://your_server_ip:3000.

המדריך הראשוני לפרויקט Rails הלך איתך דרך הוספת ועריכת רשומת דג גרייט ווייט. אם לא הוספת שום דגים נוספים, דף הנחיתה של האפליקציה ייראה כך:

לחץ על הצג ליד שם השוק הלבן הגדול. זה יביא אותך לתצוגת ה-show עבור הכריש הזה. תראה את שם הכריש ואת העובדות שלו, וכותרת פוסטים ללא תוכן. בוא נוסיף פוסט כדי למלא את חלק זה של הטופס.

לחץ על הוסף פוסט מתחת לכותרת פוסטים. זה יביא אותך לתצוגת ה-index של הפוסט, שם תהיה לך הזדמנות לבחור פוסט חדש:

תודה למנגנון האימות שהצבת ב-שלב 6 של איך לבנות אפליקציית Ruby on Rails, ייתכן שתתבקש לאמת עם שם המשתמש והסיסמה שיצרת בשלב זה, תלוי במידה שבה יצרת סשן חדש.

לחץ על פוסט חדש, שיביא אותך לתבנית ה-new של הפוסט שלך:

בשדה גוף, הקלד, "הכרישים האלה מפחידים!"

לחץ על צור פוסט. תועבר לתצוגת ה-index של כל הפוסטים ששייכים לכריש זה:

עם המשאבים של הפוסטים שלנו פועלים, אנו יכולים עכשיו לבדוק את האימותים שלנו לנתונים כדי לוודא שרק הנתונים הרצויים מתווספים לבסיס הנתונים.

מתוך התצוגה של index, לחץ על פוסט חדש. בשדה גוף של הטופס החדש, נסה להזין שוב "הכרישים האלה מפחידים!":

לחץ על צור פוסט. תראה את השגיאה הבאה:

לחץ על חזרה כדי לחזור לעמוד הראשי של הפוסטים.

כדי לבדוק את האימות השני שלנו, לחץ שוב על פוסט חדש. השאר את הפוסט ריק ולחץ על צור פוסט. תראה את השגיאה הבאה:

עם המשאבים המקוננים שלך והאימות העובד כראוי, יש לך כעת יישום Rails פעיל שבו ניתן להשתמש כנקודת התחלה לפיתוח נוסף.

מסקנה

עם היישום שלך ב- Rails במקום, כעת ניתן לעבוד על דברים כמו עיצוב ופיתוח מרכיבי קידמה אחרים. אם ברצונך ללמוד עוד על מערכת הניתוב והמשאבים המקוננים, תיעוד Rails הוא המקום המושלם להתחיל.

כדי ללמוד עוד על אינטגרציה של מסגרות עבודה קדמית עם היישום שלך, תסתכל על איך להגדיר פרויקט Ruby on Rails עם קדמה React.

Source:
https://www.digitalocean.com/community/tutorials/how-to-create-nested-resources-for-a-ruby-on-rails-application