סקופים ב Rails הם סוג של פונקציות סטטיות שמאפשרות להגדיר שאילתות שחוזרות על עצמן בתוך מודלים, שזה מה שמייצג טבלאות. לדוגמה אם יש לי טבלה של פתקים אוכל להגדיר במודל Note את הסקופ:
scope :latest, -> { order(created_at: :desc) }
ואז פקודת ה order by תצורף לשאילתה. עד לפה הכל קל, עכשיו נסתכל על סקופ יותר מסובך:
scope :with_questions, ->() {
where("questions is not null and cardinality(questions) > 0")
}
פה יש לנו טבלה עם עמודה בשם questions שהיא עמודה מסוג מערך ואנחנו מחפשים שורות שעבורן מוגדרות שאלות.
הבעיה עם הסקופ השני היא שהוא משתמש בתבנית מסוכנת ויישבר בקלות. אחרי שבעטתי קצת ב ChatGPT הוא הסכים לראות למה זה שבור וגם לייצר לי קוד לדוגמה. הרעיון הוא שאם נחבר את המודל עם מודל אחר ב JOIN ובמקרה גם למודל האחר יש עמודת questions אז השאילתה תהיה דו משמעית. נדמיין:
MyModel.joins(:other_table).with_questions
ונדמיין שגם ל other_table יש עמודה בשם questions. עכשיו מקבלים את ה SQL:
SELECT "my_models".* FROM "my_models"
INNER JOIN "other_table" ON "other_table".my_model_id = "my_models".id
WHERE questions IS NOT NULL AND cardinality(questions) > 0
ואם לשתי הטבלאות יש עמודת questions נקבל שגיאה:
ERROR: column reference "questions" is ambiguous
התיקון הוא פשוט אבל הכי טוב לזכור את הטיפ הכללי - כשכותבים scope שכולל SQL כדאי לצרף את שם הטבלה, כלומר נגדיר את הסקופ:
scope :with_questions, ->() {
where("quizzes.questions IS NOT NULL AND cardinality(quizzes.questions) > 0")
}