لماذا يختلف السلوك النموذجي. يختلف السلوك في بيئة منتشرة عن ذلك في بيئة تطوير؟

StackOverflow https://stackoverflow.com/questions/2214367

سؤال

باستخدام Ruby على القضبان مجتمعة مع Capistrano و Git، لقد واجهت مشكلة مزعجة ..

لدي جهاز تحكم "أشخاص" مع إجراء الفهرس الذي يبدو شيئا مثل هذا:

def index
  @people = Person.find( :conditions => params[:search] )
end

هناك عمود "is_admin" المنطقي في طاولة الشخص. على افتراض أن بعض الأشخاص هم المسؤولون وبعضهم لا يدعون http: // localhost: 3000 / people؟ البحث [is_admin] = صحيح يجب ملء @اشخاص مع بعض المستخدمين ... وهذا صحيح لجهاز الكمبيوتر المحلي الخاص بي عندما أقوم بتشغيل التطبيق في تطوير الوضع..

ولكن .... عندما نشرت في حساب الخادم الخاص بي (Railsplaygrayground)، اتصل http://mydomain.com/people؟Search Budris_Adminpline=== فشل في العثور على أي عناصر مطابقة. ومع ذلك، إذا غيرت ...؟ البحث [is_admin] = صحيح ل ...؟ البحث [is_admin] = 1 ترجع الاستجابة مستخدمي المسؤول كما هو متوقع ...

مرة أخرى على جهاز الكمبيوتر المحلي الخاص بي، فإن استخدام "1" بدلا من "صحيح" فشل.

خلاصة القول هو ذلك

Person.find( :all, :conditions => { :is_admin => 'true' } )

يعمل بيئة تطوير بلدي، و

Person.find( :all, :conditions => { :is_admin => 1 } )

يعمل في بيئتي المنشورة.

لماذا هذا؟ وكيف يمكنني إصلاحه؟

من الناحية المثالية، أود وضع روابط مثل:

link_to( "Administrators", {
  :controller => '/people',
  :action => :index,
  :search => { :is_admin => true }
})

والحصول على قوائم المسؤولين :).

قد تكون جديرة بالملاحظة أن قاعدة بيانات التطوير الخاصة بي هي ملف SQLite3، والإنتاج عبارة عن قاعدة بيانات MySQL ...

تحرير: أفهم الاعتراضات على إدخال المستخدم، ولكن في هذه الحالة الاستثنائية، فإنه تهديد بسيط للغاية. أيضا، يعمل الرمز الحالي الخاص بي تماما في جهاز الكمبيوتر الخاص بي أو حساب الإنتاج الخاص بي، ولكن ليس على كليهما. يبدو أن أسهل التقدير لتغيير الطريقة التي يحفظها SQLite3 وقيم المنطقية، لذلك أود أن أغير سؤالي "كيف يمكنني تغيير الطريقة التي يوفرها SQLite قيم منطقية" ... إذا كان SQLite من شأنه أن يحاكي سلوك MySQL بشكل مثالي، فسيخدم تطوراتي يحتاج تماما ...

هل كانت مفيدة؟

المحلول

المشكلة هي أنك تمر بقيمة منطقية كسلسلة، ويعتمد السلوك النهائي على قاعدة البيانات النشطة. إليك شرح أكثر تفصيلا.

عندما تقرأ params[:search] متغير، المحتوى هو سلسلة وليس هناك نوع. وذلك لأن سلسلة الاستعلام لا تستطيع فهم ما إذا كان

params[:search][:is_admin] = "true"

يعني فعلا

params[:search][:is_admin] = "true"
params[:search][:is_admin] = true

وبالمثل، عندما تمر 1 ينتهي بك الأمر

params[:search][:is_admin] = "1"

وهو مختلف

params[:search][:is_admin] = 1

عند تمرير القيمة إلى الاستعلام، لأنك لا تمرغل منطقي، لا ترجمت القيمة بواسطة محول قاعدة البيانات. استفسارك النهائي يؤدي إلى شيء مثل

SELECT * FROM `persons` WHERE `persons.is_admin` = 'true'

مخازن SQLITE3 منطقية باسم T / F سلاسل. true يتم تخزينه كما 't' و false يتم تخزينه كما 'f'. وبعد أعتقد أنه يفهم أيضا صحيحا / خطأ وترجم تلقائيا استفسارك. على العكس، يفهم MySQL فقط 0/1 وحقيقية / خطأ وفشل.

عند تشغيل السلوك، تمر 1 بدلاً من true, ، أنت تسبب فشل SQLite لأنه لا يمكن ترجمة السلسلة "1" ل 't'. وبعد على العكس، يمكن mysql ولا يفعل ذلك.

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

اقتراحي هو تطبيع الخاص بك params[:search] قبل التغذية Person.find.

نصائح أخرى

أعتقد أن الفرق بين استخدام SQLite و MySQL هو سبب مشكلتك.

ولكن السماح بسجل نشط مشروط يتم تمريره مباشرة من سلسلة الاستعلام يبدو وكأنه فكرة سيئة بالنسبة لي، ويمكن أن يترك تطبيقك مفتوحا إلى هجمات حقن SQL.

يشرح الإجابة Simone لماذا تحصل على مثل هذا السلوك. للحصول على النتيجة الصحيحة في كل من SQLite3 و MySQL يجب أن تمر:

Person.find( :all, :conditions => { :is_admin => true } )

إذا كان لديك مستوى واحد فقط من المعلمات (لديك params[:search][:something] ولكن لا شيء أعمق) مما يمكنك إنشاء التجزئة الصحيحة مع ظروف مثل هذا:

my_conditions = Hash.new
params[:search].each do |item, value|
  my_conditions[item.to_sym] = value == 'true' ? true : value == 'false' ? false : value
end

سوف يتكرر جميع معارقة البحث وسوف تتغير كل شيء 'true' ل true و 'false' ل false. وبعد إذا كانت هناك قيمة أخرى، فسوف يترك الأمر كما هو. بالطبع يمكنك وضع هنا أي منطق تريده. إذا كان سيحصل على أكثر تعقيدا مما يمكنك إعادة كتابةه if أو مع switch.

مما تستطيع:

Person.all(:conditions => my_conditions)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top