القضبان:تعارض الموارد المتداخلة، وكيفية تحديد نطاق إجراء الفهرس اعتمادًا على المسار المطلوب
-
06-07-2019 - |
سؤال
تخيل أن لديك طريقين محددين:
map.resources articles
map.resources categories, :has_many => :articles
كلاهما يمكن الوصول إليهما عن طريق المساعدين/المسارات
articles_path # /articles
category_articles_path(1) # /category/1/articles
إذا قمت بزيارة /articles
, index
العمل من ArticlesController
يتم تنفيذ.
إذا قمت بزيارة /category/1/articles
, index
العمل من ArticlesController
يتم تنفيذه أيضًا.
إذًا، ما هو أفضل أسلوب للاختيار المشروط للمقالات المحددة فقط اعتمادًا على مسار الاستدعاء؟
#if coming from the nested resource route
@articles = Articles.find_by_category_id(params[:category_id])
#else
@articles = Articles.all
المحلول
لديك خيارين هنا، وهذا يتوقف على مقدار المنطق وجهة نظركم مرتبط النطاق. اسمحوا لي أن أشرح أكثر من ذلك.
والخيار الأول هو لتحديد نطاق داخل جهاز تحكم، كما سبق شرحه في الردود الأخرى. أنا عادة تعيين متغيرscope للحصول على بعض المزايا الإضافية في قوالب بلدي.
class Articles
before_filter :determine_scope
def index
@articles = @scope.all
# ...
end
protected
def determine_scope
@scope = if params[:category_id]
Category.find(params[:category_id]).articles
else
Article
end
end
end
والسبب في المتغيرscope هو أنك قد تحتاج إلى معرفة نطاق طلبك خارج عمل واحد. دعنا نفترض أنك ترغب في عرض عدد السجلات في وجهة نظركم. عليك أن تعرف ما إذا كنت يتم تصفية حسب الفئة أم لا. في هذه الحالة، يمكنك ببساطة تحتاج إلى استدعاء @scope.count
أو @scope.my_named_scope.count
بدلا من تكرار كل مرة الاختيار على params[:category_id]
.
وهذا النهج يعمل بشكل جيد إذا وجهات نظركم، واحد مع فئة واحدة دون فئة، هي مماثلة تماما. ولكن ماذا يحدث عندما إدراج تصفيتها حسب الفئة هي مختلفة تماما مقارنة مع واحد من دون فئة؟ يحدث هذا في كثير من الأحيان: يعرض القسم الفئة الخاصة بك بعض الحاجيات التي تركز على فئة بينما القسم مقالك بعض الحاجيات ذات الصلة المادة والتصفية. أيضا، وتحكم المادة لديه بعض before_filters خاص قد ترغب في استخدام، ولكن لم يكن لديك لاستخدامها عندما ينتمي إدراج المادة إلى فئة.
في هذه الحالة، قد ترغب في فصل الإجراءات.
map.resources articles
map.resources categories, :collection => { :articles => :get }
articles_path # /articles and ArticlesController#index
category_articles_path(1) # /category/1/articles and CategoriesController#articles
والآن تدار القائمة التي تمت تصفيتها حسب الفئة التي CategoriesController
ويرث جميع المرشحات تحكم، وتخطيطات، وإعدادات ... في حين تتم إدارة الإدراج غير المرشحة من قبل ArticlesController
.
وهذا عادة ما يكون خياري المفضل لأنك لم يكن لديك مع اتخاذ إجراءات إضافية لفوضى وجهات نظركم والتحكم مع طن من الشيكات المشروطة.
نصائح أخرى
كثيرا ما أحب أن أفصل بين تلك الأفعال.عندما تكون الإجراءات الناتجة متشابهة جدًا، يمكنك فصل النطاقات داخل وحدة التحكم بسهولة من خلال معرفة ما إذا كانت المعلمات [:category_id] موجودة وما إلى ذلك (راجع إجابة @SimoneCarletti).
عادةً ما يمنحك فصل الإجراءات في وحدة التحكم باستخدام المسارات المخصصة أقصى قدر من المرونة والنتائج الواضحة.ينتج عن التعليمات البرمجية التالية أسماء مساعد توجيه عادية ولكن يتم توجيه المسارات إلى إجراءات محددة في وحدة التحكم.
في الطرق.rb:
resources categories do
resources articles, :except => [:index] do
get :index, :on => :collection, :action => 'index_articles'
end
end
resources articles, :except => [:index] do
get :index, :on => :collection, :action => 'index_all'
end
ثم يمكنك الدخول المقالاتController.rb
def index_all
@articles = @articles = Articles.all
render :index # or something else
end
def index_categories
@articles = Articles.find_by_category_id(params[:category_id])
render :index # or something else
end
وبعد فقط مورد متداخلة واحد، وذلك باستخدام مشروطة على أساس بارامس لتحديد انها لن نطاق يكون النهج أسهل. وهذا هو الأرجح وسيلة للذهاب في قضيتك.
if params[:category_id]
@articles = Category.find(params[:category_id]).articles
else
@articles = Article.all
end
ومع ذلك، اعتمادا على ما غيرها من الموارد متداخلة لديك لنموذج، وإصرارها على هذا النهج يمكن الحصول على مملة جدا. في هذه الحالة، وذلك باستخدام البرنامج المساعد مثل resource_controller أو <وأ href = "http://github.com / hcatlin / make_resourceful "يختلط =" نوفولو noreferrer "> سوف make_resourceful جعل هذا أبسط من ذلك بكثير.
class ArticlesController < ResourceController::Base
belongs_to :category
end
وهذا سوف تفعل في الواقع كل شيء كنت تتوقع. فهو يوفر لك جميع الإجراءات راحة القياسية وتلقائيا الإعداد نطاق /categories/1/articles
.
if params[:category_id].blank?
# all
else
# find by category_id
end
وأود أن تنظر في الإجراءات مستقلة عن الطريق. بغض النظر عن مدى وصولهم إلى هناك، وجعل قرار معقول حول ما يجب القيام به.