الجمعيات متعددة الأشكال القضبان بالإضافة إلى الطرق
-
20-09-2019 - |
سؤال
لدي نموذج ، تقرير ، وهو متعدد الأشكال. قد يكون لدى الكثير من العوامل في موقعي الكثير منها.
وأود أن يكون لديك وحدة تحكم عامة لنشرها. إنه نموذج بسيط للغاية ، وله رسالة نصية فقط والرابطة.
في طريقي ، أنا أفعل شيئًا مثل
map.resources :users, :has_many => [ :reports ]
map.resources :posts, :has_many => [ :reports ]
لكن في تقريري _controller ، أود الحصول على العلاقة من قبل.
مثل:
before_filter :get_reportable
def get_reportable
reportable = *reportable_class*.find params[:reportable_id]
end
هل هذا ممكن؟
كيف يمكنني الحصول على تقرير _class و identable_id؟
يمكنني الحصول على params [: user_id] عندما يأتي من وحدة تحكم المستخدمين ، أو params [: post_id] عندما يأتي من المنشورات. يمكنني القيام بحالة مع كل العلاقات ، لكنها لا تبدو حلًا نظيفًا على الإطلاق ...
وجود جمعية متعددة الأشكال سيكون الأفضل ، هل هناك أي كيفية؟
المحلول
إذا كان لديك وحدة تحكم واحدة تعالج الطلبات من خلال مسارين مختلفين ، فأنت بحاجة إلى إدراكها للسياقات التي سيتم استدعاؤها. غالبًا ما ترى الكثير من التعليمات البرمجية التي تبدو مثل هذا:
before_filter :load_reportable
def load_reportable
if (params[:user_id])
@user = User.find(params[:user_id])
@reportable = @user
elsif (params[:post_id])
@post = Post.find(params[:post_id])
@reportable = @post
end
rescue ActiveRecord::RecordNotFound
render(:partial => 'not_found', :status => :not_found)
return false
end
نظرًا لأنك تستخدم ارتباطًا متعدد الأشكال ، فقد تتمكن من القيام بشيء مثل هذا بدلاً من ذلك:
before_filter :load_reportable
def load_reportable
unless (@reportable = @report.reportable)
# No parent record found
render(:partial => 'not_found', :status => :not_found)
return false
end
# Verify that the reportable relationship is expressed properly
# in the path.
if (params[:user_id])
unless (@reportable.to_param == params[:user_id])
render(:partial => 'user_not_found', :status => :not_found)
return false
end
elsif (params[:post_id])
unless (@reportable.to_param == params[:post_id])
render(:partial => 'post_not_found', :status => :not_found)
return false
end
end
end
إن المشكلة في هذا النهج ، حيث لديك وحدة تحكم واحدة تخدم طريقين مختلفين تمامًا ، هي أن إنشاء رسائل خطأ ، مثل "المستخدم لم يتم العثور عليه" مقابل "Post Not Found". قد يكون هذا أمرًا صعبًا إذا لم تكن ترث من المستخدمين :: basecontroller ، على سبيل المثال.
في كثير من الحالات ، من الأسهل إنشاء وحدات تحكم "تقريرين" مستقلين ، مثل المستخدمين/التقارير والمنشورات/التقارير ، حيث يتم استيراد أي وظيفة مشتركة من وحدة نمطية. عادة ما ترث وحدات التحكم هذه من وحدة تحكم قاعدة تنفذ التحميل والتعامل مع الأخطاء. يمكن لجهاز التحكم الأساسي أيضًا إنشاء تخطيط وعنوان الصفحة وما إلى ذلك ، دون الحاجة إلى إعادة تنفيذ هذه الوظيفة لكل وحدة تحكم من الموارد الفرعية.
البديل هو إلغاء تقارير التقارير وجعلها تعمل كوحدة تحكم خاصة بها حيث تكون العلاقة مع السجل "القابل للإبلاغ" غير ذي صلة في الغالب.
نصائح أخرى
أو حاول ذلك:
before_filter :get_reportable
def get_reportable
params.each do |name, value|
if name =~ /(.+)_id$/
@reportable = $1.classify.constantize.find(value)
end
end
end
إنها تمر بجميع المعلمات ويحاول العثور على نهاية واحدة مع _id ، ثم يمسك بذلك قبل الجزء ويجد السجل ذي الصلة.