سؤال

لدي مشروع رايلس 3. مع القضبان 3 جاء Arel والقدرة على إعادة استخدام نطاق واحد لبناء آخر. أتساءل عما إذا كانت هناك طريقة لاستخدام النطاقات عند تحديد علاقة (مثل "has_many").

لدي سجلات لها أعمدة الأذونات. أرغب في بناء Default_scope الذي يأخذ أعمدة الإذن في الاعتبار حتى يتم تصفية السجلات (حتى تلك التي تم الوصول إليها عبر العلاقة).

في الوقت الحاضر، في القضبان 3، Default_scope (بما في ذلك التصحيحات التي وجدتها) لا تقدم وسيلة عملية تمرير Proc (التي أحتاجها للتغلب المتغير المتأخر). هل من الممكن تحديد has_many التي يمكن أن يتم فيها تمرير نطاق اسمه؟

فكرة إعادة استخدام نطاق اسمه ستبدو:

Orders.scope :my_orders, lambda{where(:user_id => User.current_user.id)}
has_many :orders, :scope => Orders.my_orders

أو التشفير الضمني الذي يدعى النطاق في العلاقة سيبدو كما يلي:

has_many :orders, :scope => lambda{where(:user_id => User.current_user.id)}

أنا ببساطة أحاول تطبيق Default_scope مع الربط المتأخر. أفضل استخدام نهج Arel (إذا كان هناك واحد)، ولكن سيستخدم أي خيار عملي.

منذ أن أشير إلى المستخدم الحالي، لا يمكنني الاعتماد على الشروط التي لا يتم تقييمها في اللحظة الأخيرة الممكنة، مثل:

has_many :orders, :conditions => ["user_id = ?", User.current_user.id]
هل كانت مفيدة؟

المحلول

أقترح عليك إلقاء نظرة على "نطاقات المسماة ميتة"

يشرح المؤلف هناك مدى قوة Arel هو :)

آمل أن تساعد.

تحرير رقم 1 مارس 2014

كما ذكرت بعض التعليقات، فإن الفرق هو الآن مسألة ذوق شخصي.

ومع ذلك، ما زلت أوصي شخصيا بتجنب تعريض نطاق AREL إلى طبقة علوية (كونها وحدة تحكم أو أي شيء آخر يمكن أن يصل إلى الطرز مباشرة)، والقيام بذلك يتطلب:

  1. إنشاء نطاق، وفضحه من خلال طريقة في النموذج الخاص بك. ستكون هذه الطريقة هي التي تعرضها لوحدة التحكم؛
  2. إذا لم تعرض النماذج الخاصة بك أبدا إلى وحدات التحكم الخاصة بك (حتى يكون لديك نوع من طبقة الخدمة على رأسها)، فأنت بخير. طبقة مكافحة الفساد يكون خدمتك ويمكنها الوصول إلى نطاق النموذج الخاص بك دون القلق أكثر من الكثير حول كيفية تنفيذ النطاقات.

نصائح أخرى

ماذا عن ملحقات الرابطة؟

class Item < ActiveRecord::Base
  has_many :orders do
    def for_user(user_id)
      where(user_id: user_id)
    end
  end
end

Item.first.orders.for_user(current_user)

UPDATE: أود أن أشير إلى ميزة ملحقات الجمعيات بدلا من طرق الفصل أو النطاقات هي أن لديك إمكانية الوصول إلى Internals of the Capsivity Proxy:

proxy_association.owner إرجاع الكائن الذي تعد الجمعية جزءا منه. proxy_association.reflection إرجاع كائن الانعكاس الذي يصف الجمعية. Broxy_association.target إرجاع الكائن المرتبط بانهلاك_to أو HAD_ONE، أو مجموعة الكائنات المرتبطة به للحصول على has_many أو has_and_belongs_to_many.

مزيد من التفاصيل هنا: http://guides.rubyonrails.org/association_basics.html#association-extenses.

بدلا من النطاقات التي كنت أعرف فقط أساليب الطبقة، والتي كانت تعمل بشكل رائع

def self.age0 do
  where("blah")
end

يمكنني استخدام شيء مثل:

class Invoice < ActiveRecord::Base
  scope :aged_0,  lambda{ where("created_at IS NULL OR created_at < ?", Date.today + 30.days).joins(:owner) }
end 

يمكنك استخدام دمج الطريقة من أجل دمج النطاقات من نماذج مختلفة. لمزيد من التفاصيل ابحث عن دمج في هذا Railscast.

إذا كنت تحاول فقط الحصول على أوامر المستخدم، فلماذا لا تستخدم العلاقة فقط؟

يفترض أن المستخدم الحالي يمكن الوصول إليه من طريقة Current_User في وحدة التحكم الخاصة بك:

@my_orders = current_user.orders

هذا يضمن عرض أوامر مستخدم خاصة للمستخدم فقط. يمكنك أيضا القيام بنواب متداخلة تعسفا للحصول على موارد أعمق باستخدام joins

current_user.orders.joins(:level1 => { :level2 => :level3 }).where('level3s.id' => X)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top